verifydoc 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- verifydoc-0.4.0/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
- verifydoc-0.4.0/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- verifydoc-0.4.0/.github/pull_request_template.md +11 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/.gitignore +8 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/CHANGELOG.md +40 -0
- verifydoc-0.4.0/CITATION.cff +17 -0
- verifydoc-0.4.0/CODE_OF_CONDUCT.md +32 -0
- verifydoc-0.4.0/CONTRIBUTING.md +55 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/Makefile +7 -1
- {verifydoc-0.2.0 → verifydoc-0.4.0}/PKG-INFO +59 -18
- {verifydoc-0.2.0 → verifydoc-0.4.0}/PROJECT.md +3 -10
- {verifydoc-0.2.0 → verifydoc-0.4.0}/README.md +52 -17
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/datasets/cord.py +57 -11
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/datasets/funsd.py +1 -0
- verifydoc-0.4.0/configs/cord-apivlm.yaml +13 -0
- verifydoc-0.4.0/configs/cord-paddleocr.yaml +15 -0
- verifydoc-0.4.0/configs/cord-rapidocr.yaml +11 -0
- verifydoc-0.4.0/configs/funsd-paddleocr.yaml +9 -0
- verifydoc-0.4.0/configs/funsd-rapidocr.yaml +9 -0
- verifydoc-0.4.0/docs/REAL_MODELS.md +77 -0
- verifydoc-0.4.0/docs/how-it-works.md +57 -0
- verifydoc-0.4.0/examples/README.md +25 -0
- verifydoc-0.4.0/examples/invoice.txt +8 -0
- verifydoc-0.4.0/examples/invoice_schema.json +12 -0
- verifydoc-0.4.0/paper/generated/REAL_MODELS_RESULTS.md +60 -0
- verifydoc-0.4.0/paper/generated/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/cord/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/cord/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/cord/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/calibration.md +34 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/conformal.md +16 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/extraction.md +5 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/grounding.md +5 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/selective.md +10 -0
- verifydoc-0.4.0/paper/generated/cord-paddleocr/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/calibration.md +34 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/conformal.md +16 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/extraction.md +5 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/grounding.md +5 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/selective.md +10 -0
- verifydoc-0.4.0/paper/generated/cord-rapidocr/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/funsd/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/funsd/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/calibration.md +34 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/conformal.md +16 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/extraction.md +5 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/grounding.md +5 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/selective.md +10 -0
- verifydoc-0.4.0/paper/generated/funsd-paddleocr/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/calibration.md +34 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/calibration.tex +37 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/conformal.md +16 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/conformal.tex +19 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/extraction.md +5 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/extraction.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/grounding.md +5 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/selective.md +10 -0
- verifydoc-0.4.0/paper/generated/funsd-rapidocr/selective.tex +13 -0
- verifydoc-0.4.0/paper/generated/grounding.tex +8 -0
- verifydoc-0.4.0/paper/generated/selective.tex +13 -0
- verifydoc-0.4.0/paper/main.tex +167 -0
- verifydoc-0.4.0/paper/refs.bib +35 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/pyproject.toml +3 -1
- verifydoc-0.4.0/scripts/tables_to_latex.py +87 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_pipeline.py +106 -3
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_types.py +13 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/__init__.py +1 -1
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/__init__.py +1 -0
- verifydoc-0.4.0/verifydoc/adapters/api_vlm.py +172 -0
- verifydoc-0.4.0/verifydoc/adapters/paddleocr_vl.py +99 -0
- verifydoc-0.4.0/verifydoc/adapters/rapidocr.py +94 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/text_search.py +6 -2
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/harness.py +6 -2
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/types.py +2 -0
- verifydoc-0.2.0/CLAUDE.md +0 -51
- verifydoc-0.2.0/configs/cord-paddleocr.yaml +0 -14
- verifydoc-0.2.0/docs/REAL_MODELS.md +0 -61
- verifydoc-0.2.0/paper/main.tex +0 -90
- verifydoc-0.2.0/verifydoc/adapters/api_vlm.py +0 -97
- verifydoc-0.2.0/verifydoc/adapters/paddleocr_vl.py +0 -50
- {verifydoc-0.2.0 → verifydoc-0.4.0}/.github/workflows/ci.yml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/.github/workflows/release.yml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/.pre-commit-config.yaml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/LICENSE +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/card.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/datasets/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/datasets/synthetic.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/benchmark/labeling/guide.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/configs/cord.yaml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/configs/demo.yaml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/configs/funsd.yaml +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/docs/USP.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/docs/demo.gif +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/calibration.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/conformal.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/calibration.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/conformal.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/extraction.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/grounding.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/rc_curves.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/reliability.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/selective.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/cord/summary.json +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/extraction.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/calibration.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/conformal.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/extraction.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/grounding.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/rc_curves.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/reliability.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/selective.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/funsd/summary.json +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/grounding.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/rc_curves.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/reliability.png +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/selective.md +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/paper/generated/summary.json +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/scripts/make_demo_gif.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/scripts/run_benchmark.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_calibration.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_calibrators.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_confidence.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_cord_loader.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_extraction.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_funsd_loader.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_grounding.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_harness.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_harness_extractors.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_learned_combiner.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_selective.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/tests/test_stats.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/ui/streamlit_app.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/_ocr_common.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/base.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/docling.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/dots_ocr.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/adapters/mock.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/base.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/conformal.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/histogram.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/isotonic.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/platt.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/splits.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/calibration/temperature.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/cli.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/combined.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/consensus.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/grounding_based.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/learned.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/token_prob.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/confidence/verbalized.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/calibration.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/extraction.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/grounding.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/selective.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/eval/stats.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/grounding/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/grounding/attach.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/ingest/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/ingest/loader.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/pipeline.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/policy/__init__.py +0 -0
- {verifydoc-0.2.0 → verifydoc-0.4.0}/verifydoc/policy/abstention.py +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something isn't working as documented
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What happened**
|
|
8
|
+
A clear description of the bug.
|
|
9
|
+
|
|
10
|
+
**Minimal repro**
|
|
11
|
+
Ideally a tiny document + schema and the `verify(...)` call or CLI command.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# your repro here
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Expected vs actual**
|
|
18
|
+
- Expected:
|
|
19
|
+
- Actual:
|
|
20
|
+
|
|
21
|
+
**Environment**
|
|
22
|
+
- verifydoc version (`verifydoc version`):
|
|
23
|
+
- Python version:
|
|
24
|
+
- OS:
|
|
25
|
+
- Extractor/adapter (if relevant):
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request / new adapter or dataset
|
|
3
|
+
about: Propose an extractor adapter, dataset slice, signal, calibrator, or feature
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What and why**
|
|
8
|
+
What should VerifyDoc do, and what does it enable?
|
|
9
|
+
|
|
10
|
+
**Which layer**
|
|
11
|
+
- [ ] Adapter (new extractor) — recall: one file in `verifydoc/adapters/`
|
|
12
|
+
- [ ] Dataset slice (`benchmark/datasets/`)
|
|
13
|
+
- [ ] Confidence signal / calibrator
|
|
14
|
+
- [ ] Eval metric
|
|
15
|
+
- [ ] Other
|
|
16
|
+
|
|
17
|
+
**Sketch (optional)**
|
|
18
|
+
Interface or output shape you have in mind. For metrics, include a
|
|
19
|
+
hand-computed expected value so it becomes a regression test.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## What this does
|
|
2
|
+
|
|
3
|
+
Brief description. Link any issue it closes (`Closes #N`).
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `make test lint typecheck` all green locally
|
|
8
|
+
- [ ] New/changed code has tests; metric code has a numeric regression test
|
|
9
|
+
- [ ] Docs updated if the public API changed (`README.md` / `PROJECT.md`)
|
|
10
|
+
- [ ] Conventional Commit title (`feat:` / `fix:` / `docs:` / `test:` / `bench:` …)
|
|
11
|
+
- [ ] If this adds a model adapter: all SDK code stays inside `verifydoc/adapters/`
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.4.0 — 2026-07-21
|
|
4
|
+
|
|
5
|
+
Paper-ready: fair API-VLM comparison + a compilable paper.
|
|
6
|
+
|
|
7
|
+
- **Vendor-neutral API-VLM extractor** (`verifydoc/adapters/api_vlm.py`):
|
|
8
|
+
OpenAI + Anthropic clients behind one `CompletionClient` protocol, with
|
|
9
|
+
**temperature-based k-sample sampling** so self-consistency consensus and
|
|
10
|
+
verbalized confidence are non-degenerate (the fair comparison the paper
|
|
11
|
+
needs). Harness `adapter_kwargs` passthrough; `configs/cord-apivlm.yaml`;
|
|
12
|
+
`ocr` and `api` install extras.
|
|
13
|
+
- **Compilable paper** (`paper/main.tex`) with real RapidOCR/PaddleOCR/
|
|
14
|
+
synthetic numbers, auto-generated LaTeX result tables
|
|
15
|
+
(`scripts/tables_to_latex.py`, booktabs) and `refs.bib`; `make paper`.
|
|
16
|
+
- **Docs**: `docs/how-it-works.md`; README documentation index; runnable
|
|
17
|
+
`examples/`.
|
|
18
|
+
- Repo hygiene: removed internal build-tooling notes; tidied PROJECT.md.
|
|
19
|
+
|
|
20
|
+
## v0.3.0 — 2026-07-21
|
|
21
|
+
|
|
22
|
+
First **real-model** results (issue #3).
|
|
23
|
+
|
|
24
|
+
- **RapidOCR adapter** (PP-OCRv6 via ONNX Runtime) — architecture-independent,
|
|
25
|
+
the robust real-OCR default; runs where paddle's GPU wheels don't.
|
|
26
|
+
- **PaddleOCR adapter** validated end-to-end (PP-OCRv5 pipeline) on a real GPU.
|
|
27
|
+
- **Real results on CORD + FUNSD** for both extractors, committed under
|
|
28
|
+
`paper/generated/` with an honest reading (`REAL_MODELS_RESULTS.md`):
|
|
29
|
+
grounding/learned signals rank errors (AUROC 0.74–0.89) while
|
|
30
|
+
verbalized/consensus don't; grounding-conditioned gap +0.83/+0.84. The
|
|
31
|
+
floor field-finder's low recall forces conformal abstention at 2–5% — the
|
|
32
|
+
documented motivation for the selective framing.
|
|
33
|
+
- **Harness**: `extractor:` dispatch via the adapter registry; CORD/FUNSD
|
|
34
|
+
image export (`with_images`); schema `x-aliases` for on-page label variants.
|
|
35
|
+
- **Learned combiner** (`verifydoc/confidence/learned.py`) as a harness row.
|
|
36
|
+
- **Grounder ~1000× faster** (exact-match fast path, token-anchored fuzzy
|
|
37
|
+
scan, token-overlap for paragraph values) — FUNSD grounding hours → seconds.
|
|
38
|
+
- **GPU runbook** (`docs/REAL_MODELS.md`) with the hard-won version pins
|
|
39
|
+
(`paddlex==3.1.0`, `langchain<0.2`, Blackwell caveat, dots.ocr→vllm).
|
|
40
|
+
- dots.ocr: adapter stub validated to load/generate with `transformers==4.51.3`;
|
|
41
|
+
full run deferred to its vllm serving path (issue #3).
|
|
42
|
+
|
|
3
43
|
## v0.2.0 — 2026-07-21
|
|
4
44
|
|
|
5
45
|
Real data, faster grounding, learned fusion.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use VerifyDoc or VerifyDocBench, please cite it."
|
|
3
|
+
title: "VerifyDoc: Calibrated, Abstaining, Grounded Document Extraction"
|
|
4
|
+
authors:
|
|
5
|
+
- family-names: Gurram
|
|
6
|
+
given-names: Bhaskar
|
|
7
|
+
repository-code: "https://github.com/bhaskargurram-ai/verifydoc"
|
|
8
|
+
license: Apache-2.0
|
|
9
|
+
version: 0.4.0
|
|
10
|
+
date-released: 2026-07-21
|
|
11
|
+
keywords:
|
|
12
|
+
- document-extraction
|
|
13
|
+
- calibration
|
|
14
|
+
- selective-prediction
|
|
15
|
+
- conformal-prediction
|
|
16
|
+
- grounding
|
|
17
|
+
- hallucination-detection
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and maintainers pledge to make participation in
|
|
6
|
+
VerifyDoc a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic
|
|
9
|
+
status, nationality, personal appearance, race, religion, or sexual identity
|
|
10
|
+
and orientation.
|
|
11
|
+
|
|
12
|
+
## Our standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to a positive environment:
|
|
15
|
+
|
|
16
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
17
|
+
- Giving and gracefully accepting constructive feedback
|
|
18
|
+
- Focusing on what is best for the community and the project
|
|
19
|
+
|
|
20
|
+
Unacceptable behavior includes harassment, insulting or derogatory comments,
|
|
21
|
+
personal or political attacks, publishing others' private information, and
|
|
22
|
+
other conduct that could reasonably be considered inappropriate.
|
|
23
|
+
|
|
24
|
+
## Enforcement
|
|
25
|
+
|
|
26
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
27
|
+
reported to the project maintainers via a GitHub issue or direct contact.
|
|
28
|
+
Maintainers will review and respond, and will respect the privacy and
|
|
29
|
+
security of the reporter.
|
|
30
|
+
|
|
31
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
|
|
32
|
+
version 2.1.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Contributing to VerifyDoc
|
|
2
|
+
|
|
3
|
+
Thanks for helping build the open trust layer for document extraction. This
|
|
4
|
+
project is designed so contributions are small and self-contained.
|
|
5
|
+
|
|
6
|
+
## Ground rules (the architecture makes these easy)
|
|
7
|
+
|
|
8
|
+
1. **Adapters are isolated.** All model-specific code lives behind the
|
|
9
|
+
`ExtractorAdapter` interface in `verifydoc/adapters/`. **Adding a new
|
|
10
|
+
extractor = one new file** — nothing outside `adapters/` imports a model SDK.
|
|
11
|
+
2. **Stages are independent:** ingest → adapter → confidence → calibration →
|
|
12
|
+
grounding → policy → report. Each has typed inputs/outputs
|
|
13
|
+
(`verifydoc/types.py`) and its own tests. No stage reaches into another.
|
|
14
|
+
3. **The eval harness is decoupled.** It scores anything that emits
|
|
15
|
+
`FieldPrediction`. Never couple a metric to a specific model.
|
|
16
|
+
4. **Never tune on test.** Calibration/abstention thresholds are fit only on
|
|
17
|
+
the dedicated calibration split (enforced by `assert_disjoint`).
|
|
18
|
+
5. **No network in unit tests.** Mock adapters. Every metric gets a numeric
|
|
19
|
+
regression test against a hand-computed fixture.
|
|
20
|
+
|
|
21
|
+
## Good first issues
|
|
22
|
+
|
|
23
|
+
Look for the [`good first issue`](https://github.com/bhaskargurram-ai/verifydoc/labels/good%20first%20issue)
|
|
24
|
+
label. Great starting points:
|
|
25
|
+
|
|
26
|
+
- **Add an extractor adapter** (Surya, GOT-OCR2.0, an API VLM) — one file in
|
|
27
|
+
`adapters/`, plus a normalization test (see `tests/test_pipeline.py`).
|
|
28
|
+
- **Add a dataset slice** (SROIE, DocILE, XFUND) — a loader in
|
|
29
|
+
`benchmark/datasets/` returning `BenchDocument`s, following `funsd.py`.
|
|
30
|
+
- **A new confidence signal or calibrator** behind the existing interfaces.
|
|
31
|
+
|
|
32
|
+
## Dev setup
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/bhaskargurram-ai/verifydoc && cd verifydoc
|
|
36
|
+
uv venv .venv && uv pip install -e ".[dev]"
|
|
37
|
+
make test lint typecheck # all must be green
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Before you open a PR
|
|
41
|
+
|
|
42
|
+
- `ruff`, `black`, `mypy`, and `pytest` all pass (CI enforces; no PR merges red).
|
|
43
|
+
- New/changed code has tests; metric code has a numeric regression test.
|
|
44
|
+
- Public-API changes update `README.md` / `PROJECT.md`.
|
|
45
|
+
- Use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
46
|
+
`feat:` `fix:` `docs:` `test:` `refactor:` `chore:` `perf:` `bench:`.
|
|
47
|
+
- Branch off `main`, open a PR, we squash-merge.
|
|
48
|
+
|
|
49
|
+
## Reporting bugs / ideas
|
|
50
|
+
|
|
51
|
+
Open an issue with a minimal repro (a tiny document + schema is ideal). For
|
|
52
|
+
metric bugs, include the expected hand-computed value — that becomes the
|
|
53
|
+
regression test.
|
|
54
|
+
|
|
55
|
+
By contributing you agree your work is licensed under Apache-2.0.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.PHONY: install lint format typecheck test cov results demo clean
|
|
1
|
+
.PHONY: install lint format typecheck test cov results paper demo clean
|
|
2
2
|
|
|
3
3
|
PY ?= python
|
|
4
4
|
|
|
@@ -28,6 +28,12 @@ results:
|
|
|
28
28
|
$(PY) scripts/run_benchmark.py --config configs/demo.yaml --out paper/generated
|
|
29
29
|
$(PY) scripts/run_benchmark.py --config configs/cord.yaml --out paper/generated/cord
|
|
30
30
|
$(PY) scripts/run_benchmark.py --config configs/funsd.yaml --out paper/generated/funsd
|
|
31
|
+
$(PY) scripts/tables_to_latex.py paper/generated
|
|
32
|
+
|
|
33
|
+
# Compile the paper (needs a LaTeX toolchain); tables come from `make results`.
|
|
34
|
+
paper:
|
|
35
|
+
$(PY) scripts/tables_to_latex.py paper/generated
|
|
36
|
+
cd paper && pdflatex -interaction=nonstopmode main.tex && bibtex main && pdflatex -interaction=nonstopmode main.tex && pdflatex -interaction=nonstopmode main.tex
|
|
31
37
|
|
|
32
38
|
demo:
|
|
33
39
|
streamlit run ui/streamlit_app.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: verifydoc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A trust layer for document -> structured-JSON extraction: calibrated per-field confidence, source grounding, and abstention on top of any extractor.
|
|
5
5
|
Project-URL: Homepage, https://github.com/bhaskargurram-ai/verifydoc
|
|
6
6
|
Project-URL: Repository, https://github.com/bhaskargurram-ai/verifydoc
|
|
@@ -226,6 +226,9 @@ Requires-Dist: pyyaml>=6.0
|
|
|
226
226
|
Requires-Dist: scikit-learn>=1.3
|
|
227
227
|
Requires-Dist: scipy>=1.11
|
|
228
228
|
Requires-Dist: typer>=0.9
|
|
229
|
+
Provides-Extra: api
|
|
230
|
+
Requires-Dist: anthropic>=0.39; extra == 'api'
|
|
231
|
+
Requires-Dist: openai>=1.40; extra == 'api'
|
|
229
232
|
Provides-Extra: data
|
|
230
233
|
Requires-Dist: datasets>=2.16; extra == 'data'
|
|
231
234
|
Provides-Extra: dev
|
|
@@ -235,6 +238,9 @@ Requires-Dist: pre-commit>=3.6; extra == 'dev'
|
|
|
235
238
|
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
236
239
|
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
237
240
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
241
|
+
Provides-Extra: ocr
|
|
242
|
+
Requires-Dist: onnxruntime>=1.17; extra == 'ocr'
|
|
243
|
+
Requires-Dist: rapidocr>=1.3; extra == 'ocr'
|
|
238
244
|
Provides-Extra: pdf
|
|
239
245
|
Requires-Dist: pdfplumber>=0.10; extra == 'pdf'
|
|
240
246
|
Requires-Dist: pillow>=10.0; extra == 'pdf'
|
|
@@ -282,7 +288,8 @@ pip install 'verifydoc[pdf]' # + PDF/image ingestion
|
|
|
282
288
|
```python
|
|
283
289
|
from verifydoc import verify
|
|
284
290
|
|
|
285
|
-
|
|
291
|
+
# ready-to-run sample lives in examples/
|
|
292
|
+
result = verify("examples/invoice.txt", schema="examples/invoice_schema.json")
|
|
286
293
|
for f in result.fields:
|
|
287
294
|
print(f"{f.path:12} = {f.value!r:24} conf={f.confidence:.2f} {f.decision}")
|
|
288
295
|
if f.grounding:
|
|
@@ -290,10 +297,12 @@ for f in result.fields:
|
|
|
290
297
|
```
|
|
291
298
|
|
|
292
299
|
```bash
|
|
293
|
-
verifydoc extract invoice.txt --schema invoice_schema.json --
|
|
300
|
+
verifydoc extract examples/invoice.txt --schema examples/invoice_schema.json --threshold 0.8
|
|
294
301
|
streamlit run ui/streamlit_app.py # review UI: green/red fields + click-through to source
|
|
295
302
|
```
|
|
296
303
|
|
|
304
|
+
See [`examples/`](examples/) for the full runnable walk-through.
|
|
305
|
+
|
|
297
306
|
Schemas are plain JSON Schema, with each leaf optionally declaring **how it is scored** (the executable-schema pattern):
|
|
298
307
|
|
|
299
308
|
```json
|
|
@@ -311,14 +320,37 @@ Schemas are plain JSON Schema, with each leaf optionally declaring **how it is s
|
|
|
311
320
|
|
|
312
321
|
| Layer | Modules | Status |
|
|
313
322
|
|---|---|---|
|
|
314
|
-
| **Adapters** (all model code isolated here) | mock · text-search · PaddleOCR
|
|
323
|
+
| **Adapters** (all model code isolated here) | mock · text-search · RapidOCR · PaddleOCR · dots.ocr · Docling/MinerU output · API-VLM (OpenAI/Anthropic) | ✅ |
|
|
315
324
|
| **Confidence signals** | token-prob · verbalized · consensus (k-sample voting) · grounding-based · combined | ✅ |
|
|
316
325
|
| **Calibrators** (fit on a dedicated split, never test) | temperature · Platt · isotonic · histogram · **split conformal** with finite-sample risk guarantee | ✅ |
|
|
317
326
|
| **Grounding** | value → page/bbox/char-span attachment with support scores | ✅ |
|
|
318
327
|
| **Policy** | empirical & conformal accept thresholds for a target selective risk | ✅ |
|
|
319
328
|
| **Eval harness / VerifyDocBench scorer** | Field-F1 · exact · CER/WER · ANLS · TEDS/TEDS-Struct · GriTS · omission vs hallucination · ECE/Adaptive-ECE/MCE/Brier/NLL/TCE · RC/AURC/E-AURC/Coverage@Risk/AUROC/AUPR/FPR@95 · box IoU/span-F1/grounding-conditioned correctness · bootstrap CIs + paired tests | ✅ |
|
|
320
329
|
|
|
321
|
-
Every metric implements the exact definition in [PROJECT.md §5](PROJECT.md) with a hand-computed numeric regression test (
|
|
330
|
+
Every metric implements the exact definition in [PROJECT.md §5](PROJECT.md) with a hand-computed numeric regression test (201 tests, `eval/` coverage 98%).
|
|
331
|
+
|
|
332
|
+
## Results on real documents
|
|
333
|
+
|
|
334
|
+
Two independent real OCR extractors (**RapidOCR** and **PaddleOCR**) on real
|
|
335
|
+
**CORD** receipts and **FUNSD** forms, scored by the harness
|
|
336
|
+
([full tables + reading](paper/generated/REAL_MODELS_RESULTS.md)):
|
|
337
|
+
|
|
338
|
+
| Confidence signal | ranks errors? | CORD AUROC (RapidOCR / PaddleOCR) |
|
|
339
|
+
|---|---|---|
|
|
340
|
+
| **learned combiner** | ✅ best | **0.89 / 0.84** |
|
|
341
|
+
| **grounding** | ✅ strong | 0.82 / 0.74 |
|
|
342
|
+
| token-probability | ~ moderate | 0.69 / 0.68 |
|
|
343
|
+
| verbalized / consensus | ✗ uninformative | 0.50 / 0.50 |
|
|
344
|
+
|
|
345
|
+
- **Grounding is a real trust signal:** grounded fields are **84–85% correct
|
|
346
|
+
vs ~1%** for ungrounded (gap ≈ +0.84; box accuracy @IoU 0.5 = 0.75–0.78).
|
|
347
|
+
- **The abstention layer is honest:** with a weak field-extractor the base
|
|
348
|
+
error rate is high, so conformal abstention at a 2–5% budget correctly
|
|
349
|
+
refuses to auto-accept — you report *selective risk*, not headline accuracy.
|
|
350
|
+
- The synthetic slice (strong extractor) shows the other end: Coverage@2% ≈ 1.0.
|
|
351
|
+
|
|
352
|
+
The thesis holds on real data: **grounding + a learned fusion rank errors;
|
|
353
|
+
self-reported and single-sample-consensus confidence do not.**
|
|
322
354
|
|
|
323
355
|
## The benchmark
|
|
324
356
|
|
|
@@ -328,16 +360,13 @@ make results # regenerates every table/figure in paper/generated from config
|
|
|
328
360
|
|
|
329
361
|
The harness runs **signals × calibrators × the full metric suite** with a
|
|
330
362
|
document-level calibration split (disjointness asserted in code), bootstrap
|
|
331
|
-
CIs, and a conformal-guarantee row.
|
|
332
|
-
slice
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
- **The conformal row holds its guarantee** on every tested α, and reports the abstention it forces.
|
|
339
|
-
|
|
340
|
-
These self-checks run as unit tests — the repo's core claims are CI-enforced, not just stated.
|
|
363
|
+
CIs, and a conformal-guarantee row. It ships a deterministic **synthetic**
|
|
364
|
+
slice (runs in CI) plus **CORD** and **FUNSD** loaders with gold source boxes;
|
|
365
|
+
`extractor:` dispatches to any adapter (`rapidocr`, `paddleocr-vl`, …) and
|
|
366
|
+
`dataset:` to any slice. See the [GPU runbook](docs/REAL_MODELS.md) to
|
|
367
|
+
reproduce the real-model rows. Core claims (grounding beats verbalized;
|
|
368
|
+
conformal holds its guarantee) are also **CI-enforced as unit tests**, not
|
|
369
|
+
just stated.
|
|
341
370
|
|
|
342
371
|
## Why not just use the parser's own score?
|
|
343
372
|
|
|
@@ -350,9 +379,19 @@ buys you.
|
|
|
350
379
|
## Roadmap
|
|
351
380
|
|
|
352
381
|
- [x] v0.1 — library + CLI + harness + synthetic benchmark slice + UI
|
|
353
|
-
- [
|
|
354
|
-
- [
|
|
355
|
-
- [
|
|
382
|
+
- [x] v0.2 — CORD + FUNSD real slices with gold boxes; learned combiner; 1000× faster grounder
|
|
383
|
+
- [x] v0.3 — real-model results (RapidOCR + PaddleOCR on CORD/FUNSD)
|
|
384
|
+
- [x] v0.4 — vendor-neutral API-VLM extractor (OpenAI/Anthropic) with k-sample consensus; compilable paper with auto-generated tables
|
|
385
|
+
- [ ] Run the API-VLM row at scale (fair verbalized + consensus comparison; needs an API key)
|
|
386
|
+
- [ ] dots.ocr via vllm; SROIE / DocILE / XFUND slices; human-labeled correctness + IAA
|
|
387
|
+
- [ ] Paper submission ([contributions welcome](CONTRIBUTING.md))
|
|
388
|
+
|
|
389
|
+
## Documentation
|
|
390
|
+
|
|
391
|
+
- [How it works](docs/how-it-works.md) — the pipeline, the abstention idea, why grounding is a trust signal
|
|
392
|
+
- [Real-model results](paper/generated/REAL_MODELS_RESULTS.md) — RapidOCR + PaddleOCR numbers and reading
|
|
393
|
+
- [GPU runbook](docs/REAL_MODELS.md) — reproduce the real-extractor rows
|
|
394
|
+
- [USP audit](docs/USP.md) · [Paper draft](paper/main.tex) · [Full spec](PROJECT.md)
|
|
356
395
|
|
|
357
396
|
## Development
|
|
358
397
|
|
|
@@ -360,6 +399,8 @@ buys you.
|
|
|
360
399
|
git clone https://github.com/bhaskargurram-ai/verifydoc && cd verifydoc
|
|
361
400
|
uv venv .venv && uv pip install -e ".[dev]"
|
|
362
401
|
make test lint typecheck # all green before any PR (CI enforces)
|
|
402
|
+
make results # regenerate benchmark tables + LaTeX
|
|
403
|
+
make paper # compile the paper (needs a LaTeX toolchain)
|
|
363
404
|
```
|
|
364
405
|
|
|
365
406
|
Contributions welcome — see the issues tagged `good-first-issue`. All model-specific code goes in `verifydoc/adapters/`; a new extractor is one file.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# VerifyDoc — A Trust Layer for Document → Structured-JSON Extraction
|
|
2
2
|
|
|
3
|
-
**Project document /
|
|
3
|
+
**Project document / design spec (v1.0).** This is the single source of truth for VerifyDoc's design. It contains the motivation, the precise problem definition, the literature-grounded evaluation methodology (the core of the paper), the system architecture, the repository layout, a six-week implementation plan, the git workflow, and the paper plan. Build module by module against the "Definition of Done" in each section.
|
|
4
4
|
|
|
5
5
|
One-liner: *VerifyDoc wraps any document-extraction model and returns, for every field, a calibrated confidence score, a source-grounding box/span, and an abstain-or-accept decision — so a human reviews the 5% of fields that are actually wrong instead of eyeballing all of them.*
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ Document → structured-JSON extraction is one of the highest-volume uses of LLM
|
|
|
12
12
|
|
|
13
13
|
That is the wedge. VerifyDoc does not compete with the parsers — it *layers on top of any of them* and adds the missing reliability contract: field-level confidence + provenance + abstention. Commercial APIs already prove the demand (Box shipped field-level confidence in Jan 2026; Azure Document Intelligence, AWS Textract, and Extend all expose per-field confidence), but no popular open-source parser leads with it. Practitioner leaderboards name exactly this unmet need: whether a reviewer can trace an uncertain value back to the page before it enters a downstream system. VerifyDoc is the open-source answer.
|
|
14
14
|
|
|
15
|
-
Why
|
|
15
|
+
Why the scope works: the tool is model-agnostic and thin (it wraps existing extractors), the paper contribution is the reliable "benchmark + released dataset + strong open baseline" type rather than a risky "beat-SOTA architecture" play, and the demo (highlight-the-hallucinated-field on the rendered page) is instantly shareable.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -216,7 +216,6 @@ Design rules: adapters isolate all model-specific code behind one interface (`ex
|
|
|
216
216
|
```
|
|
217
217
|
verifydoc/
|
|
218
218
|
├── README.md # quickstart + the killer demo GIF
|
|
219
|
-
├── CLAUDE.md # Claude Code working context (see separate file)
|
|
220
219
|
├── PROJECT.md # this document
|
|
221
220
|
├── LICENSE # Apache-2.0 (permissive → adoption)
|
|
222
221
|
├── pyproject.toml # packaging (pip install verifydoc)
|
|
@@ -269,7 +268,7 @@ verifydoc/
|
|
|
269
268
|
|
|
270
269
|
---
|
|
271
270
|
|
|
272
|
-
## 9. Implementation plan (6 weeks
|
|
271
|
+
## 9. Implementation plan (6 weeks)
|
|
273
272
|
|
|
274
273
|
**Week 1 — skeleton + types + one adapter + eval stubs.** Repo, packaging, CI, pre-commit. Define `types.py` (`FieldPrediction`, `Grounding`). Implement ingest (PDF→images + text layer). Ship the **PaddleOCR-VL adapter** end-to-end on a handful of CORD receipts. Stub `eval/extraction.py` with Field-F1 + exact-match. *DoD: `verifydoc extract sample.pdf --schema cord.json` returns JSON with placeholder confidences; CI green.*
|
|
275
274
|
|
|
@@ -320,12 +319,6 @@ verifydoc/
|
|
|
320
319
|
|
|
321
320
|
---
|
|
322
321
|
|
|
323
|
-
## 13. EB1-A mapping (brief, honest)
|
|
324
|
-
|
|
325
|
-
This project can contribute to (a) **authorship of scholarly articles** (arXiv + workshop/TMLR paper); (b) **original contributions of major significance** — best evidenced by demonstrable open-source adoption (stars, PyPI downloads, dependents, external citations of VerifyDocBench); and (c) **judging the work of others** if you also serve as a reviewer for the workshop you submit to. Be realistic: USCIS requires meeting **at least three** criteria plus a holistic final-merits determination, and strong petitions usually document more, with independent corroboration (sustained citations, media, memberships, and recommendation letters). VerifyDoc is engineered to *generate* that downstream evidence (adoption → citations → letters), but **two projects alone are not a sufficient petition** — pair it with the second project and the complementary criteria.
|
|
326
|
-
|
|
327
|
-
---
|
|
328
|
-
|
|
329
322
|
## References (select; verify at write-up)
|
|
330
323
|
|
|
331
324
|
- ExtractBench — arXiv:2602.12247 (SIGKDD 2026); code github.com/ContextualAI/extract-bench.
|
|
@@ -36,7 +36,8 @@ pip install 'verifydoc[pdf]' # + PDF/image ingestion
|
|
|
36
36
|
```python
|
|
37
37
|
from verifydoc import verify
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
# ready-to-run sample lives in examples/
|
|
40
|
+
result = verify("examples/invoice.txt", schema="examples/invoice_schema.json")
|
|
40
41
|
for f in result.fields:
|
|
41
42
|
print(f"{f.path:12} = {f.value!r:24} conf={f.confidence:.2f} {f.decision}")
|
|
42
43
|
if f.grounding:
|
|
@@ -44,10 +45,12 @@ for f in result.fields:
|
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
```bash
|
|
47
|
-
verifydoc extract invoice.txt --schema invoice_schema.json --
|
|
48
|
+
verifydoc extract examples/invoice.txt --schema examples/invoice_schema.json --threshold 0.8
|
|
48
49
|
streamlit run ui/streamlit_app.py # review UI: green/red fields + click-through to source
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
See [`examples/`](examples/) for the full runnable walk-through.
|
|
53
|
+
|
|
51
54
|
Schemas are plain JSON Schema, with each leaf optionally declaring **how it is scored** (the executable-schema pattern):
|
|
52
55
|
|
|
53
56
|
```json
|
|
@@ -65,14 +68,37 @@ Schemas are plain JSON Schema, with each leaf optionally declaring **how it is s
|
|
|
65
68
|
|
|
66
69
|
| Layer | Modules | Status |
|
|
67
70
|
|---|---|---|
|
|
68
|
-
| **Adapters** (all model code isolated here) | mock · text-search · PaddleOCR
|
|
71
|
+
| **Adapters** (all model code isolated here) | mock · text-search · RapidOCR · PaddleOCR · dots.ocr · Docling/MinerU output · API-VLM (OpenAI/Anthropic) | ✅ |
|
|
69
72
|
| **Confidence signals** | token-prob · verbalized · consensus (k-sample voting) · grounding-based · combined | ✅ |
|
|
70
73
|
| **Calibrators** (fit on a dedicated split, never test) | temperature · Platt · isotonic · histogram · **split conformal** with finite-sample risk guarantee | ✅ |
|
|
71
74
|
| **Grounding** | value → page/bbox/char-span attachment with support scores | ✅ |
|
|
72
75
|
| **Policy** | empirical & conformal accept thresholds for a target selective risk | ✅ |
|
|
73
76
|
| **Eval harness / VerifyDocBench scorer** | Field-F1 · exact · CER/WER · ANLS · TEDS/TEDS-Struct · GriTS · omission vs hallucination · ECE/Adaptive-ECE/MCE/Brier/NLL/TCE · RC/AURC/E-AURC/Coverage@Risk/AUROC/AUPR/FPR@95 · box IoU/span-F1/grounding-conditioned correctness · bootstrap CIs + paired tests | ✅ |
|
|
74
77
|
|
|
75
|
-
Every metric implements the exact definition in [PROJECT.md §5](PROJECT.md) with a hand-computed numeric regression test (
|
|
78
|
+
Every metric implements the exact definition in [PROJECT.md §5](PROJECT.md) with a hand-computed numeric regression test (201 tests, `eval/` coverage 98%).
|
|
79
|
+
|
|
80
|
+
## Results on real documents
|
|
81
|
+
|
|
82
|
+
Two independent real OCR extractors (**RapidOCR** and **PaddleOCR**) on real
|
|
83
|
+
**CORD** receipts and **FUNSD** forms, scored by the harness
|
|
84
|
+
([full tables + reading](paper/generated/REAL_MODELS_RESULTS.md)):
|
|
85
|
+
|
|
86
|
+
| Confidence signal | ranks errors? | CORD AUROC (RapidOCR / PaddleOCR) |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| **learned combiner** | ✅ best | **0.89 / 0.84** |
|
|
89
|
+
| **grounding** | ✅ strong | 0.82 / 0.74 |
|
|
90
|
+
| token-probability | ~ moderate | 0.69 / 0.68 |
|
|
91
|
+
| verbalized / consensus | ✗ uninformative | 0.50 / 0.50 |
|
|
92
|
+
|
|
93
|
+
- **Grounding is a real trust signal:** grounded fields are **84–85% correct
|
|
94
|
+
vs ~1%** for ungrounded (gap ≈ +0.84; box accuracy @IoU 0.5 = 0.75–0.78).
|
|
95
|
+
- **The abstention layer is honest:** with a weak field-extractor the base
|
|
96
|
+
error rate is high, so conformal abstention at a 2–5% budget correctly
|
|
97
|
+
refuses to auto-accept — you report *selective risk*, not headline accuracy.
|
|
98
|
+
- The synthetic slice (strong extractor) shows the other end: Coverage@2% ≈ 1.0.
|
|
99
|
+
|
|
100
|
+
The thesis holds on real data: **grounding + a learned fusion rank errors;
|
|
101
|
+
self-reported and single-sample-consensus confidence do not.**
|
|
76
102
|
|
|
77
103
|
## The benchmark
|
|
78
104
|
|
|
@@ -82,16 +108,13 @@ make results # regenerates every table/figure in paper/generated from config
|
|
|
82
108
|
|
|
83
109
|
The harness runs **signals × calibrators × the full metric suite** with a
|
|
84
110
|
document-level calibration split (disjointness asserted in code), bootstrap
|
|
85
|
-
CIs, and a conformal-guarantee row.
|
|
86
|
-
slice
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- **The conformal row holds its guarantee** on every tested α, and reports the abstention it forces.
|
|
93
|
-
|
|
94
|
-
These self-checks run as unit tests — the repo's core claims are CI-enforced, not just stated.
|
|
111
|
+
CIs, and a conformal-guarantee row. It ships a deterministic **synthetic**
|
|
112
|
+
slice (runs in CI) plus **CORD** and **FUNSD** loaders with gold source boxes;
|
|
113
|
+
`extractor:` dispatches to any adapter (`rapidocr`, `paddleocr-vl`, …) and
|
|
114
|
+
`dataset:` to any slice. See the [GPU runbook](docs/REAL_MODELS.md) to
|
|
115
|
+
reproduce the real-model rows. Core claims (grounding beats verbalized;
|
|
116
|
+
conformal holds its guarantee) are also **CI-enforced as unit tests**, not
|
|
117
|
+
just stated.
|
|
95
118
|
|
|
96
119
|
## Why not just use the parser's own score?
|
|
97
120
|
|
|
@@ -104,9 +127,19 @@ buys you.
|
|
|
104
127
|
## Roadmap
|
|
105
128
|
|
|
106
129
|
- [x] v0.1 — library + CLI + harness + synthetic benchmark slice + UI
|
|
107
|
-
- [
|
|
108
|
-
- [
|
|
109
|
-
- [
|
|
130
|
+
- [x] v0.2 — CORD + FUNSD real slices with gold boxes; learned combiner; 1000× faster grounder
|
|
131
|
+
- [x] v0.3 — real-model results (RapidOCR + PaddleOCR on CORD/FUNSD)
|
|
132
|
+
- [x] v0.4 — vendor-neutral API-VLM extractor (OpenAI/Anthropic) with k-sample consensus; compilable paper with auto-generated tables
|
|
133
|
+
- [ ] Run the API-VLM row at scale (fair verbalized + consensus comparison; needs an API key)
|
|
134
|
+
- [ ] dots.ocr via vllm; SROIE / DocILE / XFUND slices; human-labeled correctness + IAA
|
|
135
|
+
- [ ] Paper submission ([contributions welcome](CONTRIBUTING.md))
|
|
136
|
+
|
|
137
|
+
## Documentation
|
|
138
|
+
|
|
139
|
+
- [How it works](docs/how-it-works.md) — the pipeline, the abstention idea, why grounding is a trust signal
|
|
140
|
+
- [Real-model results](paper/generated/REAL_MODELS_RESULTS.md) — RapidOCR + PaddleOCR numbers and reading
|
|
141
|
+
- [GPU runbook](docs/REAL_MODELS.md) — reproduce the real-extractor rows
|
|
142
|
+
- [USP audit](docs/USP.md) · [Paper draft](paper/main.tex) · [Full spec](PROJECT.md)
|
|
110
143
|
|
|
111
144
|
## Development
|
|
112
145
|
|
|
@@ -114,6 +147,8 @@ buys you.
|
|
|
114
147
|
git clone https://github.com/bhaskargurram-ai/verifydoc && cd verifydoc
|
|
115
148
|
uv venv .venv && uv pip install -e ".[dev]"
|
|
116
149
|
make test lint typecheck # all green before any PR (CI enforces)
|
|
150
|
+
make results # regenerate benchmark tables + LaTeX
|
|
151
|
+
make paper # compile the paper (needs a LaTeX toolchain)
|
|
117
152
|
```
|
|
118
153
|
|
|
119
154
|
Contributions welcome — see the issues tagged `good-first-issue`. All model-specific code goes in `verifydoc/adapters/`; a new extractor is one file.
|