Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import base64 | |
| import json | |
| from functools import cmp_to_key | |
| from html import escape | |
| from pathlib import Path | |
| from typing import Any | |
| import gradio as gr | |
| HOME_VIEW = "HOME" | |
| TASK_ORDER = [ | |
| "K-disentQA", | |
| "SQA", | |
| "Instruct", | |
| "ASR", | |
| "Translation", | |
| "LSQA", | |
| ] | |
| ROOT = Path(__file__).parent | |
| DATA_PATH = ROOT / "data" / "leaderboard-data.json" | |
| IMAGES_DIR = ROOT / "images" | |
| def to_num(value: Any) -> float | None: | |
| try: | |
| num = float(value) | |
| except (TypeError, ValueError): | |
| return None | |
| return num | |
| def average(values: list[float | None]) -> float | None: | |
| valid = [value for value in values if value is not None] | |
| if not valid: | |
| return None | |
| return sum(valid) / len(valid) | |
| def compare_scores(left: float | None, right: float | None, lower_better: bool) -> int: | |
| if left is None and right is None: | |
| return 0 | |
| if left is None: | |
| return 1 | |
| if right is None: | |
| return -1 | |
| if left == right: | |
| return 0 | |
| if lower_better: | |
| return -1 if left < right else 1 | |
| return -1 if left > right else 1 | |
| def ordered_tasks(tasks: list[dict[str, Any]]) -> list[dict[str, Any]]: | |
| def sort_key(task: dict[str, Any]) -> tuple[int, str]: | |
| try: | |
| task_index = TASK_ORDER.index(task["id"]) | |
| except ValueError: | |
| task_index = 10**6 | |
| return task_index, task["label"] | |
| return sorted(tasks, key=sort_key) | |
| def dataset_ids(task: dict[str, Any]) -> list[str]: | |
| return [dataset["id"] for dataset in task.get("datasets", [])] | |
| def metric_value(entry: dict[str, Any], task_id: str, dataset_id: str) -> float | None: | |
| dataset = entry.get("tasks", {}).get(task_id, {}).get(dataset_id) | |
| if not dataset: | |
| return None | |
| return to_num(dataset.get("value")) | |
| def metric_display(entry: dict[str, Any], task_id: str, dataset_id: str) -> str: | |
| dataset = entry.get("tasks", {}).get(task_id, {}).get(dataset_id) | |
| if not dataset: | |
| return "-" | |
| if dataset.get("display") is not None: | |
| return str(dataset["display"]) | |
| if dataset.get("value") is None: | |
| return "-" | |
| return str(dataset["value"]) | |
| def compute_task_overall(entry: dict[str, Any], task: dict[str, Any]) -> float | None: | |
| return average([metric_value(entry, task["id"], dataset_id) for dataset_id in dataset_ids(task)]) | |
| def normalize_task_scores(entries: list[dict[str, Any]], tasks: list[dict[str, Any]]) -> dict[str, dict[str, float] | None]: | |
| ranges: dict[str, dict[str, float] | None] = {} | |
| for task in tasks: | |
| values = [entry["task_overall"][task["id"]] for entry in entries if entry["task_overall"][task["id"]] is not None] | |
| if not values: | |
| ranges[task["id"]] = None | |
| continue | |
| ranges[task["id"]] = {"min": min(values), "max": max(values)} | |
| return ranges | |
| def normalized_score(value: float | None, score_range: dict[str, float] | None, lower_better: bool) -> float | None: | |
| if value is None or score_range is None: | |
| return None | |
| if score_range["min"] == score_range["max"]: | |
| return 100.0 | |
| if lower_better: | |
| return ((score_range["max"] - value) / (score_range["max"] - score_range["min"])) * 100 | |
| return ((value - score_range["min"]) / (score_range["max"] - score_range["min"])) * 100 | |
| def enrich_entries(entries: list[dict[str, Any]], tasks: list[dict[str, Any]]) -> list[dict[str, Any]]: | |
| entries_with_task_overall = [] | |
| for entry in entries: | |
| task_overall = {} | |
| for task in tasks: | |
| task_overall[task["id"]] = compute_task_overall(entry, task) | |
| entries_with_task_overall.append({**entry, "task_overall": task_overall}) | |
| task_ranges = normalize_task_scores(entries_with_task_overall, tasks) | |
| enriched_entries = [] | |
| for entry in entries_with_task_overall: | |
| normalized_task_scores = {} | |
| for task in tasks: | |
| normalized_task_scores[task["id"]] = normalized_score( | |
| entry["task_overall"][task["id"]], | |
| task_ranges[task["id"]], | |
| task["lowerBetter"], | |
| ) | |
| enriched_entries.append( | |
| { | |
| **entry, | |
| "normalized_task_scores": normalized_task_scores, | |
| "overall": average([normalized_task_scores[task["id"]] for task in tasks]), | |
| } | |
| ) | |
| return enriched_entries | |
| def sort_overall(entries: list[dict[str, Any]]) -> list[dict[str, Any]]: | |
| sorted_entries = sorted( | |
| entries, | |
| key=cmp_to_key(lambda left, right: compare_scores(left["overall"], right["overall"], False)), | |
| ) | |
| return [{**entry, "rank": index} for index, entry in enumerate(sorted_entries, start=1)] | |
| def sort_task(entries: list[dict[str, Any]], task: dict[str, Any], dataset_id: str) -> list[dict[str, Any]]: | |
| def compare(left: dict[str, Any], right: dict[str, Any]) -> int: | |
| left_value = left["task_overall"][task["id"]] if dataset_id == "Overall" else metric_value(left, task["id"], dataset_id) | |
| right_value = right["task_overall"][task["id"]] if dataset_id == "Overall" else metric_value(right, task["id"], dataset_id) | |
| return compare_scores(left_value, right_value, task["lowerBetter"]) | |
| sorted_entries = sorted(entries, key=cmp_to_key(compare)) | |
| return [{**entry, "rank": index} for index, entry in enumerate(sorted_entries, start=1)] | |
| def metric_class(lower_better: bool, value: float | None) -> str: | |
| if value is None: | |
| return "muted" | |
| return "metric-bad" if lower_better else "metric-good" | |
| def fmt_score(value: float | None) -> str: | |
| return "-" if value is None else f"{value:.2f}" | |
| def image_data_uri(path: Path) -> str: | |
| encoded = base64.b64encode(path.read_bytes()).decode("ascii") | |
| suffix = path.suffix.lower().lstrip(".") or "png" | |
| mime = "image/png" if suffix == "png" else f"image/{suffix}" | |
| return f"data:{mime};base64,{encoded}" | |
| def load_payload() -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: | |
| payload = json.loads(DATA_PATH.read_text(encoding="utf-8")) | |
| tasks = ordered_tasks(payload.get("tasks", [])) | |
| entries = enrich_entries(payload.get("entries", []), tasks) | |
| return tasks, entries | |
| TASKS, ENTRIES = load_payload() | |
| TASK_MAP = {task["id"]: task for task in TASKS} | |
| RANKED_OVERALL = sort_overall(ENTRIES) | |
| BADGE_IMAGES = { | |
| 1: image_data_uri(IMAGES_DIR / "1st.png"), | |
| 2: image_data_uri(IMAGES_DIR / "2nd.png"), | |
| 3: image_data_uri(IMAGES_DIR / "3rd.png"), | |
| } | |
| EXTERNAL_LINK_IMAGE = image_data_uri(IMAGES_DIR / "external-link.png") | |
| def menu_choices() -> list[tuple[str, str]]: | |
| choices = [("Home\nOverall ranking", HOME_VIEW)] | |
| for task in TASKS: | |
| choices.append((f"{task['label']}\n{len(task['datasets'])} datasets", task["id"])) | |
| return choices | |
| def dataset_choices(task_id: str) -> list[str]: | |
| task = TASK_MAP[task_id] | |
| return ["Overall", *[dataset["id"] for dataset in task.get("datasets", [])]] | |
| def render_rank_strip(entries: list[dict[str, Any]]) -> str: | |
| cards = [] | |
| for entry in entries[:12]: | |
| if entry["rank"] in BADGE_IMAGES: | |
| badge = f'<img class="rank-badge-image" src="{BADGE_IMAGES[entry["rank"]]}" alt="{entry["rank"]} place" />' | |
| else: | |
| badge = f'<span class="rank-badge">#{entry["rank"]}</span>' | |
| cards.append( | |
| f""" | |
| <article class="rank-pill"> | |
| <div class="rank-badge-wrap">{badge}</div> | |
| <span class="rank-name">{escape(entry["rank_name"])}</span> | |
| </article> | |
| """ | |
| ) | |
| return f""" | |
| <section class="section-card card"> | |
| <div class="section-head"> | |
| <h3>Top Ranking</h3> | |
| </div> | |
| <div class="rank-strip-list"> | |
| {"".join(cards)} | |
| </div> | |
| </section> | |
| """ | |
| def render_home_table(entries: list[dict[str, Any]]) -> str: | |
| header_top = [ | |
| '<th rowspan="2" class="rank-col col-rank">Rank</th>', | |
| '<th rowspan="2" class="col-rankname">RankName</th>', | |
| '<th rowspan="2" class="col-model">Model</th>', | |
| '<th rowspan="2">URL</th>', | |
| '<th rowspan="2">Overall</th>', | |
| *[f'<th class="grouped" colspan="1">{escape(task["label"])}</th>' for task in TASKS], | |
| ] | |
| header_bottom = [f'<th>{escape(task["shortMetric"])}</th>' for task in TASKS] | |
| rows = [] | |
| for entry in entries: | |
| url = entry.get("url") or "" | |
| if url: | |
| url_cell = ( | |
| f'<a class="url-link" href="{escape(url)}" target="_blank" rel="noopener noreferrer" ' | |
| f'aria-label="External link"><img src="{EXTERNAL_LINK_IMAGE}" width="5px" height="5px" alt="" /></a>' | |
| ) | |
| else: | |
| url_cell = "-" | |
| task_cells = [] | |
| for task in TASKS: | |
| value = entry["task_overall"][task["id"]] | |
| task_cells.append(f'<td><span class="{metric_class(task["lowerBetter"], value)}">{fmt_score(value)}</span></td>') | |
| rows.append( | |
| "<tr>" | |
| f'<td class="rank-col col-rank">{entry["rank"]}</td>' | |
| f'<td class="col-rankname">{escape(entry["rank_name"])}</td>' | |
| f'<td class="col-model">{escape(entry.get("model") or entry["rank_name"])}</td>' | |
| f"<td>{url_cell}</td>" | |
| f"<td>{fmt_score(entry['overall'])}</td>" | |
| f"{''.join(task_cells)}" | |
| "</tr>" | |
| ) | |
| return f""" | |
| <section class="section-card card"> | |
| <div class="section-head"> | |
| <h3>Overall Leaderboard</h3> | |
| </div> | |
| <div class="table-scroll"> | |
| <table> | |
| <colgroup> | |
| <col class="col-rank" /> | |
| <col class="col-rankname" /> | |
| <col class="col-model" /> | |
| <col /> | |
| <col /> | |
| {"".join("<col />" for _ in TASKS)} | |
| </colgroup> | |
| <thead> | |
| <tr>{"".join(header_top)}</tr> | |
| <tr>{"".join(header_bottom)}</tr> | |
| </thead> | |
| <tbody>{"".join(rows)}</tbody> | |
| </table> | |
| </div> | |
| </section> | |
| """ | |
| def render_home() -> str: | |
| return f"{render_rank_strip(RANKED_OVERALL)}{render_home_table(RANKED_OVERALL)}" | |
| def render_task_title(task: dict[str, Any]) -> str: | |
| return f""" | |
| <div class="section-head"> | |
| <div> | |
| <h3 class="task-title">Task : {escape(task["label"])}</h3> | |
| </div> | |
| </div> | |
| """ | |
| def render_task_table(task: dict[str, Any], dataset_id: str) -> str: | |
| ranked_entries = sort_task(ENTRIES, task, dataset_id) | |
| active_label = "Overall" | |
| if dataset_id != "Overall": | |
| active_label = next( | |
| (dataset["label"] for dataset in task["datasets"] if dataset["id"] == dataset_id), | |
| dataset_id, | |
| ) | |
| rows = [] | |
| for entry in ranked_entries: | |
| numeric_value = entry["task_overall"][task["id"]] if dataset_id == "Overall" else metric_value(entry, task["id"], dataset_id) | |
| display_value = fmt_score(numeric_value) if dataset_id == "Overall" else metric_display(entry, task["id"], dataset_id) | |
| rows.append( | |
| "<tr>" | |
| f'<td class="rank-col col-rank">{entry["rank"]}</td>' | |
| f'<td class="col-rankname">{escape(entry["rank_name"])}</td>' | |
| f'<td class="col-model">{escape(entry.get("model") or entry["rank_name"])}</td>' | |
| f'<td><span class="{metric_class(task["lowerBetter"], numeric_value)}">{escape(display_value)}</span></td>' | |
| "</tr>" | |
| ) | |
| return f""" | |
| <div id="taskTableMount"> | |
| <div class="table-scroll"> | |
| <table class="task-performance-table"> | |
| <colgroup> | |
| <col class="col-rank" /> | |
| <col class="col-rankname" /> | |
| <col class="col-model" /> | |
| <col /> | |
| </colgroup> | |
| <thead> | |
| <tr> | |
| <th class="rank-col col-rank">Rank</th> | |
| <th class="col-rankname">RankName</th> | |
| <th class="col-model">Model</th> | |
| <th>{escape(active_label)}</th> | |
| </tr> | |
| </thead> | |
| <tbody>{"".join(rows)}</tbody> | |
| </table> | |
| </div> | |
| </div> | |
| """ | |
| def update_view(active_view: str, current_dataset: str | None) -> tuple[Any, Any, str, str, str]: | |
| if active_view == HOME_VIEW: | |
| first_task = TASKS[0] | |
| return ( | |
| gr.update(visible=True), | |
| gr.update(visible="hidden"), | |
| gr.update(choices=dataset_choices(first_task["id"]), value="Overall"), | |
| render_task_title(first_task), | |
| first_task["metricLabel"], | |
| render_task_table(first_task, "Overall"), | |
| ) | |
| task = TASK_MAP[active_view] | |
| choices = dataset_choices(active_view) | |
| dataset_id = current_dataset if current_dataset in choices else "Overall" | |
| return ( | |
| gr.update(visible="hidden"), | |
| gr.update(visible=True), | |
| gr.update(choices=choices, value=dataset_id), | |
| render_task_title(task), | |
| task["metricLabel"], | |
| render_task_table(task, dataset_id), | |
| ) | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Noto+Sans+KR:wght@400;500;700&display=swap'); | |
| :root { | |
| --bg: #f2f4f8; | |
| --bg-strong: #dde5f2; | |
| --panel: rgba(255, 255, 255, 0.84); | |
| --panel-strong: #ffffff; | |
| --text: #0c1730; | |
| --muted: #66748b; | |
| --line: rgba(12, 23, 48, 0.14); | |
| --primary: #0e3a8a; | |
| --accent: #c56b12; | |
| --pending: #74674a; | |
| --pending-bg: #f4ecd8; | |
| --success: #0c8f61; | |
| --danger: #b8612f; | |
| --shadow: 0 14px 38px rgba(12, 23, 48, 0.08); | |
| } | |
| html, body, .gradio-container { | |
| margin: 0 !important; | |
| min-height: 100vh; | |
| font-family: "Noto Sans KR", "Space Grotesk", sans-serif !important; | |
| color: var(--text); | |
| background: | |
| radial-gradient(circle at 15% 0%, #dce8ff 0%, transparent 32%), | |
| radial-gradient(circle at 95% 5%, #ffe4cf 0%, transparent 24%), | |
| linear-gradient(180deg, #f8fbff 0%, #eef2f7 100%) !important; | |
| } | |
| .gradio-container { | |
| max-width: 100% !important; | |
| } | |
| .app-root { | |
| position: relative; | |
| max-width: 1440px; | |
| margin: 0 auto; | |
| padding: 24px 20px 56px; | |
| overflow-x: auto; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .bg-orb { | |
| position: fixed; | |
| border-radius: 999px; | |
| filter: blur(70px); | |
| opacity: 0.45; | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| .orb-1 { | |
| width: 280px; | |
| height: 280px; | |
| background: #a7c5ff; | |
| top: -110px; | |
| left: -80px; | |
| } | |
| .orb-2 { | |
| width: 240px; | |
| height: 240px; | |
| background: #ffd2a4; | |
| top: -70px; | |
| right: -60px; | |
| } | |
| .layout-row { | |
| position: relative; | |
| z-index: 1; | |
| flex-wrap: nowrap !important; | |
| gap: 24px; | |
| align-items: flex-start; | |
| min-width: 1180px; | |
| } | |
| .sidebar-panel { | |
| flex: 0 0 260px !important; | |
| width: 260px !important; | |
| min-width: 260px !important; | |
| max-width: 260px !important; | |
| position: sticky; | |
| top: 20px; | |
| align-self: start; | |
| border: 1px solid var(--line); | |
| border-radius: 26px; | |
| background: rgba(7, 17, 40, 0.95); | |
| color: #ffffff; | |
| padding: 22px 18px; | |
| box-shadow: var(--shadow); | |
| } | |
| .sidebar-head, | |
| .sidebar-head * { | |
| color: #ffffff !important; | |
| } | |
| .sidebar-head { | |
| margin-bottom: 26px; | |
| } | |
| .sidebar-kicker, .kicker { | |
| margin: 0; | |
| letter-spacing: 0.12em; | |
| text-transform: uppercase; | |
| font-size: 12px; | |
| } | |
| .sidebar-kicker { | |
| color: rgba(255, 255, 255, 0.82) !important; | |
| } | |
| .sidebar-head h1 { | |
| color: #ffffff !important; | |
| } | |
| .sidebar-head h1 { | |
| margin: 8px 0 0; | |
| font-size: 34px; | |
| line-height: 0.95; | |
| color: #ffffff; | |
| } | |
| .content-panel { | |
| flex: 1 1 auto !important; | |
| min-width: 0; | |
| } | |
| .hero { | |
| margin-bottom: 20px; | |
| } | |
| .hero .kicker { | |
| font-size: 14px !important; | |
| letter-spacing: 0.18em; | |
| color: var(--muted) !important; | |
| } | |
| .hero-topline { | |
| display: flex; | |
| align-items: flex-start; | |
| justify-content: space-between; | |
| gap: 20px; | |
| text-align: center; | |
| } | |
| .hero-topline > div { | |
| flex: 1; | |
| } | |
| .hero h2 { | |
| margin: 8px 0 6px; | |
| font-family: "Space Grotesk", sans-serif; | |
| font-size: clamp(56px, 7vw, 80px) !important; | |
| line-height: 1.02; | |
| color: var(--text); | |
| font-weight: 700; | |
| } | |
| .desc { | |
| margin: 0 auto; | |
| max-width: 760px; | |
| color: var(--muted); | |
| font-size: 17px; | |
| } | |
| .card { | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: 24px; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(8px); | |
| } | |
| .section-card { | |
| padding: 18px; | |
| } | |
| .section-head { | |
| display: flex; | |
| align-items: baseline; | |
| justify-content: space-between; | |
| gap: 12px; | |
| margin-bottom: 12px; | |
| } | |
| .section-head h3, | |
| .task-title { | |
| margin: 0; | |
| font-size: 28px; | |
| font-family: "Space Grotesk", sans-serif; | |
| } | |
| .rank-strip-list { | |
| display: grid; | |
| grid-template-columns: repeat(6, minmax(120px, 1fr)); | |
| gap: 10px; | |
| } | |
| .rank-pill { | |
| border: 1px solid var(--line); | |
| border-radius: 16px; | |
| padding: 12px; | |
| background: linear-gradient(135deg, #ffffff 0%, var(--bg-strong) 100%); | |
| } | |
| .rank-badge-wrap { | |
| min-height: 28px; | |
| } | |
| .rank-badge { | |
| display: inline-flex !important; | |
| align-items: center; | |
| justify-content: center; | |
| min-width: 34px; | |
| height: 34px; | |
| padding: 0 10px; | |
| border-radius: 999px; | |
| background: var(--primary); | |
| color: #ffffff !important; | |
| font-size: 13px; | |
| font-weight: 700; | |
| line-height: 1; | |
| } | |
| .rank-badge-image { | |
| display: block; | |
| width: auto; | |
| height: 28px; | |
| } | |
| .rank-name { | |
| display: block; | |
| margin-top: 8px; | |
| font-weight: 700; | |
| color: var(--text) !important; | |
| } | |
| .table-scroll { | |
| overflow-x: auto; | |
| overflow-y: visible; | |
| border-radius: 0; | |
| border: 1px solid #ffffff !important; | |
| background: var(--panel-strong); | |
| } | |
| table { | |
| width: 100%; | |
| min-width: 1080px; | |
| border-collapse: collapse; | |
| border: 1px solid #ffffff !important; | |
| } | |
| .task-performance-table { | |
| table-layout: fixed; | |
| } | |
| thead th { | |
| background: #e8edf6; | |
| border-bottom: 1px solid #ffffff !important; | |
| white-space: nowrap; | |
| } | |
| thead tr:first-child th.grouped { | |
| text-align: center; | |
| } | |
| th, td { | |
| padding: 12px 14px; | |
| text-align: left; | |
| border-bottom: 1px solid #ffffff !important; | |
| border-right: 1px solid #ffffff !important; | |
| font-size: 14px; | |
| } | |
| th:first-child, | |
| td:first-child { | |
| border-left: 1px solid #ffffff !important; | |
| } | |
| th:last-child, | |
| td:last-child { | |
| border-right: 0; | |
| } | |
| .table-scroll table, | |
| .table-scroll thead, | |
| .table-scroll tbody, | |
| .table-scroll tr, | |
| .table-scroll th, | |
| .table-scroll td { | |
| border-color: #ffffff !important; | |
| } | |
| tbody tr:hover { | |
| background: #f8fbff; | |
| } | |
| .rank-col { | |
| font-family: "Space Grotesk", sans-serif; | |
| font-weight: 700; | |
| width: 72px; | |
| } | |
| .col-rank { | |
| width: 96px; | |
| } | |
| .col-rankname { | |
| width: 240px; | |
| } | |
| .col-model { | |
| width: 320px; | |
| } | |
| .url-link { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 24px; | |
| height: 24px; | |
| } | |
| .url-link img { | |
| display: block; | |
| width: 18px; | |
| height: 18px; | |
| } | |
| .metric-good { | |
| color: var(--success); | |
| font-weight: 700; | |
| } | |
| .metric-bad { | |
| color: var(--danger); | |
| font-weight: 700; | |
| } | |
| .muted { | |
| color: var(--muted); | |
| } | |
| .task-filters { | |
| display: flex; | |
| flex-wrap: nowrap; | |
| align-items: flex-start; | |
| gap: 12px; | |
| margin-top: 12px; | |
| width: 100%; | |
| overflow-x: auto; | |
| -webkit-overflow-scrolling: touch; | |
| padding-bottom: 6px; | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| .task-filters .dataset-wrap { flex: 0 0 620px; min-width: 620px; } | |
| .task-filters .metric-wrap { flex: 0 0 340px; min-width: 340px; } | |
| .task-filters .dataset-wrap, | |
| .task-filters .metric-wrap, | |
| .task-filters .dataset-wrap > div, | |
| .task-filters .metric-wrap > div { | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| /* Keep Dataset / Metric columns pinned to the same top baseline. */ | |
| .task-filters .dataset-wrap, | |
| .task-filters .metric-wrap { | |
| align-self: flex-start !important; | |
| justify-self: flex-start !important; | |
| margin-top: 0 !important; | |
| padding-top: 0 !important; | |
| } | |
| .task-view-shell .filter-title { | |
| margin: 0 0 6px 0 !important; | |
| font-size: 13px !important; | |
| color: var(--muted) !important; | |
| line-height: 1.2 !important; | |
| } | |
| #taskTableMount { | |
| margin-top: 18px; | |
| } | |
| .task-menu-radio { | |
| gap: 8px; | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| padding: 0 !important; | |
| } | |
| .task-menu-radio > div, | |
| .task-menu-radio .block, | |
| .task-menu-radio .gradio-radio, | |
| .task-menu-radio .form { | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| padding: 0 !important; | |
| } | |
| .task-menu-radio label > span, | |
| .task-menu-radio label > div, | |
| .task-menu-radio label .wrap { | |
| white-space: pre-line !important; | |
| } | |
| .task-menu-radio label:has(input[type="radio"]) { | |
| width: 100%; | |
| margin: 0 !important; | |
| border: 1px solid rgba(255, 255, 255, 0.1) !important; | |
| background: rgba(255, 255, 255, 0.05) !important; | |
| color: #f5f7fb !important; | |
| border-radius: 14px !important; | |
| padding: 12px 14px !important; | |
| cursor: pointer !important; | |
| min-height: 72px; | |
| align-content: center; | |
| box-shadow: none !important; | |
| transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease; | |
| } | |
| .task-menu-radio label:has(input[type="radio"]):hover { | |
| background: rgba(255, 255, 255, 0.1) !important; | |
| } | |
| .task-menu-radio label:has(input[type="radio"]:checked) { | |
| background: linear-gradient(135deg, #fcf7eb 0%, #dfeaff 100%) !important; | |
| color: var(--text) !important; | |
| border-color: transparent !important; | |
| } | |
| .task-menu-radio input[type="radio"] { | |
| display: none !important; | |
| } | |
| .task-menu-radio label span, | |
| .task-menu-radio label div, | |
| .task-menu-radio label p { | |
| color: inherit !important; | |
| } | |
| .task-menu-radio label:has(input[type="radio"]) span, | |
| .task-menu-radio label:has(input[type="radio"]) div { | |
| color: #f5f7fb !important; | |
| } | |
| .task-menu-radio label:has(input[type="radio"]:checked) span, | |
| .task-menu-radio label:has(input[type="radio"]:checked) div { | |
| color: var(--text) !important; | |
| } | |
| .task-menu-radio .wrap, | |
| .task-menu-radio label span:last-child { | |
| opacity: 0.72; | |
| font-size: 12px; | |
| } | |
| .task-view-shell .gradio-radio, | |
| .task-view-shell .gradio-textbox { | |
| margin: 0 !important; | |
| min-width: 0 !important; | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| .task-view-shell .gradio-radio label, | |
| .task-view-shell .gradio-textbox label { | |
| font-size: 13px !important; | |
| color: var(--muted) !important; | |
| } | |
| .task-view-shell .dataset-radio { | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| padding: 0 !important; | |
| margin-left: 0 !important; | |
| margin-bottom: 12px !important; | |
| max-width: 100% !important; | |
| width: 100% !important; | |
| } | |
| .task-view-shell .dataset-radio > div, | |
| .task-view-shell .dataset-radio .block, | |
| .task-view-shell .dataset-radio .form { | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| padding: 0 !important; | |
| display: grid !important; | |
| grid-template-columns: repeat(2, minmax(180px, 1fr)) !important; | |
| gap: 8px 10px !important; | |
| align-items: start !important; | |
| justify-content: start !important; | |
| min-height: 86px !important; | |
| align-content: start !important; | |
| max-width: 100% !important; | |
| width: 100% !important; | |
| } | |
| .task-view-shell .dataset-radio label:has(input[type="radio"]) { | |
| margin: 0 !important; | |
| border: 1px solid var(--line) !important; | |
| background: rgba(255, 255, 255, 0.88) !important; | |
| color: var(--text) !important; | |
| border-radius: 10px !important; | |
| padding: 0 12px !important; | |
| height: 40px !important; | |
| min-height: 40px !important; | |
| width: auto !important; | |
| display: flex !important; | |
| align-items: center !important; | |
| box-shadow: none !important; | |
| justify-content: flex-start !important; | |
| font-size: 14px !important; | |
| line-height: 1.2 !important; | |
| } | |
| .task-view-shell .dataset-radio label:has(input[type="radio"]:checked) { | |
| background: linear-gradient(135deg, #fcf7eb 0%, #dfeaff 100%) !important; | |
| border-color: rgba(14, 58, 138, 0.22) !important; | |
| font-weight: 700 !important; | |
| } | |
| .task-view-shell .dataset-radio input[type="radio"] { | |
| display: none !important; | |
| } | |
| .task-view-shell .metric-field, | |
| .task-view-shell .dataset-field { | |
| align-self: flex-start !important; | |
| background: transparent !important; | |
| } | |
| /* Remove any residual top spacing on metric box so it aligns with Dataset. */ | |
| .task-view-shell .metric-wrap .metric-field, | |
| .task-view-shell .metric-wrap .gradio-textbox, | |
| .task-view-shell .metric-wrap .gradio-textbox > div, | |
| .task-view-shell .metric-wrap .gradio-textbox .block, | |
| .task-view-shell .metric-wrap .gradio-textbox .form, | |
| .task-view-shell .metric-wrap .gradio-textbox .wrap { | |
| margin-top: 0 !important; | |
| padding-top: 0 !important; | |
| } | |
| .task-view-shell .metric-field > div, | |
| .task-view-shell .dataset-field > div { | |
| background: transparent !important; | |
| } | |
| .task-view-shell .metric-field .gradio-textbox, | |
| .task-view-shell .metric-field .gradio-textbox > div, | |
| .task-view-shell .metric-field .gradio-textbox .block, | |
| .task-view-shell .metric-field .gradio-textbox .form { | |
| background: transparent !important; | |
| border: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| .task-view-shell .metric-field, | |
| .task-view-shell .metric-field .gradio-textbox, | |
| .task-view-shell .metric-field .gradio-textbox .wrap { | |
| width: 100% !important; | |
| max-width: none !important; | |
| } | |
| .task-view-shell .metric-field .gradio-textbox .wrap, | |
| .task-view-shell .metric-field .gradio-textbox textarea, | |
| .task-view-shell .metric-field .gradio-textbox input { | |
| height: 40px !important; | |
| min-height: 40px !important; | |
| width: 100% !important; | |
| } | |
| .task-view-shell input, | |
| .task-view-shell textarea, | |
| .task-view-shell .wrap-inner, | |
| .task-view-shell button.secondary-down-arrow, | |
| .task-view-shell .gradio-textbox .wrap { | |
| border-radius: 12px !important; | |
| } | |
| .task-view-shell .gradio-textbox .wrap, | |
| .task-view-shell .gradio-textbox textarea, | |
| .task-view-shell .gradio-textbox input { | |
| border: 1px solid var(--line) !important; | |
| background: rgba(255, 255, 255, 0.88) !important; | |
| color: var(--text) !important; | |
| } | |
| @media (max-width: 1280px) { | |
| .layout-row { | |
| min-width: 1120px; | |
| } | |
| .task-filters .dataset-wrap { flex-basis: 560px; min-width: 560px; } | |
| .task-filters .metric-wrap { flex-basis: 320px; min-width: 320px; } | |
| .task-view-shell .dataset-radio > div, | |
| .task-view-shell .dataset-radio .block, | |
| .task-view-shell .dataset-radio .form { | |
| grid-template-columns: repeat(2, minmax(150px, 1fr)) !important; | |
| } | |
| } | |
| @media (max-width: 980px) { | |
| .layout-row { | |
| min-width: 1040px; | |
| } | |
| .rank-strip-list { | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| } | |
| .task-view-shell .dataset-radio > div, | |
| .task-view-shell .dataset-radio .block, | |
| .task-view-shell .dataset-radio .form { | |
| grid-template-columns: repeat(2, minmax(140px, 1fr)) !important; | |
| } | |
| } | |
| @media (max-width: 720px) { | |
| .app-root { | |
| padding: 16px 14px 40px; | |
| } | |
| .hero-topline { | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .hero h2 { | |
| font-size: 40px; | |
| } | |
| .rank-strip-list { | |
| grid-template-columns: 1fr; | |
| } | |
| .task-view-shell .dataset-radio > div, | |
| .task-view-shell .dataset-radio .block, | |
| .task-view-shell .dataset-radio .form { | |
| grid-template-columns: 1fr !important; | |
| } | |
| } | |
| """ | |
| def build_app() -> gr.Blocks: | |
| with gr.Blocks(title="Ko-Speech-Eval Leaderboard", fill_width=True) as demo: | |
| with gr.Column(elem_classes=["app-root"]): | |
| gr.HTML('<div class="bg-orb orb-1"></div><div class="bg-orb orb-2"></div>') | |
| with gr.Row(elem_classes=["layout-row"]): | |
| with gr.Column(scale=0, min_width=260, elem_classes=["sidebar-panel"]): | |
| gr.HTML( | |
| """ | |
| <div class="sidebar-head"> | |
| <p class="sidebar-kicker">KoALa-bench</p> | |
| <h1>Leaderboard</h1> | |
| <a href="https://huggingface.co/datasets/scailaboratory/KoALA" target="_blank"> | |
| <img src="https://img.shields.io/badge/huggingface-FFD21E?style=flat&logo=huggingface&logoColor=white"/> | |
| </a> | |
| <a href="https://github.com/scai-research/KoALa-Bench?tab=readme-ov-file" target="_blank"> | |
| <img src="https://img.shields.io/badge/GiHub-181717?style=flat&logo=github&logoColor=white"/> | |
| </a> | |
| </div> | |
| """ | |
| ) | |
| menu = gr.Radio( | |
| choices=menu_choices(), | |
| value=HOME_VIEW, | |
| show_label=False, | |
| container=False, | |
| elem_classes=["task-menu", "task-menu-radio"], | |
| ) | |
| with gr.Column(scale=1, elem_classes=["content-panel"]): | |
| gr.HTML( | |
| """ | |
| <header class="hero"> | |
| <div class="hero-topline"> | |
| <div> | |
| <p class="kicker">Korean Audio Language benchmark</p> | |
| <h2>Leaderboard for KoALa</h2> | |
| </div> | |
| </div> | |
| </header> | |
| """ | |
| ) | |
| home_view = gr.HTML(render_home(), visible=True) | |
| with gr.Column(visible="hidden", elem_classes=["task-view-shell", "section-card", "card"]) as task_view: | |
| task_title = gr.HTML() | |
| with gr.Row(elem_classes=["task-filters"]): | |
| with gr.Column(scale=3, min_width=420, elem_classes=["dataset-wrap"]): | |
| gr.HTML('<p class="filter-title">Dataset</p>') | |
| dataset_dropdown = gr.Radio( | |
| choices=dataset_choices(TASKS[0]["id"]), | |
| value="Overall", | |
| show_label=False, | |
| elem_classes=["dataset-field", "dataset-radio"], | |
| ) | |
| with gr.Column(scale=2, min_width=280, elem_classes=["metric-wrap"]): | |
| gr.HTML('<p class="filter-title">Metric</p>') | |
| metric_text = gr.Textbox( | |
| show_label=False, | |
| interactive=False, | |
| elem_classes=["metric-field"], | |
| ) | |
| task_table = gr.HTML() | |
| menu.change( | |
| fn=update_view, | |
| inputs=[menu, dataset_dropdown], | |
| outputs=[home_view, task_view, dataset_dropdown, task_title, metric_text, task_table], | |
| ) | |
| dataset_dropdown.change( | |
| fn=update_view, | |
| inputs=[menu, dataset_dropdown], | |
| outputs=[home_view, task_view, dataset_dropdown, task_title, metric_text, task_table], | |
| ) | |
| demo.load( | |
| fn=update_view, | |
| inputs=[menu, dataset_dropdown], | |
| outputs=[home_view, task_view, dataset_dropdown, task_title, metric_text, task_table], | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| app = build_app() | |
| app.launch(css=CUSTOM_CSS) | |