277 lines
6.5 KiB
Markdown
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.
|