Image-to-Text
Transformers
Joblib
Persian
English
document-ai
ocr
invoice
persian
enterprise
aria-ai
Instructions to use alirezaaminzadeh/docflow-invoice-parser-fa with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use alirezaaminzadeh/docflow-invoice-parser-fa with Transformers:
# Use a pipeline as a high-level helper # Warning: Pipeline type "image-to-text" is no longer supported in transformers v5. # You must load the model directly (see below) or downgrade to v4.x with: # 'pip install "transformers<5.0.0' from transformers import pipeline pipe = pipeline("image-to-text", model="alirezaaminzadeh/docflow-invoice-parser-fa")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("alirezaaminzadeh/docflow-invoice-parser-fa", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| """FastAPI application for DocFlow AI.""" | |
| from __future__ import annotations | |
| import io | |
| import os | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| from fastapi import Depends, FastAPI, File, HTTPException, Query, UploadFile | |
| from fastapi.responses import StreamingResponse | |
| from sqlalchemy.orm import Session | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT)) | |
| from api.database import get_db, init_db # noqa: E402 | |
| from api.review_service import approve_review, create_review, get_review, list_reviews, reject_review # noqa: E402 | |
| from api.schemas import ExtractResponse, HealthResponse, ReviewAction, ReviewDetail, ReviewSummary # noqa: E402 | |
| from docflow.export import to_excel_bytes, to_json # noqa: E402 | |
| from docflow.pipeline import DocFlowPipeline # noqa: E402 | |
| app = FastAPI( | |
| title="DocFlow AI API", | |
| description="Enterprise invoice extraction and accountant review workflow by Aria AI", | |
| version="1.0.0", | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| ) | |
| pipeline = DocFlowPipeline(validate=True) | |
| MAX_UPLOAD_MB = int(os.getenv("MAX_UPLOAD_SIZE_MB", "10")) | |
| ALLOWED_TYPES = {"image/png", "image/jpeg", "image/jpg", "application/pdf"} | |
| def on_startup() -> None: | |
| init_db() | |
| def health(db: Session = Depends(get_db)) -> HealthResponse: | |
| try: | |
| db.execute(__import__("sqlalchemy").text("SELECT 1")) | |
| db_status = "connected" | |
| except Exception: | |
| db_status = "disconnected" | |
| return HealthResponse(database=db_status) | |
| async def extract_invoice( | |
| file: UploadFile = File(...), | |
| validate: bool = Query(True), | |
| queue_review: bool = Query(True), | |
| db: Session = Depends(get_db), | |
| ) -> ExtractResponse: | |
| if file.content_type not in ALLOWED_TYPES: | |
| raise HTTPException(400, f"Unsupported file type: {file.content_type}") | |
| content = await file.read() | |
| if len(content) > MAX_UPLOAD_MB * 1024 * 1024: | |
| raise HTTPException(413, f"File exceeds {MAX_UPLOAD_MB}MB limit") | |
| suffix = Path(file.filename or "upload.png").suffix or ".png" | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp: | |
| tmp.write(content) | |
| tmp_path = tmp.name | |
| try: | |
| pipeline.validate = validate | |
| invoice, validation, _ = pipeline.process(tmp_path) | |
| except Exception as exc: | |
| raise HTTPException(422, f"OCR/processing failed: {exc}") from exc | |
| finally: | |
| Path(tmp_path).unlink(missing_ok=True) | |
| review_id = None | |
| if queue_review: | |
| review = create_review(db, invoice, validation) | |
| review_id = review.id | |
| return ExtractResponse( | |
| invoice=invoice.to_export_dict(), | |
| validation=validation.model_dump() if validation else None, | |
| review_id=review_id, | |
| ) | |
| async def export_excel( | |
| file: UploadFile = File(...), | |
| validate: bool = Query(True), | |
| ): | |
| content = await file.read() | |
| suffix = Path(file.filename or "upload.png").suffix or ".png" | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp: | |
| tmp.write(content) | |
| tmp_path = tmp.name | |
| try: | |
| pipeline.validate = validate | |
| invoice, validation, _ = pipeline.process(tmp_path) | |
| excel_bytes = to_excel_bytes(invoice, validation) | |
| except Exception as exc: | |
| raise HTTPException(422, f"Processing failed: {exc}") from exc | |
| finally: | |
| Path(tmp_path).unlink(missing_ok=True) | |
| return StreamingResponse( | |
| io.BytesIO(excel_bytes), | |
| media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
| headers={"Content-Disposition": "attachment; filename=docflow_export.xlsx"}, | |
| ) | |
| def get_reviews(status: str | None = Query(None), db: Session = Depends(get_db)) -> list[ReviewSummary]: | |
| reviews = list_reviews(db, status=status) | |
| return [ | |
| ReviewSummary( | |
| id=r.id, | |
| vendor_name=r.vendor_name, | |
| invoice_number=r.invoice_number, | |
| total_amount=r.total_amount, | |
| currency=r.currency, | |
| confidence=r.confidence, | |
| status=r.status, | |
| created_at=r.created_at, | |
| reviewer=r.reviewer, | |
| ) | |
| for r in reviews | |
| ] | |
| def get_review_detail(review_id: str, db: Session = Depends(get_db)) -> ReviewDetail: | |
| review = get_review(db, review_id) | |
| if not review: | |
| raise HTTPException(404, "Review not found") | |
| return ReviewDetail( | |
| id=review.id, | |
| vendor_name=review.vendor_name, | |
| invoice_number=review.invoice_number, | |
| total_amount=review.total_amount, | |
| currency=review.currency, | |
| confidence=review.confidence, | |
| status=review.status, | |
| created_at=review.created_at, | |
| reviewer=review.reviewer, | |
| invoice_data=review.invoice_data, | |
| validation_data=review.validation_data, | |
| review_notes=review.review_notes, | |
| reviewed_at=review.reviewed_at, | |
| ) | |
| def approve(review_id: str, action: ReviewAction, db: Session = Depends(get_db)) -> ReviewDetail: | |
| review = approve_review(db, review_id, action.reviewer, action.notes) | |
| if not review: | |
| raise HTTPException(404, "Review not found") | |
| return get_review_detail(review_id, db) | |
| def reject(review_id: str, action: ReviewAction, db: Session = Depends(get_db)) -> ReviewDetail: | |
| review = reject_review(db, review_id, action.reviewer, action.notes) | |
| if not review: | |
| raise HTTPException(404, "Review not found") | |
| return get_review_detail(review_id, db) | |