Datalumina

Getting started

The sample documents

The 13-document fictional corpus, the four demo documents, and the manifest that defines what "working" means before any model runs.

By the end of this stage you know the data. You have looked at real (fictional) invoices and receipts in four languages, you know which documents are supposed to pass and which are supposed to fail, and you have a manifest that acts as ground truth for the rest of the build.

This is the gather-the-data phase, and it comes before any model. You cannot judge an extraction you have no expectations for.

Why a fictional corpus

Scraped invoices from the internet are a legal and privacy problem, and they rarely cover the failure cases you actually want to teach. The repo ships with a generated corpus instead. It is safe to redistribute, and every document was designed on purpose, including the broken ones.

The corpus lives in samples/generated/ with its ground truth in samples/manifest.json. Count it:

jq '{documents: length, pages: ([.[].pages] | add)}' samples/manifest.json
# {
#   "documents": 13,
#   "pages": 14
# }

Thirteen documents, fourteen pages. Twelve invoices and one imperfect Dutch fuel receipt, spread across English, Dutch, German, and French, with multiple layouts, one two-page invoice, and one scan-quality image.

List what each document is supposed to produce:

jq -r '.[] | [.filename, .document_type, .language, .scenario] | @tsv' \
  samples/manifest.json

Here is the whole corpus at a glance, with the policy outcome each document was designed to produce:

01en

Happy path, classic layout

Ready
02nl

Happy path, compact layout

Ready
03de

Happy path, modern layout

Ready
04fr

Happy path, classic layout

Ready
05nl

Missing vendor VAT

Needs review
06de

Invalid vendor VAT

Needs review
07fr

Wrong customer VAT

Needs review
08en

Total mismatch

Needs review
09nl

Missing purchase order

Warning
10de

Duplicate invoice

Needs review
11fr

Degraded scan

Ready
12en

Happy path, two pages

Ready
13nl

Fuel receipt

Ready
Passes policyApprovable with a warningBlocked until corrected

Four documents tell the story

You will process all thirteen eventually, but four of them carry the demo:

DocumentWhat it demonstrates
02-nl-happy-compact.pdfA normal Dutch invoice that should sail through
06-de-invalid-vendor-vat.pdfA VAT problem the supplier can fix, which triggers the correction email
08-en-total-mismatch.pdfA deterministic totals failure that no model should be allowed to wave through
13-nl-fuel-receipt.pngA degraded petrol-station receipt, which routes to a different model and a different policy

Open a few of them. Invoices and receipts overlap, but they do not have the same requirements. A paid fuel receipt has no purchase order, invoice number, customer VAT number, or due date, and demanding those would be wrong. That observation becomes a real design decision later, when invoices and receipts get separate validation policies.

The manifest is an evaluation contract

Decide what "working" means before calling Azure. A convincing extraction demo needs more than one good-looking response, so the manifest records, for every document, the expected type, the expected field values, and the expected policy outcome. The evaluators you run later track three kinds of evidence against it:

  • Field accuracy, expected normalized values versus extracted values
  • Exact documents, where every compared field matches
  • Workflow result, ready, needs_review, or provider failure after the rules run

The corpus is regenerable, so you can always reset to a known state:

cd backend
uv run --locked --no-sync python scripts/generate_samples.py

The expected data and the evaluation criteria exist independently of Document Intelligence, Azure OpenAI, FastAPI, SQLite, and React. Nothing about this stage would change if we swapped any of those out. That independence is what makes the evaluation trustworthy.

Checkpoint

  • samples/manifest.json reports 13 documents and 14 pages
  • You can name the four demo documents and say what each one should produce
  • You can explain why a receipt has fewer required fields than an invoice

Next: Local setup

Install the toolchain and reproduce the locked backend and frontend environments.

On this page