Metadata-Version: 2.4
Name: amagi-receipts-to-csv
Version: 0.1.0
Summary: Turn a folder of receipt photos and PDFs into a clean CSV (date, vendor, subtotal, tax, total, category) with local OCR. QuickBooks Online bank-import preset. No cloud upload.
Author-email: "AmagiLabs (Amagisolutionsgroup, Inc.)" <dev@amagisolutionsgroup.com>
License: MIT
Project-URL: Homepage, https://github.com/amagilabs/amagi-receipts-to-csv
Keywords: receipts,ocr,expenses,bookkeeping,quickbooks,csv,local-first,cli
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pillow>=9.0
Requires-Dist: pypdfium2>=4.0
Requires-Dist: rapidocr-onnxruntime<1.3,>=1.2
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# amagi-receipts-to-csv

Point it at a folder of receipt photos and PDFs and get one CSV back: date, vendor, subtotal,
tax, tip, total and an expense category for every receipt. OCR runs on your own machine, so
nothing is uploaded. It can also write a file that QuickBooks Online will take through
Banking > Upload from file.

Built for freelancers and small-business bookkeepers who keep a shoebox (or a camera roll) of
receipts and type them into a spreadsheet once a month.

![amagi-receipts-to-csv reading five example receipts](https://raw.githubusercontent.com/amagilabs/amagi-receipts-to-csv/master/assets/demo.gif)

## Install

```
pipx install amagi-receipts-to-csv
```

Needs Python 3.10 or newer.
The OCR models ship inside the `rapidocr-onnxruntime` package, so there is nothing else to set
up and no API key.

## Usage

The repo includes five made-up receipts in `examples/receipts`: two photos, one crumpled photo,
one scanned PDF and one PDF with a real text layer.

```
amagi-receipts-to-csv examples/receipts
```

```
amagi-receipts-to-csv: 5 file(s) in examples\receipts
  ok     2026-10-07  Blue Fern Cafe                 23.50  Meals            blue_fern_cafe.jpg
  ok     2026-10-03  Corner Hardware & Supply       51.21  Supplies         corner_hardware.png
  check  2026-10-12  Harbor Street Parking          12.00  Parking & Tolls  crumpled_parking.jpg
         no subtotal line; subtotal is the sum of the item lines
         subtotal 11.86 looks misread; corrected to 11.06 so the receipt adds up
  ok     2026-09-28  Metro Office Supply           171.17  Office Supplies  metro_office_supply.pdf
  ok     2026-09-30  Quickfuel #118                 42.18  Fuel             quickfuel_scan.pdf
5 receipt(s): 4 ok, 1 to check. Sum of totals: 300.06
Wrote receipts.csv
```

`receipts.csv` has one row per receipt:

```
file,date,vendor,subtotal,tax,tip,fees,total,category,status,notes,source
```

A row is `ok` only when the date, vendor and total were all found and, if the receipt prints a
subtotal, subtotal + tax + fees + tip equals the total. Everything else is `check`, and `notes` says what to look at. In the run
above, OCR read the parking stub's subtotal as 11.86. The tool caught that 11.86 + 0.94 does not
make 12.00, fixed the one digit that made the receipt add up, and still marked it for you to
check.

`source` tells you how the text was read: `text-layer` for a PDF with real text (no OCR
needed), or `ocr:rapidocr` / `ocr:tesseract`.

### QuickBooks Online

```
amagi-receipts-to-csv examples/receipts -f qbo
```

This writes `qbo_import.csv` in the 3-column layout QuickBooks accepts for a bank upload, with
each receipt as money going out:

```
Date,Description,Amount
10/07/2026,Blue Fern Cafe,-23.50
10/03/2026,Corner Hardware & Supply,-51.21
10/12/2026,Harbor Street Parking,-12.00
09/28/2026,Metro Office Supply,-171.17
09/30/2026,Quickfuel #118,-42.18
```

Use `-f qbo4` if your bank account is set up for the 4-column Date, Description, Credit, Debit
layout. Add `--only-ok` to leave out the receipts marked `check` until you have looked at them.
Receipts with no date or no total are always left out of the QuickBooks file, and the CLI lists
them.

### Your own categories

The built-in categories are Meals, Fuel, Parking & Tolls, Office Supplies, Supplies, Travel,
Software & Subscriptions, Postage & Shipping, Utilities & Phone and Groceries, picked by
keyword. To use your own chart of accounts, pass a rules file. Your rules are tried before the
built-in ones, and the `vendors` block cleans up names:

```json
{
  "categories": {"Client Meals": ["blue fern"], "Vehicle": ["quickfuel"]},
  "vendors": {"sq *blue fern": "Blue Fern Cafe"}
}
```

```
amagi-receipts-to-csv receipts/ --rules rules.json
```

Add `--no-builtin-categories` to use only your list.

### A local LLM for the hard ones

If you run [Ollama](https://ollama.com), the tool can ask a local model about receipts where a
field is missing or the amounts don't add up:

```
amagi-receipts-to-csv receipts/ --llm llama3.2
```

For LM Studio or llama.cpp, add `--llm-api openai --llm-url http://localhost:1234`. The model
fills in missing fields, and it can replace an amount only when the receipt does not add up.
Any amount or date it gives that is not printed on the receipt is thrown away, and the notes say
so. The tool refuses to talk to a server that is not on your machine unless you pass
`--llm-allow-remote`.

## Options

```
  -o, --output OUTPUT   output file, or - for stdout (default depends on --format)
  -f, --format {csv,qbo,qbo4,json}
  -r, --recursive       look in subfolders too
  --ocr {auto,rapidocr,tesseract}
                        OCR engine: rapidocr (bundled), tesseract (if installed), auto
  --day-first           read 03/10/2026 as 3 October, not March 10
  --rules RULES         JSON file with your own categories and vendor renames
  --no-builtin-categories
                        use only the categories in --rules
  --only-ok             leave receipts marked 'check' out of the output
  --text-dir TEXT_DIR   also save the OCR text of each receipt here, for review
  --llm MODEL           ask a local model (e.g. llama3.2) about receipts the rules could not finish
  --llm-url LLM_URL     LLM server URL. Default: http://localhost:11434 (Ollama)
  --llm-api {ollama,openai}
  --llm-allow-remote    allow an LLM server that is not on localhost
  -q, --quiet           print only the output path
```

It reads .jpg, .png, .webp, .tif, .bmp, .gif and .pdf. iPhone .heic photos work after
`pipx inject amagi-receipts-to-csv pillow-heif`.

Exit codes: 0 means the run finished (even if some receipts need checking). 1 means it could not
run: missing path, no receipt files, bad rules file, no OCR engine, or an LLM server that is not
local. 2 means a bad option.

## How accurate is it?

On the five example receipts every field matches the expected values, and the test suite checks
that with the real OCR engine. Made-up receipts are the easy case, though, so we also scored it
on 13 real receipt photos from Wikimedia Commons, labelled by hand. Four of them have no fair
answer (out of focus, a blank guest check, a slip with no printed total, a coin-counting
voucher). On the other nine:

| Field | Right |
|---|---|
| Date | 6 of 6 labelled |
| Vendor | 4 of 8 labelled |
| Total | 6 of 7 labelled |

Four of the 13 photos came back `ok`, and all four were right on every labelled field. Every
miss landed on a `check` row. Four is a small sample, so look over your first batch closely.

To re-run the benchmark yourself (it downloads the photos once, with credits):

```
python bench/run_commons.py
```

## Limits

- Crumpled, faded, blurry and handwritten receipts lose fields. The tool marks them `check`
  instead of guessing, and the add-up check flags a misread amount, but a wrong vendor name can
  still come through on an `ok` row. Vendor is the weakest field (4 of 8 in the test above).
- A date with no year ("07/23") is left blank.
- One currency per receipt and no currency column. Totals are added up as plain numbers.
- Categories come from keywords. Expect to fix some, or write a rules file.
- Speed on a plain CPU (no GPU): the OCR model takes about 2 seconds to load, then about 2 to 6
  seconds per photo. PDFs with a text layer skip OCR.

## Use it from Claude Code

The repo ships a [SKILL.md](SKILL.md). Copy it to `~/.claude/skills/amagi-receipts-to-csv/SKILL.md` and
Claude Code will run amagi-receipts-to-csv when you ask it to put a folder of receipts in a
spreadsheet or get them into QuickBooks.

## Star it if it saved you an evening

If amagi-receipts-to-csv got you out of a month of typing receipts into a spreadsheet, a star helps
other freelancers and bookkeepers find it. Bug reports with the OCR text of a receipt it got
wrong (`--text-dir` saves it) are the most useful thing you can send.

## Other AmagiLabs projects

- [amagilabs on GitHub](https://github.com/amagilabs): the full catalog of small open-source
  tools from AmagiLabs (Amagisolutionsgroup, Inc.).
- [amagi-watch](https://github.com/amagilabs/amagi-watch): turns a video URL into something
  Claude can read (transcript, key frames and a timestamped index).
- [amagi-legal-review-skills](https://github.com/amagilabs/amagi-legal-review-skills): Claude Code skills
  for contract and lease review.

## Development

```
pip install -e ".[dev]"
pytest
```

`python tests/make_fixtures.py` rebuilds the example receipts. The tests run the real RapidOCR
engine on them; the Tesseract test is skipped if Tesseract is not installed.

## License

MIT. See [LICENSE](LICENSE). Copyright (c) 2026 Amagisolutionsgroup, Inc. (AmagiLabs).
