"""HTML UI for the WebPageBench leaderboard.""" from __future__ import annotations import html from pathlib import Path from typing import Any from src.bench_config import load_bench_config, task_count from src.formatting import fmt_cost, fmt_duration, fmt_number, fmt_pct_value, fmt_steps, round2 from src.i18n import get_lang, section_desc_t, section_label_t, t, taxonomy_desc_t from src.load_entries import sort_entries from src.models import LeaderboardEntry from src.token_display import fmt_tokens, format_model_usage_breakdown_html _DETAIL_TAB_LABELS = { "submission": "Details", "sections": "Sections", "taxonomy": "UI taxonomy", "metrics": "Metrics", } def load_css() -> str: return (Path(__file__).resolve().parent.parent / "assets" / "webpagebench.css").read_text(encoding="utf-8") def score_tier(pct: float | None) -> str: if pct is None: return "danger" if pct >= 70: return "success" if pct >= 40: return "warning" return "danger" def fmt_pct(value: float | None) -> str: return fmt_pct_value(value) def fmt_pct_display(entry: LeaderboardEntry) -> str: if entry.success_rate is None: return "—" return fmt_pct_value(entry.success_rate) def provider_from_model(model: str, provider: str | None = None) -> str: if provider: return provider if "/" in model: return model.split("/", 1)[0] return model.split("-", 1)[0] def _badge_link(label: str, passed: object, total: object, css_class: str, title: str, nav: str) -> str: stat_html = "" try: passed_i = int(passed) if passed is not None else None total_i = int(total) if total is not None else None except (TypeError, ValueError): passed_i = total_i = None if passed_i is not None and total_i is not None: stat_html = f'{passed_i}/{total_i}' return ( f'' f"{html.escape(label)}{stat_html}" ) def _badge(label: str, css_class: str, title: str) -> str: return ( f'' f"{html.escape(label)}" ) def _row_badges(entry: LeaderboardEntry) -> str: config = load_bench_config() badges: list[str] = [] ranked_sections = sorted( ( (stats.success_rate, stats.section_id, section_label_t(stats.section_id), stats.passed, stats.total) for stats in entry.sections.values() if stats.success_rate is not None ), reverse=True, )[:2] for _, section_id, label, passed, total in ranked_sections: desc = section_desc_t(section_id) or label nav = f"sections:{section_id}" badges.append(_badge_link(label, passed, total, "domain", str(desc), nav)) ranked_taxonomy = sorted( ( (float(row.get("success_rate")), class_id) for class_id, row in entry.ui_classes.items() if isinstance(row.get("success_rate"), (int, float)) ), reverse=True, )[:2] if not ranked_taxonomy and entry.ui_badges: for class_id in entry.ui_badges[:2]: meta = config.get("ui_classes", {}).get(class_id, {}) label = str(meta.get("label") or class_id) row = entry.ui_classes.get(class_id) or {} nav = f"taxonomy:{class_id}" badges.append( _badge_link( label, row.get("passed"), row.get("total"), "taxonomy", taxonomy_desc_t(class_id) or str(meta.get("description") or class_id), nav, ) ) else: for _, class_id in ranked_taxonomy: meta = config.get("ui_classes", {}).get(class_id, {}) row = entry.ui_classes.get(class_id) or {} label = str(meta.get("label") or class_id) nav = f"taxonomy:{class_id}" badges.append( _badge_link( label, row.get("passed"), row.get("total"), "taxonomy", taxonomy_desc_t(class_id) or str(meta.get("description") or class_id), nav, ) ) return "".join(badges) def top_section_badges(entry: LeaderboardEntry, limit: int = 2) -> list[str]: ranked = [ (stats.success_rate, section_label_t(stats.section_id)) for stats in entry.sections.values() if stats.success_rate is not None ] ranked.sort(reverse=True) return [label for _, label in ranked[:limit]] def pick_winner(entries: list[LeaderboardEntry], metric: str, *, ascending: bool = False) -> LeaderboardEntry | None: if not entries: return None values = [(entry, entry.metric(metric)) for entry in entries] values = [(entry, value) for entry, value in values if value is not None] if not values: return None return min(values, key=lambda pair: pair[1])[0] if ascending else max(values, key=lambda pair: pair[1])[0] def _quick_card(label: str, headline: str, entry: LeaderboardEntry, subtitle: str) -> str: return f"""
{html.escape(label)}
{html.escape(headline)}
{html.escape(entry.model)}
{html.escape(subtitle)}
{html.escape(entry.harness)}
""" def _pick_headline(entry: LeaderboardEntry, metric: str) -> str: if metric == "success_rate" or metric == "full_bench_success_rate": return fmt_pct_display(entry) if metric == "avg_duration_seconds": return fmt_duration(entry.avg_duration_seconds) if metric == "total_duration_seconds": return fmt_duration(entry.total_duration_seconds) if metric in {"total_cost_usd", "avg_cost_per_task_usd"}: return fmt_cost(entry.total_cost_usd) if metric == "value_score": value = entry.value_score return fmt_number(value) if value is not None else "—" if metric.startswith("domain:"): return fmt_pct(entry.metric(metric)) return fmt_pct_display(entry) _GLOBAL_HIGHLIGHTS: tuple[dict[str, object], ...] = ( { "label": "best_overall", "metric": "success_rate", "ascending": False, "subtitle": "best_overall_sub", }, { "label": "best_budget", "metric": "total_cost_usd", "ascending": True, "subtitle": "best_budget_sub", }, { "label": "fastest", "metric": "total_duration_seconds", "ascending": True, "subtitle": "fastest_sub", }, ) def build_highlight_picks(entries: list[LeaderboardEntry]) -> str: """Top highlights shown above view tabs on every leaderboard page.""" cards: list[str] = [] for pick in _GLOBAL_HIGHLIGHTS: metric = str(pick["metric"]) winner = pick_winner(entries, metric, ascending=bool(pick["ascending"])) if winner is None: continue cards.append( _quick_card( t(str(pick["label"])), _pick_headline(winner, metric), winner, t(str(pick["subtitle"])), ) ) if not cards: return "" return ( '
' f'
{"".join(cards)}
' "
" ) def build_quick_picks(entries: list[LeaderboardEntry], view_id: str) -> str: config = load_bench_config() picks = config["quick_picks"].get(view_id, []) cards: list[str] = [] for pick in picks: metric = pick["metric"] ascending = metric in {"avg_duration_seconds", "total_duration_seconds", "total_cost_usd"} winner = pick_winner(entries, metric, ascending=ascending) if winner is None: continue cards.append(_quick_card(pick["label"], _pick_headline(winner, metric), winner, pick["subtitle"])) if not cards: return "" return f'
{"".join(cards)}
' def _input_badge(entry: LeaderboardEntry) -> str: modality = entry.input_modality css = modality.replace("+", "-plus-") if modality not in {"—", ""} else "unknown" return ( f'{html.escape(modality)}' ) def _strict_cell(entry: LeaderboardEntry) -> str: if entry.strict_passed_tasks is None or entry.total_tasks <= 0: return "—" pct = entry.strict_success_pct or 0 tier = score_tier(pct) return ( f'
{html.escape(fmt_pct_value(entry.strict_success_rate))}
' f'
{entry.strict_passed_tasks}/{entry.total_tasks}
' ) def _sort_value(value: float | None) -> str: if value is None: return "" return f"{value:.6f}" def _sort_th(label: str, key: str, *, active: bool = False, title: str = "") -> str: active_cls = " is-active" if active else "" direction = ' data-wab-dir="desc"' if active else "" title_attr = f' title="{html.escape(title)}"' if title else "" return ( f"" f'" ) def _success_row(idx: int, entry: LeaderboardEntry) -> str: pct = entry.success_pct or 0 tier = score_tier(pct) badges = _row_badges(entry) nav = html.escape(f"submission:{entry.entry_id}") tasks_ratio = entry.passed_tasks / entry.total_tasks if entry.total_tasks else None return f""" {idx + 1}
{html.escape(entry.model)}
{badges}
{html.escape(entry.harness)} {_input_badge(entry)} {entry.passed_tasks}/{entry.total_tasks}
{html.escape(fmt_pct_display(entry))}
{_strict_cell(entry)} """ def _speed_row(idx: int, entry: LeaderboardEntry) -> str: pct = entry.success_pct or 0 tier = score_tier(pct) nav = html.escape(f"submission:{entry.entry_id}") return f""" {idx + 1}
{html.escape(entry.model)}
{html.escape(entry.harness)}{_input_badge(entry)}
{html.escape(fmt_duration(entry.total_duration_seconds))} {html.escape(fmt_duration(entry.avg_duration_seconds))} {html.escape(fmt_steps(entry.total_agent_steps))}
{html.escape(fmt_pct_display(entry))}
""" def _cost_row(idx: int, entry: LeaderboardEntry) -> str: pct = entry.success_pct or 0 tier = score_tier(pct) value = entry.value_score nav = html.escape(f"submission:{entry.entry_id}") return f""" {idx + 1}
{html.escape(entry.model)}
{html.escape(entry.harness)}{_input_badge(entry)}
{html.escape(fmt_cost(entry.total_cost_usd))} {html.escape(fmt_cost(entry.avg_cost_per_task_usd))} {html.escape(fmt_tokens(entry.total_tokens))} {html.escape(fmt_tokens(entry.avg_tokens_per_task))} {format_model_usage_breakdown_html(entry)} {fmt_number(value) if value is not None else "—"}
{html.escape(fmt_pct_display(entry))}
""" def build_table(entries: list[LeaderboardEntry], view_id: str) -> str: sorted_entries = sort_entries(entries, view_id) if view_id == "speed": head = ( f"#{html.escape(t('model'))}{html.escape(t('total_time'))}" f"{html.escape(t('avg_time'))}{html.escape(t('total_steps'))}" f"{html.escape(t('success'))}" ) rows = [_speed_row(i, entry) for i, entry in enumerate(sorted_entries)] subtitle = t("speed_sub") view_label = t("view_speed") elif view_id == "cost": head = ( f"#{html.escape(t('model'))}{html.escape(t('total_cost'))}" f"{html.escape(t('per_task'))}{html.escape(t('total_tokens'))}" f"{html.escape(t('tokens_per_task'))}{html.escape(t('model_usage'))}" f"{html.escape(t('value'))}{html.escape(t('success'))}" ) rows = [_cost_row(i, entry) for i, entry in enumerate(sorted_entries)] subtitle = t("cost_sub") view_label = t("view_cost") else: head = ( f"#{html.escape(t('model'))}{html.escape(t('harness'))}" f"{html.escape(t('input'))}" f"{_sort_th(t('tasks_col'), 'tasks')}" f"{_sort_th(t('success'), 'success', active=True)}" f"{_sort_th(t('done_pass'), 'strict', title=t('done_pass_title'))}" ) rows = [_success_row(i, entry) for i, entry in enumerate(sorted_entries)] subtitle = t("success_sub") view_label = t("view_success") body = ( "".join(rows) if rows else f'{html.escape(t("no_runs_filter"))}' ) return f"""

{html.escape(t("by_model", label=view_label))}

{html.escape(subtitle)}

{head}{body}
""" _GITHUB_URL = "https://github.com/ai-forever/WebPageBench" _GITHUB_ICON = ( '' ) def build_shell_top(entries: list[LeaderboardEntry]) -> str: """Header with page menu and GitHub link. View switcher is a separate Gradio control.""" config = load_bench_config() benchmark = config["benchmark"] lang = get_lang() en_active = " active" if lang != "ru" else "" ru_active = " active" if lang == "ru" else "" return f"""

{html.escape(benchmark["name"])}

{html.escape(t("tagline"))}

{len(entries)} {html.escape(t("runs"))}
{task_count()} {html.escape(t("tasks"))}
{len(config["sections"])} {html.escape(t("sections_n"))}
{_GITHUB_ICON}
""" def build_board(entries: list[LeaderboardEntry], view_id: str = "success") -> str: return f"""
{build_table(entries, view_id)}
""" def build_shell(entries: list[LeaderboardEntry], view_id: str = "success") -> str: return build_shell_top(entries) + build_board(entries, view_id) def build_nav_js() -> str: """Client-side navigation for badge deep links (passed to demo.load js=).""" labels = ", ".join(f'"{key}": "{value}"' for key, value in _DETAIL_TAB_LABELS.items()) return f""" () => {{ if (window.__wabNavInit) return []; window.__wabNavInit = true; const TAB_LABELS = {{{labels}}}; function setPayload(value) {{ const root = document.getElementById("wab-nav-payload"); if (!root) return; const input = root.querySelector("textarea, input"); if (!input) return; const proto = input.tagName === "TEXTAREA" ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype; const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set; if (setter) setter.call(input, value); else input.value = value; input.dispatchEvent(new Event("input", {{ bubbles: true }})); }} window.wabOpenPage = function (label) {{ const root = document.getElementById("wab-page-tabs"); if (!root || !label) return; const wrap = root.querySelector(":scope > .tab-wrapper") || root; wrap.querySelectorAll("button").forEach((btn) => {{ if ((btn.textContent || "").trim() === label) btn.click(); }}); document.querySelectorAll("[data-wab-page]").forEach((el) => {{ el.classList.toggle("active", el.getAttribute("data-wab-page") === label); }}); }}; const CHROME = {{ en: {{ Details: "Details", Sections: "Sections", "UI taxonomy": "UI taxonomy", Metrics: "Metrics", Filters: "Filters", Run: "Run" }}, ru: {{ Details: "Подробности", Sections: "Разделы", "UI taxonomy": "Таксономия UI", Metrics: "Метрики", Filters: "Фильтры", Run: "Прогон" }} }}; function currentLang() {{ return window.__wabLang === "ru" ? "ru" : "en"; }} function setHidden(id, value) {{ const root = document.getElementById(id); if (!root) return false; const input = root.matches("textarea, input") ? root : root.querySelector("textarea, input"); if (!input) return false; const proto = input.tagName === "TEXTAREA" ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype; const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set; if (setter) setter.call(input, value); else input.value = value; input.dispatchEvent(new Event("input", {{ bubbles: true }})); input.dispatchEvent(new Event("change", {{ bubbles: true }})); return true; }} function clickHidden(id) {{ const root = document.getElementById(id); if (!root) return false; const btn = root.matches("button") ? root : root.querySelector("button"); if (!btn) return false; btn.click(); return true; }} let applyingChrome = false; function applyChrome(lang) {{ const map = CHROME[lang] || CHROME.en; if (applyingChrome) return; applyingChrome = true; try {{ const detail = document.getElementById("wab-detail-tabs"); if (detail) {{ detail.querySelectorAll('button[role="tab"]').forEach((btn) => {{ if (!btn.dataset.wabTabKey) btn.dataset.wabTabKey = (btn.textContent || "").trim(); const key = btn.dataset.wabTabKey; if (map[key] && btn.textContent !== map[key]) btn.textContent = map[key]; }}); }} const filters = document.getElementById("wab-filters"); if (filters) {{ const label = filters.querySelector(":scope > .label-wrap span, :scope > button span"); const node = label || filters.querySelector(":scope > .label-wrap, :scope > button"); if (node && map.Filters && (node.textContent.trim() === "Filters" || node.textContent.trim() === "Фильтры" || node.dataset.wabChrome === "filters")) {{ if (node.dataset.wabChrome !== "filters") node.dataset.wabChrome = "filters"; if (node.textContent.trim() !== map.Filters) node.textContent = map.Filters; }} }} const run = document.getElementById("wab-submission-dropdown"); if (run) {{ const lab = run.querySelector("label span, label"); if (lab && map.Run) {{ const current = (lab.textContent || "").trim(); if (current === "Run" || current === "Прогон" || lab.dataset.wabChrome === "run") {{ if (lab.dataset.wabChrome !== "run") lab.dataset.wabChrome = "run"; if (current !== map.Run) lab.textContent = map.Run; }} }} }} }} finally {{ applyingChrome = false; }} }} function syncPageMenu() {{ const root = document.getElementById("wab-page-tabs"); if (!root) return; const panels = [...root.querySelectorAll(":scope > .tabitem")]; const visible = panels.findIndex((el) => getComputedStyle(el).display !== "none"); const label = visible === 1 ? "About" : "Leaderboard"; document.querySelectorAll("[data-wab-page]").forEach((el) => {{ el.classList.toggle("active", el.getAttribute("data-wab-page") === label); }}); }} window.wabOpenDetailTab = function (tabId) {{ const label = TAB_LABELS[tabId]; if (!label) return; const root = document.getElementById("wab-detail-tabs") || document.querySelector(".wab-tabs"); if (!root) return; const buttons = root.querySelectorAll('button[role="tab"]'); for (const btn of buttons) {{ const key = btn.dataset.wabTabKey || (btn.textContent || "").trim(); if (key === label) {{ btn.click(); return; }} }} }}; function clickNavButton() {{ const root = document.getElementById("wab-nav-go"); if (!root) return false; const btn = root.matches("button") ? root : root.querySelector("button"); if (!btn) return false; btn.click(); return true; }} function scrollToDetail() {{ const anchor = document.getElementById("wab-detail-anchor"); if (anchor) anchor.scrollIntoView({{ behavior: "smooth", block: "start" }}); }} window.wabNavigate = function (payload) {{ if (!payload) return; window.__wabPendingNav = payload; setPayload(payload); const tab = payload.split(":", 1)[0] || "submission"; window.wabOpenDetailTab(tab); scrollToDetail(); setTimeout(clickNavButton, 60); }}; document.addEventListener("click", function (event) {{ const sortBtn = event.target.closest("[data-wab-sort]"); if (sortBtn) {{ event.preventDefault(); event.stopPropagation(); const table = sortBtn.closest("table"); const tbody = table && table.querySelector("tbody"); if (!tbody) return; const key = sortBtn.getAttribute("data-wab-sort"); const attr = key === "tasks" ? "data-wab-tasks" : key === "strict" ? "data-wab-strict" : "data-wab-success"; const nextDir = sortBtn.classList.contains("is-active") && sortBtn.getAttribute("data-wab-dir") === "desc" ? "asc" : "desc"; table.querySelectorAll("[data-wab-sort]").forEach((el) => {{ el.classList.remove("is-active"); el.removeAttribute("data-wab-dir"); }}); sortBtn.classList.add("is-active"); sortBtn.setAttribute("data-wab-dir", nextDir); const rows = [...tbody.querySelectorAll("tr.wab-row")]; rows.sort((a, b) => {{ const rawA = a.getAttribute(attr); const rawB = b.getAttribute(attr); const numA = rawA === null || rawA === "" ? null : Number(rawA); const numB = rawB === null || rawB === "" ? null : Number(rawB); if (numA === null && numB === null) return 0; if (numA === null || Number.isNaN(numA)) return 1; if (numB === null || Number.isNaN(numB)) return -1; return nextDir === "asc" ? numA - numB : numB - numA; }}); rows.forEach((row, index) => {{ tbody.appendChild(row); const rank = row.querySelector(".wab-rank"); if (rank) rank.textContent = String(index + 1); }}); return; }} const traceTab = event.target.closest("[data-wab-trace-tab]"); if (traceTab && traceTab.closest(".wab-trace-detail-view")) {{ event.preventDefault(); event.stopPropagation(); const root = traceTab.closest(".wab-trace-detail-view"); const tabId = traceTab.getAttribute("data-wab-trace-tab"); root.querySelectorAll("[data-wab-trace-tab]").forEach((el) => {{ el.classList.toggle("active", el === traceTab); }}); root.querySelectorAll("[data-wab-trace-panel]").forEach((panel) => {{ panel.classList.toggle("active", panel.getAttribute("data-wab-trace-panel") === tabId); }}); return; }} const stepBtn = event.target.closest("[data-wab-trace-step]"); if (stepBtn && stepBtn.closest(".wab-trace-detail-view")) {{ event.preventDefault(); event.stopPropagation(); const root = stepBtn.closest(".wab-trace-detail-view"); const stepId = stepBtn.getAttribute("data-wab-trace-step"); root.querySelectorAll("[data-wab-trace-step]").forEach((el) => {{ el.classList.toggle("active", el === stepBtn); }}); root.querySelectorAll("[data-wab-trace-step-panel]").forEach((panel) => {{ panel.classList.toggle("active", panel.getAttribute("data-wab-trace-step-panel") === stepId); }}); return; }} const exportBtn = event.target.closest("[data-wab-trace-export]"); if (exportBtn && exportBtn.closest(".wab-trace-detail-view")) {{ event.preventDefault(); event.stopPropagation(); const root = exportBtn.closest(".wab-trace-detail-view"); const dataEl = root.querySelector(".wab-trace-export-data"); if (!dataEl) return; const blob = new Blob([dataEl.textContent], {{ type: "application/json" }}); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = (root.querySelector(".wab-trace-crumb-current")?.textContent || "trace") + ".json"; a.click(); URL.revokeObjectURL(url); return; }} const langBtn = event.target.closest("[data-wab-lang]"); if (langBtn) {{ event.preventDefault(); event.stopPropagation(); const lang = langBtn.getAttribute("data-wab-lang") === "ru" ? "ru" : "en"; window.__wabLang = lang; try {{ localStorage.setItem("wab-lang", lang); }} catch (err) {{}} document.querySelectorAll("[data-wab-lang]").forEach((el) => {{ el.classList.toggle("active", el.getAttribute("data-wab-lang") === lang); }}); applyChrome(lang); setHidden("wab-lang-value", lang); setTimeout(() => clickHidden("wab-lang-go"), 30); return; }} const pageLink = event.target.closest("[data-wab-page]"); if (pageLink) {{ event.preventDefault(); event.stopPropagation(); window.wabOpenPage(pageLink.getAttribute("data-wab-page")); return; }} const jump = event.target.closest(".wab-jump-link"); if (jump) {{ event.preventDefault(); const href = jump.getAttribute("href") || ""; const target = href.startsWith("#") ? document.querySelector(href) : null; if (target) target.scrollIntoView({{ behavior: "smooth", block: "start" }}); else scrollToDetail(); return; }} const badge = event.target.closest("[data-wab-nav]"); if (!badge) return; event.preventDefault(); event.stopPropagation(); window.wabNavigate(badge.getAttribute("data-wab-nav")); }}); document.addEventListener("keydown", function (event) {{ if (event.key !== "Enter" && event.key !== " ") return; const badge = event.target.closest("[data-wab-nav]"); if (!badge) return; event.preventDefault(); window.wabNavigate(badge.getAttribute("data-wab-nav")); }}); function hidePageTablist() {{ const pageTabs = document.getElementById("wab-page-tabs"); const wrap = pageTabs && pageTabs.querySelector(":scope > .tab-wrapper"); if (wrap) wrap.style.display = "none"; }} hidePageTablist(); setTimeout(hidePageTablist, 300); let savedLang = "en"; try {{ savedLang = localStorage.getItem("wab-lang") === "ru" ? "ru" : "en"; }} catch (err) {{}} window.__wabLang = savedLang; applyChrome(savedLang); if (savedLang === "ru") {{ const kickLang = (attempt) => {{ const shell = document.querySelector(".wab-shell"); if (shell && shell.getAttribute("data-wab-current-lang") === "ru") return; setHidden("wab-lang-value", "ru"); const clicked = clickHidden("wab-lang-go"); if (attempt < 12 && (!clicked || !(shell && shell.getAttribute("data-wab-current-lang") === "ru"))) {{ setTimeout(() => kickLang(attempt + 1), 500); }} }}; setTimeout(() => kickLang(0), 400); }} let chromeQueued = false; const chromeObserver = new MutationObserver(() => {{ if (applyingChrome || chromeQueued) return; chromeQueued = true; requestAnimationFrame(() => {{ chromeQueued = false; if (applyingChrome) return; syncPageMenu(); applyChrome(currentLang()); }}); }}); chromeObserver.observe(document.body, {{ childList: true, subtree: true }}); document.addEventListener("input", function (event) {{ const input = event.target.closest(".wab-trace-step-filter"); if (!input) return; const root = input.closest(".wab-trace-detail-view"); if (!root) return; const query = (input.value || "").trim().toLowerCase(); root.querySelectorAll("[data-wab-trace-step]").forEach((btn) => {{ const label = btn.getAttribute("data-wab-step-label") || ""; btn.style.display = !query || label.includes(query) ? "" : "none"; }}); }}); return []; }} """