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
ID", "Organization": "Org.", "Source URL": "Source
URL", "sberquad-retrieval": "sberquad
retrieval", "ruscibench-retrieval": "ruscibench
retrieval", "wikifacts-articles": "wikifacts
articles", "wikifacts-para": "wikifacts
para", "wikifacts-sents": "wikifacts
sents", "wikifacts-window_2": "wikifacts
window 2", "wikifacts-window_3": "wikifacts
window 3", "wikifacts-window_4": "wikifacts
window 4", "wikifacts-window_5": "wikifacts
window 5", "wikifacts-window_6": "wikifacts
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'' 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'{DISPLAY_COLUMN_NAMES.get(column, escape(column))}' 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'source' 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'{cell}') body.append(f"{''.join(cells)}") return f'
{headers}{"".join(body)}
' 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'' for item in METRICS) task_options = "".join(f'' for item in tasks) checked = " checked" if verified else "" return f"""
""" 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"""
Russian Information Retrieval Benchmark

RusBEIR Leaderboard

Compare dense retrievers, sparse baselines, and reranker pipelines on official RusBEIR datasets. The default ranking is the macro-average of {escape(metric)}.

Metric: {escape(metric)} Official datasets: {len(datasets)} Rows: {len(records)} Types: {escape(type_text)}
{logo_html()}
Best Model
{escape(str(best_model))}
Highest average {escape(metric)}
Best Score
{best_score}
Shown as percentage points
Models
{len(records)}
Imported and reviewable JSONL rows
Datasets
{len(datasets)}
Official benchmark tasks
""" def render_datasets() -> str: rows = [] for dataset in load_datasets(): if not dataset.get("official", True): continue rows.append( "" f"{escape(str(dataset.get('name', '')))}" f"{escape(str(dataset.get('task', '')))}" f"{escape(str(dataset.get('split', '')))}" f"{escape(str(dataset.get('hf_repo', '')))}" f"{escape(str(dataset.get('qrels_repo', '')))}" f"{escape(str(dataset.get('origin', '')))}" "" ) return f""" {''.join(rows)}
DatasetTaskSplitCorpus repoQrels repoOrigin
""" 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'{label}') return f'' def render_page_content(page: str, metric: str, task: str, verified: bool, query: str, query_string: str) -> str: if page == "datasets": return f"""

Official Datasets

RusBEIR tasks used for the default macro-average ranking.

{render_datasets()}
""" if page == "submit": return f"""

Submit Results

Paste JSONL content or upload a ready JSONL file. Each record must include model_id, scores, and at least one numeric metric.

""" if page == "about": return """

About RusBEIR

RusBEIR is a Russian BEIR-style benchmark for zero-shot information retrieval. The leaderboard is backed by a plain JSONL file.

Verified rows should point to reproducible logs or a commit with generated retrieval results.

""" return f"""

Model Rankings

Filter by task family, model name, or verification status. Scores are stored as fractions.

{render_filters(metric, task, verified, query)} {render_table(metric, task, verified, query)}
""" 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'
{escape(status)}
' 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""" RusBEIR Leaderboard
{render_summary(metric)} {render_nav(active_page)} {status_html} {render_page_content(active_page, metric, task, verified, query, query_string)}
""" 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()