Files
IPSExtractor/README.md
T

277 lines
6.5 KiB
Markdown

## IPSExtractor Microservices
Monorepo con servicios separados como si fueran repos independientes. Cada
servicio tiene su propia API, dependencias, Dockerfile, codigo de dominio e
infraestructura local. No hay paquetes compartidos entre servicios.
```text
services/
extraction/ Repo/servicio de extraccion
api/ API FastAPI
domain/ Dominio propio de extraccion y normalizacion
core/ Utilidades propias para PDF, texto y filas
infrastructure/ Persistencia propia del servicio
requirements.txt
Dockerfile
cleaning/ Repo/servicio de limpieza
api/ API FastAPI
domain/ Reglas propias de limpieza
infrastructure/ Persistencia propia del servicio
requirements.txt
Dockerfile
api_gateway/ API central opcional
api/ Proxy HTTP hacia extraction y cleaning
requirements.txt
Dockerfile
desktop_app/ App desktop Windows/Mac
electron/ Main process, preload y dialogos nativos
src/ React UI, cliente API y export CSV
package.json
```
La base de datos Postgres es compartida como contrato de integracion, pero el
codigo de acceso a datos esta duplicado dentro de cada servicio para que puedan
vivir por separado.
### Puertos
| Servicio | Puerto | Uso |
| --- | ---: | --- |
| `api_gateway` | `8000` | API central opcional |
| `extraction` | `8001` | API propia de extraccion |
| `cleaning` | `8002` | API propia de limpieza |
| `database` | `5432` | Postgres |
| `desktop_app` | local | App desktop fuera de Docker |
Documentacion interactiva:
- `http://localhost:8000/docs`
- `http://localhost:8001/docs`
- `http://localhost:8002/docs`
### Variables
```env
IPS_DOCUMENT_ROOT=C:/ruta/a/documentos
# Ejemplo: extraccion con Grok/xAI
EXTRACTOR_PROVIDER=xai
EXTRACTOR_BASE_URL=https://api.x.ai/v1
EXTRACTOR_API_KEY=tu_xai_api_key
EXTRACTOR_MODEL=grok-tu-modelo
EXTRACTOR_TIMEOUT_S=120
# Ejemplo: normalizacion con OpenAI
NORMALIZER_PROVIDER=openai
NORMALIZER_BASE_URL=https://api.openai.com/v1
NORMALIZER_API_KEY=tu_openai_api_key
NORMALIZER_MODEL=gpt-tu-modelo
NORMALIZER_TIMEOUT_S=120
PDF_DPI=600
PDF_THREAD_COUNT=10
CONCURRENCY_LIMIT=4
ALLOWED_DOCUMENT_TYPES=CC,TI,CE,RC,PA,PPT,PEP,EPT,NUIP
```
Si `NORMALIZER_BASE_URL` o `NORMALIZER_API_KEY` se dejan vacios, el servicio usa
el mismo backend configurado en `EXTRACTOR_BASE_URL` y `EXTRACTOR_API_KEY`.
Dentro de Docker, `IPS_DOCUMENT_ROOT` se monta como `/data`.
### Levantar
```bash
docker compose up --build
```
Health checks:
```bash
curl http://localhost:8000/health
curl http://localhost:8001/health
curl http://localhost:8002/health
```
### Flujo Directo Por Servicio
1. Ver modelos disponibles en extraccion:
```bash
curl http://localhost:8001/models
```
2. Descubrir campos:
```bash
curl -X POST http://localhost:8001/schemas \
-H "Content-Type: application/json" \
-d '{"document_path": "/data/radicado-1/factura.pdf"}'
```
3. Ejecutar extraccion:
```bash
curl -X POST http://localhost:8001/batches \
-H "Content-Type: application/json" \
-d '{
"root_path": "/data",
"keywords": ["factura"],
"fields": ["numero_factura", "items/*/codigo", "items/*/valor"],
"alias_map": {
"numero_factura": "factura",
"items/*/codigo": "codigo",
"items/*/valor": "valor"
},
"structure_mode": "radicados"
}'
```
La respuesta devuelve `id`; ese valor es el `batch_id`.
4. Consultar filas extraidas:
```bash
curl http://localhost:8001/batches/{batch_id}/rows
```
5. Ver reglas de limpieza:
```bash
curl http://localhost:8002/rules
```
6. Analizar columnas extraidas:
```bash
curl http://localhost:8002/batches/{batch_id}/analysis
```
7. Ejecutar limpieza:
```bash
curl -X POST http://localhost:8002/jobs \
-H "Content-Type: application/json" \
-d '{
"extraction_batch_id": "{batch_id}",
"rules_per_column": {
"valor": ["to_integer"],
"fecha": ["date_to_ddmmyyyy"]
}
}'
```
La respuesta devuelve `id`; ese valor es el `job_id`.
8. Consultar filas limpias:
```bash
curl http://localhost:8002/jobs/{job_id}/rows
```
### Flujo Por API Gateway
El gateway no importa codigo interno de los servicios; solo enruta HTTP.
```bash
curl http://localhost:8000/models
curl http://localhost:8000/config
curl http://localhost:8000/extraction/batches/{batch_id}/rows
curl http://localhost:8000/cleaning/jobs/{job_id}/rows
```
Para llamar cualquier endpoint propio de un servicio:
- `http://localhost:8000/extraction/...`
- `http://localhost:8000/cleaning/...`
### Desarrollo Independiente
Extraccion como repo aparte:
```bash
cd services/extraction
pip install -r requirements.txt
uvicorn api.main:app --host 0.0.0.0 --port 8001
```
Limpieza como repo aparte:
```bash
cd services/cleaning
pip install -r requirements.txt
uvicorn api.main:app --host 0.0.0.0 --port 8002
```
Gateway como repo aparte:
```bash
cd services/api_gateway
pip install -r requirements.txt
uvicorn api.main:app --host 0.0.0.0 --port 8000
```
App desktop como repo aparte:
```bash
cd services/desktop_app
npm install
npm run dev
```
La app desktop usa `http://localhost:8000` por defecto. **No monta la carpeta
en Docker**: indexa los documentos localmente y los sube uno a uno al API
(`POST /extraction/schemas/upload` y `POST /tasks/{id}/ingest`). Solo se
persisten las filas extraidas en Postgres; los PDFs permanecen en el equipo del
usuario.
```bash
cd services/desktop_app
npm install
npm run dev
```
#### Flujo desktop (sin volumen `/data`)
1. Seleccionar carpeta local en la app.
2. Descubrir campos (sube un PDF de muestra por tipo).
3. Ejecutar extraccion (crea tarea `source=desktop` e ingesta cada archivo).
4. Consultar tareas y exportar CSV opcional.
#### Modo legacy API / curl
Si llamas al API con `root_path` y rutas bajo `/data`, monta documentos al
levantar Docker:
```bash
IPS_DOCUMENT_ROOT=C:/ruta/a/documentos docker compose up --build
```
### Error: No se encontraron documentos en /data
Ese mensaje aparece en clientes legacy que envian `root_path=/data` sin montar
documentos. La app desktop no deberia usar ese modo. Verifica:
```bash
docker exec ipsextractor-extraction ls -la /data
```
Para la app desktop, asegurate de usar Electron (`npm run dev`) y de que el
gateway responda en `http://localhost:8000`.
### Contrato De Base De Datos
Los servicios se integran por Postgres:
- `extraction_batches`
- `extraction_rows`
- `tasks`
- `cleaning_jobs`
- `cleaned_rows`
Cada servicio mantiene su propia copia del modelo SQLAlchemy para no depender
de un paquete comun.