benchmark playgroup
UK Charity Document Extraction — Multi-Model Benchmark
- Why
- A playgroup needed a fair comparison of models on the same real charity PDFs, with the same fields and the same score.
- Problem
- UK charity annual reports are PDFs. Eight financial fields have to come out correctly, and models differ in accuracy, failed runs, time, and cost.
- Built
- A scored extractor across OpenRouter, the Doubleword Batch API, and V7 Go, plus a public playground of every run.
- Result
- 122 scored runs. The best models reach about 0.95 F1. Provider averages and failures are on the leaderboard below.
Results snapshot: 2026-09-18 · 122 scored runs · playground 2026-09-18T0710Z (25 archived versions from git history)
Who is this for?
- Playgroup attendees — start with QUICKSTART.md, then run extraction and scoring locally.
- Curious explorers — read the key findings below and open the latest playground or browse all snapshots (no code required).
- Contributors — see the repo file map for scripts, registries, and workflow.
- Doubleword / V7 teams — provider tables and timing notes mirror
python score.pyoutput in the repo README.
Key findings
Provider aggregates match python score.py over every data/*_dev_extracted__*.tsv file on
2026-09-18: 122 scored runs
(46 OpenRouter, 43 Doubleword, 33 V7 Go). Registries: 39 OpenRouter keys, 36 Doubleword models, 32 V7 keys.
| Provider | Models | Active | Failed | Avg F1 | Best F1 | Best model | Avg fields | Avg time | Avg cost |
|---|---|---|---|---|---|---|---|---|---|
| Doubleword | 43 | 41 | 2 | 0.827 | 0.947 | dw-deepseek-v4-pro-0813 | 65.1/85 (77%) | 735s | $0.067 |
| OpenRouter | 46 | 33 | 13 | 0.788 | 0.946 | gemini-3-pro | 59.9/85 (71%) | 1030s | $0.158 |
| V7 Go | 33 | 33 | 0 | 0.833 | 0.852 | gpt4-1 | 62.8/85 (74%) | 124s | $0.000 |
Doubleword’s average F1 among active models (0.827) edges OpenRouter (0.788), and Doubleword retains the highest
single-model F1 (dw-deepseek-v4-pro-0813, 0.947). gemini-3-pro ranks 2nd at 0.946;
new entry dw-deepseek-v4.1-flash joins at rank 10 (F1 0.941, $0.032/run — highly cost-efficient).
V7 averages 0.833 F1 with no failed runs in this snapshot. V7 cost stays at zero until
price_in / price_out are set in config_models_v7.py.
Top 5 models by F1
| Rank | Model | Provider | F1 | Precision | Recall | Fields found |
|---|---|---|---|---|---|---|
| 1 | dw-deepseek-v4-pro-0813 | Doubleword | 0.947 | 0.975 | 0.920 | 78.2/85 |
| 2 | gemini-3-pro | OpenRouter | 0.946 | 0.975 | 0.918 | 78.1/85 |
| 3 | kimi-k3 | OpenRouter | 0.944 | 0.975 | 0.916 | 77.8/85 |
| 4 | kimi-k2.6 | OpenRouter | 0.944 | 0.975 | 0.915 | 77.8/85 |
| 5 | glm-5.3-flash | OpenRouter | 0.944 | 0.975 | 0.914 | 77.7/85 |
Takeaways
- Doubleword holds 5 of the global top 10. Retains the global leader (
dw-deepseek-v4-pro-0813, 0.947);gemini-3-prois 2nd at 0.946.dw-qwen3.8-27bis rank 6 at F1 0.943. - 41 of 43 Doubleword models produced usable results (F1 range 0.827–0.947 for standard text LLMs).
- Free-tier models universally failed — the zero-score runs are free-tier or had context/format issues.
- Precision is consistently high (0.96–0.97); recall differentiates leaders.
- Hardest fields:
income_annually_in_british_poundsandspending_annually_in_british_pounds.
Interactive playground
The hosted playground is a static snapshot generated by python playground.py in the repo.
Eight tabs: Rankings, Field Heatmap, Document Analysis, Error Breakdown, Deep Dive, Recommendations,
Provider Analysis, and Project Evolution.
score.py; heatmaps and error tabs use exact-match vs expected TSV. F1 can exceed
exact-match when values are close but not identical — that is expected.
Open latest playground Browse all snapshots
Playground version history
Each row is a frozen copy of which-models-extracted-playground.html from git, named with its commit time in UTC.
Use this to see how the benchmark grew from 40 OpenRouter-only models (Feb 2026) to 122 scored runs across three providers (Sep 2026).
| Snapshot (UTC) | Models | F1 runs | Highlights | |
|---|---|---|---|---|
| 2026-09-18T0710Z | 122 | 122 | Latest — dw-deepseek-v4.1-flash (F1=0.941, rank 10) | Open |
| 2026-09-11T0000Z | 121 | 121 | DW/OR catalog prices & cost backfill | Open |
| 2026-09-10T2232Z | 121 | 121 | OpenRouter Gemini, Kimi, GLM results | Open |
| 2026-09-09T2357Z | 115 | 115 | Four new Doubleword model results | Open |
| 2026-08-22T0830Z | 111 | 111 | dw-deepseek-ocr-2 OCR results | Open |
| 2026-08-21T2219Z | 111 | 111 | dw-qwen3.8-27b, dw-muse-glimmer-30b | Open |
| 2026-08-21T2145Z | 109 | 109 | Tab sync fix across all dashboards | Open |
| 2026-08-09T0746Z | 109 | 109 | Aug 2026 benchmark refresh | Open |
| 2026-07-29T1317Z | 107 | 107 | 34 Doubleword models | Open |
| 2026-04-11T1748Z | 85 | 85 | V7 Go provider added | Open |
| 2026-03-07T2116Z | 47 | 47 | Provider Analysis tab | Open |
| 2026-03-07T2104Z | 47 | 47 | F1 scoring & provider summary | Open |
| 2026-02-28T1312Z | 40 | — | First leaderboard (exact-match tabs) | Open |
View all 25 snapshots with search and filters →
Dataset & fields
Small export from the Kleister Charity dataset
(dev-0): 11 UK charity financial PDFs (up to 200 pages each) with pre-extracted OCR text.
Data is UK open data — see Kleister license.
Workflow (local)
Step-by-step video guide for Doubleword batch runs: extractor.py --all-doubleword.
# Smoke test
python llm_openrouter.py
# Extract (auto-detects OpenRouter / Doubleword / V7 from registries)
python extractor.py gemini-2.0-flash
python extractor.py --all-doubleword
python extractor.py --all-v7
# Score and regenerate playground
python score.py
python playground.py
Repo essentials
extractor.py— unified runner with checkpoint/resume for async backendsscore.py— F1 / precision / recall leaderboardplayground.py— generateswhich-models-extracted-playground.htmlconfig_models_*.py— OpenRouter, Doubleword, and V7 model registriesdata/extraction_stats.csv— per-run stats (time, cost, field hits)docs/v7-go.md— focused V7 Go setup guide