This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
receipt-sorter turns a messy folder of receipts and invoices into something an accountant can use. It reads each photo, PDF, or text file, pulls out the vendor, date, total, currency, and a category, then copies the file to sorted/<category>/2026-10-01_blue-bottle_12.50.jpg and writes a summary.csv.
It's for freelancers and small-business owners who dread tax season. They have a year of phone photos and emailed PDFs. Their clients' invoices contain names, rates, and project details that they'd rather not upload to a third-party service. Cloud receipt apps charge a monthly fee and want those documents on their servers. This one runs entirely on the user's laptop.
Demo
$ python3 receipt_sorter.py ~/Receipts -o ~/Receipts/sorted
IMG_4412.jpg -> sorted/meals/2026-10-01_blue-bottle_12.50.jpg
inv_0093.pdf -> sorted/services/2026-09-14_acme-design_850.00.pdf
...
<N> sorted, <M> failed. Summary: sorted/summary.csv
Code
sharkie3
/
receipt-sorter
Sort receipts and invoices locally with open-weight Gemma via Ollama. No cloud, no API key.
receipt-sorter
Sort receipts and invoices locally with an open-weight model (Gemma) running on Ollama No cloud, no API key, and client data never leaves your laptop.
Point it at a folder of receipt photos, PDFs, or text files. It extracts the vendor, date, total, currency, and category, then copies each file to sorted/<category>/<date>_<vendor>_<total>.ext and writes a summary.csv for your accountant.
IMG_4412.jpg -> sorted/meals/2026-10-01_blue-bottle_12.50.jpg
inv_0093.pdf -> sorted/services/2026-09-14_acme-design_850.00.pdf
Setup
- Install Ollama and pull a vision model:
ollama pull gemma3:4b - Python 3.9+ is the only other requirement. For PDFs, also run
pip install pypdf.
Usage
python3 receipt_sorter.py ~/Receipts -o ~/Receipts/sorted
| Option | Default | Meaning |
|---|---|---|
-o, --out |
sorted |
Output folder |
-m, --model |
gemma3:4b |
Any Ollama vision model (e.g. gemma3:12b for harder receipts) |
--host |
http://localhost:11434 |
Ollama server |
Categories: software, travel, meals, office, equipment, services, utilities, other.
Notes
- Originals are copied, never modified or moved.
- Model output is validated: bad dates, unknown categories, and malformed totals…
How I Built It
-
Model: Gemma 3 (
gemma3:4bby default) served locally by Ollama. It takes image input, has a 128K context window, and is a 3.4 GB download, so it fits on an ordinary laptop. For harder receipts,gemma3:12b(8.2 GB) is a one-flag swap with-m. Any other Ollama vision model works too. -
Images go to the model as base64 through Ollama's
/api/chat. PDFs and text are extracted to text first (pypdf) and sent as a prompt. -
Structured output: the request uses
format: "json"andtemperature: 0. The code still treats the reply as untrusted. Dates must matchYYYY-MM-DD, categories must be in a fixed list, and totals are parsed defensively. Anything invalid falls back to a safe default (other, undated) instead of crashing the run. - Safe by design: originals are copied, never moved or modified. Name collisions get a numeric suffix. One bad file is reported and skipped, not fatal.
- The whole tool is a single Python file using only the standard library (plus optional
pypdf).
Why Does Open Innovation Matter?
- Privacy is the product. Client invoices never leave the machine. With a closed API, "we don't train on your data" is a promise. Here it's how the system is built, and it works with the network off.
- Cost. Inference is free after the model download, so a one-time-purchase or low-priced tool is viable. Per-page API pricing would force a subscription.
- Swappable and tunable. If a model misreads a particular receipt style, such as a local restaurant's handwritten tickets, I can swap in another model with one flag. I can also fine-tune later without waiting for a vendor.
- No lock-in. A provider's price change or model retirement can't break the tool.
Prize Categories
- Best Use of Gemma: Gemma runs locally and does all extraction.
Top comments (0)