"""Build the self-contained leaderboard.json that the Hugging Face Space renders. The Space must run standalone on Hugging Face with no access to the parent repository, so this script merges the repo's canonical artifacts into a single file committed alongside the app: - results/summary.json -> scores, aggregates, file-type / language breakdowns - sources.json -> per-document provenance (name, license, source url) - docubench-explorer.html -> per-document capability flags (arrays, RTL, CJK, ...) - results//.json -> the model id stamped in each result's meta block Scores always come from summary.json (the output of `docubench report`); this script never recomputes them. Run it from anywhere after regenerating the report: python3 space/build_data.py """ from __future__ import annotations import json import math from json import JSONDecoder from pathlib import Path from typing import Any REPO_ROOT = Path(__file__).resolve().parent.parent SPACE_DIR = Path(__file__).resolve().parent OUTPUT_PATH = SPACE_DIR / "leaderboard.json" CAPABILITY_LABELS = { "arrays": "Array / line-item tables", "reconcile": "Totals must reconcile", "rtl": "Right-to-left script", "cjk": "CJK script", "handwriting": "Handwriting", "rotated": "Rotated scan", "needle": "Needle-in-haystack lookup", "nested": "Nested objects", } def load_json(path: Path) -> Any: with open(path, encoding="utf-8") as f: return json.load(f) def extract_explorer_flags(html_path: Path) -> dict[str, dict[str, bool]]: """Pull the per-document capability flags out of the explorer's embedded DATA blob.""" if not html_path.exists(): return {} text = html_path.read_text(encoding="utf-8") marker = "const DATA = " start = text.find(marker) if start == -1: return {} brace = text.find("{", start) data, _ = JSONDecoder().raw_decode(text[brace:]) flags: dict[str, dict[str, bool]] = {} for doc in data.get("docs", []): if "id" in doc and isinstance(doc.get("flags"), dict): flags[doc["id"]] = {k: bool(v) for k, v in doc["flags"].items()} return flags def engine_model(engine: str, doc_ids: list[str]) -> str | None: """Best-effort model id from the first result file that records one in meta.""" for doc_id in doc_ids: path = REPO_ROOT / "results" / engine / f"{doc_id}.json" if not path.exists(): continue try: meta = (load_json(path) or {}).get("meta") or {} except (json.JSONDecodeError, OSError): continue if meta.get("model"): return str(meta["model"]) return None def mean(values: list[float]) -> float | None: values = [v for v in values if v is not None] return math.fsum(values) / len(values) if values else None def build() -> dict[str, Any]: summary = load_json(REPO_ROOT / "results" / "summary.json") sources = {row["doc_id"]: row for row in load_json(REPO_ROOT / "sources.json") if "doc_id" in row} flags_by_doc = extract_explorer_flags(REPO_ROOT / "docubench-explorer.html") engines = list(summary["aggregates"].keys()) display_names = summary.get("engine_display_names", {}) per_doc_scores = {row["doc_id"]: row for row in summary["per_doc"]} doc_ids = [row["doc_id"] for row in summary["per_doc"]] documents = [] for doc_id in doc_ids: src = sources.get(doc_id, {}) scores = {engine: per_doc_scores[doc_id].get(engine) for engine in engines} documents.append({ "doc_id": doc_id, "name": src.get("name", doc_id), "lang": src.get("lang", "unknown"), "ftype": src.get("ftype", "unknown"), "pages": src.get("pages"), "feature": src.get("hard_feature", ""), "license": src.get("license", ""), "source_url": src.get("source_url", ""), "flags": flags_by_doc.get(doc_id, {}), "scores": scores, }) # capability breakdown: per-engine mean over the documents carrying each flag capability_rows = [] for flag, label in CAPABILITY_LABELS.items(): matching = [d for d in documents if d["flags"].get(flag)] if not matching: continue row: dict[str, Any] = {"flag": flag, "label": label, "doc_count": len(matching)} for engine in engines: row[engine] = mean([d["scores"].get(engine) for d in matching]) capability_rows.append(row) return { "benchmark": summary.get("benchmark", {}), "engines": [ { "key": engine, "display": display_names.get(engine, engine), "model": engine_model(engine, doc_ids), "overall": summary["aggregates"][engine], } for engine in engines ], "breakdowns": { "ftype": summary["breakdowns"].get("ftype", []), "lang": summary["breakdowns"].get("lang", []), "capability": capability_rows, }, "documents": documents, } def main() -> int: data = build() with open(OUTPUT_PATH, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) f.write("\n") print( f"wrote {OUTPUT_PATH.relative_to(REPO_ROOT)}: " f"{len(data['engines'])} engines, {len(data['documents'])} documents, " f"{len(data['breakdowns']['capability'])} capability rows" ) return 0 if __name__ == "__main__": raise SystemExit(main())