"""Chinese Classical Bench — leaderboard Space. Single source of truth = the committed `leaderboard.md` (produced by the GitHub repo's scripts/aggregate.py). This Space renders it verbatim so the public leaderboard can never drift from the repo again. The interactive table/chart are recomputed from the same results/*.json the markdown was built from, so they always agree. Primary metric per task matches scripts/aggregate.py: translate/char-gloss use the Opus LLM judge (chrF under-rates synonymous paraphrase); chrF is the labelled reproducible floor in the markdown's transparency table. """ import json from pathlib import Path import gradio as gr import pandas as pd HERE = Path(__file__).parent RESULTS_DIR = HERE / "results" LEADERBOARD_MD = HERE / "leaderboard.md" PRIMARY = { "translate": ("judge_norm", "translate (Judge)"), "punctuate": ("punct_f1", "punctuate (Punct F1)"), "char-gloss": ("judge_norm", "char-gloss (Judge)"), "idiom-source": ("book_em", "idiom-source (Book EM)"), "fill-in": ("exact_match", "fill-in (Exact)"), "compress": ("efficiency", "compress (Eff)"), } TASK_ORDER = list(PRIMARY) def load_leaderboard() -> pd.DataFrame: rows = [] for fp in sorted(RESULTS_DIR.glob("*.json")): if fp.name.startswith("_"): continue d = json.loads(fp.read_text(encoding="utf-8")) row = {"Model": d.get("model", fp.stem)} vals, missing = [], [] for t in TASK_ORDER: key, label = PRIMARY[t] v = d.get("tasks", {}).get(t, {}).get("summary", {}).get(key) if isinstance(v, (int, float)): row[label] = round(v, 3) vals.append(v) else: row[label] = None missing.append(t) cp = (d.get("tasks", {}).get("punctuate", {}) .get("summary", {}).get("char_preserved")) row["Preserve"] = round(cp, 3) if isinstance(cp, (int, float)) else None row["Avg"] = round(sum(vals) / len(vals), 3) if vals else None row["_note"] = ("⚠ missing " + ",".join(missing)) if missing else "" rows.append(row) df = pd.DataFrame(rows) df = df.sort_values("Avg", ascending=False, na_position="last").reset_index(drop=True) df.insert(0, "#", range(1, len(df) + 1)) return df DF = load_leaderboard() TOP = DF.iloc[0]["Model"] if len(DF) else "—" N_MODELS = len(DF) LB_MD = (LEADERBOARD_MD.read_text(encoding="utf-8") if LEADERBOARD_MD.exists() else "_leaderboard.md missing_") INTRO = f""" # 🏛️ Chinese Classical Bench — Leaderboard 中国古典语言能力评测基准 — **6 个任务 × 100 题 = 600 道**(古译今 / 断句加标点 / 字义解释 / 典故出处 / 单字填空 / 今译古压缩)。回答一个具体问题: **国产开源 LLM 在中国古典文献理解上谁更强?** 当前榜单:**{N_MODELS} 个模型**,按 primary 平均分榜首 **`{TOP}`**。 - 📦 评测集 (HF): [`gujilab/chinese-classical-bench`](https://huggingface.co/datasets/gujilab/chinese-classical-bench) - 🧩 配套语料 (CC0): [`gujilab/chinese-classical-corpus`](https://huggingface.co/datasets/gujilab/chinese-classical-corpus) - 💻 评测代码 / 完整方法与发现: [github.com/gujilab/chinese-classical-bench](https://github.com/gujilab/chinese-classical-bench) (见 `docs/findings.md` — 心理测量学审计、污染探针、judge 提升) > **方法变更(v1.6+)**:`translate` / `char-gloss` 的 headline 已从 chrF > 升级为 **Claude Opus 4.7 LLM judge**(chrF 系统性低估同义改写);chrF 作为 > 可复现下限保留在下方 *Transparency* 表。新增 *Canonicity-stratified* 段: > 按来源典籍知名度分层,暴露模型对"背过名篇"的依赖(`idiom-source` ρ=0.68)。 """ with gr.Blocks(title="Chinese Classical Bench Leaderboard", theme=gr.themes.Soft()) as demo: gr.Markdown(INTRO) gr.Markdown("### Primary leaderboard(可排序)") gr.Dataframe(value=DF, interactive=False, wrap=True) gr.BarPlot(value=DF[["Model", "Avg"]].dropna(), x="Model", y="Avg", title="Primary 平均分 (Avg)") gr.Markdown("---\n以下为仓库 `leaderboard.md` 原文" "(含 canonicity-stratified 与 transparency 两表," "与仓库严格一致):\n") gr.Markdown(LB_MD) if __name__ == "__main__": demo.launch()