尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A self-hosted, AI-powered receipt tracker that builds a personal price history database from your grocery receipts. Built with FastAPI, SQLite, HTMX, Tailscale and Google Gemini.
Just want a look? Try the live demo — the
whole app on fictional data, no install. See DEMO.md for how it's built.
To run it locally with the same data, use the demo seed script:
This populates the database with ~4months of ~52 fictional receipts across multiple stores enough to make all dashboards charts and trends pages populate.查看完整 README ↗A self-hosted, AI-powered receipt tracker that builds a personal price history database from your grocery receipts. Built with FastAPI, SQLite, HTMX, Tailscale and Google Gemini.
Just want a look? Try the live demo — the whole app on fictional data, no install. See DEMO.md for how it's built.
To run it locally with the same data, use the demo seed script:
cd backend
uv run python scripts/seed_demo.py
This populates the database with ~4months of ~52 fictional receipts across multiple stores enough to make all dashboards charts and trends pages populate.
CORRECTION_PROMPT_LIMIT lessons (default 10) — pinned ones first, then the newest.uv run python scripts/backfill_store_names.py --apply (run from backend/; without --apply it only previews). When a review changes what a store's text means, the review page offers to move that store's earlier lines with the same text to the new item, after showing exactly which lines would change.scripts/ocr_eval.py measures extraction accuracy against your own reviewed receipts (--stored for a free baseline, --live to benchmark prompt or model changes).data/inbox and they process automatically through the full OCR + review pipeline. (FOLDER_WATCH=0 to disable.)[!NOTE] Edge Cases & Why Things Don't Always Add Up Every store's POS system has its own dialect. Some stores (like Target) distribute a basket discount proportionally across every item. Others put a "-$5.00" line at the bottom, leaving the AI to guess what it applies to. The Sandbox Review step exists to smooth out these idiosyncrasies — separate basket-level rewards into negative line items, or manually adjust prices before data hits your analytics. These corrections are remembered and improve future OCR.
extension/) that surfaces your personal purchase history while browsing Amazon Fresh, Whole Foods on Amazon, and Safeway (safeway.com).Good deal, Typical price, Above avg).static/css/tailwind.css — no Node required).This project is developed through Ensemble AI Programming — a coordinated group of AI harnesses and models, each with a distinct role:
Different models specialize in specific tasks — architectural planning, precise code execution, adversarial review, and OCR parsing — so no single model's weaknesses go unchecked.
curl -LsSf https://astral.sh/uv/install.sh | sh)[!TIP] Getting a free Gemini API key takes about a minute:
- Go to Google AI Studio and sign in with any Google account.
- Click Create API key and copy the key.
- Paste it into your
.envasGEMINI_API_KEY=...(see step 1 below).The free tier is plenty for personal receipt volume — the app minimizes API calls with a rule-based fast path for digital PDFs, OCR result caching, and token-light text-paste ingestion. No credit card required.
Clone & Configure:
git clone https://github.com/smcgarrigle/ihavethereceipts.git
cd ihavethereceipts
cp .env.example .env
# Edit .env and pick an OCR backend:
# OCR_BACKEND=gemini + GEMINI_API_KEY=your_key (cloud)
# or
# OCR_BACKEND=local + OCR_MODEL=granite3.3-vision:2b (LM Studio/Ollama)
# + OCR_BACKEND_URL=http://localhost:11434/v1
Install & Run:
cd backend
uv sync # installs runtime dependencies only
uv run uvicorn app.main:app --reload
[!TIP] Contributing? Install dev tools (linter, type checker, tests) with:
uv sync --extra dev uv run pre-commit install
Optional: Local AI models (LM Studio or Ollama):
# LM Studio: download from https://lmstudio.ai and load a qwen2.5-vl or Granite model
# Ollama:
ollama pull granite3.3-vision:2b # or qwen2.5-vl
Access App: Open http://127.0.0.1:8000
Optional: Run Tailscale or similar on your device to remotely and securely connect to your server
Option 4 in ./start_server.sh runs receipts through your own OpenRouter account, on a model you choose. For users who already have OpenRouter credits and provider preferences.
# root .env
OCR_BACKEND=openrouter
OPENROUTER_API_KEY=sk-or-v1-... # https://openrouter.ai/keys
OCR_MODEL=google/gemma-4-26b-a4b-it:free # any model accepting image input
Privacy Note. When using OpenRoutes receipts leave your machine. Every request carries provider.data_collection=deny, so OpenRouter refuses providers that retain or train on inputs, enforced server-side. Whether a given model still has an endpoint under that policy depends on its providers — some free models do, some don't, and a model with none returns a 404 explaining the options. You can remove that request paramenter from @/app/services/ocr.py return {"provider": {"data_collection": "deny"}}
https://openrouter.ai/models?zdr=true&max_price=0&input_modalities=image
Dependencies are declared in backend/pyproject.toml and pinned in backend/uv.lock.
| Audience | Install command | What you get |
|---|---|---|
| Users | uv sync | Runtime deps only (FastAPI, SQLAlchemy, Gemini, etc.) |
| Contributors | uv sync --extra dev | Runtime + dev tools (Ruff, Mypy, pytest, pre-commit) |
uv.lock pins Python packages only. The frontend stack is vendored and updated manually:
| Asset | Where | How to update |
|---|---|---|
| Tailwind CSS | static/css/tailwind.css (compiled) | Bump VERSION in scripts/build_css.sh, delete tools/tailwindcss, re-run the script, then visually check key pages. Major versions (v4+) change the config format — do not bump casually. |
| HTMX / Alpine.js / Chart.js | static/js/vendor/ | Download the new minified build over the old file, update SBOM.md, and exercise the UI (modals, drawers, charts). |
| Inter font | static/fonts/ | Re-vendor the woff2 subsets and regenerate inter.css. |
Tailwind precautions (precompiled build):
static/css/tailwind.css only contains classes that existed in templates when it was last built. After adding any new Tailwind class, re-run ./scripts/build_css.sh and commit the rebuilt CSS together with the template change — otherwise the class silently renders unstyled.templates/**/*.html, app/api/pages.py, and static/js/**/*.js. If you embed Tailwind classes elsewhere, add that path to content in tailwind.config.js.safelist.'unsafe-eval' from the CSP: the standard Alpine build evaluates inline expressions via AsyncFunction, and every modal/drawer/tab depends on it.The committed uv.lock keeps installs reproducible indefinitely. Refresh it deliberately (every few months, or after a CVE) rather than routinely, and always run the tests before committing the new lock.
cd backend
# Upgrade everything to latest compatible versions
uv lock --upgrade
uv sync --extra dev
uv run pytest && uv run ruff check . && uv run mypy . # verify
# Or upgrade a single package
uv lock --upgrade-package fastapi
Commit the updated uv.lock after a successful test run.
[!NOTE] For security auditing, run
uv run pip-auditperiodically. See SBOM.md for the full dependency inventory.
See ROADMAP.md for the full strategic backlog. Highlights:
Install system dependencies before running uv sync:
# PDF processing + file-type detection
sudo apt install -y poppler-utils
# Optional: local AI via Ollama
curl -fsSL https://ollama.com/install.sh | sh
ollama pull granite3.3-vision:2b # or qwen2.5-vl
Then follow the standard Setup steps. The Makefile in the project root wraps common commands:
make setup # uv sync + pre-commit install
make run # start the dev server
make test # run pytest suite
make lint # ruff check + format check
Common Linux issues:
| Issue | Resolution |
|---|---|
pdfplumber fails to open PDFs | Run sudo apt install poppler-utils |
| Port 8000 already in use | make run PORT=8001 |
| Ollama slow on first run | First inference downloads model weights — normal |
SQLite database is locked | WAL mode is on by default; this is rare under normal use |
[!NOTE] WSL2 users: The app runs fine under WSL2. Access it at
http://127.0.0.1:8000in your Windows browser. For best performance, clone the repo into the WSL2 filesystem (~/projects/) rather than a Windows-mounted path (/mnt/c/...) — cross-filesystem I/O adds latency to file watching and uploads.
The app runs natively on Apple Silicon. After cloning, install system dependencies first:
# Homebrew (if not installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install uv poppler # uv + PDF + file-type detection
# Optional: local AI via Ollama
brew install ollama
ollama pull granite3.3-vision:2b # or qwen2.5-vl
Then follow the standard Setup steps above. A Makefile in the project root also wraps common commands:
make setup # uv sync + pre-commit install
make run # start the dev server
make test # run pytest suite
make lint # ruff check + format check
Common Mac issues:
| Issue | Resolution |
|---|---|
pdfplumber fails to open PDFs | Run brew install poppler |
| Port 8000 already in use | make run PORT=8001 |
| LM Studio / Ollama slow on first run | First inference downloads model weights — normal |
SQLite database is locked | WAL mode is on by default; this is rare under normal use |
[!TIP] The app defaults to SQLite (zero config). No extra database setup needed for single-user use on Mac.