- Integrar Tesseract OCR para leer PDFs escaneados automáticamente - Detectar automáticamente si el PDF tiene texto o requiere OCR - Agregar servicio ocr_service.py con funciones de OCR - Actualizar Dockerfile con tesseract-ocr, tesseract-ocr-spa y poppler-utils - Agregar variables de configuración OCR (OCR_ENABLED, OCR_LANGUAGE, OCR_DPI, OCR_TIMEOUT) - Crear endpoint de debug para ver texto extraído (/api/v1/debug/extract-text) - Agregar scripts de instalación y prueba (install_ocr.ps1, test_ocr.py, debug_pdf.ps1) - Documentación completa (OCR_SETUP.md, DOCKER_OCR.md, COMO_PROBAR.md) - Actualizar docker-compose.yml con variables de entorno OCR - Modificar pdf_text.py para usar OCR cuando sea necesario - Actualizar requirements.txt con pytesseract, Pillow, pdf2image
92 lines
2.5 KiB
Python
92 lines
2.5 KiB
Python
"""Main FastAPI application."""
|
|
import logging
|
|
import sys
|
|
from fastapi import FastAPI, Request, status
|
|
from fastapi.responses import JSONResponse
|
|
from fastapi.exceptions import RequestValidationError
|
|
from contextlib import asynccontextmanager
|
|
|
|
from app.core.config import get_settings
|
|
from app.api import auth
|
|
from app.api.v1 import incrementables, debug
|
|
from app.schemas import HealthResponse
|
|
|
|
# Configure logging
|
|
settings = get_settings()
|
|
logging.basicConfig(
|
|
level=getattr(logging, settings.log_level.upper()),
|
|
format='{"time": "%(asctime)s", "level": "%(levelname)s", "name": "%(name)s", "message": "%(message)s"}',
|
|
stream=sys.stdout
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Application lifespan manager."""
|
|
logger.info(f"Starting {settings.service_name} v{settings.service_version}")
|
|
yield
|
|
logger.info(f"Shutting down {settings.service_name}")
|
|
|
|
|
|
# Create FastAPI app
|
|
app = FastAPI(
|
|
title=settings.service_name,
|
|
version=settings.service_version,
|
|
description="MVE Incrementables Parser - Extracts incrementables data from PDFs",
|
|
lifespan=lifespan
|
|
)
|
|
|
|
|
|
# Exception handlers
|
|
@app.exception_handler(RequestValidationError)
|
|
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
"""Handle validation errors with custom format."""
|
|
logger.warning(f"Validation error: {exc.errors()}")
|
|
return JSONResponse(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
content={
|
|
"detail": "Validation error",
|
|
"errors": exc.errors()
|
|
}
|
|
)
|
|
|
|
|
|
@app.exception_handler(Exception)
|
|
async def general_exception_handler(request: Request, exc: Exception):
|
|
"""Handle unexpected errors."""
|
|
logger.error(f"Unexpected error: {str(exc)}", exc_info=True)
|
|
return JSONResponse(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
content={
|
|
"detail": "Internal server error"
|
|
}
|
|
)
|
|
|
|
|
|
# Health check endpoint
|
|
@app.get("/health", response_model=HealthResponse, tags=["Health"])
|
|
async def health_check():
|
|
"""
|
|
Health check endpoint.
|
|
|
|
Returns service status and version information.
|
|
"""
|
|
return HealthResponse(
|
|
status="ok",
|
|
service=settings.service_name,
|
|
version=settings.service_version
|
|
)
|
|
|
|
|
|
# Include routers
|
|
app.include_router(auth.router)
|
|
app.include_router(incrementables.router)
|
|
app.include_router(debug.router)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
uvicorn.run(app, host="0.0.0.0", port=9876)
|