# `application/flows.py` ## Propósito Orquesta el procesamiento por radicado para: - Calcular encabezados CSV unificados a partir de muestras y selección de campos. - Extraer información de factura y, opcionalmente, preformato. - Escribir filas en CSV y emitir JSON a la interfaz gráfica mediante callbacks. Incluye una heurística para inferir qué listas deben expandirse por filas y cuáles agregarse como columnas (en preformato). ## API pública ### `compute_csv_header_union(...) -> tuple[list[str] | None, dict[str, str]]` Calcula el encabezado CSV común (unión) desde datos de muestra y paths seleccionados, aplicando alias y resolviendo duplicados. Parámetros clave: - `sample_fact`, `sample_pre`: ejemplos (dict o compatible) para derivar columnas. - `selected_fields_fact`, `selected_fields_pre`: paths seleccionados por documento. - `pre_enabled`: habilita el cálculo para preformato. - `alias_map_fact`, `alias_map_pre`: alias opcionales path->nombre. Devuelve: - Lista de encabezados finales (o `None` si no hay columnas). - Mapa `path -> alias final` aplicado. Notas: - `radicado` siempre se incluye como columna. - Duplicados de alias se desambiguarán con sufijos `(n)`. ### `process_radicados_parallel(...) -> None` Procesa en paralelo los radicados, realizando: 1) Extracción de datos de factura y preformato (si está habilitado). 2) Emisión de JSON via `on_output`. 3) Escritura incremental en CSV con encabezado dado (`csv_header_union`) o derivado. Parámetros clave: - `service`: Debe exponer `extract_full_from_pdf(...)` y `_append_rows_to_csv(...)`. - `root`, `keywords`, `pre_keywords`: Búsqueda de documentos por radicado. - `selected_fields_fact`, `selected_fields_pre`: paths de salida. - `csv_path`: Archivo CSV destino (si `None`, no escribe). - `on_output`: Callback que recibe texto JSON por radicado. - `on_progress`: Callback `(radicado, done, total)` para progreso. - `instruction_invoice`, `instruction_pre`: instrucciones LLM. - `alias_final_map`: alias finales a aplicar a encabezados/filas. Concurrencia: - Usa `ThreadPoolExecutor` con `max_workers=4` para balancear IO/CPU. - Los errores por documento se capturan y se registran sin detener el flujo. ## Consideraciones - Si se define `csv_header_union`, éste manda sobre encabezados derivados por radicado. - Para preformato, la heurística `_infer_aggregate_list_paths_from_selected` selecciona la lista principal y las listas a agregar; si no hay inferencia, se consulta `profiles`. - `on_output` y `on_progress` son opcionales y tolerantes a errores (capturados). ## Ejemplos ### Cálculo de encabezado ```python from application.flows import compute_csv_header_union header, alias_map = compute_csv_header_union( sample_fact={'radicado': 'x', 'items': [{'codigo': 'A1', 'cantidad': 2}]}, sample_pre=None, selected_fields_fact=['radicado', 'items/*/codigo', 'items/*/cantidad'], selected_fields_pre=None, pre_enabled=False, ) # header ~= ['radicado', 'items/*/codigo', 'items/*/cantidad'] ``` ### Proceso por radicado (escritura CSV) ```python from application.flows import process_radicados_parallel process_radicados_parallel( service=my_service, # Debe implementar extract_full_from_pdf y _append_rows_to_csv root="C:/carpeta/raiz", keywords=["FACTURA", "RADICADO"], pre_enabled=True, pre_keywords=["PREFORMATO"], selected_fields_fact=['radicado', 'items/*/codigo', 'items/*/cantidad'], selected_fields_pre=['radicado', 'dx/*/descripcion'], csv_path="salida.csv", on_output=lambda txt: print(txt), on_progress=lambda r,d,t: print(f"{d}/{t} -> {r}"), ) ```