The Problem
Manual review of credit‑application PDFs is slow, error‑prone, and costly. Teams need a repeatable way to extract structured financial fields from scanned documents without sending data to external APIs.
What This Does
The repository implements a self‑contained OCR pipeline that runs entirely on‑premise. Core code lives under src/:
src/ocr/easyocrclient.py – wraps EasyOCR, returns raw text and bounding boxes. src/llm/fieldextractor.py – feeds OCR output to a local LLM (served by Ollama) to produce key‑value pairs. src/tasks/pipelinetasks.py and src/celeryapp.py – define Celery workers that orchestrate OCR → LLM → validation asynchronously.
The Flask API (src/api/main.py) exposes endpoints for document upload and status queries, while src/visualization/ocrvisualization.py creates overlay images for human review. Configuration files (config/credit-ocr-system.conf, config/documenttypes.conf) drive document‑type rules and storage paths.
How To Use It
Prepare the environment # Copy the template and edit as needed cp .env.template .env # Edit .env to set POSTGRES, REDIS, AZURITE, and Ollama connection strings
The .env values are consumed by docker-compose.yml and by the Flask app via src/api/config.py. Build and start the stack docker compose up --build -d
Dockerfile builds the Python image used by the api service. compose.yml defines PostgreSQL, Redis, Azurite (Azure Blob emulator), Ollama, and the API container. Run the API locally (optional) If you prefer a direct Python launch: uv pip install -r <(uv pip compile pyproject.toml) # installs declared deps python runapi.py # starts Flask on port 5000 Upload a document Send a POST request to http://localhost:5000/upload with a PDF file. The API stores the blob in Azurite, creates a Celery job, and returns a job ID. Check processing status curl http://localhost:5000/status/<jobid>
When completed, the response includes extracted fields, confidence scores, and a URL to the visual overlay image.
All notebooks under notebooks/ (e.g., 02ocrtextextraction.ipynb) demonstrate each stage step‑by‑step and can be used as reference implementations.
Real‑World Use
A loan‑origination service can embed the API behind its existing web portal:
import requests
files = {'file': open('loanapplication.pdf', 'rb')} resp = requests.post('https://ocr.mycompany.com/upload', files=files) jobid = resp.json()['jobid']
poll until done while True: status = requests.get(f'https://ocr.mycompany.com/status/{jobid}').json() if status['state'] == 'COMPLETED': break time.sleep(2)
print(status['extractedfields'])
The workflow runs entirely on internal infrastructure, preserving data privacy while delivering sub‑10‑minute turnaround.
Code Health & Issues
| Severity | Issue | Location |
|---|---|---|
| Medium | No CI/CD pipeline (no .github/, GitLab CI, etc.) – builds and tests are not gated automatically. | Root |
| Medium | No LICENSE file – downstream users cannot be sure of redistribution rights. | Root |
| Low | Dependencies are declared only in pyproject.toml; there is no lockfile (uv.lock exists but is not referenced in CI). | pyproject.toml, uv.lock |
| Low | .env.template contains placeholder secrets; production deployment relies on manual editing, increasing risk of accidental commit of real credentials. | .env.template |
| Low | Celery tasks (src/tasks/pipelinetasks.py) lack explicit retry/back‑off policies, which could cause lost work under transient failures. | src/tasks/pipelinetasks.py |
| Low | API input validation is minimal – uploaded files are accepted without size/type checks. | src/api/routes.py |
| Low | Documentation is extensive (README, notebooks, docs/), but the quick‑start section in the README is truncated, leaving the exact start command ambiguous. | README.md |
Overall the test suite (tests/) covers API routes, DMS integration, and the full pipeline, indicating reasonable functional coverage.
The Bottom Line
The repo provides a complete, on‑premise OCR‑LLM pipeline with Docker‑compose orchestration, suitable for organizations that must keep credit‑application data internal. Code quality is solid, but the lack of CI, a license, and automated dependency locking means additional operational effort is required before production adoption. Teams with in‑house DevOps resources will find it a practical foundation; smaller teams may need to add the missing governance pieces.