Inspiration
In October 2025, Deloitte refunded part of a $440,000 report to the Australian government because their AI had invented citations and a court quote that didn't exist. Two months later, FINRA told regulated firms that AI hallucination is now a risk they must test for and log.
Everyone's answer to this is "make the AI more accurate." We think that's the wrong goal. Hallucination is inherent to how these models work a language model is a text engine, not a calculator. So we stopped trying to build an AI that doesn't make mistakes, and built one that tells you exactly where its mistakes are.
What it does
Upload a financial statement, PDF or spreadsheet. FinVerify extracts every figure and claim, then runs two independent checks before you see anything:
1. Citation check. The model must quote the exact source line for every number it reports. Python then confirms that quote exists in the document, character for character. Invented numbers have nowhere to hide.
2. Math check. Python independently re-runs every calculation from the cited figures. Fixed operations only, no eval, ever. The model never grades its own homework.
Every claim comes back in one of three states which are verified, unverified, or mismatch. Nothing renders until it has passed through the pipeline. On top of the verified figures, the engine surfaces business risks (liquidity, cash-flow, receivables trends), each one citing the specific facts it rests on.
Crucially: verification blesses facts, never advice. A number can be exactly right and still be misread. So the analysis and recommendations carry no trust badge they're framed as prompts to investigate, grounded only in your document, never as conclusions. We'd rather under-claim than rebuild the false confidence we set out to dismantle.
How we built it
Python + FastAPI, streaming an NDJSON pipeline to a browser UI that shows each stage live with real timings: parse → redact → extract → verify-math → verify-citations → release. pdfplumber and openpyxl for ingestion, DeepSeek for strict-JSON extraction, and a deterministic verifier that is deliberately boring, three fixed operations, anything exotic returns UNVERIFIABLE rather than a guess.
PDPA compliance is structural, not a policy page. Personal data such as names, emails, Malaysian phone numbers, NRIC (with date validation, so real dates aren't mangled by a naive 12-digit rule) is stripped locally before any text reaches the model. Only redacted text is transmitted; the file itself never leaves the machine. The exact transmitted payload is inspectable in the UI, and one click purges the upload from disk. Retention is the duration of the request.
Challenges we ran into
The verifier caught our own model grading its own homework by setting its own expected value and then confirming it. Every check now compares against a separately cited fact. That bug is in the git history, and finding it is what convinced us the verification layer was the product.
We also had to be honest about scope. Early on we described this as anomaly detection. It isn't a distressed company can pass every arithmetic check cleanly, because its books balance perfectly while the business struggles. So we narrowed the claim to what we can actually prove: invented figures, and totals that don't reconcile. The business-risk layer sits above that, clearly marked as interpretation.
What we learned
Trust isn't accuracy. A tool that's right 95% of the time and can't tell you which 95% is worse than one that's right 80% of the time and flags the rest. Knowing which numbers to check by hand is worth more than a confident answer you can't audit.
What's next
Named-entity recognition to catch bare names that regex misses, OCR for scanned documents, and a wider operation set for the verifier. Each one added the same way: test first, and UNVERIFIABLE until proven otherwise.
Built With
- css
- deepseek
- fastapi
- github-actions
- html
- javascript
- ndjson
- openpyxl
- pdfplumber
- pytex
- python
- regex
- reportlab
- uv
- uvicorn
Log in or sign up for Devpost to join the conversation.