feat: Implement moderadora preferences management and enhance CSV cleaning rules for COP/MOD separation. Introduce new GUI components for moderadora settings, including default values and user input handling. Update application preferences to support new extraction models and improve overall user experience in data processing.
This commit is contained in:
@@ -69,6 +69,89 @@ def _get_at_path(obj: Any, path: str) -> Any:
|
||||
return cur
|
||||
|
||||
|
||||
def set_at_path(root: Dict[str, Any], path: str, value: Any) -> None:
|
||||
"""Asigna ``value`` en ``root`` siguiendo la ruta con segmentos ``/`` (crea dicts intermedios)."""
|
||||
parts = [p for p in path.split('/') if p]
|
||||
if not parts:
|
||||
return
|
||||
cur: Any = root
|
||||
for p in parts[:-1]:
|
||||
if not isinstance(cur, dict):
|
||||
return
|
||||
nxt = cur.get(p)
|
||||
if not isinstance(nxt, dict):
|
||||
cur[p] = {}
|
||||
nxt = cur[p]
|
||||
cur = nxt
|
||||
if isinstance(cur, dict):
|
||||
cur[parts[-1]] = value
|
||||
|
||||
|
||||
def _resolve_raw_string_for_scalar_path(raw: Dict[str, Any], path: str) -> tuple[Optional[str], bool]:
|
||||
"""Resuelve un string en ``raw`` para la ruta canónica ``path``.
|
||||
|
||||
Devuelve ``(valor, ambiguous)``. Si ``ambiguous`` es True, no debe usarse ningún valor
|
||||
(varias claves aplanadas comparten el último segmento del path).
|
||||
"""
|
||||
direct = _get_at_path(raw, path)
|
||||
if isinstance(direct, str) and direct.strip():
|
||||
return direct, False
|
||||
|
||||
parts = [p for p in path.split('/') if p]
|
||||
if not parts:
|
||||
return None, False
|
||||
last = parts[-1]
|
||||
raw_flat = flatten_non_list_fields(raw)
|
||||
same_last: List[tuple[str, str]] = []
|
||||
for k, v in raw_flat.items():
|
||||
if not isinstance(v, str) or not v.strip():
|
||||
continue
|
||||
segs = [s for s in k.split('/') if s]
|
||||
if not segs:
|
||||
continue
|
||||
if segs[-1] == last:
|
||||
same_last.append((k, v))
|
||||
if len(same_last) == 1:
|
||||
return same_last[0][1], False
|
||||
if len(same_last) > 1:
|
||||
return None, True
|
||||
return None, False
|
||||
|
||||
|
||||
def merge_verbatim_long_strings(
|
||||
raw: Dict[str, Any],
|
||||
normalized: Dict[str, Any],
|
||||
paths: Optional[List[str]],
|
||||
) -> Dict[str, Any]:
|
||||
"""Sustituye en ``normalized`` cadenas truncadas por la versión más larga del ``raw`` (misma ruta o sufijo único).
|
||||
|
||||
Solo actúa sobre rutas escalares (sin ``*``). Evita sustituciones cuando hay varias claves
|
||||
candidatas con el mismo último segmento o cuando el texto normalizado no parece un prefijo
|
||||
del crudo (salvo cadena vacía o solo espacios).
|
||||
"""
|
||||
if not isinstance(normalized, dict) or not isinstance(raw, dict):
|
||||
return normalized
|
||||
for path in paths or []:
|
||||
if not path or '*' in path:
|
||||
continue
|
||||
norm_val = _get_at_path(normalized, path)
|
||||
if not isinstance(norm_val, str):
|
||||
continue
|
||||
raw_val, ambiguous = _resolve_raw_string_for_scalar_path(raw, path)
|
||||
if ambiguous or raw_val is None:
|
||||
continue
|
||||
if len(raw_val) <= len(norm_val):
|
||||
continue
|
||||
nt = norm_val.strip()
|
||||
if nt:
|
||||
if nt not in raw_val:
|
||||
lim = min(80, len(nt))
|
||||
if lim == 0 or not raw_val.startswith(nt[:lim]):
|
||||
continue
|
||||
set_at_path(normalized, path, raw_val)
|
||||
return normalized
|
||||
|
||||
|
||||
def aggregate_list_fields(data: Dict[str, Any], aggregate_paths: List[str]) -> Dict[str, Any]:
|
||||
aggregated: Dict[str, Any] = {}
|
||||
for base_path in aggregate_paths:
|
||||
|
||||
Reference in New Issue
Block a user