Download server.py from kaengreg/rusBEIR: direct link, hf CLI and curl.
- Browser
- Download file 28.5 kB
-
https://huggingface.co/spaces/kaengreg/rusBEIR/resolve/main/server.py
- Command line
-
hf download hf://spaces/kaengreg/rusBEIR/server.py
-
curl -L -o server.py https://huggingface.co/spaces/kaengreg/rusBEIR/resolve/main/server.py
28.5 kB
| import base64 | |
| import json | |
| import os | |
| import re | |
| from datetime import date | |
| from html import escape | |
| from http import HTTPStatus | |
| from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer | |
| from pathlib import Path | |
| from typing import Any | |
| from urllib.parse import parse_qs, urlencode, urlparse | |
| ROOT = Path(__file__).resolve().parent | |
| DATASETS_PATH = ROOT / "data" / "datasets.json" | |
| RESULTS_PATH = Path(os.getenv("RUSBEIR_RESULTS_PATH", ROOT / "data" / "results.jsonl")) | |
| LOGO_PATH = ROOT / "assets" / "rusBeIR_logo.png" | |
| PORT = int(os.getenv("PORT", "7860")) | |
| DEFAULT_METRIC = "NDCG@10" | |
| METRICS = ["NDCG@10", "MAP@10", "Recall@10", "P@10", "MRR@10"] | |
| TRAILING_COLUMNS = ["Date", "Source URL"] | |
| DISPLAY_COLUMN_NAMES = { | |
| "Model ID": "Model<br>ID", | |
| "Organization": "Org.", | |
| "Source URL": "Source<br>URL", | |
| "sberquad-retrieval": "sberquad<br>retrieval", | |
| "ruscibench-retrieval": "ruscibench<br>retrieval", | |
| "wikifacts-articles": "wikifacts<br>articles", | |
| "wikifacts-para": "wikifacts<br>para", | |
| "wikifacts-sents": "wikifacts<br>sents", | |
| "wikifacts-window_2": "wikifacts<br>window 2", | |
| "wikifacts-window_3": "wikifacts<br>window 3", | |
| "wikifacts-window_4": "wikifacts<br>window 4", | |
| "wikifacts-window_5": "wikifacts<br>window 5", | |
| "wikifacts-window_6": "wikifacts<br>window 6", | |
| } | |
| CSS = """ | |
| :root { | |
| --bg: #f9fafb; | |
| --panel: #ffffff; | |
| --panel-soft: #f6f7f9; | |
| --text: #1f2937; | |
| --muted: #6b7280; | |
| --line: #e5e7eb; | |
| --line-strong: #d1d5db; | |
| --accent: #ff6f00; | |
| --accent-soft: #fff7ed; | |
| --shadow: 0 1px 2px rgba(0, 0, 0, 0.04); | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| font-size: 14px; | |
| } | |
| a { color: #c2410c; font-weight: 600; text-decoration: none; } | |
| a:hover { text-decoration: underline; } | |
| .page { | |
| width: min(1480px, 100%); | |
| margin: 0 auto; | |
| padding: 24px; | |
| } | |
| .shell { display: flex; flex-direction: column; gap: 16px; } | |
| .hero, .card, .panel { | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| box-shadow: var(--shadow); | |
| } | |
| .hero { | |
| display: grid; | |
| grid-template-columns: 1fr auto; | |
| gap: 18px; | |
| align-items: start; | |
| padding: 22px; | |
| } | |
| .logo { width: 132px; max-width: 24vw; height: auto; object-fit: contain; } | |
| .kicker { | |
| color: #9a3412; | |
| font-size: 12px; | |
| font-weight: 800; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| margin-bottom: 8px; | |
| } | |
| h1 { font-size: 36px; line-height: 1.12; margin: 0 0 10px; letter-spacing: 0; } | |
| .subtitle { color: var(--muted); font-size: 15px; line-height: 1.55; margin: 0; max-width: 860px; } | |
| .badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; } | |
| .badge { | |
| display: inline-flex; | |
| align-items: center; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: var(--panel-soft); | |
| color: #374151; | |
| padding: 5px 10px; | |
| font-size: 13px; | |
| font-weight: 600; | |
| } | |
| .cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; } | |
| .card { padding: 15px; } | |
| .card-label { color: var(--muted); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; } | |
| .card-value { font-size: 24px; line-height: 1.2; font-weight: 750; margin-top: 8px; overflow-wrap: anywhere; } | |
| .card-note { color: var(--muted); font-size: 13px; margin-top: 6px; } | |
| .nav { | |
| display: flex; | |
| gap: 4px; | |
| flex-wrap: wrap; | |
| border-bottom: 1px solid var(--line); | |
| padding-left: 4px; | |
| } | |
| .nav a { | |
| border: 1px solid transparent; | |
| border-bottom: 0; | |
| border-radius: 8px 8px 0 0; | |
| background: transparent; | |
| color: #4b5563; | |
| padding: 9px 12px; | |
| font-weight: 650; | |
| } | |
| .nav a.active { | |
| background: var(--panel); | |
| border-color: var(--line); | |
| color: #111827; | |
| margin-bottom: -1px; | |
| } | |
| .panel { padding: 16px; overflow-x: visible; } | |
| .section-title { font-size: 18px; font-weight: 750; margin: 0 0 4px; } | |
| .section-note { color: var(--muted); font-size: 13px; margin: 0 0 14px; } | |
| .filters { | |
| display: grid; | |
| grid-template-columns: minmax(150px, 0.8fr) minmax(190px, 1fr) minmax(320px, 2fr) minmax(110px, 0.7fr) auto; | |
| gap: 12px; | |
| align-items: end; | |
| margin: 14px 0; | |
| } | |
| label { display: grid; gap: 6px; color: #374151; font-size: 13px; font-weight: 650; } | |
| label.checkbox-label { align-items: center; grid-template-columns: auto 1fr; gap: 8px; min-height: 38px; } | |
| label.checkbox-label input { min-height: auto; width: 16px; height: 16px; padding: 0; } | |
| input, select, textarea, button { | |
| border: 1px solid var(--line-strong); | |
| border-radius: 8px; | |
| background: var(--panel); | |
| color: var(--text); | |
| font: inherit; | |
| padding: 9px 11px; | |
| min-height: 38px; | |
| outline: none; | |
| } | |
| input:focus, select:focus, textarea:focus { | |
| border-color: #fb923c; | |
| box-shadow: 0 0 0 3px rgba(251, 146, 60, 0.18); | |
| } | |
| textarea { width: 100%; min-height: 260px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; } | |
| input[type="file"] { width: 100%; background: var(--panel-soft); } | |
| button { | |
| cursor: pointer; | |
| font-weight: 700; | |
| background: var(--panel-soft); | |
| color: #111827; | |
| } | |
| button:hover { background: #eef0f4; } | |
| .status { border: 1px solid var(--line); border-radius: 8px; background: var(--panel-soft); padding: 10px 12px; margin-bottom: 12px; color: #374151; } | |
| .submit-grid { display: grid; gap: 14px; } | |
| .submit-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: end; } | |
| .file-control { flex: 1 1 320px; } | |
| .table-scroll { | |
| width: 100%; | |
| max-height: 720px; | |
| overflow: auto; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: var(--panel); | |
| } | |
| table { border-collapse: separate; border-spacing: 0; min-width: 2600px; width: max-content; table-layout: fixed; font-size: 13px; } | |
| th, td { | |
| border-right: 1px solid var(--line); | |
| border-bottom: 1px solid #eef0f3; | |
| padding: 9px 10px; | |
| background: var(--panel); | |
| color: #1f2937; | |
| vertical-align: middle; | |
| overflow-wrap: anywhere; | |
| } | |
| th { | |
| position: sticky; | |
| top: 0; | |
| z-index: 4; | |
| background: #f6f7f9; | |
| color: #374151; | |
| font-weight: 750; | |
| white-space: normal; | |
| line-height: 1.15; | |
| } | |
| td { height: 46px; font-weight: 600; } | |
| tr:nth-child(even) td { background: #fcfcfd; } | |
| .col-rank { width: 58px; min-width: 58px; max-width: 58px; text-align: center; } | |
| .col-model { width: 260px; min-width: 260px; max-width: 260px; } | |
| .col-average { width: 104px; min-width: 104px; max-width: 104px; text-align: right; } | |
| .col-meta { width: 110px; min-width: 110px; max-width: 110px; } | |
| .col-model-id { width: 260px; min-width: 260px; max-width: 260px; } | |
| .col-dataset { width: 96px; min-width: 96px; max-width: 96px; text-align: right; } | |
| .col-date { width: 112px; min-width: 112px; max-width: 112px; } | |
| .col-source { width: 220px; min-width: 220px; max-width: 220px; } | |
| .sticky-rank, .sticky-model, .sticky-average { position: sticky; z-index: 3; } | |
| th.sticky-rank, th.sticky-model, th.sticky-average { z-index: 6; } | |
| .sticky-rank { left: 0; } | |
| .sticky-model { left: 58px; } | |
| .sticky-average { left: 318px; box-shadow: 8px 0 12px rgba(31, 41, 55, 0.06); } | |
| .datasets { min-width: 100%; } | |
| .datasets th, .datasets td { width: auto; min-width: 120px; } | |
| @media (max-width: 900px) { | |
| .page { padding: 12px; } | |
| .hero { grid-template-columns: 1fr; } | |
| h1 { font-size: 30px; } | |
| .cards { grid-template-columns: 1fr; } | |
| .filters { grid-template-columns: 1fr; } | |
| } | |
| """ | |
| def read_json(path: Path, default: Any) -> Any: | |
| if not path.exists(): | |
| return default | |
| with path.open("r", encoding="utf-8") as file: | |
| return json.load(file) | |
| def read_jsonl(path: Path) -> list[dict[str, Any]]: | |
| if not path.exists(): | |
| return [] | |
| records = [] | |
| with path.open("r", encoding="utf-8") as file: | |
| for line in file: | |
| line = line.strip() | |
| if line: | |
| records.append(json.loads(line)) | |
| return records | |
| def metric_value(metrics: dict[str, Any], metric: str) -> float | None: | |
| value = metrics.get(metric) | |
| if value is None: | |
| return None | |
| try: | |
| return float(value) | |
| except (TypeError, ValueError): | |
| return None | |
| def load_datasets() -> list[dict[str, Any]]: | |
| return read_json(DATASETS_PATH, []) | |
| def load_results() -> list[dict[str, Any]]: | |
| return read_jsonl(RESULTS_PATH) | |
| def logo_html() -> str: | |
| if not LOGO_PATH.exists(): | |
| return "" | |
| data = base64.b64encode(LOGO_PATH.read_bytes()).decode("ascii") | |
| return f'<img class="logo" src="data:image/png;base64,{data}" alt="RusBEIR logo">' | |
| def dataset_names_for_task(task_filter: str) -> set[str]: | |
| datasets = load_datasets() | |
| if task_filter != "All": | |
| datasets = [dataset for dataset in datasets if dataset.get("task") == task_filter] | |
| return {dataset["name"] for dataset in datasets if dataset.get("official", True)} | |
| def compute_average(record: dict[str, Any], metric: str, dataset_names: set[str]) -> float | None: | |
| scores = record.get("scores", {}) | |
| explicit = metric_value(scores.get("average", {}), metric) | |
| if explicit is not None: | |
| return explicit | |
| values = [] | |
| for dataset_name, dataset_metrics in scores.get("datasets", {}).items(): | |
| if dataset_name in dataset_names: | |
| value = metric_value(dataset_metrics, metric) | |
| if value is not None: | |
| values.append(value) | |
| return sum(values) / len(values) if values else None | |
| def leaderboard_rows(metric: str, task_filter: str, verified_only: bool, query: str) -> tuple[list[dict[str, Any]], set[str]]: | |
| dataset_names = dataset_names_for_task(task_filter) | |
| rows = [] | |
| for record in load_results(): | |
| if verified_only and not record.get("verified", False): | |
| continue | |
| model_text = f"{record.get('model_id', '')} {record.get('model_name', '')}".lower() | |
| if query and query.lower() not in model_text: | |
| continue | |
| dataset_scores = record.get("scores", {}).get("datasets", {}) | |
| row = { | |
| "Rank": None, | |
| "Model": record.get("model_name") or record.get("model_id"), | |
| metric: compute_average(record, metric, dataset_names), | |
| "Model ID": record.get("model_id", ""), | |
| "Organization": record.get("organization", ""), | |
| "Type": record.get("type", ""), | |
| "Verified": "yes" if record.get("verified", False) else "no", | |
| "Date": record.get("date", ""), | |
| "Source URL": record.get("source_url", ""), | |
| } | |
| for dataset_name in sorted(dataset_names): | |
| row[dataset_name] = metric_value(dataset_scores.get(dataset_name, {}), metric) | |
| rows.append(row) | |
| rows.sort(key=lambda row: row[metric] if row[metric] is not None else -1, reverse=True) | |
| for index, row in enumerate(rows, start=1): | |
| row["Rank"] = index | |
| return rows, dataset_names | |
| def format_score(value: Any) -> str: | |
| if value is None: | |
| return "" | |
| try: | |
| return f"{float(value):.4f}" | |
| except (TypeError, ValueError): | |
| return escape(str(value)) | |
| def column_class(column: str, metric: str, index: int) -> str: | |
| if index == 0: | |
| return "col-rank sticky-rank" | |
| if index == 1: | |
| return "col-model sticky-model" | |
| if column == metric: | |
| return "col-average sticky-average" | |
| if column == "Model ID": | |
| return "col-model-id" | |
| if column in {"Organization", "Type", "Verified"}: | |
| return "col-meta" | |
| if column == "Date": | |
| return "col-date" | |
| if column == "Source URL": | |
| return "col-source" | |
| return "col-dataset" | |
| def render_table(metric: str, task_filter: str, verified_only: bool, query: str) -> str: | |
| rows, dataset_names = leaderboard_rows(metric, task_filter, verified_only, query) | |
| columns = [ | |
| "Rank", | |
| "Model", | |
| metric, | |
| "Model ID", | |
| "Organization", | |
| "Type", | |
| "Verified", | |
| *sorted(dataset_names), | |
| *TRAILING_COLUMNS, | |
| ] | |
| headers = "".join( | |
| f'<th class="{column_class(column, metric, index)}">{DISPLAY_COLUMN_NAMES.get(column, escape(column))}</th>' | |
| for index, column in enumerate(columns) | |
| ) | |
| body = [] | |
| for row in rows: | |
| cells = [] | |
| for index, column in enumerate(columns): | |
| value = row.get(column, "") | |
| if column == "Source URL" and value: | |
| cell = f'<a href="{escape(str(value), quote=True)}" target="_blank" rel="noopener noreferrer">source</a>' | |
| elif column == "Rank" or column in {"Model", "Model ID", "Organization", "Type", "Verified", "Date"}: | |
| cell = escape(str(value)) | |
| else: | |
| cell = format_score(value) | |
| cells.append(f'<td class="{column_class(column, metric, index)}">{cell}</td>') | |
| body.append(f"<tr>{''.join(cells)}</tr>") | |
| return f'<div class="table-scroll"><table><thead><tr>{headers}</tr></thead><tbody>{"".join(body)}</tbody></table></div>' | |
| def normalize_submission_record(record: dict[str, Any]) -> dict[str, Any]: | |
| model_id = str(record.get("model_id", "")).strip() | |
| if not model_id: | |
| raise ValueError("`model_id` is required.") | |
| scores = record.get("scores") | |
| if not isinstance(scores, dict): | |
| raise ValueError("`scores` must be an object.") | |
| average_scores = scores.get("average") or {} | |
| dataset_scores = scores.get("datasets") or {} | |
| if not isinstance(average_scores, dict) or not isinstance(dataset_scores, dict): | |
| raise ValueError("`scores.average` and `scores.datasets` must be objects.") | |
| has_metric = any(metric_value(average_scores, metric) is not None for metric in METRICS) | |
| if not has_metric: | |
| has_metric = any( | |
| isinstance(metrics, dict) and any(metric_value(metrics, metric) is not None for metric in METRICS) | |
| for metrics in dataset_scores.values() | |
| ) | |
| if not has_metric: | |
| raise ValueError(f"At least one numeric metric is required: {', '.join(METRICS)}.") | |
| normalized = dict(record) | |
| normalized["model_id"] = model_id | |
| normalized["model_name"] = str(record.get("model_name") or model_id.split("/")[-1]).strip() | |
| normalized["organization"] = str(record.get("organization") or (model_id.split("/", 1)[0] if "/" in model_id else "")).strip() | |
| normalized["type"] = str(record.get("type") or "dense").strip() | |
| normalized["date"] = str(record.get("date") or date.today().isoformat()).strip() | |
| normalized["verified"] = bool(record.get("verified", False)) | |
| normalized["source_url"] = str(record.get("source_url", "")).strip() | |
| normalized["scores"] = {"average": average_scores, "datasets": dataset_scores} | |
| return normalized | |
| def add_submission(record_text: str) -> str: | |
| parsed = json.loads(record_text) | |
| if not isinstance(parsed, dict): | |
| raise ValueError("Submission must be a single JSON object.") | |
| record = normalize_submission_record(parsed) | |
| serialized = json.dumps(record, ensure_ascii=False, sort_keys=True, separators=(",", ":")) | |
| existing = { | |
| json.dumps(normalize_submission_record(item), ensure_ascii=False, sort_keys=True, separators=(",", ":")) | |
| for item in load_results() | |
| } | |
| if serialized in existing: | |
| return f"`{record['model_id']}` is already present with the same scores." | |
| RESULTS_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| needs_newline = RESULTS_PATH.exists() and RESULTS_PATH.stat().st_size > 0 | |
| with RESULTS_PATH.open("a", encoding="utf-8") as file: | |
| if needs_newline: | |
| with RESULTS_PATH.open("rb") as check_file: | |
| check_file.seek(-1, os.SEEK_END) | |
| if check_file.read(1) != b"\n": | |
| file.write("\n") | |
| file.write(serialized) | |
| return f"Added `{record['model_id']}` to `{RESULTS_PATH.name}`." | |
| def add_submissions(record_text: str) -> str: | |
| record_text = record_text.strip() | |
| if not record_text: | |
| raise ValueError("Paste JSONL content or upload a JSONL file first.") | |
| if record_text.startswith("["): | |
| parsed = json.loads(record_text) | |
| if not isinstance(parsed, list): | |
| raise ValueError("JSON array submission must contain result objects.") | |
| lines = [json.dumps(item, ensure_ascii=False) for item in parsed] | |
| else: | |
| lines = [line.strip() for line in record_text.splitlines() if line.strip()] | |
| added = 0 | |
| skipped = 0 | |
| messages = [] | |
| for line_no, line in enumerate(lines, start=1): | |
| try: | |
| message = add_submission(line) | |
| except (json.JSONDecodeError, ValueError) as exc: | |
| raise ValueError(f"Line {line_no}: {exc}") from exc | |
| if "already present" in message: | |
| skipped += 1 | |
| else: | |
| added += 1 | |
| messages.append(message) | |
| summary = f"Added {added} record(s)" | |
| if skipped: | |
| summary += f"; skipped {skipped} duplicate(s)" | |
| if len(messages) == 1: | |
| return messages[0] | |
| return summary + "." | |
| def parse_multipart_form(body: bytes, content_type: str) -> tuple[dict[str, str], dict[str, tuple[str, str]]]: | |
| boundary_match = re.search(r'boundary="?([^";]+)"?', content_type) | |
| if not boundary_match: | |
| raise ValueError("Missing multipart boundary.") | |
| boundary = ("--" + boundary_match.group(1)).encode("utf-8") | |
| fields: dict[str, str] = {} | |
| files: dict[str, tuple[str, str]] = {} | |
| for part in body.split(boundary): | |
| part = part.strip() | |
| if not part or part == b"--": | |
| continue | |
| if part.endswith(b"--"): | |
| part = part[:-2].rstrip() | |
| header_blob, separator, value = part.partition(b"\r\n\r\n") | |
| if not separator: | |
| continue | |
| headers = header_blob.decode("utf-8", errors="replace") | |
| value = value.rstrip(b"\r\n") | |
| disposition = next((line for line in headers.splitlines() if line.lower().startswith("content-disposition:")), "") | |
| name_match = re.search(r'name="([^"]+)"', disposition) | |
| if not name_match: | |
| continue | |
| name = name_match.group(1) | |
| filename_match = re.search(r'filename="([^"]*)"', disposition) | |
| text = value.decode("utf-8-sig", errors="replace") | |
| if filename_match and filename_match.group(1): | |
| files[name] = (filename_match.group(1), text) | |
| else: | |
| fields[name] = text | |
| return fields, files | |
| def render_filters(metric: str, task: str, verified: bool, query: str) -> str: | |
| tasks = ["All", *sorted({dataset["task"] for dataset in load_datasets() if dataset.get("official", True)})] | |
| metric_options = "".join(f'<option value="{escape(item)}"{" selected" if item == metric else ""}>{escape(item)}</option>' for item in METRICS) | |
| task_options = "".join(f'<option value="{escape(item)}"{" selected" if item == task else ""}>{escape(item)}</option>' for item in tasks) | |
| checked = " checked" if verified else "" | |
| return f""" | |
| <form class="filters" method="get" action="/"> | |
| <label>Metric<select name="metric">{metric_options}</select></label> | |
| <label>Task<select name="task">{task_options}</select></label> | |
| <label>Model<input name="q" value="{escape(query, quote=True)}" placeholder="intfloat, BGE, FRIDA..."></label> | |
| <label class="checkbox-label"><input type="checkbox" name="verified" value="1"{checked}>Verified</label> | |
| <button type="submit">Apply</button> | |
| </form> | |
| """ | |
| def render_summary(metric: str) -> str: | |
| datasets = [dataset for dataset in load_datasets() if dataset.get("official", True)] | |
| records = load_results() | |
| rows, _ = leaderboard_rows(metric, "All", False, "") | |
| best_model = rows[0]["Model"] if rows else "No results yet" | |
| best_score = f"{rows[0][metric] * 100:.2f}" if rows and rows[0].get(metric) is not None else "n/a" | |
| types = sorted({str(record.get("type", "")).strip() for record in records if record.get("type")}) | |
| type_text = ", ".join(types) if types else "n/a" | |
| return f""" | |
| <section class="hero"> | |
| <div> | |
| <div class="kicker">Russian Information Retrieval Benchmark</div> | |
| <h1>RusBEIR Leaderboard</h1> | |
| <p class="subtitle">Compare dense retrievers, sparse baselines, and reranker pipelines on official RusBEIR datasets. The default ranking is the macro-average of <strong>{escape(metric)}</strong>.</p> | |
| <div class="badges"> | |
| <span class="badge">Metric: {escape(metric)}</span> | |
| <span class="badge">Official datasets: {len(datasets)}</span> | |
| <span class="badge">Rows: {len(records)}</span> | |
| <span class="badge">Types: {escape(type_text)}</span> | |
| </div> | |
| </div> | |
| {logo_html()} | |
| </section> | |
| <section class="cards"> | |
| <div class="card"><div class="card-label">Best Model</div><div class="card-value">{escape(str(best_model))}</div><div class="card-note">Highest average {escape(metric)}</div></div> | |
| <div class="card"><div class="card-label">Best Score</div><div class="card-value">{best_score}</div><div class="card-note">Shown as percentage points</div></div> | |
| <div class="card"><div class="card-label">Models</div><div class="card-value">{len(records)}</div><div class="card-note">Imported and reviewable JSONL rows</div></div> | |
| <div class="card"><div class="card-label">Datasets</div><div class="card-value">{len(datasets)}</div><div class="card-note">Official benchmark tasks</div></div> | |
| </section> | |
| """ | |
| def render_datasets() -> str: | |
| rows = [] | |
| for dataset in load_datasets(): | |
| if not dataset.get("official", True): | |
| continue | |
| rows.append( | |
| "<tr>" | |
| f"<td>{escape(str(dataset.get('name', '')))}</td>" | |
| f"<td>{escape(str(dataset.get('task', '')))}</td>" | |
| f"<td>{escape(str(dataset.get('split', '')))}</td>" | |
| f"<td>{escape(str(dataset.get('hf_repo', '')))}</td>" | |
| f"<td>{escape(str(dataset.get('qrels_repo', '')))}</td>" | |
| f"<td>{escape(str(dataset.get('origin', '')))}</td>" | |
| "</tr>" | |
| ) | |
| return f""" | |
| <table class="datasets"> | |
| <thead><tr><th>Dataset</th><th>Task</th><th>Split</th><th>Corpus repo</th><th>Qrels repo</th><th>Origin</th></tr></thead> | |
| <tbody>{''.join(rows)}</tbody> | |
| </table> | |
| """ | |
| def render_nav(active_page: str) -> str: | |
| items = [ | |
| ("leaderboard", "/", "Leaderboard"), | |
| ("datasets", "/datasets", "Datasets"), | |
| ("submit", "/submit", "Submit"), | |
| ("about", "/about", "About"), | |
| ] | |
| links = [] | |
| for page, href, label in items: | |
| active = " active" if page == active_page else "" | |
| links.append(f'<a class="{active.strip()}" href="{href}">{label}</a>') | |
| return f'<nav class="nav">{"".join(links)}</nav>' | |
| def render_page_content(page: str, metric: str, task: str, verified: bool, query: str, query_string: str) -> str: | |
| if page == "datasets": | |
| return f""" | |
| <section class="panel"> | |
| <h2 class="section-title">Official Datasets</h2> | |
| <p class="section-note">RusBEIR tasks used for the default macro-average ranking.</p> | |
| <div class="table-scroll">{render_datasets()}</div> | |
| </section> | |
| """ | |
| if page == "submit": | |
| return f""" | |
| <section class="panel"> | |
| <h2 class="section-title">Submit Results</h2> | |
| <p class="section-note">Paste JSONL content or upload a ready JSONL file. Each record must include model_id, scores, and at least one numeric metric.</p> | |
| <form class="submit-grid" method="post" action="/submit?{query_string}" enctype="multipart/form-data"> | |
| <label>JSONL record or records<textarea name="record" placeholder='{{"model_id":"org/model","scores":{{"average":{{"NDCG@10":0.5}},"datasets":{{}}}}}}'></textarea></label> | |
| <div class="submit-actions"> | |
| <label class="file-control">JSONL file<input type="file" name="results_file" accept=".jsonl,.json,application/json,application/x-ndjson"></label> | |
| <button type="submit">Add to leaderboard</button> | |
| </div> | |
| </form> | |
| </section> | |
| """ | |
| if page == "about": | |
| return """ | |
| <section class="panel"> | |
| <h2 class="section-title">About RusBEIR</h2> | |
| <p class="section-note">RusBEIR is a Russian BEIR-style benchmark for zero-shot information retrieval. The leaderboard is backed by a plain JSONL file.</p> | |
| <p class="section-note">Verified rows should point to reproducible logs or a commit with generated retrieval results.</p> | |
| </section> | |
| """ | |
| return f""" | |
| <section class="panel"> | |
| <h2 class="section-title">Model Rankings</h2> | |
| <p class="section-note">Filter by task family, model name, or verification status. Scores are stored as fractions.</p> | |
| {render_filters(metric, task, verified, query)} | |
| {render_table(metric, task, verified, query)} | |
| </section> | |
| """ | |
| def render_page(params: dict[str, list[str]], page: str = "leaderboard", status: str = "") -> str: | |
| metric = params.get("metric", [DEFAULT_METRIC])[0] | |
| if metric not in METRICS: | |
| metric = DEFAULT_METRIC | |
| task = params.get("task", ["All"])[0] | |
| verified = params.get("verified", [""])[0] == "1" | |
| query = params.get("q", [""])[0].strip() | |
| status_html = f'<div class="status">{escape(status)}</div>' if status else "" | |
| query_string = urlencode({"metric": metric, "task": task, "q": query, "verified": "1" if verified else ""}) | |
| active_page = page if page in {"leaderboard", "datasets", "submit", "about"} else "leaderboard" | |
| return f"""<!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>RusBEIR Leaderboard</title> | |
| <style>{CSS}</style> | |
| </head> | |
| <body> | |
| <main class="page"> | |
| <div class="shell"> | |
| {render_summary(metric)} | |
| {render_nav(active_page)} | |
| {status_html} | |
| {render_page_content(active_page, metric, task, verified, query, query_string)} | |
| </div> | |
| </main> | |
| </body> | |
| </html>""" | |
| class Handler(BaseHTTPRequestHandler): | |
| def send_html(self, html: str, status: HTTPStatus = HTTPStatus.OK) -> None: | |
| body = html.encode("utf-8") | |
| self.send_response(status) | |
| self.send_header("Content-Type", "text/html; charset=utf-8") | |
| self.send_header("Content-Length", str(len(body))) | |
| self.end_headers() | |
| self.wfile.write(body) | |
| def do_GET(self) -> None: | |
| parsed = urlparse(self.path) | |
| pages = { | |
| "/": "leaderboard", | |
| "/index.html": "leaderboard", | |
| "/datasets": "datasets", | |
| "/submit": "submit", | |
| "/about": "about", | |
| } | |
| if parsed.path not in pages: | |
| self.send_error(HTTPStatus.NOT_FOUND) | |
| return | |
| self.send_html(render_page(parse_qs(parsed.query), page=pages[parsed.path])) | |
| def do_POST(self) -> None: | |
| parsed = urlparse(self.path) | |
| if parsed.path != "/submit": | |
| self.send_error(HTTPStatus.NOT_FOUND) | |
| return | |
| length = int(self.headers.get("Content-Length", "0")) | |
| content_type = self.headers.get("Content-Type", "") | |
| body = self.rfile.read(length) | |
| try: | |
| if content_type.startswith("multipart/form-data"): | |
| fields, files = parse_multipart_form(body, content_type) | |
| parts = [] | |
| if fields.get("record", "").strip(): | |
| parts.append(fields["record"].strip()) | |
| if "results_file" in files: | |
| filename, file_text = files["results_file"] | |
| if file_text.strip(): | |
| parts.append(file_text.strip()) | |
| elif filename: | |
| raise ValueError(f"`{filename}` is empty.") | |
| status = add_submissions("\n".join(parts)) | |
| else: | |
| form = parse_qs(body.decode("utf-8")) | |
| status = add_submissions(form.get("record", [""])[0].strip()) | |
| except (json.JSONDecodeError, ValueError) as exc: | |
| status = f"Submission was not added: {exc}" | |
| self.send_html(render_page(parse_qs(parsed.query), page="submit", status=status)) | |
| def log_message(self, format: str, *args: Any) -> None: | |
| print(f"{self.address_string()} - {format % args}") | |
| if __name__ == "__main__": | |
| server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler) | |
| print(f"Serving RusBEIR leaderboard on 0.0.0.0:{PORT}") | |
| server.serve_forever() | |