feat: Phase 5 – PDF/Bild-Beleg-Import (lokal, Tesseract-OCR)
Backend: - services/ocr: PDF-Text via PyMuPDF, OCR (Tesseract) für Scans/Bilder, heuristischer Parser (Datum + Betrag je Zeile, CH/DE/US-Beträge). - routers/documents: /documents/preview (Upload -> Text -> Kandidaten -> gemeinsame Prüf-/Buchungslogik des CSV-Imports). csv_import refaktoriert: detect_rows() von CSV und Beleg gemeinsam genutzt. - requirements: PyMuPDF, pytesseract, pillow; install.sh installiert tesseract-ocr (+ deu). pytest: Heuristik-Parser und PDF-Vorschau. Frontend: - Import-Seite: CSV/PDF-Umschalter; PDF-Modus mit Beleg-Auslesen, extrahiertem Text zur Kontrolle und Best-Effort-Hinweis; gleiche Prüfansicht + Buchen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
"""PDF-/Bild-Beleg-Import (Phase 5, lokal). Nutzt die Prüf-/Buchungslogik des CSV-Imports."""
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..database import get_db
|
||||
from ..deps import get_current_user, get_owned
|
||||
from ..models import Account, User
|
||||
from ..services import csv_import, ocr
|
||||
|
||||
router = APIRouter(prefix="/documents", tags=["documents"])
|
||||
|
||||
|
||||
@router.post("/preview")
|
||||
async def preview(
|
||||
file: UploadFile = File(...),
|
||||
account_id: int = Form(...),
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
account = get_owned(db, Account, account_id, user)
|
||||
data = await file.read()
|
||||
try:
|
||||
text = ocr.extract_text(data, file.filename or "", file.content_type or "")
|
||||
except ocr.ExtractionError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
candidates = ocr.parse_transactions(text)
|
||||
rows = csv_import.detect_rows(db, user, account, candidates)
|
||||
return {
|
||||
"rows": rows,
|
||||
"text": text[:8000],
|
||||
"count": len(rows),
|
||||
"filename": file.filename or "",
|
||||
}
|
||||
Reference in New Issue
Block a user