first commit - MVE Incrementables Parser microservice with FastAPI, JWT, Celery, Redis

This commit is contained in:
Ernesto Herrera
2026-03-02 21:31:50 -07:00
commit 068d859f42
27 changed files with 2337 additions and 0 deletions

0
app/tasks/__init__.py Normal file
View File

95
app/tasks/parse_tasks.py Normal file
View File

@@ -0,0 +1,95 @@
"""Celery tasks for PDF parsing."""
import logging
import hashlib
from app.core.celery_app import celery_app
from app.services.pdf_text import extract_text_from_pdf, PDFExtractionError
from app.services.parser import parse_incrementables, ParsingError
logger = logging.getLogger(__name__)
@celery_app.task(bind=True, name="parse_pdf_task")
def parse_pdf_task(self, pdf_bytes_hex: str, filename: str, document_ref: str = None):
"""
Celery task to parse PDF incrementables asynchronously.
Args:
self: Celery task instance
pdf_bytes_hex: PDF content as hex string (to serialize)
filename: Original filename
document_ref: Optional document reference
Returns:
Dictionary with parsed data or error information
"""
task_id = self.request.id
logger.info(f"Starting PDF parse task {task_id} for {filename}")
try:
# Convert hex back to bytes
pdf_bytes = bytes.fromhex(pdf_bytes_hex)
# Calculate SHA256
file_hash = hashlib.sha256(pdf_bytes).hexdigest()
# Extract text
try:
text, page_count, extraction_method = extract_text_from_pdf(pdf_bytes)
logger.info(f"Task {task_id}: Extracted {len(text)} chars from {page_count} pages")
except PDFExtractionError as e:
logger.error(f"Task {task_id}: Extraction failed - {str(e)}")
return {
"status": "failed",
"error": "extraction_failed",
"message": str(e),
"task_id": task_id
}
# Parse incrementables
try:
parsed_data = parse_incrementables(text)
logger.info(f"Task {task_id}: Successfully parsed incrementables")
except ParsingError as e:
logger.error(f"Task {task_id}: Parsing failed - {str(e)}")
return {
"status": "failed",
"error": "parsing_failed",
"message": str(e),
"task_id": task_id
}
# Build successful response
result = {
"status": "completed",
"task_id": task_id,
"document": {
"filename": filename,
"pages": page_count,
"sha256": file_hash,
"document_ref": document_ref
},
"incrementables": {
"currency": parsed_data["currency"],
"fletes": parsed_data["fletes"],
"seguros": parsed_data["seguros"],
"almacenaje_consolidacion": parsed_data["almacenaje_consolidacion"],
"regalias": parsed_data["regalias"]
},
"extraction": {
"method": extraction_method,
"anchors_found": parsed_data["anchors_found"],
"warnings": parsed_data["warnings"]
}
}
logger.info(f"Task {task_id}: Completed successfully")
return result
except Exception as e:
logger.error(f"Task {task_id}: Unexpected error - {str(e)}", exc_info=True)
return {
"status": "failed",
"error": "unexpected_error",
"message": str(e),
"task_id": task_id
}