OCR minimalista y eficiente basado en PaddleOCR 3.x con API REST profesional.
- Thread-Safety:
threading.Semaphore(1)serializa peticiones OCR (PaddleOCR no es thread-safe) - Concurrencia: Evita race conditions y errores
std::exceptionen alta carga - UUID único: Archivos temporales con UUID evitan colisiones en peticiones concurrentes
- Probado: 5/5 peticiones simultáneas exitosas sin errores
- Bug Fix: os.getenv sin default corregido
- Bug Fix: Context managers para archivos PDF (previene fugas)
- Seguridad: Validación path traversal en
/ocrendpoint - Código: OCR_CONFIG unificado con init_ocr()
- Verificado con 10 pruebas: confianza promedio 0.927
- BUG CRÍTICO: Corregidas funciones inexistentes (
initialize_*→init_*) - Seguridad: Añadido
secure_filenamepara prevenir path traversal - Seguridad: Límite de 50MB para archivos subidos
- Seguridad: Enmascarado de contraseñas en logs
- Robustez: Timeouts (30-120s) en todas las llamadas subprocess
- Código: Corregidos bare except clauses
- Código: Consolidados imports duplicados
- Auditoría completa en REVISION_CODIGO.md
- Detección de tablas con mínimo 2 filas (antes 3)
- Nueva función
is_potential_data_row()para detectar filas de datos - Registro de mejoras en MEJORAS.md
- Parámetros OCR optimizados para reducir fragmentación
- Mejor separación de palabras en documentos escaneados
- +1% confianza OCR promedio
- Minimalista: Solo 2241 líneas de código (vs 7000+ de versiones anteriores)
- Rápido: 2.5x más rápido que versiones extendidas
- API REST: Endpoints limpios y fáciles de usar
- Formato Layout: Reconstrucción espacial del documento con detección de tablas
- Tablas con Pipes: Formateo automático
|col1|col2|col3| - Compatibilidad n8n: Mantiene endpoint
/ocroriginal
| Endpoint | Método | Descripción |
|---|---|---|
/ |
GET | Dashboard web - Interfaz visual para probar OCR |
/health |
GET | Estado del servidor y modelos |
/stats |
GET | Estadísticas de uso |
/process |
POST | Principal - Procesa documentos con formato seleccionable |
/ocr |
POST | Compatibilidad con n8n (archivos en /home/n8n/in/) |
Accede a http://localhost:8505/ para usar la interfaz visual:
- Arrastra y suelta PDF/imágenes
- Selecciona formato: Layout (tablas) o Normal
- Visualiza resultados con estadísticas
# Formato normal (texto plano)
curl -X POST http://localhost:8505/process \
-F "file=@factura.pdf"
# Formato layout (preserva estructura espacial + tablas con pipes)
curl -X POST http://localhost:8505/process \
-F "file=@factura.pdf" \
-F "format=layout"{
"success": true,
"format": "layout",
"text": "... texto formateado ...",
"stats": {
"avg_confidence": 0.967,
"processing_time": 18.183,
"total_blocks": 157,
"total_pages": 1
},
"timestamp": 1733664000.123
}|ALB. |PED. |CODIGO |DESCRIPCION |CANT. |PRECIO |DTO. |NETO |IMPORTE |
+------+------+-------------+-------------+------+-------+-----+------+--------+
|7.740 |8.316 |C80514 DISCO | |2 |27,90 | |27,90 |55,80 |
# Clonar repositorio
git clone https://github.com/webcomunicasolutions/paddleocr_webcomunicav5.git
cd paddleocr_webcomunicav5
# Construir y ejecutar
docker-compose build
docker-compose up -d
# Verificar estado
curl http://localhost:8505/health- 8505: Puerto expuesto (mapea al 8503 interno)
Variables de entorno principales en docker-compose.yml:
| Variable | Default | Descripción |
|---|---|---|
FLASK_PORT |
8503 | Puerto interno |
OCR_LANG |
es | Idioma OCR |
OCR_VERSION |
PP-OCRv3 | Versión del modelo |
OCR_TEXT_DET_THRESH |
0.05 | Umbral detección texto |
OCR_TEXT_DET_BOX_THRESH |
0.2 | Umbral cajas texto |
Comparativa con versión extendida (7071 líneas):
| Métrica | v5 (2241 líneas) | Versión extendida |
|---|---|---|
| Tiempo procesamiento | 18.2s | 45.2s |
| Confianza OCR | 0.967 | 0.956 |
| Líneas de código | 2241 | 7071 |
┌─────────────────────────────────────────┐
│ API REST (336 líneas) │
│ /health /stats /process /ocr │
├─────────────────────────────────────────┤
│ Format Layout (150 líneas) │
│ - Detección de tablas multi-idioma │
│ - Formateo con pipes │
│ - Posicionamiento espacial │
├─────────────────────────────────────────┤
│ Core OCR Paco (1755 líneas) │
│ - PaddleOCR 3.x via PaddleX │
│ - OpenCV preprocessing │
│ - Corrección perspectiva/orientación │
│ - PDF multipágina │
└─────────────────────────────────────────┘
PaddleOCR tiene un bug conocido donde peticiones concurrentes causan RuntimeError: std::exception.
Referencias:
- Issue #16238 - std::exception en threads
- Issue #11605 - No se puede lograr concurrencia
Usamos threading.Semaphore(1) para serializar peticiones OCR:
ocr_semaphore = threading.Semaphore(1)
with ocr_semaphore:
result = ocr_instance.predict(image)Ventajas:
- Simple y robusto
- 0 errores std::exception
- Bajo uso de memoria (1 instancia)
Limitación:
- 1 petición OCR a la vez (throughput limitado)
Para escenarios de alta demanda (>100 req/min), considerar PaddleServing oficial:
# Instalación
paddlex --install serving
# Lanzar servidor OCR
paddlex --serve --pipeline OCR --port 8080Ventajas:
- Diseñado para alta concurrencia
- Soporte multi-lenguaje (C++, Java, Go, Node.js)
- Basado en NVIDIA Triton para máximo rendimiento
Documentación: PaddleOCR Server Deployment
| Tráfico | Solución | RAM |
|---|---|---|
| Bajo (<10 req/min) | Semaphore(1) actual | 4GB |
| Medio (10-50 req/min) | Múltiples contenedores + balanceador | 4GB x N |
| Alto (>100 req/min) | PaddleServing | Variable |
Ver MEJORAS_FUTURAS.md para guías detalladas de implementación.
- Docker con soporte AVX/AVX2
- 4GB RAM mínimo
- CPU con instrucciones AVX (no funciona en VPS básicos)
Para desplegar en EasyPanel (sin docker-compose), consulta la guia completa:
Resumen rapido:
- Repo:
https://github.com/webcomunicasolutions/paddleocr_webcomunicav5 - Branch:
main - Puerto:
8503 - RAM minima: 4GB
- Volumenes:
/home/n8n/.paddlex(cache modelos)/home/n8n/.paddleocr(cache modelos)
MIT License
- Base OCR: Proyecto de Paco (PaddleOCR optimizado)
- API REST y Layout: WebComunica Solutions