feat(api): implement /extract and /validate endpoints with error handling
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
66
src/main.py
66
src/main.py
@@ -1,5 +1,6 @@
|
||||
"""FastAPI application for ZUGFeRD invoice processing."""
|
||||
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
@@ -9,8 +10,15 @@ from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from src.extractor import ExtractionError
|
||||
from src.models import HealthResponse
|
||||
from src.extractor import ExtractionError, extract_zugferd
|
||||
from src.models import (
|
||||
ExtractRequest,
|
||||
ExtractResponse,
|
||||
HealthResponse,
|
||||
ValidateRequest,
|
||||
ValidateResponse,
|
||||
)
|
||||
from src.validator import validate_invoice
|
||||
|
||||
|
||||
class JSONFormatter(logging.Formatter):
|
||||
@@ -60,6 +68,25 @@ async def extraction_error_handler(request: Request, exc: ExtractionError):
|
||||
)
|
||||
|
||||
|
||||
@app.exception_handler(HTTPException)
|
||||
async def http_exception_handler(request: Request, exc: HTTPException):
|
||||
if isinstance(exc.detail, dict) and "error" in exc.detail:
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={
|
||||
"error": exc.detail.get("error"),
|
||||
"message": exc.detail.get("message"),
|
||||
},
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={
|
||||
"error": "http_error",
|
||||
"message": str(exc.detail),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@app.exception_handler(Exception)
|
||||
async def generic_error_handler(request: Request, exc: Exception):
|
||||
logger.error(f"Internal error: {exc}")
|
||||
@@ -82,6 +109,41 @@ async def health_check() -> HealthResponse:
|
||||
return HealthResponse(status="healthy", version="1.0.0")
|
||||
|
||||
|
||||
@app.post("/extract", response_model=ExtractResponse)
|
||||
async def extract_pdf(request: ExtractRequest) -> ExtractResponse:
|
||||
"""Extract ZUGFeRD data from PDF.
|
||||
|
||||
Args:
|
||||
request: ExtractRequest with pdf_base64 field
|
||||
|
||||
Returns:
|
||||
ExtractResponse with extraction results
|
||||
"""
|
||||
try:
|
||||
pdf_bytes = base64.b64decode(request.pdf_base64)
|
||||
except Exception:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail={"error": "invalid_base64", "message": "Invalid base64 encoding"},
|
||||
)
|
||||
|
||||
return extract_zugferd(pdf_bytes)
|
||||
|
||||
|
||||
@app.post("/validate", response_model=ValidateResponse)
|
||||
async def validate_invoice_endpoint(request: ValidateRequest) -> ValidateResponse:
|
||||
"""Validate ZUGFeRD invoice data.
|
||||
|
||||
Args:
|
||||
request: ValidateRequest with xml_data, pdf_text, checks
|
||||
|
||||
Returns:
|
||||
ValidateResponse with validation results
|
||||
"""
|
||||
result = validate_invoice(request)
|
||||
return ValidateResponse(result=result)
|
||||
|
||||
|
||||
def run(host: str = "0.0.0.0", port: int = 5000) -> None:
|
||||
"""Run the FastAPI application.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user