refactor: Introduce accumulate_usage function for token aggregation, enhance alias map expansion in BatchProcessor, and streamline error handling in PreclassificationService. Update PDF processing utilities for improved image conversion and error logging.

This commit is contained in:
erik
2026-03-01 20:55:52 -05:00
parent 3c258ebf12
commit e7fde25227
29 changed files with 321 additions and 1206 deletions
+23 -19
View File
@@ -15,19 +15,28 @@ from PIL import Image, ImageSequence
Image.MAX_IMAGE_PIXELS = None
from application.config import settings
logger = logging.getLogger(__name__)
_DEFAULT_POPPLER = 'dependencies/poppler-24.08.0/Library/bin'
def pdf_to_images_bs64(pdf_path: str, validate: bool = True, dpi: int = 800, thread_count: int = 10) -> List[str]:
def _resolve_poppler(poppler_path: str | None) -> str:
"""Devuelve la ruta a Poppler: usa la provista o el default del proyecto."""
return poppler_path or _DEFAULT_POPPLER
def pdf_to_images_bs64(
pdf_path: str,
validate: bool = True,
dpi: int = 800,
thread_count: int = 10,
poppler_path: str | None = None,
) -> List[str]:
"""Convierte un PDF a una lista de PNGs en base64.
Usa pdf2image + Poppler. Lanza ValueError si una imagen no valida.
"""
poppler_bin = settings.imaging.poppler_path or 'dependencies/poppler-24.08.0/Library/bin'
poppler_bin = _resolve_poppler(poppler_path)
t0 = time.time()
logger.info("Convirtiendo PDF a imágenes", extra={"pdf": pdf_path, "dpi": dpi})
images = convert_from_path(pdf_path, dpi=dpi, thread_count=thread_count, poppler_path=poppler_bin)
@@ -50,10 +59,9 @@ def pdf_to_images_bs64(pdf_path: str, validate: bool = True, dpi: int = 800, thr
return resultados
def get_pdf_num_pages(pdf_path: str) -> int:
def get_pdf_num_pages(pdf_path: str, poppler_path: str | None = None) -> int:
"""Devuelve el número de páginas de un PDF usando pdfinfo_from_path."""
poppler_bin = settings.imaging.poppler_path or 'dependencies/poppler-24.08.0/Library/bin'
info = pdfinfo_from_path(pdf_path, poppler_path=poppler_bin)
info = pdfinfo_from_path(pdf_path, poppler_path=_resolve_poppler(poppler_path))
try:
return int(info.get('Pages') or info.get('pages') or 0)
except Exception:
@@ -69,12 +77,13 @@ def pdf_pages_to_images_bs64(
grayscale: bool = True,
validate: bool = False,
thread_count: int = 10,
poppler_path: str | None = None,
) -> List[str]:
"""Convierte un rango [first_page, last_page] (1-indexed, inclusivo) a PNGs base64.
Opcionalmente aplica escala de grises y omite validación para acelerar.
"""
poppler_bin = settings.imaging.poppler_path or 'dependencies/poppler-24.08.0/Library/bin'
poppler_bin = _resolve_poppler(poppler_path)
t0 = time.time()
logger.debug(
f"Convirtiendo rango PDF→imgs (first={first_page}, last={last_page}, dpi={dpi}, gray={grayscale})",
@@ -155,26 +164,21 @@ def document_to_images_bs64(
thread_count: int = 10,
tiff_pages: Optional[Tuple[int, int]] = (2, 3),
tiff_page_range: Optional[Tuple[int, int]] = None,
poppler_path: str | None = None,
) -> List[str]:
"""Puerta de entrada: decide conversión según la extensión (.pdf, .tif/.tiff).
`tiff_page_range` permite indicar un rango explícito (inicio, fin) 1-based
para TIFF. Si es None, se usa `tiff_pages` como valor por defecto.
`poppler_path` se pasa a las funciones PDF; si es None se usa el default del proyecto.
"""
ext = os.path.splitext(path)[1].lower()
if ext == ".pdf":
return pdf_to_images_bs64(path, validate=validate, dpi=dpi, thread_count=thread_count)
return pdf_to_images_bs64(path, validate=validate, dpi=dpi, thread_count=thread_count, poppler_path=poppler_path)
if ext in (".tif", ".tiff"):
# Prioridad:
# - (None, None) => procesar todas las páginas del TIFF (sin recorte).
# - rango explícito (inicio, fin) => usar ese rango.
# - None => usar el valor por defecto de configuración (`tiff_pages`).
effective_range = tiff_pages
if tiff_page_range is not None:
if tiff_page_range == (None, None):
effective_range = None
else:
effective_range = tiff_page_range
effective_range = None if tiff_page_range == (None, None) else tiff_page_range
return tiff_to_images_bs64(path, validate=validate, pages_range=effective_range)
raise ValueError(f"Formato no soportado: {ext}")