NOVA3 Pro
Manual de Usuario
Portal de control de costes industriales con extracción automática de facturas por IA y análisis de precios de materiales.
1. Qué es NOVA3 Pro
NOVA3 Pro es una aplicación web de escritorio construida con Streamlit orientada al control de costes de materiales industriales. Sus tres ejes principales son:
| Eje | Descripción |
|---|---|
| Extracción | Procesa facturas en PDF de forma automática mediante OCR + LLM local (Ollama) |
| Análisis | Genera estadísticas de gasto por proveedor, evolución temporal de precios y comparativas entre grupos de materiales |
| Mercado | Lanza un agente que busca precios en internet (DuckDuckGo + OpenAI) y permite etiquetar nuevos proveedores |
2. Arquitectura general
PDFs nuevos
│
▼
invoices_in/ ← carpeta de entrada
│
▼ (botón "Procesar" en Dashboard)
process.sh
│
▼
.agent/skills/invoice-router/
scripts/process_invoices.py
│
├── invoice-preprocess → extrae texto del PDF (PyPDF)
├── invoice-router → detecta proveedor, parsea, valida
└── csv_export → escribe CSVs y JSONs de salida
│
├── out/invoices.csv → cabeceras de facturas
├── out/invoice_lines.csv → líneas de detalle
├── facturas_revisadas/ → PDFs procesados con éxito
└── facturas_error/ → PDFs que fallaron validación
│
▼
app.py (Streamlit UI) ← lee los CSVs y JSONs, presenta la interfaz
La aplicación no usa base de datos SQL. Todo el estado persiste en archivos CSV y JSON en la carpeta out/.
3. Modelo de datos
Archivos principales
| Archivo | Contenido |
|---|---|
out/invoices.csv | Una fila por factura: invoice_key, invoice_number, invoice_date, provider_name, total_amount, source_file |
out/invoice_lines.csv | Una fila por línea de factura: invoice_key, product_name, quantity, unit_price, line_total |
out/confirmed_prices.json | Precios validados manualmente: {material, category, price, provider, date} |
out/tagged_providers.json | Red de proveedores web: {"Nombre": {"status": "Alta"/"Baja", "link": "...", "date_included": "..."}} |
out/grouped_materials.json | Grupos de materiales: {"Nombre grupo": {"members": ["variante1", "variante2", ...]}} |
Relaciones
invoices (invoice_key) ──< invoice_lines (invoice_key)
invoice_lines (product_name) ──> grouped_materials (members)
4. Pipeline de extracción de facturas
Flujo paso a paso
- Depósito: coloca los PDFs en
invoices_in/ - Disparo: pulsa "Procesar Nuevas Facturas" en el Dashboard
- Hash SHA-256: el sistema comprueba si la factura ya fue procesada (idempotencia)
- OCR / extracción de texto:
invoice-preprocessusa PyPDF para leer el texto - Detección de proveedor:
provider_registrypuntúa cada parser disponible y elige el de mayor score (umbral mínimo: 0.3) - Parseo: el parser seleccionado extrae campos estructurados (número, fecha, proveedor, líneas)
- Normalización: fechas, importes y cantidades se normalizan a tipos Python estándar
- Validación contable: comprueba que suma de líneas ≈ total factura
- Exportación: se añade al CSV si pasa validación; si no, va a
out/review/para revisión manual - Clasificación de archivo: éxito →
facturas_revisadas/, error →facturas_error/
Parsers disponibles
| Skill | Función |
|---|---|
invoice-parse-generic | Parser genérico usando Ollama (gemma4:latest) para cualquier formato desconocido |
invoice-parse-vendor-template | Parsers específicos por proveedor: LECU, LLAVE, IDELLA, vendor_b |
invoice-preprocess | Extracción de texto puro del PDF |
invoice-router | Orquestador del pipeline completo |
5. Páginas de la aplicación
5.1 Dashboard
Propósito: visión global y punto de entrada de procesamiento.
KPIs en cabecera:
- Facturas procesadas totales
- Importe total acumulado
- Número de proveedores distintos
- Archivos pendientes en
invoices_in/
Botón "Procesar Nuevas Facturas": ejecuta process.sh, muestra un resumen diferencial (cuántas facturas nuevas, materiales añadidos, errores) y recarga la interfaz.
Grid de proveedores: tarjetas con nombre, total de facturas y fecha de última actividad. Cada tarjeta tiene un expander con el listado de facturas del proveedor y botón de descarga del PDF original.
5.2 Proveedores
Propósito: análisis detallado por proveedor.
- Selector global de proveedor
- Pestaña "Listado de Facturas": tabla con todas las facturas del proveedor seleccionado
- Pestaña "Análisis de Materiales": editor interactivo donde se puede asignar categoría y confirmar el precio unitario de cada material. Al pulsar "Confirmar Precios", los datos se escriben en
confirmed_prices.json
5.3 Catálogo de Materiales
Propósito: búsqueda, selección y agrupación de variantes de nombres de materiales.
Flujo de agrupación
- Escribe una palabra clave en el buscador (ej:
Cable) — la tabla se filtra en tiempo real - Marca las filas que quieres consolidar usando el checkbox de cada fila
- El banner verde muestra cuántas filas llevas seleccionadas (persiste aunque cambies el filtro)
- Escribe el nombre canónico del grupo (ej:
Cable Cobre Unipolar 1.5mm) y pulsa Guardar - Alternativamente, pulsa uno de los botones naranjas para añadir a un grupo ya existente
Panel derecho: lista de grupos existentes con sus miembros. Cada miembro tiene un botón ✕ para quitarlo individualmente del grupo.
Truco: puedes filtrar por
Cable, marcar los de 1.5mm, luego filtrar porTuboy marcar los de PVC — la selección acumula materiales de distintos filtros. El botón↺limpia la selección completa.
5.4 Material Agrupado
Propósito: trazabilidad completa de cada grupo hasta la factura origen.
Por cada grupo se muestra:
- Variantes incluidas: chips con el nombre de cada variante y botón
✕para eliminarla del grupo - Histórico de compras: tabla con todas las facturas en las que aparece cualquier variante del grupo (denominación original, precio, proveedor, fecha, ID de factura)
- Botón "Eliminar grupo completo"
5.5 Estadísticas Precios Materiales
Propósito: comparativa de precio unitario entre proveedores para un grupo de materiales, con filtros de ventana temporal y proveedor.
Controles
| Control | Descripción |
|---|---|
| Selector de grupo | Elige el grupo a analizar |
| Mes/Año inicio | Primer mes de la ventana temporal |
| Mes/Año fin | Último mes de la ventana temporal |
↺ Todo | Restablece la ventana al rango completo |
| Selector de proveedores | Multiselect para incluir/excluir proveedores |
Contenido
KPIs: número de proveedores, compras totales, precio mínimo, medio y máximo en la ventana seleccionada.
Gráfico dumbbell — "Precio unitario por proveedor": línea horizontal de mínimo a máximo, punto sólido en la media, proveedores ordenados de más barato a más caro, línea de media global como referencia.
Gráfico de evolución temporal: una línea por proveedor, banda verde "Zona óptima", marcador destacado en el último punto con el precio más reciente. Si la ventana no es completa: líneas verticales marcando inicio y fin.
Tabla resumen: mínimo, media, máximo, número de compras y fecha de última compra por proveedor. La media más baja aparece en verde, la más alta en rojo.
5.6 Estadísticas
Propósito: análisis global de gasto por proveedor y evolución temporal.
- KPIs globales: total de proveedores, proveedor principal y ticket medio
- Gráfico de líneas: evolución del gasto mensual por proveedor, eje X categórico (solo meses con datos), relleno semitransparente, hover unificado
- Tab "Totales Acumulados": gráfico de barras horizontal con importe total y porcentaje
- Tab "Micro-Análisis por Material": evolución de precio unitario por proveedor + tabla ranking de optimización de costes
5.7 Analizador de Precios
Propósito: búsqueda en internet de precios de mercado para un material específico, usando DuckDuckGo + GPT-3.5-turbo.
- Selecciona un material del catálogo
- Introduce tu clave de OpenAI API
- Pulsa "Iniciar Agente": el sistema busca en DuckDuckGo, recoge hasta 15 resultados y los envía a GPT-3.5-turbo para que extraiga precios reales
- Se muestran cards con nombre del proveedor web, precio detectado y enlace
- Cada card tiene un botón para dar de alta ese proveedor en
tagged_providers.json
5.8 Red de Proveedores Web
Propósito: gestión de la base de datos de proveedores web (encontrados por el agente o añadidos manualmente).
- Alta manual: formulario con nombre y URL
- Listado activo: solo se muestran los proveedores con
status = "Alta", con su enlace y fecha de incorporación - Dar de baja: cambia el status a
"Baja"sin borrar el registro
5.9 Generador de Test (PDF)
Propósito: crear facturas ficticias para probar el pipeline de extracción sin necesidad de facturas reales.
- Elige empresa ficticia, fecha y número de factura
- Editor de líneas de materiales (concepto, cantidad, precio unitario)
- Calcula automáticamente subtotales, IVA (21%) y total
- Genera el PDF y lo deposita directamente en
invoices_in/listo para procesar
6. Stack tecnológico
| Componente | Tecnología |
|---|---|
| Interfaz de usuario | Python · Streamlit |
| Gráficos | Plotly Express + Plotly Graph Objects |
| Procesado de datos | pandas |
| LLM local (OCR) | Ollama — modelo gemma4:latest |
| LLM en la nube | OpenAI gpt-3.5-turbo (solo Analizador de Precios) |
| Búsqueda web | DuckDuckGo HTML scraping + BeautifulSoup |
| Extracción de PDF | PyPDF |
| Persistencia | Archivos CSV + JSON (sin base de datos) |
| Tipografías | Google Fonts: Sora (títulos) · Inter (cuerpo) |
| Tema visual | Claro — fondo #F1F5F9, acento teal #0D9488 |
7. Estructura de carpetas
NOVA3/
├── app.py # Aplicación principal (Streamlit)
├── process.sh # Script shell que lanza el pipeline
├── ollama_parser.py # Cliente directo de Ollama (utilidad)
│
├── .agent/skills/
│ ├── invoice-router/ # Orquestador del pipeline
│ │ └── scripts/
│ │ ├── process_invoices.py
│ │ └── lib/ # normalize, validate, csv_export, models…
│ ├── invoice-preprocess/ # Extracción de texto PDF
│ ├── invoice-parse-generic/ # Parser genérico (Ollama)
│ └── invoice-parse-vendor-template/ # Parsers por proveedor
│ └── scripts/parsers/ # lecu.py · llave.py · idella.py …
│
├── out/
│ ├── invoices.csv
│ ├── invoice_lines.csv
│ ├── confirmed_prices.json
│ ├── tagged_providers.json
│ └── grouped_materials.json
│
├── invoices_in/ # Bandeja de entrada de PDFs
├── facturas_revisadas/ # PDFs procesados con éxito
├── facturas_error/ # PDFs que fallaron el pipeline
│
├── .streamlit/
│ └── config.toml # Puerto, tema claro, colores
│
└── tests/ # Tests unitarios (pytest)
├── test_registry.py
├── test_validate.py
└── test_normalize.py