A receipt sorter that never leaves your laptop (Gemma + Ollama)
This is a submission for the Hacktoberfest Challenge, Week 2: Side Hustle. What I Built Freelancers collect receipts and invoices from many places: email PDFs, phone photos, app screenshots. At tax time someone has to
This is a submission for the Hacktoberfest Challenge, Week 2: Side Hustle.
What I Built
Freelancers collect receipts and invoices from many places: email PDFs, phone photos, app screenshots. At tax time someone has to type each one into a spreadsheet. Those documents hold client names, rates and payment details, and many freelancers donβt want them uploaded to a service they donβt control.
Local Receipt Sorter is a small app that runs entirely on the userβs own computer. You drop in receipts, it reads the vendor, date, invoice number, currency, subtotal, tax and total, flags anything suspicious, and exports a CSV or Excel file for the accountant. It also suggests a clean filename for each document, like 2026-03-04_acme-cloud_1180.00.pdf.
The side hustle idea: sell it to freelancers as [a one-time license / a monthly fee of X / a done-for-you service for X per batch].
Demo
Local Receipt Sorter
Drop in receipts and invoices; get a reviewed CSV/Excel. Runs fully offline.
Setup
- Install Ollama (https://ollama.com), then:
ollama pull gemma3:4b pip install -r requirements.txtstreamlit run app.py
Use a bigger model with RECEIPT_MODEL=gemma3:12b streamlit run app.py.
Measure accuracy
Put 30-50 receipts and a labels.json in eval_set/, then python eval.py eval_set.
How I Built It
Model: a Gemma vision model (gemma3:4b) served locally through Ollama. Documents never leave the machine.
Structured output: the modelβs answer is forced into a JSON schema, so every field comes back in a predictable shape.
Checks instead of self-reported confidence: small models are poor at judging their own accuracy, so I didnβt ask the model how sure it was. A rule-based checker flags missing fields, bad or future dates, non-positive totals, and rows where subtotal plus tax doesnβt equal the total.
Review before export: every row appears in an editable table, so the user fixes mistakes before the file is exported.
Stack: Python, PyMuPDF for PDFs, Streamlit for the interface, pandas for export.
What I Found
I tested it on 25 documents: 15 PDFs, 10 photos and 15 screenshots. .
One result I liked: my first test files were order pages that can generate an invoice, not actual invoices, and they had no date. I assumed the empty date column was a model failure and loosened my prompt. Then I realized the model was right: there was no date to read. I changed the prompt to say βnever invent a date, vendor or amountβ so it stays that way.
Why Open Innovation Matters
Privacy is the product. The documents are read by a model running on the userβs own computer.

I turned off Wi-Fi and it still worked.
No per-document fee. Thereβs no API bill that grows with each receipt, so a flat price can work.
I can change it. I can swap in a larger Gemma model with one setting, tighten the prompt, or fine-tune later for a specific kind of invoice.
I did not compare it against a closed model, so Iβm not claiming itβs better. The claim is smaller: a small open model, running locally, can do a useful part of this job.
Limits
I tested only 25 documents, so these results show it works, not how often.
Whatβs Next
More test documents, a larger model, fine-tuning for a niche such as GST invoices, a first paying user
Prize Category
Best Use of Gemma. The whole project runs on Gemma through Ollama.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.
