Financial PDF Extraction Agent (v2)
Give it any company's annual-report PDF. It finds the financial statements, pulls out the key numbers, proves each one is correct, and writes a tidy Excel where every value carries its own receipt (page number, the exact label it came from, and which checks it passed).
The one idea behind it
Accuracy comes from verification, not extraction.
Reading numbers off a PDF is easy to get almost right and very hard to get exactly right — tables are borderless, layouts differ per company, a "5" in the wrong column ruins everything. So this tool doesn't trust what it reads.
Financial statements are self-verifying. They obey rules:
- Assets = Liabilities + Equity
- Current + Non-current = Total
- The closing cash in the cash-flow statement equals cash on the balance sheet
So every extracted number is checked against these rules. A value that passes a rule is VERIFIED. A value that breaks one is FLAGGED for a human. We never hand over a confident-but-wrong number.
How it works — 7 stages, like an assembly line
PDF
│
▼
┌─────────────┐ What kind of PDF is this? Page sizes, orientation,
│ 1 PROFILE │ and whether each page has readable text.
└─────────────┘
│
▼
┌─────────────┐ Some reports print two pages side-by-side on one wide
│ 2 GEOMETRY │ sheet. Split those back into single logical pages.
└─────────────┘
│
▼
┌─────────────┐ Which pages ARE the Balance Sheet / P&L / Cash Flow?
│ 3 LOCATE │ (and prefer the consolidated version)
└─────────────┘
│
▼
┌─────────────┐ Read the chosen pages line by line: "label … numbers".
│ 4 EXTRACT │ Borderless-table safe — rebuilds rows from coordinates.
└─────────────┘
│
▼
┌─────────────┐ Clean the numbers and match each label to our standard
│ 5 NORMALIZE │ vocabulary ("Turnover" and "Net sales" both -> revenue).
└─────────────┘
│
▼
┌─────────────┐ Prove the numbers using accounting identities.
│ 6 VALIDATE │ -> VERIFIED / PROBABLE / FLAGGED / MISSING
└─────────────┘
│
▼
┌─────────────┐ A number the report never printed but the identities
│ 6b DERIVE │ pin down exactly? Compute it. Mark it DERIVED.
└─────────────┘
│
▼
┌─────────────┐ Excel: value + status + page + matched label + checks.
│ 7 WRITE │ Colour-coded so you see trust level at a glance.
└─────────────┘
│
▼
metrics.xlsx
Status colours in the Excel: 🟢 VERIFIED · 🟡 PROBABLE · 🔴 FLAGGED · 🔵 DERIVED · ⬜ MISSING.
Run it
# one report
.venv\Scripts\python.exe finagent_single.py test_pdfs\TCS_2024-2025.pdf
# scorecard across all 12 test reports
.venv\Scripts\python.exe benchmark.py
Output lands in output\<Company>_metrics.xlsx. All commands use the project
venv (.venv). First-time setup: pip install -r requirements.txt.
Install a released build
The project is packaged as a wheel and published on a version tag. Grab a build from the Releases page and install it:
pip install finagent-0.1.0-py3-none-any.whl
(TestPyPI publishing via OIDC trusted publishing is being wired up — once live,
pip install -i https://test.pypi.org/simple/ finagent will work directly.)
CI/CD
This repo doubles as a hands-on CI/CD build-out (tracked level-by-level in
WORKLOG.md):
- CI (
.github/workflows/ci.yml) — every push and PR runsruff+pytestacross Python 3.11 / 3.12 / 3.13 in parallel, with pip caching. A singleall-greencheck gates merges;mainis branch-protected, so broken code cannot merge. - CD (
.github/workflows/release.yml) — pushing avX.Y.Ztag builds the wheel + sdist and publishes a GitHub Release with the artifacts attached.
Cut a release:
git tag v0.1.0
git push origin v0.1.0
Two ways to read the code (same logic, your choice)
| What | When to read it | |
|---|---|---|
| Single file | finagent_single.py |
You want to understand or share the whole thing top-to-bottom. The 7 stages appear in pipeline order, each in its own clearly-marked section. |
| Package | finagent/ (one file per stage) |
You're maintaining or extending it. Smaller files, one responsibility each. |
Both produce identical results. The package is the source of truth; the single file is a flattened, portable build of it.
📖 Want the full, plain-language walkthrough of every function and why it works the way it does? See
ARCHITECTURE.md. It's the guide to use when explaining this project to anyone.
Package map
| File | Stage | Job |
|---|---|---|
finagent/profiler.py |
1 | Per-page: text quality, size, orientation (fast, via pypdf) |
finagent/geometry.py |
2 | Split two-up A3 sheets into single logical pages |
finagent/locator.py |
3 | Find + classify statement pages (consolidated BS / PL / CF) |
finagent/extractors/geometric.py |
4 | Line-based extraction, borderless-table safe (pdfplumber) |
finagent/normalizer.py |
5 | Parse numbers, strip note columns, fuzzy-match labels to schema |
finagent/validator.py |
6 | Voting + accounting identities + cross-statement ties |
finagent/deriver.py |
6b | Fill numbers the report omitted but the identities fix exactly |
finagent/writer.py |
7 | Excel with value, status, page citation, matched label, checks |
finagent/schema.py |
— | The canonical metric vocabulary + label synonyms |
finagent/pipeline.py |
— | Glue that runs stages 1→7 in order |
What's in this folder
finagent_single.py the whole agent in one file (start here to understand it)
finagent/ the same logic as a package, one file per stage
schema is shared ── the vocabulary every stage speaks
benchmark.py scorecard over every test PDF
golden_check.py checks extracted values against hand-verified answers
render_pages.py renders statement pages to PNGs (for eyeballing)
requirements.txt dependencies: pypdf, pdfplumber, rapidfuzz, openpyxl
test_pdfs/ 12 deliberately-different real annual reports
golden/ hand-verified correct answers for grading
output/ generated Excel files + rendered pages
scratch/ throwaway debug scripts (safe to ignore)
graphify-out/ generated knowledge-graph cache (safe to ignore)
The test set (chosen to break things on purpose)
8+ deliberately-different reports in test_pdfs/: Adani (683 pages), Airtel
(A3 two-up layout), BMW (landscape, in EUR), HDFC (a bank, different schema),
Newgen (small-cap), Reliance (A3 two-up), TCS (clean baseline), Wilmar
(foreign report). If it works on all of these, it generalises.
Roadmap (improve only what the benchmark proves)
- ✅ Walking skeleton: all stages thin but connected
- ✅ Geometry fixer: two-up A3 page split (Airtel, Reliance)
- ✅ IFRS locator vocabulary ("profit OR loss", comprehensive-income cues)
- Second extractor (Docling/TableFormer) + cross-extractor voting
- Unit detection (crores/lakhs/millions) + vision-LLM third voter
- Bank/NBFC schema variant (HDFC), OCR path for scanned pages
Metadata
Release files for akshu-finagent 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| akshu_finagent-0.2.0.tar.gz | 43.8 kB | With provenance | Details for akshu_finagent-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| akshu_finagent-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for akshu_finagent-0.2.0-py3-none-any.whl |
Total release size: 91.4 kB
Release files / akshu_finagent-0.2.0.tar.gz
| Download URL | akshu_finagent-0.2.0.tar.gz |
|---|---|
| Size | 43.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83fea4db0a09bcf862096ecc2882af2427a4988be41ec871d7e771d529f71220
|
|
BLAKE2b-256 checksum How to use checksums |
102f65e84f534484baffbe3ecd5235b408392396c11761e2295fd4cd3af80da1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.
Transparency logRelease files / akshu_finagent-0.2.0-py3-none-any.whl
| Download URL | akshu_finagent-0.2.0-py3-none-any.whl |
|---|---|
| Size | 47.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
661ff6c758935daa155407f76649e5b6e77978846364fd6ab43505bec1e47154
|
|
BLAKE2b-256 checksum How to use checksums |
ddbad38e185b190ed557fa638bc84ddbea3fe17b61615f32e4d9d1541c37549f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.
Transparency logSecurity for akshu-finagent 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for akshu_finagent-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.