Skip to content

Latest commit

Β 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Invoice AI Backend πŸš€

A modern, production-ready, highly performant backend built with FastAPI to process and manage invoice details with local deep learning models (LayoutLMv3) and semantic search (FAISS RAG).


πŸ› οΈ System Architecture

The following diagram illustrates the complete, decoupled processing pipeline:

graph TD
    Client[Client Browser / API Client] -->|1. POST /extract-invoice| API[FastAPI Gateway]
    API -->|2. Save File| Disk[(Local Uploads Volume)]
    API -->|3. Register Job| DB[(PostgreSQL Database)]
    API -->|4. Push Task| Broker[Redis Message Broker]
    API -->|5. 202 Accepted job_id| Client
    
    Broker -->|6. Consume Task| Worker[Celery Processing Worker]
    Worker -->|7. Load Image| Disk
    Worker -->|8. Run Pipeline| Inference[Inference Pipeline]
    
    subgraph Inference Pipeline
        Inference -->|8a. Preprocess & OCR| OCR[PaddleOCR]
        OCR -->|8b. Spatial Word Tokens| LLM[LayoutLMv3 Token Classification]
        LLM -->|8c. Grounded Entities| Post[Post-Processing Heuristics]
        Post -->|8d. Structured Line Items| Table[Table Parsing Engine]
    end
    
    Inference -->|9. Write Relational Records| DB
    Inference -->|10. Embed Chunks| Embedder[Sentence-Transformers]
    Embedder -->|11. Ingest dense vectors| FAISS[FAISS Vector Store]
    Inference -->|12. Set Job status to COMPLETED| DB
    
    Client -->|13. GET /jobs/job_id| API
    API -->|14. Query Job & Invoice| DB
    API -->|15. Return JSON Result| Client
Loading

πŸ—„οΈ Relational Database Schema (ERD)

The relational schema decouples vector indexing metadata from core business entities:

erDiagram
    jobs ||--o| invoices : "links on completion"
    invoices ||--o{ line_items : "contains"
    invoices ||--o{ embedding_metadata : "maps vectors to"

    invoices {
        uuid invoice_id PK
        string raw_invoice_id
        string seller
        string buyer
        string invoice_date
        string due_date
        string currency
        numeric total_amount
        string processing_status
        float confidence_score
        json extraction_confidence
        json extraction_source
        json extraction_metadata
        float processing_time_ms
        string model_version
        string ocr_engine
        datetime created_at
        datetime updated_at
    }

    line_items {
        uuid line_item_id PK
        uuid invoice_id FK
        string item_name
        string quantity
        string unit_price
        string tax
        string total
        datetime created_at
        datetime updated_at
    }

    embedding_metadata {
        uuid embedding_id PK
        uuid invoice_id FK
        string chunk_type
        integer chunk_index
        integer faiss_index
        datetime created_at
    }

    jobs {
        uuid job_id PK
        string status
        string file_path
        integer retry_count
        datetime last_retry_at
        string failure_reason
        string error_message
        datetime started_at
        datetime completed_at
        string worker_hostname
        uuid invoice_id FK
        datetime created_at
        datetime updated_at
    }

    users {
        uuid id PK
        string username
        string hashed_password
        datetime created_at
    }
Loading

πŸ“– API Reference

Endpoint Method Description Request Payload / Params Response Payload
/ GET Home / Metadata endpoint. None {"message": str, "environment": str}
/health GET Liveness probe checking API health. None {"status": "healthy", ...}
/ready GET Readiness probe checking Postgres, models, and FAISS. None {"status": "ready" | "not_ready", "checks": dict}
/auth/register POST Registers a new user. {"username": str, "password": str} {"id": UUID, "username": str}
/auth/login POST User login to retrieve signed JWT access token. OAuth2 password form (username, password) {"access_token": str, "token_type": "bearer"}
/extract-invoice POST Upload file, create database job, queue worker task (JWT Protected). Multipart form file (image/png or jpeg) {"job_id": UUID, "status": "QUEUED"}
/jobs/{job_id} GET Job polling endpoint (JWT Protected). Path Parameter: job_id (UUID) Complete Job status + nested Invoice JSON
/query POST Retrieves matching context segments from FAISS (JWT Protected). {"query": str, "top_k": int} {"query": str, "results": list}
/query/ask POST QA assistant endpoint over invoices using Groq (JWT Protected). {"question": str, "top_k": int} {"answer": str, "sources": list}
/invoices GET Paginated metadata list of all processed invoices (JWT Protected). Query Params: skip (default 0), limit (default 100) List of Invoice metadata summaries
/invoices/{invoice_uuid} GET Detailed metadata and line items of a specific invoice (JWT Protected). Path Parameter: invoice_uuid (UUID) Complete Invoice + Line Items JSON
/invoices/review GET Lists all invoices requiring manual review (JWT Protected). Query Params: skip (default 0), limit (default 100) List of low-confidence Invoice Response objects
/invoices/{invoice_uuid}/correct POST Submits manual reviewer corrections for fields/line-items (JWT Protected). Path Parameter: invoice_uuid, Correction JSON payload Updated Invoice Response object
/metrics GET Resources and application index counters (Prometheus registry). None CPU, Memory, Disk, and telemetry metrics
/rag/status GET Total chunks and document metrics inside FAISS (JWT Protected). None FAISS total index segment metrics
/jobs/cleanup POST Housekeeping task enforcing retention policies (JWT Protected). Query Parameter: retention_days (default 7) {"message": str}

⚑ Quick Start

1. Prerequisites

Ensure you have Python 3.10+ installed on your system.

2. Set Up Virtual Environment

It is highly recommended to use a virtual environment.

On Windows (PowerShell):

# Create virtual environment
python -m venv .venv

# Activate virtual environment
.venv\Scripts\Activate.ps1

On macOS/Linux:

# Create virtual environment
python3 -m venv .venv

# Activate virtual environment
source .venv/bin/activate

3. Install Dependencies

pip install -r requirements.txt

4. Run the Development Server

Launch the application with live reload enabled:

uvicorn app.main:app --reload

The application will be running at http://127.0.0.1:8000. Swagger API docs are accessible at http://127.0.0.1:8000/docs.

5. Run the Test Suite

The backend features an isolated, mocked testing suite. Execute tests with:

python -m pytest -v

πŸ“ Project Structure

invoice_ai_backend/
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── ci.yml                 # GitHub Actions CI workflow (Ruff + Pytest + Docker Build)
β”œβ”€β”€ app/                           # Core application logic
β”‚   β”œβ”€β”€ auth.py                    # JWT cryptography & password hashing dependencies
β”‚   β”œβ”€β”€ auth_routes.py             # User Register / Login endpoints
β”‚   β”œβ”€β”€ celery_app.py              # Celery config instance
β”‚   β”œβ”€β”€ config.py                  # Pydantic Settings layer (dotenv files loader)
β”‚   β”œβ”€β”€ crud.py                    # SQLAlchemy database CRUD operations
β”‚   β”œβ”€β”€ database.py                # Postgres connection pool and session maker
β”‚   β”œβ”€β”€ inference.py               # Invoice extraction coordinator (OCR + LayoutLMv3)
β”‚   β”œβ”€β”€ llm_engine.py              # Groq prompt formatting & QA scaffolding
β”‚   β”œβ”€β”€ logging_config.py          # Loguru JSON / colorized structured logging
β”‚   β”œβ”€β”€ main.py                    # FastAPI entrypoint, HTTP middleware, routes
β”‚   β”œβ”€β”€ metrics_manager.py         # Telemetry manager exposing app & system counters
β”‚   β”œβ”€β”€ models.py                  # SQLAlchemy relational tables
β”‚   β”œβ”€β”€ ocr_engine.py              # PaddleOCR image text extraction
β”‚   β”œβ”€β”€ rag_engine.py              # Embedding generation and retrieval router
β”‚   β”œβ”€β”€ rate_limiter.py            # Redis-based sliding window rate limiter
β”‚   β”œβ”€β”€ reranker.py                # Cross-Encoder candidate reranker integration
β”‚   β”œβ”€β”€ review_routes.py           # Human-in-the-loop review & manual correction router
β”‚   β”œβ”€β”€ schemas.py                 # Pydantic schemas
β”‚   β”œβ”€β”€ table_engine.py            # Line-item coordinate parsing
β”‚   β”œβ”€β”€ tasks.py                   # Celery tasks (idempotency, transient/exp retry)
β”‚   β”œβ”€β”€ utils.py                   # Heuristic regex helper methods
β”‚   └── vector_db.py               # FAISS vector store wrapper
β”œβ”€β”€ docker/
β”‚   β”œβ”€β”€ docker-compose.yml         # Dev/Production multi-container composition
β”‚   β”œβ”€β”€ prometheus.yml             # Prometheus scraping configurations
β”‚   └── grafana/                   # Grafana dashboards configuration volume
β”œβ”€β”€ model/
β”‚   └── layoutlmv3_production_model/ # Fine-tuned LayoutLMv3 weights & configurations
β”œβ”€β”€ outputs/                       # Persisted FAISS binary index & document JSON
β”œβ”€β”€ scratch/                       # Diagnostic and development scripts
β”œβ”€β”€ scripts/
β”‚   └── evaluate.py                # Pipeline evaluation script (Precision, Recall, F1)
└── tests/                         # Pytest suite with import-time ML mocks

πŸš€ Production Capabilities

⚑ 1. Asynchronous Job Architecture (Celery & Redis)

Ingestion workloads are decoupled from the API gateway using Celery and Redis. File uploads register a tracker state in PostgreSQL and push extraction to background workers, immediately returning a 202 Accepted status with a job_id. Workers feature exponential retry backoff (5s $\rightarrow$ 15s $\rightarrow$ 45s) for transient failures, and a clean cron housekeeping scheduler removes stale uploads older than a configured day threshold.

πŸ” 2. Hybrid RAG, Query Router & Cross-Encoder Reranker

Retrieval utilizes a hybrid search system:

  • Segmented Chunking: Invoices are parsed into semantic regions (header, seller, buyer, totals, line_items).
  • Query Router: Parses natural language expressions for query filters (e.g. "from Amazon", "above $100", "last month") and executes metadata filtering on PostgreSQL first.
  • RRF & Reranking: Combines keyword search (Okapi BM25) and dense similarity matches (FAISS FlatIP) using Reciprocal Rank Fusion, then re-scores the merged candidates with cross-encoder/ms-marco-MiniLM-L-6-v2 (lightweight ~80MB, CPU-optimized) to output the top 5 relevant document nodes.

πŸ”’ 3. JWT Access Controls & Redis Rate Limiter

Endpoints are guarded by JWT tokens (signed with HMAC-SHA256, passwords hashed via Bcrypt). API resources are protected against denial of service through a Redis sliding-window rate limiter enforcing a 100 requests/minute limit per user using Redis Sorted Sets (zsets), with path exemptions for monitoring hooks.

πŸ“Š 4. Telemetry & Observability (Prometheus & Grafana)

Application execution phases (OCR, LayoutLMv3, post-process, tables, FAISS, embeddings) are instrumented using a unified metrics_manager.py telemetry layer. Performance metrics and host resource states are scraped by Prometheus every 5 seconds and visualized on dedicated Grafana dashboards using Docker container compositions backed by persistent volume mounts.

πŸ§ͺ 5. Dynamic SQLite Mock Testing & CI/CD

Our automated test suite features:

  • Temporary file-based SQLite database session overlays to isolate integration tests from PostgreSQL database files.
  • Lazy loading ML model wrappers and mock overrides to bypass heavy GPU/CPU model loading and online weights download attempts during testing.
  • Continuous Integration (CI): Integrated ruff linting, ruff formatting, pytest runs, and Docker multi-stage CPU builds inside a GitHub Actions pipeline.

πŸ‘₯ 6. Explainability & Human-in-the-Loop (HITL) Workflow

LayoutLMv3 outputs are mapped to spatial bounding boxes [x1, y1, x2, y2] to explain extraction coordinates. Invoices producing an average field confidence below 0.70 are flagged with "NEEDS_REVIEW" status. Humans can fetch these invoices via GET /invoices/review and post manual field/line-item corrections via POST /invoices/{uuid}/correct, which updates the relational tables, marks status as "COMPLETED", and exports a training JSON pair mapping the original image, OCR text, and corrected fields to corrected_data/ for future model retraining.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages