Invoice Reader (OpenVINO): Bills and Invoices to structured data
Point it at a photo, scan or PDF of a bill and get back the seller, buyer, GSTINs, invoice number, date, line items, taxable value, CGST/SGST/IGST/VAT, round off and total, checked with GST arithmetic. It runs fully offline on an ordinary Intel PC (CPU or Intel integrated/Arc GPU) using Intel OpenVINO. No cloud and no API key, and your bills never leave the computer.
> python invoice_reader.py bill.jpg
=== bill.jpg (... s on CPU, confidence: HIGH)
Seller : MALABAR TRADING COMPANY GSTIN 32AABCM1234K1ZV Kerala
Buyer : Thomas Supermarket GSTIN 32AAFCT5678P1ZM Kerala
Invoice: MTC/2026/0457 Date: 2026-10-14
Items:
Basmati Rice 5kg 10 x 620.00 = 6,200.00
Sunflower Oil 1L 24 x 145.50 = 3,492.00
Tea Dust 500g 12 x 210.00 = 2,520.00
Taxable 12,212.00 | CGST 1,099.08 | SGST 1,099.08 | IGST - | Round off -0.16 | TOTAL 14,410.00
[OK] seller GSTIN checksum: 32AABCM1234K1ZV
[OK] items add up to taxable value: 12212.00 vs 12212.00
[OK] taxable + tax = total: 14410.00 vs 14410.00
[OK] CGST equals SGST: 1099.08 / 1099.08
[OK] tax type matches states: same state: CGST+SGST expected
Quick start (Windows)
- Install Python 3.9+ from python.org.
- Double-click
setup.bat. It creates a private Python environment (.venv, so your other projects' packages are not changed), installs OpenVINO and OpenCV, downloads the two OCR models once (about 15 MB), converts them to OpenVINO IR and runs a self-test on the sample bills. - Then use it in either of two ways:
- Drag and drop: double-click
run_app.bat. A page opens in your browser; drop bills on it. - Folder of bills: drag a bill or a folder onto
read_bills.bat. - Command line (inside the environment:
.venv\Scripts\activatefirst):python invoice_reader.py bill.jpg # one bill -> bill.json python invoice_reader.py D:\Bills # a folder -> invoices.csv + items.csv (opens in Excel) python invoice_reader.py bill.pdf --device GPU # Intel graphics; AUTO also works python invoice_reader.py bill.jpg --text # also show the raw OCR lines
- Drag and drop: double-click
From Python:
from invoice_reader import read_invoice
r = read_invoice("bill.jpg")
print(r["seller"]["gstin"], r["total"], r["confidence"])
How it works
image / PDF โโโบ OpenVINO text detection (DBNet) โโโบ OpenVINO text recognition (CRNN + CTC) โโโบ lines โโโบ GST field extractor โโโบ checks โโโบ JSON / CSV
1. OCR on OpenVINO (ocr_openvino.py)
- Uses the PaddleOCR PP-OCRv4 detection and recognition networks, converted to OpenVINO IR (FP16).
- Detection: the page is resized to a multiple of 32, and the probability map is turned into rotated text boxes.
- Each box is straightened with a perspective transform, then read by the recognition network with greedy CTC decoding.
- Crops of similar width are batched together, which keeps it fast on a CPU.
2. Field extraction (invoice_parser.py, pure Python)
- Groups OCR boxes into lines by position.
- Finds labels such as Taxable Value, CGST @ 9%, Grand Total, Bill To and Invoice No.
- Reads the item table (description, qty, rate, amount) using
qty ร rate = amountto pick the right numbers. - Understands Indian number formats (
1,23,456.00,โน,Rs.) and many date formats (14/10/2026,05-Oct-2026).
3. GSTIN repair and validation
- A GSTIN has a fixed pattern (2 digits, 5 letters, 4 digits, โฆ) and a mod-36 check character.
- OCR mix-ups such as
Oโ0,Iโ1,Sโ5andBโ8are corrected position by position, and the result is accepted only if the checksum is valid. - The state is decoded from the first two digits.
4. Cross-checks
- Items add up to the taxable value.
- Taxable value + tax + round off = total.
- CGST = SGST.
- The tax type matches the states: IGST for inter-state supply, CGST+SGST within a state.
The result has a confidence of high, medium or low, so you know which bills to check by hand.
Output fields
seller{name,gstin,state}, buyer{name,gstin,state}, invoice_no, date (ISO), items[{description,qty,rate,amount}],
taxable_value, cgst, sgst, igst, cess, discount, round_off, total,
checks[{name,ok,detail}], confidence, lines (raw OCR text), seconds, device.
Tests
python test_parser.py: 4 invoice layouts (intra-state GST, inter-state IGST, retail receipt, service invoice), each clean and with 12 kinds of simulated OCR noise:- GSTIN digits read as letters,
- missing or changed currency signs,
- cells split into words,
- uneven baselines,
- shuffled order.
52/52 pass.
python test_ocr_pipeline.py: checks the OCR pre- and post-processing (resize, box extraction, crops, CTC decoding).python invoice_reader.py --selftest: the full pipeline on the real models with the bundled sample bills.
Limits
- Printed English bills work best. Handwritten bills and regional-language text are not supported (the recognizer is English).
- Photos should be reasonably flat, sharp and well lit. A slight tilt is fine.
- Unusual layouts can still be missed. Check bills marked low or medium confidence.
- This model needs Python and OpenVINO on your PC, so there is no free online demo: Hugging Face static Spaces cannot run it.
Credits
The OCR networks are PaddleOCR PP-OCR models (Apache-2.0), run with OpenVINO. The field extractor, GSTIN repair and checks are original to this repo.