|
1 | | -from typing import Any |
| 1 | +import re |
| 2 | +from typing import Any, List |
2 | 3 | from flask import Blueprint |
3 | 4 | from kernelboard.lib.db import get_db_connection |
4 | 5 | from kernelboard.lib.time import to_time_left |
|
9 | 10 |
|
10 | 11 | logger = logging.getLogger(__name__) |
11 | 12 |
|
12 | | -leaderboard_bp = Blueprint("leaderboard_bp", __name__, url_prefix="/leaderboard") |
| 13 | +leaderboard_bp = Blueprint( |
| 14 | + "leaderboard_bp", __name__, url_prefix="/leaderboard" |
| 15 | +) |
13 | 16 |
|
14 | 17 |
|
15 | 18 | @leaderboard_bp.route("/<int:leaderboard_id>", methods=["GET"]) |
@@ -188,3 +191,122 @@ def is_result_invalid(result): |
188 | 191 | return True |
189 | 192 |
|
190 | 193 | return False |
| 194 | + |
| 195 | + |
| 196 | +# ai generated code hardcoded user_id |
| 197 | +HARDCODED_USER_ID = "205851652572315658" |
| 198 | + |
| 199 | + |
| 200 | +@leaderboard_bp.route("/ai_trend/<int:leaderboard_id>", methods=["GET"]) |
| 201 | +def get_ai_trend(leaderboard_id: int): |
| 202 | + """ |
| 203 | + GET /leaderboard/timeseries/<leaderboard_id> |
| 204 | +
|
| 205 | + Returns time series data for submissions matching file name patterns like: |
| 206 | + - H100_claude-opus-4.5_ka_submission |
| 207 | + - H100_gpt-5-2_ka_submission |
| 208 | + - H100_gpt-5_ka_submission |
| 209 | + """ |
| 210 | + total_start = time.perf_counter() |
| 211 | + |
| 212 | + conn = get_db_connection() |
| 213 | + query_start = time.perf_counter() |
| 214 | + |
| 215 | + with conn.cursor() as cur: |
| 216 | + sql = """ |
| 217 | + SELECT |
| 218 | + s.id AS submission_id, |
| 219 | + s.file_name, |
| 220 | + s.submission_time, |
| 221 | + r.score, |
| 222 | + r.passed, |
| 223 | + r.runner AS gpu_type, |
| 224 | + r.mode |
| 225 | + FROM leaderboard.submission s |
| 226 | + JOIN leaderboard.runs r ON r.submission_id = s.id |
| 227 | + WHERE s.user_id = %s |
| 228 | + AND s.leaderboard_id = %s |
| 229 | + AND r.score IS NOT NULL |
| 230 | + AND r.passed = true |
| 231 | + AND NOT r.secret |
| 232 | + ORDER BY s.submission_time ASC |
| 233 | + """ |
| 234 | + cur.execute(sql, (HARDCODED_USER_ID, leaderboard_id)) |
| 235 | + rows = cur.fetchall() |
| 236 | + |
| 237 | + query_time = (time.perf_counter() - query_start) * 1000 |
| 238 | + |
| 239 | + if not rows: |
| 240 | + return http_success(data={ |
| 241 | + "leaderboard_id": leaderboard_id, |
| 242 | + "time_series": {}, |
| 243 | + }) |
| 244 | + |
| 245 | + items = [] |
| 246 | + for row in rows: |
| 247 | + (submission_id, file_name, submission_time, |
| 248 | + score, passed, gpu_type, mode) = row |
| 249 | + model_name = parse_model_from_filename(file_name) |
| 250 | + |
| 251 | + items.append({ |
| 252 | + "submission_id": submission_id, |
| 253 | + "file_name": file_name, |
| 254 | + "submission_time": ( |
| 255 | + submission_time.isoformat() if submission_time else None |
| 256 | + ), |
| 257 | + "score": score, |
| 258 | + "passed": passed, |
| 259 | + "gpu_type": gpu_type, |
| 260 | + "mode": mode, |
| 261 | + "model": model_name, |
| 262 | + }) |
| 263 | + |
| 264 | + series_by_model = group_by_model(items) |
| 265 | + |
| 266 | + total_time = (time.perf_counter() - total_start) * 1000 |
| 267 | + logger.info( |
| 268 | + "[Perf] timeseries leaderboard_id=%s | query=%.2fms | total=%.2fms", |
| 269 | + leaderboard_id, query_time, total_time, |
| 270 | + ) |
| 271 | + |
| 272 | + return http_success(data={ |
| 273 | + "leaderboard_id": leaderboard_id, |
| 274 | + "time_series": series_by_model, |
| 275 | + }) |
| 276 | + |
| 277 | + |
| 278 | +def parse_model_from_filename(file_name: str) -> str: |
| 279 | + """ |
| 280 | + Extract model name from file names like: |
| 281 | + - matmul_py_H100_claude-opus-4.5_ka_submission.py -> claude-opus-4.5 |
| 282 | + - matmul_py_H100_gpt-5-2_ka_submission.py -> gpt-5-2 |
| 283 | + - matmul_py_H100_gpt-5_ka_submission.py -> gpt-5 |
| 284 | + - 1.py -> 1.py (no match, return as-is) |
| 285 | + """ |
| 286 | + if not file_name: |
| 287 | + return "unknown" |
| 288 | + |
| 289 | + # Pattern: {problem}_py_{gpu}_{model}_ka_submission.py |
| 290 | + pattern = r"^.+_py_[A-Za-z0-9]+_(.+?)_ka_submission\.py$" |
| 291 | + match = re.match(pattern, file_name) |
| 292 | + if match: |
| 293 | + return match.group(1) |
| 294 | + |
| 295 | + return file_name |
| 296 | + |
| 297 | + |
| 298 | +def group_by_model(items: List[dict]) -> dict: |
| 299 | + """ |
| 300 | + Group time series items by model name for easier charting. |
| 301 | + """ |
| 302 | + series = {} |
| 303 | + for item in items: |
| 304 | + model = item.get("model", "unknown") |
| 305 | + if model not in series: |
| 306 | + series[model] = [] |
| 307 | + series[model].append({ |
| 308 | + "submission_time": item["submission_time"], |
| 309 | + "score": item["score"], |
| 310 | + "submission_id": item["submission_id"], |
| 311 | + }) |
| 312 | + return series |
0 commit comments