A small, runnable pipeline that reads an architectural floor-plan PDF and extracts the parts a downstream system needs — title-block metadata, per-room stamps (name / number / floor area), and the fixtures table — into structured JSON + Excel, with a validation layer that flags low-confidence values for manual review instead of letting them enter the pipeline as fact.
Honest scope, up front. The demo runs on a synthetic sample plan I generate (
src/make_sample.py), so it has something to run on without any client's confidential drawings. It shows the method — layout-aware parsing, a defined output schema, and confidence flagging — on the native-text (vector PDF) path. Real plans vary (different CAD exports, layer names, stamp formats, scanned pages); the pipeline is built to be pointed at yours, and the parsing rules are configured per document family. See "On real plans".
python -m venv .venv && . .venv/bin/activate # (Windows: .venv\Scripts\activate)
pip install -r requirements.txt
python src/run.pyOutput (console + output/output.json + output/output.xlsx):
Rooms (5):
nr name area m² review
01 Wohnzimmer 24.5 ok
02 Küche 12.8 ok
03 Bad 6.2 ok
04 Schlafzimmer 18.0 ok
05 Abstellraum — ⚠ area_unparsable ← routed to manual review
Document needs_review: True
The last room's area is deliberately broken (BF: -- m²) to show the
validation layer doing its job: a value it cannot trust is flagged, not
guessed.
| Job requirement | Where it lives |
|---|---|
| Native-text and scanned (OCR) ingestion | vector path in extract.py; OCR path described below |
| Text + table extraction, German field names | extract.py (_title_block, _rooms, _fixtures) |
| Layout-aware parsing (values ↔ correct room) | line clustering + column split, so side-by-side stamps don't merge |
| Structured output (JSON schema + Excel) | run.py → output.json, output.xlsx |
| Validation layer flagging low-confidence | per-value flags + document needs_review |
| CLI to run the pipeline | python src/run.py |
The core discipline: a value the pipeline is not sure about must be flagged for review, never silently emitted. Concretely:
- Native-text plans: values come straight from the PDF text layer (high confidence). Range/format checks (e.g. a floor area outside 1–200 m², an unparsable stamp) still route to review.
- Scanned plans: the same parsers run on OCR output, and each value carries
the OCR confidence. Below a threshold →
needs_review. Two levers raise accuracy before flagging: (1) fuse OCR with any residual vector text when a plan is hybrid; (2) cross-check a value against its neighbours (a room area that contradicts the fixtures table, a dimension that breaks the plan scale). What can't be made confident is handed to a human with the crop that produced it — cheap to verify, never wrong-by-guess.
This is the same accuracy-by-fusion + confidence-gating approach behind a table recognition system I took from 55% to 99.5% on hard documents.
Point the pipeline at your documents and configure per family:
- stamp patterns —
_roomsmatchesRaum Nr <n>+BF: <area> m²; real offices use different stamp formats, added as patterns / a small abbreviation map. - layers — when a CAD export has named layers, they disambiguate rooms; when it doesn't, geometry + stamp proximity carry it.
- schema —
output.jsonis one shape; align it to your JSON schema and the Excel columns follow.
src/make_sample.py— generates the synthetic sample plansrc/extract.py— layout-aware extraction + confidence flaggingsrc/run.py— one-command: PDF → JSON + Excel + review summary
MIT — see LICENSE.