跳到正文
DEV Community· Vedant Gajbhiye·· 3 小時前AI 評分41

BillSift:本地 GST 帳單整理工具會核對 AI 結果

BillSift: a local GST bill sorter that double-checks its own AI

AI 導讀

BillSift 在用戶電腦以開源 OCR 和小型開放權重 LLM 擷取 GST 帳單資料,並以程式碼核對後匯出 Excel 或 CSV。以 11 張合成帳單測試時,8 張完全正確,3 張標記供人工覆核,沒有錯誤資料未經標記便通過。完整版本可透過 Ollama 執行 qwen2.5:3b 或 gemma3:4b;作者尚未以大量真實帳單測試。

正文

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

What I Built

BillSift turns a folder of bill photos and PDFs into a clean spreadsheet for your CA, entirely on your own laptop.

Anyone in India who runs a small shop, freelances, or works with a Chartered Accountant ends up with a pile of GST bills: petrol pumps, restaurants, hardware shops, online orders. Someone has to read each one and type the vendor, GSTIN, date, taxable amount, CGST/SGST/IGST and total into a sheet. That someone is usually the CA's staff, once a quarter, and a wrong digit causes trouble at filing time.

Who would pay: freelancers and small shops who want to hand their CA clean data, and small CA practices that spend staff hours on data entry. I haven't sold it yet, so this is a prototype and not a business. But a per-client price only works if the cost per bill is close to zero, and local models give you that.

What it does:

  • Drop in photos or PDFs of bills (PNG, JPG, PDF).
  • A local model reads each bill, then plain code checks the result before anything is exported.
  • Bills where something doesn't add up are marked ⚠️ with the exact reason, and you fix them in a table.
  • Correct a category once and every bill from that vendor gets it, past and future.
  • Export one Excel file: Bills, a GST summary by financial year / quarter / month, a By Category sheet, and a Needs Review sheet. CSV too.

Demo

Live demo: https://billsift-demo.onrender.com

Press Try it with 11 sample bills to see it work: most pass every check, and 3 are flagged for review, with the reason shown for each. It runs on Render's free tier, so the first visit after a quiet spell can take about a minute while the server wakes up.

The hosted copy is deliberately limited. A free server has 512 MB of RAM and no GPU, so it has no AI model, it only shows pre-processed synthetic sample bills, and uploads are switched off. That also means nobody's real bills ever reach a server. The full version runs on your own laptop with a local model.

Code

🧾 BillSift

A local, privacy-first GST bill sorter for freelancers, small shops and their CAs.

Drop in photos or PDFs of bills. BillSift reads them with open-source OCR and a small open-weight LLM running on your own laptop, then checks the result with plain code before anything reaches your spreadsheet. Your clients' financial documents never leave your machine and there is no per-page API bill.

Why a verification layer?

Small local models make small mistakes: a swapped digit, a wrong field. In accounting a silently wrong digit is worse than a missing one. So the model's output is never trusted as-is:

Check What it catches
GSTIN format + official mod-36 checksum mistyped or misread GSTINs
Tax maths (rate x taxable = CGST+SGST / IGST) wrong amounts, wrong rate
CGST = SGST, not mixed with IGST swapped or misread tax lines
Taxable + tax = total (₹1 round-off allowed) tampered or

…

Run it: pip install -r requirements.txt, ollama pull qwen2.5:3b, streamlit run app.py. Setup steps are in the README.

How I Built It

photo / PDF -> RapidOCR (open source, CPU) -> small LLM via Ollama (JSON-schema constrained)
            -> verification layer (plain code) -> SQLite -> review UI -> Excel / CSV

Open pieces: RapidOCR for text, Ollama serving open-weight qwen2.5:3b and gemma3:4b, PyMuPDF for PDFs, SQLite, and Streamlit.

The idea: the model is an untrusted component. Small models make small mistakes, like a swapped digit or a wrong field, and in accounting a silently wrong number is worse than a missing one. So nothing the model returns is trusted until code has checked it:

Check What it catches
GSTIN format + the official mod-36 checksum mistyped or misread GSTINs
Tax maths: rate x taxable = CGST+SGST or IGST wrong amounts, wrong rate
CGST = SGST, never mixed with IGST swapped or misread tax lines
Taxable + tax = total (with round-off tolerance) misread or tampered totals
Grounding: every amount, GSTIN and invoice number must literally appear in the OCR text numbers the model invented
Duplicate detection the same invoice uploaded twice
Date sanity future dates, and years that look misread

It also repairs what it can safely repair. OCR reads the letter O as a zero, or a thousands comma as a dot (3.339.40), and a GSTIN fix is only accepted if the checksum confirms it.

A real example: on my first run, gemma3:4b read a café bill's CGST 2.5% + SGST 2.5% as a GST rate of 2.5% instead of 5%. The checker caught it ("2.5% of 660.00 is 16.50, but bill shows 33.00"). I then taught the code to recognise the half-rate mistake, so now it fixes it and leaves a note instead of flagging a correct bill. A genuinely wrong rate still gets flagged.

Testing: I made 11 synthetic hard bills with invented vendors and valid-checksum GSTINs: thermal receipts, skewed phone photos with shadows and JPEG noise, a digital PDF, a scanned PDF, a discount, IGST, buyer and seller GSTINs, and one with a deliberately wrong tax. The test that matters is whether a wrong value ever passes unflagged.

  • First run, rule-based extraction with no AI model: 10 of 11 handled safely, and one silent error. My date reader turned 2026/10/11 into 2011-10-26.
  • I fixed that and added a check that flags dates over 3 years old. I also fixed OCR slips (a misread "Payable", dot-as-comma amounts) and made digital PDFs read label and value on one line.
  • Now: 11 of 11 handled safely. 8 bills come out fully correct, 3 are flagged for a human, 0 silent errors, and 52 of 55 fields are right. The 3 flagged are two with genuinely damaged OCR and the deliberately wrong tax. <!-- If you run python scripts/eval_samples.py --llm qwen2.5:3b and --llm gemma3:4b, add their results here. -->

On my laptop (RTX 3050 6 GB, 16 GB RAM), both models process a batch of 7 bills in about a minute. My first run took 2-3 minutes. Keeping the model loaded between bills and capping the output length fixed that.

Limits, honestly:

  • All my test bills are synthetic. I haven't tested on a stack of real bills yet.
  • It handles English bills. Marathi and Hindi are on the roadmap.
  • The checker assumes one GST rate per bill, so multi-rate invoices need a human look.
  • Some fields can't be checked by maths, like an invoice number where OCR reads S as 5.

Why Does Open Innovation Matter?

  • Privacy is the product. A GST bill carries a vendor's GSTIN and what you paid them. With a local model and local OCR, nothing leaves the laptop, which is the only way I'd ask an accountant to feed client documents into a tool like this.
  • Cost per bill is zero. Cloud OCR and LLM APIs charge per page, which makes a cheap per-client price hard to sustain. Here the cost is electricity.
  • I could swap models in one dropdown. I ran both qwen2.5:3b and gemma3:4b through the same pipeline and compared them, with no code changes and no pricing or API terms to renegotiate.
  • Control over the output. Ollama's JSON-schema constrained output and temperature 0 give me a model I can run over every bill and treat as a component to verify, not a black box to trust. I haven't benchmarked against a closed API, and a bigger closed model would probably misread fewer bills. But BillSift is designed around the model being wrong sometimes, so a better model would only mean fewer bills in the review list. The open, local setup is what lets this run offline, at no cost per page, on data the user never has to hand over.

My First User

A friend of mine who is a CA, went through this and gave mee a positive response. She found BillSift useful in calculations, managing accounts and bills. She did not pay but considered using BillSift in future. Another user I got was a Shop vendor, I loaded BillSift on his desktop and showed him how he can manage his Bills. And he was happy with the results. He did not pay as well.

Prize Categories

  • Render: the live demo's front end is hosted on Render (free web service, Docker). The hosted copy runs the rule-based extractor over pre-processed samples. The AI model runs locally, not on Render.
  • Gemma: the AI extraction runs Google's open-weight gemma3:4b locally through Ollama (next to qwen2.5:3b), constrained to a JSON schema, with every result checked by the verification layer.

A huge shoutout to shreyashkakad for contributing (https://dev.to/shreyashkakad)

來源:DEV Community · dev.to