DEV Community

Sudharsan B
Sudharsan B

Posted on

I Built a Receipt Sorter That Never Sends Your Client Data Anywhere

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

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
Enter fullscreen mode Exit fullscreen mode

Code

GitHub logo 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

  1. Install Ollama and pull a vision model:
    ollama pull gemma3:4b
    
  2. 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:4b by 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" and temperature: 0. The code still treats the reply as untrusted. Dates must match YYYY-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)