This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
GST Invoice & Receipt Sorter: a local app that turns a messy folder of invoice photos and PDFs into one clean, validated Excel sheet.
In India, freelancers, small shops and small CA (accountant) offices collect dozens of invoices a month, and someone types them into a spreadsheet by hand to file GST returns. It is slow, and one wrong digit in a 15-character tax ID (GSTIN) or a total can cause problems later. Those people also don't want to upload client financial documents to a cloud service, and per-page cloud OCR/LLM pricing adds up.
You drop in files like IMG_2031.jpg or bill_final.pdf and get one row per invoice: vendor, GSTIN, invoice number, date, taxable amount, CGST/SGST/IGST and total. Every row carries its source file, a review status and the exact reason for any warning.
The key design rule: the model only copies what is printed. It never decides whether an invoice is correct. Plain Python checks do that (GSTIN checksum, tax arithmetic, state codes, dates, duplicates), and nothing is "verified" until a person marks it Reviewed.
Demo
Code
GST Invoice & Receipt Sorter
Turns a folder of Indian GST invoices (PDF, JPG, PNG) into one validated spreadsheet. Everything runs on your computer: OCR, the language model, validation, storage and export. No cloud AI, no paid API, no telemetry.
Files → ingest → render PDF pages → preprocess → OCR → local LLM (Ollama) → deterministic GST checks
→ human review & correction → Excel / CSV
The model only copies what is printed. All GST checks (GSTIN checksum, tax arithmetic, state codes, dates
duplicates) are plain Python in pipeline/validate.py. Extraction success is never shown as "verified": only a person
can mark an invoice Reviewed.
1. Prerequisites
| Need | Notes |
|---|---|
| Python 3.11 or 3.12 | Recommended: PaddleOCR/PaddlePaddle wheels lag behind the newest Python. The code and tests also ran on 3.13 with Tesseract. |
| Ollama | Local model server. |
| 8 GB RAM minimum | The default 7B model needs roughly 5-6 |
How I Built It
Pipeline: files -> render PDF pages -> OpenCV preprocessing -> OCR -> local LLM -> deterministic GST validation -> human review -> Excel/CSV
-
Open-weight model: Qwen2.5 Instruct (7B by default, configurable) served locally by Ollama. It returns strict JSON that is parsed with Pydantic, with one repair retry at most. Missing values stay
null, never0. - OCR: PaddleOCR as the primary engine, Tesseract as fallback.
- App: Streamlit review screen (original page beside editable fields), SQLite for saved corrections, pandas/openpyxl for export.
- Validation (no LLM involved): GSTIN format and mod-36 checksum, total = taxable + taxes within a configurable tolerance, CGST/SGST consistency, state-code vs tax-type warnings, date parsing, duplicate detection, and a check that every extracted value actually appears in the OCR text (to catch hallucinations).
- Safety: spreadsheet formula-injection protection, localhost-only Ollama (non-loopback hosts are refused), logs that never contain invoice contents.
What I measured (20 fictitious invoices, 5 degradation types, Tesseract, CPU only):
| Field | Found in OCR text |
|---|---|
| Names, invoice no., date, total, CGST, SGST | 100% |
| Vendor GSTIN / Buyer GSTIN | 70% / 55% |
GSTINs are where OCR struggles (letter O for digit 0, and so on). Of 40 GSTINs copied from OCR text, 17 were misread and the checksum caught 15 of them; the other 2 were a role mix-up in my test script, not a checksum failure. That is the point of the validation layer.
I also found a real bug through testing: Tesseract's default mode dropped the large vendor-name heading (4/10 found); a different page-segmentation mode fixed it (10/10).
300 automated tests cover validation, malformed LLM output, Ollama being down, failed OCR, multi-page PDFs, persistence of manual corrections and export safety.
Why Does Open Innovation Matter?
- Privacy is the product. Invoices contain tax IDs and client amounts. With open weights and local inference, nothing leaves the laptop, and a small CA office can say that to its clients and mean it.
- Cost stays near zero. No per-page fee, so the business works even at a few rupees of margin per document.
- I could inspect and control every layer. Swapping the model for a smaller one on an 8 GB laptop is one setting. I could pin the output schema, tune OCR settings, and test failures with test doubles, none of which depends on someone else's API changing.
- Honest limits: a small local model makes more mistakes than a large closed one, which is exactly why I built the deterministic checks and review screen around it instead of trusting it.
My First User
My first user was a friend who runs a small electronics business and regularly handles supplier invoices and purchase receipts. Before trying the tool, he managed invoice details manually in spreadsheets, which was repetitive and took time away from other business tasks.
I tested the workflow using 10 sample invoices. The tool extracted the key fields into a structured spreadsheet and flagged entries that needed manual review. The biggest challenge was GSTIN recognition, where similar-looking characters could be misread by OCR. This reinforced why automated validation and human review are essential rather than blindly trusting extracted data.
Would he pay? He found the tool useful, particularly because it could reduce manual data entry while keeping financial documents on his computer. We haven't established a price or confirmed his willingness to pay yet.
What he asked for next: Better GSTIN recognition and easier export into accounting software such as Tally. These would make the tool more practical for businesses that already have an established accounting workflow.
This initial feedback helped reinforce the project's core goal: making invoice processing faster without compromising privacy or treating automated extraction as infallible.
Top comments (0)