跳到正文
DEV Community· Abhinav Garg·· 4 小時前AI 評分48

BusyMobile:以店內運行的 AI 協助印度小商戶處理 GST 簿記

BusyMobile: GST bookkeeping for small Indian shops, with an AI that never leaves the shop

AI 導讀

BusyMobile 是面向印度小商戶的離線優先 GST 記帳 app,使用店內筆電透過 Ollama 運行開放權重模型 gemma3:4b,處理銀行交易分類、語音或文字輸入及供應商帳單掃描。逐行處理並加入規則校驗後,測試結單的 10 行均正確,CPU 處理時間為 53 s,較原本的 116 s 快 2×;AI 結果會先存為草稿,須由用戶確認才入帳。

正文

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I Built

My father runs a small cement trading business. Like millions of Indian shopkeepers, he keeps GST books, and every month he does the same tedious job: going through the bank statement line by line.

UPI/DR/412345678901/RAMESH KUMAR/YESB/ramesh@ybl/Payment        -5,000.00
NEFT CR-HDFC0000123-MODERN HARDWARE STORE-INV 12              +26,880.00
ACH D- BAJAJ FINANCE LTD-P400XXXX                               -8,450.00

For each line he works out who paid whom, whether it was a customer, a supplier, a loan EMI or the electricity bill, and types it in as a voucher. Then he does the same for every supplier's paper bill.

BusyMobile is an offline-first Android/iOS app for GST bookkeeping: invoices with CGST/SGST/IGST, party ledgers, stock, GSTR-1/3B summaries, and PDF invoices to share on WhatsApp. It has an AI assistant built on an open-weight model that runs on a laptop in the shop:

  • Bank import. Pick the bank's CSV. Rules settle the obvious lines (ATM, cash deposit, charges, interest, EMIs). The model reads each UPI/NEFT/IMPS narration and works out the counterparty and the kind of transaction. Confident lines post in one tap.
  • Type or speak an entry in Hinglish. "kal Bangar Cement ko 1.5 lakh cheque se payment kiya" becomes a ₹1,50,000 bank payment to Bangar Cement, dated yesterday, as a draft to confirm.
  • Scan a supplier's bill. A photo of a GST bill becomes a purchase invoice draft with bill number, date, items, HSN codes and GST rates, matched to existing stock.

Who would pay for it: small traders, kirana and hardware shops, and the accountants who keep books for twenty of them. They already pay for desktop software like BUSY or Tally, and they pay with hours every month for data entry. They won't upload their bank statements to a foreign AI service, and they won't accept a per-call bill they can't predict. A flat monthly fee for an app that runs on hardware they already own is an easy sell.

Demo

The whole video is real: a Pixel 6 emulator talking to gemma3:4b in Ollama on my laptop over the local network. Waits for the model are sped up and labelled with the real time.

AI Quick Entry Bank Import — Categorised Local AI Configuration
AI Quick Entry Bank Import — Categorised Local AI Configuration
  • src/services/ai.js: the local model client (Ollama /api/chat with a JSON schema, or any OpenAI-compatible server), plus the rule layer around it
  • src/utils/bankParser.js: CSV parsing for HDFC, SBI, ICICI, Axis, Kotak and others, and the rules for deterministic lines
  • src/utils/ledger.js: balances computed from entries, so they can't drift
  • tests/: npm test runs 22 logic tests, and npm run test:live runs the real prompts against your own model server

How I Built It

Stack: React Native + Expo on the phone, and Ollama serving Google's open-weight gemma3:4b on any laptop on the shop Wi-Fi. One 3.3 GB model handles both text and bill photos. The app also speaks the OpenAI-compatible API, so llama.cpp's server or LM Studio work too.

ollama pull gemma3:4b
OLLAMA_HOST=0.0.0.0 ollama serve      # then: Settings → Local AI → http://<laptop-ip>:11434

My first version didn't work. I sent the 4B model 8 bank lines at a time and asked for an array back. It misaligned the answers: Suresh's name ended up on the Bajaj EMI line, and two lines came back empty. It also recorded "UPI se mile" as cash, invented a party called "Bank", and in one run read "1.5 lakh" as ₹1.5.

The fix was not a bigger model. It was a different split of work:

  1. Rules decide anything that must never be wrong. ATM is a cash withdrawal. "UPI", "cheque" or "NEFT" means the bank, not cash. "1.5 lakh" is 150000, and "kal" means yesterday. "Bank" is never a party. An invalid GSTIN is never saved: the model once dropped a character from one, and validation caught it.
  2. The model handles only the fuzzy part: who is this, and what kind of transaction is it? It sees one line at a time, with a strict JSON schema where every field is required (Ollama's structured outputs).
  3. Names are matched against the shopkeeper's own party list with strict token matching, so "Ambuja Cements Ltd" maps to the existing "Ambuja Cement Ltd" ledger instead of creating a duplicate.
  4. Every AI result is a draft. Nothing is posted until a human taps it, and each line shows its confidence.

After that, all 10 lines of my test statement were correct, and it ran 2× faster (53 s vs 116 s on CPU). Small prompts with one job each beat one big prompt for a 4B model.

Measured on my laptop CPU (16 GB RAM, no GPU): about 5–10 s per bank line, ~20 s for a typed note, and 35–95 s for a bill photo. That's slow next to a cloud API, but this job runs once a month, and it's far faster than typing.

While building it I also fixed the bookkeeping underneath. Balances are now computed from the vouchers instead of being mutated in place. That fixed a sign bug, and it means editing or deleting an entry can't leave a stale balance. Without this, the AI would only have posted wrong numbers faster.

Why Does Open Innovation Matter?

1. The data can't leave the shop. A bank statement shows every customer, supplier, loan and payment of the business, and GSTINs and party ledgers are just as sensitive. Most traders I know would never upload that to a US AI API, and they shouldn't have to. With a local model, the privacy promise is simple and easy to check: unplug the router and it still works. The app shows where each request goes ("Processed on 192.168.1.x — never sent to the cloud").

2. The unit economics work. A shop's statement has hundreds of lines a month, plus bills and daily entries. With an open-weight model on a laptop the shop already owns, the marginal cost per line is zero. I can charge a flat, small monthly fee without a busy customer wiping out my margin. A closed API would turn every bank line into a cost I'd have to pass on.

3. I could build for a niche general tools handle badly. Indian bank narrations, Hinglish ("jama kiya", "nikale", "kal"), lakh and crore amounts, and GST rules are a narrow domain. Owning the whole stack let me wrap the model in rules exactly where it was weak and run it with a schema I control. When a better small model comes out, I can test it with npm run test:live in minutes.

4. No lock-in. Swapping gemma3:4b for Qwen, Llama or next year's small model is a settings change, not a migration. Nobody can change my pricing, deprecate my model or read my customers' books.

Where closed would have won, honestly: a frontier API would be more accurate on messy narrations out of the box, and much faster. For this customer, though, "private, free per use, works offline, good enough with guardrails" beats "a bit smarter, sends your books abroad, bills per call".

I built this with Claude Code as a pair programmer. The most useful part of the session was running the real prompts against the local model, seeing the batched version fail, and redesigning around one line per call plus rules.

Prize Categories

  • Best Use of Gemma: gemma3:4b runs locally through Ollama and does all three AI jobs (bank narrations, Hinglish notes and bill-photo reading) on a laptop CPU, with structured JSON outputs.

來源:DEV Community · dev.to