Receipt Auditor

Local vision, reconciled, private by construction

Receipt Auditor

Photograph a stack of receipts โ€” get reconciled, categorized spending data with PII redaction built into the schema, plus a locally fine-tuned classifier that beats Claude's cold guess on spend categorization.

By Jeremy Lee

Why

Ask a chatbot to tally your spending from receipt photos and you're trusting it to read every number right and report the sum honestly. Receipt Auditor never lets the model do arithmetic: totals are reconciled in plain code, spend answers are computed by pandas and only phrased by the model โ€” with a guard that catches a dropped or altered number before it ships.

๐Ÿ“ท

No vision API key

Local OCR (tesseract) + Claude reads each receipt โ€” refuses non-receipt photos, flags low-confidence reads.

๐Ÿงฎ

Reconciled, in code

Computed total vs. printed total, checked in plain Python. Mismatches flag for human review, never a silent "fix."

๐Ÿ”’

PII, four layers deep

Schema has no PII fields ยท raw OCR discarded ยท regex sweep ยท session-only on the Space.

๐Ÿง 

Locally fine-tuned

A LoRA-tuned classifier categorizes spending โ€” runs on a laptop, $0 marginal cost.

The categorizer, honestly benchmarked

Every line item gets a spend category from a Qwen2.5-1.5B model, LoRA fine-tuned locally on 4,799 synthetic receipts across realistic POS merchant styles. Benchmarked against the untrained base model and Claude โ€” all three given the identical blind prompt, no category list in-context:

SystemTop-1 accMacro-F1Cost
Base model (no fine-tune)27.7%0.333$0
+ LoRA fine-tune90.5%0.893$0
Claude (teacher, zero-shot)56.0%0.506Max subscription
๐Ÿ† The fine-tuned local model's Top-1 accuracy beats Claude's zero-shot Top-1 by 34.5 points โ€” same blind prompt for all three systems, so this is a fair fight, not LoRA getting a hint Claude didn't see.
๐Ÿ“‹ No real-receipt column yet: the honest synthetic-vs-real tiebreaker needs 10-20 of Jeremy's real receipts, hand-labeled โ€” reported as an open gap, not hidden.

How it works

  1. Upload a batch of receipt photos โ€” local OCR extracts the text, Claude structures it into a receipt and flags anything illegible for you to correct.
  2. Each receipt's total is reconciled against its line items + tax in plain code โ€” mismatches are flagged, never silently fixed.
  3. Each line item is categorized by the locally fine-tuned classifier; PII is swept from every field before anything is cached.
  4. Ask a spending question by voice or text โ€” pandas computes the answer, the model only phrases it, and a guard verifies the number survived phrasing.
๐Ÿ”’ Everything runs locally except one claude -p call per receipt โ€” no metered API, no vision API key. See the full writeup for the honest engineering story, including two real bugs found and fixed by the test suite.
View on GitHub Read the writeup