| --- |
| title: BudgetBuddy |
| emoji: π§Ύ |
| colorFrom: indigo |
| colorTo: green |
| sdk: gradio |
| sdk_version: 6.18.0 |
| app_file: app.py |
| pinned: false |
| short_description: Snap a bill, ask where your money went β small-model AI |
| tags: |
| - track:backyard |
| - sponsor:openbmb |
| - sponsor:modal |
| - achievement:offbrand |
| - achievement:sharing |
| - achievement:fieldnotes |
| - build-small-hackathon |
| - minicpm |
| - modal |
| - gradio |
| - agent |
| --- |
| |
| # π§Ύ BudgetBuddy |
|
|
| **A spend tracker for real people β built entirely on small, open models.** |
| Snap a messy receipt or a UPI/card screenshot (or just type it), and BudgetBuddy |
| reads it, fixes the totals, categorises it, saves it privately, and lets you |
| **chat with a tool-using agent** about where your money went β all in a custom |
| dashboard UI. No third-party AI APIs. Two MiniCPM models do everything. |
|
|
| > Build Small hackathon Β· **Backyard AI** track. Built for the people around me |
| > (homemakers, parents, small-shop owners) who want to understand their spending |
| > without a spreadsheet β and without handing their receipts to a cloud AI API. |
|
|
| ## βΆοΈ Demo & links |
| - **Live app:** https://huggingface.co/spaces/build-small-hackathon/BudgetBuddy |
| - **Demo video:** https://youtu.be/QbgY6HDbrxE |
| - **Social post:** https://x.com/KrishnaIsCoding/status/2066565121464541191 |
| - **Build write-up (Field Notes):** https://huggingface.co/blog/KrishnaGarg/budget-buddy-field-notes ([repo copy](FIELD_NOTES.md)) |
| - **Open agent traces (Sharing is Caring):** [AGENT_TRACES.md](AGENT_TRACES.md) |
|
|
| ## Why it fits "Build Small" |
| - **Small, open models β no third-party AI API.** Vision/OCR is |
| [MiniCPM-V-4.6](https://huggingface.co/openbmb/MiniCPM-V-4.6) (**1.3B**), running |
| on the Space's **ZeroGPU**. The reasoning + agent brain is |
| [MiniCPM4.1-8B](https://huggingface.co/openbmb/MiniCPM4.1-8B) (**8B**), running on |
| our own **[Modal](https://modal.com)** GPU. **~9.3B total β well under the 32B |
| cap.** We never call a hosted AI inference API (no OpenAI/Anthropic/Gemini) β only |
| open weights we run ourselves. |
| - **Real problem, honest fit.** Real bills are messy: missing totals, taxes, |
| service charges, round-offs, mixed items, weird date formats. BudgetBuddy |
| reasons about them and reconciles the math, so editing is the exception. |
|
|
| ## What it does |
| 1. **Capture, three ways** β a photographed **receipt**, a **payment screenshot** |
| (UPI / GPay / PhonePe / card), or a quick **manual** entry. |
| 2. **Read & reconcile** β the vision model extracts vendor, date (normalised to |
| `YYYY-MM-DD`), line items, taxes/service/tip/discount/round-off, and total; |
| computes a missing total; flags anything that doesn't add up. |
| 3. **Reason & categorise** β the 8B reviews the extraction, fixes obvious errors, |
| and assigns an overall + per-item category (fixed 23-category list). |
| 4. **Dashboard** β monthly spend, vs-last-month, top category, spend-by-category |
| donut, spend-over-time chart, a budget ring, a calendar heatmap, and a |
| filterable transaction list that shows every line item **and** every tax/charge. |
| 5. **Agent chat** β ask *"how much did I spend on Groceries last month?"* or |
| *"what's my biggest expense?"* and the agent answers with your real numbers, |
| showing which **tools** it used. |
|
|
| ## π€ The agent (Best Agent) |
| The assistant is a real tool-using agent over `core/analytics`, not a chatbot that |
| guesses. It exposes **11 tools** β `total_spend`, `category_spend`, `item_spend`, |
| `vendor_spend`, `top_categories`, `biggest_expense`, `average_spend`, |
| `count_transactions`, `budget_status`, `monthly_trend`, `recent` β each scoped by a |
| flexible **period** (`this_month`, `last_month`, `this_year`, a specific month like |
| `2026-07`, a year, or `all`). |
|
|
| The **8B plans every question**: it reads the question, decides which tool to call |
| (and with what period), reads the result, optionally **chains another tool**, then |
| answers β a real ReAct loop. The tools are deterministic Python, so the *numbers* |
| can never be hallucinated; an answer is only ever returned once it is **grounded by |
| an actual tool call** (ungrounded model output is rejected). A deterministic router |
| over the same tools acts as a reliability fallback if the model can't produce a |
| valid plan. Every reply shows the **trace of tools used**, so the reasoning is |
| auditable. |
|
|
| ## Custom UI (Off-Brand) |
| The frontend is a hand-built dark single-page app ([frontend/](frontend/)) served |
| by **`gradio.Server`** (Gradio 6): Python API endpoints on the Gradio backend |
| (queue + ZeroGPU), our own HTML/CSS/JS + Chart.js on top. The default Gradio shell |
| is gone entirely. |
|
|
| ## β‘ Modal (Best Use of Modal) |
| MiniCPM4.1-8B's `trust_remote_code` targets transformers ~4.56 and breaks on the |
| 5.7 that MiniCPM-V-4.6 needs. Modal resolves the conflict cleanly: the 8B runs in |
| its own container/env on an A10G, loaded once into a **memory snapshot** for fast |
| cold starts and kept warm (`scaledown_window`), and the Space calls it through the |
| Modal SDK ([core/modal_backend.py](core/modal_backend.py), |
| [modal_app.py](modal_app.py)). That's what makes the agent quick. |
|
|
| ## Privacy |
| Sign in with a **username + PIN** (PIN stored salted+hashed, never in plaintext). |
| Each user's transactions live in their own file in a **private** HF Dataset; the |
| frontend holds a signed session token, so no one can read another user's data. |
|
|
| ## Badges / prizes targeted |
| - **Backyard AI** track β a practical, everyday-life spending app. |
| - **Best MiniCPM Build** β the whole app is two MiniCPM models (vision + 8B). |
| - **Best Use of Modal** β the 8B reasoning/agent model runs on Modal. |
| - **Off-Brand** (achievement) β a fully custom `gradio.Server` frontend. |
| - **Sharing is Caring** (achievement) β open agent traces on the Hub ([AGENT_TRACES.md](AGENT_TRACES.md)). |
| - **Field Notes** (achievement) β a build write-up / report ([FIELD_NOTES.md](FIELD_NOTES.md)). |
| - **Best Agent** Β· **Best Demo** Β· **Bonus Quest Champion** β judged across entries (multi-step agent, full demo package, most bonus criteria met). |
|
|
| ## Structure |
| ``` |
| core/extract.py # MiniCPM-V-4.6: receipt + payment extraction, reconcile, date-normalise |
| core/categorize.py # 8B: refine/repair + categorise (overall + per-item) |
| core/agent.py # tool-using spending agent (router + ReAct loop, 11 tools) |
| core/chat.py # grounded one-shot answer (agent fallback) |
| core/analytics.py # pure-Python aggregations (summary, by-category, over-time, calendar) |
| core/inference.py # one place that owns the models / routes vision + text generation |
| core/modal_backend.py # client for the Modal 8B service |
| core/storage.py # per-user transactions + budget in a HF Dataset |
| core/auth.py # username + PIN accounts, signed session tokens |
| core/hubio.py # low-level dataset JSONL IO |
| app.py # gradio.Server: API endpoints + serves the custom frontend |
| modal_app.py # Modal service hosting MiniCPM4.1-8B (deploy: modal deploy modal_app.py) |
| frontend/ # custom dark SPA (index.html + assets/app.js, Chart.js) |
| ``` |
|
|
| ## Run locally |
| ```bash |
| python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate |
| pip install -r requirements.txt |
| python app.py # open http://127.0.0.1:7860 |
| ``` |
| A GPU isn't required to try the UI (first run downloads the vision weights). On the |
| Space, set an `HF_TOKEN` secret (dataset persistence) and `MODAL_TOKEN_ID` / |
| `MODAL_TOKEN_SECRET` (the 8B backend), and `BB_INFERENCE=modal`. **Tip:** log in to |
| Hugging Face in your browser to use your own ZeroGPU quota for the vision model. |
|
|