Document AI · Internal build

A scanned statement is not data until something reads it.

The statement arrives as a photograph of a page. Somewhere in it are three hundred transactions that a business needs in a spreadsheet — and typing them out is how a Saturday disappears. This pipeline reads the scan and hands back the workbook.

Document AI · Excel automation · SheetFlow internal build

Internal build — no public deployment.

The pipeline runs locally against real bank statements, and its output contains genuine account activity. It is described here and deliberately not screenshotted — the sample workbook holds real financial data belonging to a real person.

parser.py — 1,222 lines
The full pipeline: dependency bootstrap, PDF rendering, OCR, transaction extraction, categorisation and workbook generation.
output/bank_statement_analysis.xlsx
A real generated workbook, verified on 2026-08-08: four sheets — Transactions (264 rows × 9 columns), Clean Ledger, Expense Categories and Financial Summary.
input/ — two scanned statement PDFs
The actual inputs the sample output was produced from: 1.5 MB and 551 KB scans, each a photographed multi-page statement rather than a digital export.
The problem

What the build had to solve.

  • The source is a photograph, not a text PDF, so nothing can be extracted without optical character recognition.

  • A transaction line that OCR mangles becomes a wrong number in a financial record, which is worse than a missing one.

  • The output has to land somewhere the business already works, which is a spreadsheet — not a dashboard nobody opens.

Architecture

How the work moves through it.

  1. Ingest

    Scanned statement PDFs are dropped into an input folder; the pipeline picks up whatever is there with no per-file configuration.

    • input/ folder
    • Multi-file batch
    • Page rendering
  2. Read

    Each page is read twice — by direct text extraction where the PDF has a text layer, and by OCR where it does not — so digital and photographed statements both work.

    • OCR engine
    • Text-layer extraction
    • Page images
  3. Structure

    Recognised lines are parsed into dated transactions with debit, credit and running balance, each tagged with the file it came from.

    • Transaction parsing
    • Debit / credit split
    • Balance tracking
    • Source attribution
  4. Publish to Excel

    The result is written as a four-sheet workbook: every transaction, a cleaned ledger, spend grouped by category, and a summary.

    • Transactions
    • Clean Ledger
    • Expense Categories
    • Financial Summary
The build

What it is made of.

Every row was read off the source, not from a project brief. Line counts, versions and limits are the ones in the files listed above.

Language
Python — 1,222 lines, single-file pipeline
OCR
PaddleOCR over rendered pages, with pdfplumber for statements carrying a text layer
Categorisation
Anthropic API for transaction categorisation
Output
Excel workbook via openpyxl — four sheets, one file
Verified output
264 transactions across two scanned statements, written on 2026-03-11
Setup
Missing dependencies are detected and installed on first run
Engineering decisions

The choices, and why they went that way.

Excel is the destination, not a dashboard

The people who need this already live in spreadsheets — that is where their accountant wants the file and where they will filter, annotate and total it. A web dashboard would be a better demo and a worse tool: it would mean exporting to a spreadsheet anyway, with one more step in between.

Verify: The pipeline writes a single `.xlsx` with four sheets and no other output surface; the sample workbook opens with 264 rows in the Transactions sheet.

Two extraction paths, because statements arrive both ways

Some statements are digital exports with a real text layer; most that arrive from a small business are photographs taken on a phone. Running text extraction where it works and OCR where it does not means one pipeline handles both, instead of failing on whichever kind it was not built for.

Verify: Both pdfplumber and an OCR engine are required dependencies, and each transaction row records the source file it was read from.

The sample output is described here and not shown

The verified workbook is genuine, which is exactly why it cannot be a screenshot. It contains real counterparty names, real UPI identifiers and real balances. Publishing a picture of it to prove the pipeline works would leak somebody’s finances to prove a point about engineering.

Verify: This case study cites row and column counts and the sheet names rather than any transaction content, and no image of the workbook appears anywhere on this site.

The run installs what it needs

This is operated by the business owner, not by a developer with a working Python toolchain. Detecting missing packages and installing them on first run removes the single most common reason a tool like this gets abandoned before it is ever used.

Verify: The pipeline checks each required import at startup and installs any that are missing before continuing.

Business outcome

What we can prove, and what we cannot.

Not publicly disclosed.

No business outcome has been measured against a stated method and confirmed with this client, so no figure is published. We would rather show you the system and let you judge it than print a number nobody verified.

Questions

About this project.

What is the Bank Statement Parser?
A SheetFlow internal build: a Python pipeline that reads scanned bank statement PDFs using OCR, extracts every transaction with its date, debit, credit and running balance, categorises spending, and writes a four-sheet Excel workbook. A verified sample run produced 264 transactions from two scanned statements.
Why does it output Excel rather than a dashboard?
Because that is where the work continues. The workbook goes to an accountant, gets filtered and annotated, and totals get checked by hand. A dashboard would have required exporting to a spreadsheet as an extra step, so the spreadsheet is the product.
What business results has the Bank Statement Parser produced?
Not publicly disclosed. It is an internal build with no client engagement behind it, and no time-saving or accuracy figure has been measured against a stated method, so none is claimed.