from __future__ import annotations from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from pathlib import Path import csv from typing import List, Dict, Tuple APP_DIR = Path(__file__).resolve().parent CSV_PATH = APP_DIR / "YKS_leaderboard.csv" def load_leaderboard() -> Tuple[List[str], List[Dict[str, str]]]: headers: List[str] = [] rows: List[Dict[str, str]] = [] with CSV_PATH.open("r", encoding="utf-8") as f: reader = csv.DictReader(f) headers = reader.fieldnames or [] for row in reader: rows.append(dict(row)) # Sort by ALL_Total in descending order if present and numeric def parse_score(value: str) -> float: try: return float(value) except Exception: return float("-inf") if "ALL_Total" in headers: rows.sort(key=lambda r: parse_score(r.get("ALL_Total", "-inf")), reverse=True) # Add rank field for index, row in enumerate(rows, start=1): row["Rank"] = str(index) # Ensure Rank is the first header if "Rank" not in headers: headers = ["Rank"] + headers return headers, rows app = FastAPI(title="YKS 2025 LLM Leaderboard") templates = Jinja2Templates(directory=str(APP_DIR / "templates")) app.mount("/static", StaticFiles(directory=str(APP_DIR / "static")), name="static") @app.get("/", response_class=HTMLResponse) async def index(request: Request) -> HTMLResponse: headers, rows = load_leaderboard() return templates.TemplateResponse( "index.html", {"request": request, "headers": headers, "rows": rows, "csv_path": str(CSV_PATH)}, )