Files
IPSExtractor/services/services-count-facturas-medicas-serving
..

count-api

Microservicio Go que cuenta servicios facturados en facturas médicas PDF. Aplica OCR (Tesseract) + clustering espacial (DBSCAN) + clasificación ML (Random Forest vía ONNX Runtime).

Es un servicio sin estado: recibe PDFs por HTTP, procesa en memoria y devuelve el resultado. No persiste datos ni depende de bases de datos, colas ni almacenamiento de objetos.

La persistencia de resultados la maneja el servicio extraction (Python) a través de los endpoints /count-jobs.


Endpoints

Método Ruta Descripción
GET /health Liveness — {"status":"ok"}
GET /ready Readiness — {"status":"ready"}
GET /openapi.json Especificación OpenAPI
POST /v1/count Conteo síncrono de PDFs

POST /v1/count

Request

Content-Type: multipart/form-data
Query: include_rejected=true|false   (default: false)
Field: files  — uno o más archivos PDF (máx. SYNC_MAX_FILES)

Response 200

{
  "results": [
    {
      "filename": "factura_001.pdf",
      "service_count": 3,
      "status": "ok",
      "services": [
        { "text": "CONSULTA MEDICA", "probability": 0.91 },
        { "text": "LABORATORIO HEMOGRAMA", "probability": 0.87 },
        { "text": "RADIOGRAFIA TORAX", "probability": 0.83 }
      ]
    }
  ],
  "processed": 1,
  "failed": 0
}

Response 4xx/5xx

{ "error": "descripción del error" }

Pipeline de procesamiento

PDF bytes (memoria)
  │
  ▼  gen2brain/go-fitz (MuPDF)
Render de la primera página a imagen (OCR_DPI, default 300)
  │
  ▼  otiai10/gosseract (Tesseract)
OCR palabra a palabra con coordenadas (X, Y, W, H)
  │
  ▼  DBSCAN 1D sobre coordenada Y
Agrupación de palabras en filas candidatas
  │
  ▼  8 features por fila
first_token_is_code · currency_count · integer_count · x_span_norm
y_norm · token_count · special_char_ratio · digit_ratio
  │
  ▼  ONNX Runtime (Random Forest)
P(servicio) por fila → filtrar por threshold (inference.json)
  │  Si el modelo no está disponible → heurística: todas las filas = servicio
  ▼
PDFResult { service_count, services[], status }

Modelo ONNX

El modelo es opcional. Si no está disponible, el servicio arranca con una advertencia y usa heurística de conteo.

Los archivos deben montarse en /app/models/:

/app/models/model.onnx       — modelo Random Forest exportado con skl2onnx
/app/models/inference.json   — threshold y feature_columns

Para generar el modelo desde un model.joblib existente:

cd scripts
pip install -r ../requirements-export.txt
python export_onnx.py --joblib /ruta/model.joblib --out ../models/latest

Variables de entorno

Variable Default Descripción
PORT 8080 Puerto HTTP
MODEL_PATH /app/models/model.onnx Ruta al modelo ONNX
INFERENCE_CONFIG /app/models/inference.json Threshold y metadatos del modelo
OPENAPI_PATH api/openapi.yaml Ruta a la especificación OpenAPI
OCR_DPI 300 DPI de renderizado PDF para OCR
OCR_LANG spa Idioma Tesseract
OCR_POOL_SIZE 0 (→ 4) Tamaño del pool de clientes Tesseract
DBSCAN_EPS 10 Épsilon de clustering DBSCAN (píxeles en Y)
DBSCAN_MIN_SAMPLES 1 Mínimo de puntos por cluster DBSCAN
SYNC_MAX_FILES 50 Máximo de PDFs por request a /v1/count
SYNC_PROCESS_CONCURRENCY 0 (→ OCR_POOL_SIZE) Goroutines paralelas por request
MAX_PDF_SIZE_MB 20 Tamaño máximo permitido por PDF
PDF_PROCESS_TIMEOUT_SEC 120 Timeout por PDF
LOG_PIPELINE_TIMING false Loguear tiempos de cada etapa

Dependencias en producción (Docker)

  • libonnxruntime.so — ONNX Runtime (copiado en build multi-etapa)
  • tesseract-ocr tesseract-ocr-spa — OCR en español
  • libmupdf — via go-fitz, renderizado de PDFs

Sin Redis, MinIO, NATS ni bases de datos.


Estructura del código

cmd/api/            — punto de entrada del servidor HTTP
internal/
  api/              — router y handler countSync
  config/           — carga de variables de entorno
  domain/           — tipos PDFResult, CountResponse, ServiceRow
  model/            — sesión ONNX Runtime (Predictor)
  ocr/              — pool de clientes Tesseract + renderizado MuPDF
  pipeline/         — orquestación OCR → DBSCAN → features → ML
    processor.go    — ProcessPDF por documento
    clustering.go   — DBSCAN 1D en Y
    features.go     — 8 features por fila
api/openapi.yaml    — especificación OpenAPI 3.1
models/latest/      — model.onnx + inference.json (gitignored, montar en Docker)
scripts/            — export_onnx.py para generar el modelo
Dockerfile          — build multi-etapa: ONNX download + Go builder + runtime slim

Arrancar localmente (Docker)

# Desde la raíz del repositorio:
docker compose up --build count-api

El servicio queda disponible en http://localhost:8081.

Para probar el endpoint:

curl -X POST http://localhost:8081/v1/count \
  -F "files=@factura.pdf" | jq .