feat: Add database migration service with Alembic for PostgreSQL, integrating job management and counting functionalities. Update Docker Compose to include db-migrations service, enhancing the microservices architecture. Revise documentation for clarity on database schema and migration processes.

This commit is contained in:
erik
2026-07-06 00:50:50 -05:00
parent d95f8f6ad8
commit 081da999d4
43 changed files with 2911 additions and 2271 deletions
+133 -39
View File
@@ -1,45 +1,139 @@
# IPSExtractor Extraction Service
# extraction
Microservicio independiente de extraccion. Esta carpeta puede vivir como repo
propio: contiene su API REST, dominio, infraestructura, dependencias y
Dockerfile sin importar codigo de otros servicios.
Servicio Python (FastAPI) de extracción de datos estructurados desde documentos médicos PDF.
Usa LLMs (compatible con OpenAI API) para descubrir campos, estimar costos y extraer datos por lotes.
## Estructura
También actúa como capa de persistencia para el flujo de conteo: guarda los resultados del `count-api` en PostgreSQL y orquesta la extracción de documentos validados.
```text
api/ Endpoints FastAPI
domain/ Logica de extraccion, prompts, estimacion y normalizacion
core/ Utilidades propias de PDF, texto y CSV
infrastructure/ Persistencia SQLAlchemy del servicio
requirements.txt
Dockerfile
```
## Desarrollo local
```bash
pip install -r requirements.txt
uvicorn api.main:app --host 0.0.0.0 --port 8001
```
## Poppler
El contenedor instala `poppler-utils` para que `pdf2image` encuentre
`pdfinfo` y `pdftoppm` desde el PATH del sistema, sin configurar variables de
entorno.
En desarrollo local Windows, el servicio usa automaticamente la carpeta incluida
en `dependencies/poppler-24.08.0/Library/bin`.
---
## Endpoints principales
- `GET /health`
- `GET /config`
- `GET /models`
- `POST /schemas`
- `POST /schemas/upload`
- `POST /estimate`
- `POST /batches`
- `POST /tasks/extraction`
- `POST /tasks/{task_id}/ingest`
- `GET /tasks`
Puerto: **8001**
### Salud y configuración
| Método | Ruta | Descripción |
|--------|------|-------------|
| `GET` | `/health` | Liveness |
| `GET` | `/config` | Configuración LLM activa |
| `GET` | `/models` | Modelos disponibles en el backend LLM |
### Descubrimiento de esquema
| Método | Ruta | Descripción |
|--------|------|-------------|
| `POST` | `/schemas` | Descubrir campos desde ruta en disco |
| `POST` | `/schemas/upload` | Descubrir campos desde PDF subido |
### Estimación de costo
| Método | Ruta | Descripción |
|--------|------|-------------|
| `POST` | `/estimate/upload` | Estimar tokens/costo desde PDF subido |
### Tareas de extracción
| Método | Ruta | Descripción |
|--------|------|-------------|
| `POST` | `/tasks/extraction` | Crear tarea de extracción |
| `POST` | `/tasks/{id}/ingest` | Subir un PDF a la tarea |
| `POST` | `/tasks/{id}/ingest-many` | Subir varios PDFs en bulk |
| `GET` | `/tasks` | Listar tareas |
| `GET` | `/tasks/{id}` | Detalle de tarea |
| `GET` | `/tasks/{id}/rows` | Filas extraídas de la tarea |
| `POST` | `/tasks/extraction/from-count` | Crear extracción desde conteo previo |
### Jobs (contenedor de tareas)
| Método | Ruta | Descripción |
|--------|------|-------------|
| `GET` | `/jobs` | Listar jobs |
| `GET` | `/jobs/{id}` | Detalle de job |
| `GET` | `/jobs/{id}/tasks` | Tareas del job |
### Conteo (persistencia desde count-api)
| Método | Ruta | Descripción |
|--------|------|-------------|
| `POST` | `/count-jobs` | Guardar resultados de conteo en BD |
| `GET` | `/count-jobs` | Listar jobs de conteo |
| `GET` | `/count-jobs/{task_id}` | Detalle de job de conteo |
| `GET` | `/count-jobs/{task_id}/files` | Archivos del conteo |
| `PATCH` | `/count-jobs/{task_id}/files/{file_id}` | Marcar archivo como válido/inválido |
---
## Flujo de datos
```
PDF local (desktop) → POST /tasks/{id}/ingest-many → procesamiento LLM
↓
filas en extraction_rows (PG)
count-api results → POST /count-jobs → count_job_files (PG)
→ POST /tasks/extraction/from-count → lee file_path desde /data
```
---
## Variables de entorno
| Variable | Descripción |
|----------|-------------|
| `DATABASE_URL` | PostgreSQL (`postgresql+psycopg://...`) |
| `REDIS_URL` | Redis para cola ARQ (`redis://...`) |
| `EXTRACTOR_BASE_URL` | URL base del LLM (compatible OpenAI) |
| `EXTRACTOR_API_KEY` | API key del LLM extractor |
| `EXTRACTOR_MODEL` | Modelo de extracción (ej. `gpt-5.4-mini`) |
| `NORMALIZER_BASE_URL` | URL base del LLM normalizador |
| `NORMALIZER_API_KEY` | API key del LLM normalizador |
| `NORMALIZER_MODEL` | Modelo normalizador (ej. `gpt-5.4-mini`) |
| `EXTRACTOR_TIMEOUT_S` | Timeout por documento (default `120`) |
| `PDF_DPI` | DPI para renderizado PDF (default `150`) |
| `PDF_THREAD_COUNT` | Hilos de renderizado PDF (default `4`) |
| `CONCURRENCY_LIMIT` | Máximo de extracciones paralelas (default `50`) |
| `ALLOWED_DOCUMENT_TYPES` | Tipos de documento permitidos |
| `ASYNC_QUEUE` | `true` para encolar en ARQ/Redis (default: sync) |
---
## Modelo de datos (PostgreSQL)
```
jobs — contenedor de tareas del usuario
tasks — una tarea por módulo (counting / extraction / cleaning)
count_job_files — resultados de conteo por PDF
extraction_batches — lotes de extracción
extraction_rows — filas extraídas por documento
```
---
## Estructura del código
```
api/
main.py — FastAPI app (~1400 líneas), todos los endpoints
desktop_ingest.py — lógica de ingesta desde desktop Electron
domain/ — lógica de negocio: LLM, prompts, extractor, batch
core/ — utilidades PDF, CSV, texto
infrastructure/ — SQLAlchemy, migraciones, uploads temporales
worker/ — workers ARQ (procesamiento async)
main.py — punto de entrada del worker
tasks.py — tareas ARQ
settings.py — configuración del worker
Dockerfile
requirements.txt
```
---
## Arrancar localmente
```bash
# Desde la raíz del repositorio:
docker compose up --build extraction worker
```
API disponible en `http://localhost:8001`.