Spaces:
Sleeping
Sleeping
Update miniapp_leaderboard.py
Browse files- miniapp_leaderboard.py +82 -75
miniapp_leaderboard.py
CHANGED
|
@@ -162,7 +162,6 @@ def _load_entries_df() -> pd.DataFrame:
|
|
| 162 |
for c in NUMERIC_COLS:
|
| 163 |
df[c] = pd.to_numeric(df[c], errors="coerce")
|
| 164 |
|
| 165 |
-
# 默认按提交时间倒序
|
| 166 |
df = df.sort_values(by=["Submitted at"], ascending=False, kind="stable")
|
| 167 |
return df
|
| 168 |
|
|
@@ -177,9 +176,6 @@ def _parse_hf_created_at(created_at: str) -> datetime.datetime | None:
|
|
| 177 |
|
| 178 |
|
| 179 |
def _check_user_eligibility(username: str) -> tuple[bool, str]:
|
| 180 |
-
"""
|
| 181 |
-
- Must be older than ~4 months (>= 120 days)
|
| 182 |
-
"""
|
| 183 |
try:
|
| 184 |
r = requests.get(f"https://huggingface.co/api/users/{username}/overview", timeout=10)
|
| 185 |
r.raise_for_status()
|
|
@@ -192,8 +188,7 @@ def _check_user_eligibility(username: str) -> tuple[bool, str]:
|
|
| 192 |
now = datetime.datetime.now(datetime.timezone.utc)
|
| 193 |
if dt.tzinfo is None:
|
| 194 |
dt = dt.replace(tzinfo=datetime.timezone.utc)
|
| 195 |
-
|
| 196 |
-
if age_days < 120:
|
| 197 |
return False, "Account must be older than 4 months to submit."
|
| 198 |
return True, ""
|
| 199 |
except Exception:
|
|
@@ -238,11 +233,11 @@ def _render_leaderboard_html(df: pd.DataFrame, sort_col: str, sort_dir: str) ->
|
|
| 238 |
if col:
|
| 239 |
arrow = ""
|
| 240 |
if col == sort_col:
|
| 241 |
-
arrow = "
|
| 242 |
al = " left" if align_left else ""
|
| 243 |
-
return f'<th class="
|
| 244 |
al = " left" if align_left else ""
|
| 245 |
-
return f'<th class="
|
| 246 |
|
| 247 |
trs = []
|
| 248 |
for _, r in df.iterrows():
|
|
@@ -250,30 +245,30 @@ def _render_leaderboard_html(df: pd.DataFrame, sort_col: str, sort_dir: str) ->
|
|
| 250 |
for c in DISPLAY_ORDER:
|
| 251 |
val = _fmt_cell(r.get(c, ""))
|
| 252 |
if c == "Model name":
|
| 253 |
-
tds.append(f'<td class="
|
| 254 |
else:
|
| 255 |
-
tds.append(f'<td class="
|
| 256 |
-
trs.append("<tr class='
|
| 257 |
|
| 258 |
return f"""
|
| 259 |
-
<div class="
|
| 260 |
-
<div class="
|
| 261 |
-
<table class="
|
| 262 |
<thead>
|
| 263 |
-
<tr class="
|
| 264 |
{th("Avg. (%)", "Avg", cls="avg")}
|
| 265 |
{th("Model", "Model name", align_left=True, cls="model")}
|
| 266 |
-
<th class="
|
| 267 |
</tr>
|
| 268 |
-
<tr class="
|
| 269 |
-
<th class="
|
| 270 |
-
<th class="
|
| 271 |
-
<th class="
|
| 272 |
-
<th class="
|
| 273 |
</tr>
|
| 274 |
-
<tr class="
|
| 275 |
-
<th class="
|
| 276 |
-
<th class="
|
| 277 |
{th("Easy", "Easy")}
|
| 278 |
{th("Mid", "Mid")}
|
| 279 |
{th("Hard", "Hard")}
|
|
@@ -345,7 +340,6 @@ def submit(
|
|
| 345 |
if _submitted_today(submitter):
|
| 346 |
return "You have already submitted today. Please try again tomorrow.", render_lb(search_text, sort_col, sort_dir)
|
| 347 |
|
| 348 |
-
# api_key collected but NOT stored
|
| 349 |
now = datetime.datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
| 350 |
nonce = uuid.uuid4().hex[:8]
|
| 351 |
safe_user = _slug(submitter)
|
|
@@ -388,81 +382,96 @@ def submit(
|
|
| 388 |
|
| 389 |
|
| 390 |
CSS = r"""
|
| 391 |
-
/*
|
| 392 |
.gradio-container { max-width: 100% !important; }
|
| 393 |
-
#page { padding:
|
| 394 |
|
| 395 |
-
/* 顶部一行 */
|
| 396 |
-
#topbar { display:flex; align-items:center; justify-content:space-between; gap:12px; }
|
| 397 |
-
#titleline { font-weight: 700; font-size:
|
| 398 |
#searchbox { width: 280px; }
|
| 399 |
#searchbox label { display:none !important; }
|
| 400 |
#searchbox textarea, #searchbox input {
|
| 401 |
-
height:
|
| 402 |
-
border-radius:
|
| 403 |
-
border: 1px solid
|
| 404 |
-
background:
|
| 405 |
box-shadow: none !important;
|
| 406 |
}
|
| 407 |
-
#searchbox textarea::placeholder, #searchbox input::placeholder { color:
|
| 408 |
|
| 409 |
-
/*
|
| 410 |
-
.
|
| 411 |
width: 100%;
|
| 412 |
-
border: 1px solid
|
| 413 |
-
border-radius:
|
| 414 |
-
background:
|
| 415 |
}
|
| 416 |
-
.
|
| 417 |
-
table.
|
| 418 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 419 |
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
|
| 420 |
-
font-weight:
|
| 421 |
font-size: 13px;
|
| 422 |
-
color:
|
| 423 |
padding: 10px 12px;
|
| 424 |
text-align: center;
|
| 425 |
-
|
| 426 |
-
|
|
|
|
| 427 |
white-space: nowrap;
|
| 428 |
}
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
}
|
| 436 |
|
| 437 |
-
|
|
|
|
| 438 |
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
|
| 439 |
font-size: 13px;
|
|
|
|
| 440 |
padding: 10px 12px;
|
| 441 |
-
border-bottom: 1px solid
|
| 442 |
-
|
|
|
|
| 443 |
}
|
| 444 |
-
|
| 445 |
-
td.num
|
| 446 |
-
td.model
|
| 447 |
-
|
| 448 |
|
| 449 |
-
|
| 450 |
-
th.clickable
|
|
|
|
| 451 |
|
| 452 |
-
/* 提交
|
| 453 |
#submit_card{
|
| 454 |
width: 100%;
|
| 455 |
-
border: 1px solid
|
| 456 |
-
border-radius:
|
| 457 |
-
padding:
|
| 458 |
-
background:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 459 |
}
|
| 460 |
-
#submit_card .prose { margin: 0 0 10px 0; color: rgba(0,0,0,.72); font-size: 13px; }
|
| 461 |
"""
|
| 462 |
|
| 463 |
with gr.Blocks(title=f"{APP_NAME} leaderboard") as demo:
|
| 464 |
with gr.Column(elem_id="page"):
|
| 465 |
-
# 顶部栏:左标题,右搜索 + 刷新(同一行,不显眼)
|
| 466 |
with gr.Row(elem_id="topbar"):
|
| 467 |
gr.Markdown(f"<div id='titleline'>{APP_NAME} leaderboard</div>")
|
| 468 |
with gr.Row():
|
|
@@ -482,7 +491,6 @@ with gr.Blocks(title=f"{APP_NAME} leaderboard") as demo:
|
|
| 482 |
|
| 483 |
clicked_col = gr.Textbox(visible=False, elem_id="clicked_col")
|
| 484 |
|
| 485 |
-
# JS:表头点击 -> 写入隐藏 textbox -> 触发 change
|
| 486 |
gr.HTML(
|
| 487 |
"""
|
| 488 |
<script>
|
|
@@ -523,11 +531,11 @@ with gr.Blocks(title=f"{APP_NAME} leaderboard") as demo:
|
|
| 523 |
outputs=[sort_col, sort_dir, lb_html],
|
| 524 |
)
|
| 525 |
|
| 526 |
-
# 提交:全宽
|
| 527 |
gr.HTML(
|
| 528 |
"""
|
| 529 |
<div id="submit_card">
|
| 530 |
-
<div class="
|
| 531 |
<b>Submission</b> — Submit <b>Model API URL</b> and <b>API key</b> only.
|
| 532 |
Requires login (Spaces). One submission per user per day. Account must be older than 4 months.
|
| 533 |
API key will <b>not</b> be stored.
|
|
@@ -536,7 +544,6 @@ with gr.Blocks(title=f"{APP_NAME} leaderboard") as demo:
|
|
| 536 |
"""
|
| 537 |
)
|
| 538 |
|
| 539 |
-
# 用 Column/Row 做“占满横向”的提交表单
|
| 540 |
with gr.Column():
|
| 541 |
with gr.Row():
|
| 542 |
model_api = gr.Textbox(label="Model API URL", placeholder="https://...", scale=3)
|
|
|
|
| 162 |
for c in NUMERIC_COLS:
|
| 163 |
df[c] = pd.to_numeric(df[c], errors="coerce")
|
| 164 |
|
|
|
|
| 165 |
df = df.sort_values(by=["Submitted at"], ascending=False, kind="stable")
|
| 166 |
return df
|
| 167 |
|
|
|
|
| 176 |
|
| 177 |
|
| 178 |
def _check_user_eligibility(username: str) -> tuple[bool, str]:
|
|
|
|
|
|
|
|
|
|
| 179 |
try:
|
| 180 |
r = requests.get(f"https://huggingface.co/api/users/{username}/overview", timeout=10)
|
| 181 |
r.raise_for_status()
|
|
|
|
| 188 |
now = datetime.datetime.now(datetime.timezone.utc)
|
| 189 |
if dt.tzinfo is None:
|
| 190 |
dt = dt.replace(tzinfo=datetime.timezone.utc)
|
| 191 |
+
if (now - dt).days < 120:
|
|
|
|
| 192 |
return False, "Account must be older than 4 months to submit."
|
| 193 |
return True, ""
|
| 194 |
except Exception:
|
|
|
|
| 233 |
if col:
|
| 234 |
arrow = ""
|
| 235 |
if col == sort_col:
|
| 236 |
+
arrow = " ▲" if sort_dir == "asc" else " ▼"
|
| 237 |
al = " left" if align_left else ""
|
| 238 |
+
return f'<th class="th clickable{al} {cls}" data-col="{_html.escape(col)}">{_html.escape(label)}{arrow}</th>'
|
| 239 |
al = " left" if align_left else ""
|
| 240 |
+
return f'<th class="th{al} {cls}">{_html.escape(label)}</th>'
|
| 241 |
|
| 242 |
trs = []
|
| 243 |
for _, r in df.iterrows():
|
|
|
|
| 245 |
for c in DISPLAY_ORDER:
|
| 246 |
val = _fmt_cell(r.get(c, ""))
|
| 247 |
if c == "Model name":
|
| 248 |
+
tds.append(f'<td class="td model">{_html.escape(val)}</td>')
|
| 249 |
else:
|
| 250 |
+
tds.append(f'<td class="td num">{_html.escape(val)}</td>')
|
| 251 |
+
trs.append("<tr class='tr'>" + "".join(tds) + "</tr>")
|
| 252 |
|
| 253 |
return f"""
|
| 254 |
+
<div class="table-wrap">
|
| 255 |
+
<div class="table-scroll">
|
| 256 |
+
<table class="table" id="lb_table">
|
| 257 |
<thead>
|
| 258 |
+
<tr class="r1">
|
| 259 |
{th("Avg. (%)", "Avg", cls="avg")}
|
| 260 |
{th("Model", "Model name", align_left=True, cls="model")}
|
| 261 |
+
<th class="th group" colspan="9">Pass Rate (%)</th>
|
| 262 |
</tr>
|
| 263 |
+
<tr class="r2">
|
| 264 |
+
<th class="th"></th>
|
| 265 |
+
<th class="th"></th>
|
| 266 |
+
<th class="th group" colspan="3">Difficulty</th>
|
| 267 |
+
<th class="th group" colspan="6">Domain</th>
|
| 268 |
</tr>
|
| 269 |
+
<tr class="r3">
|
| 270 |
+
<th class="th"></th>
|
| 271 |
+
<th class="th"></th>
|
| 272 |
{th("Easy", "Easy")}
|
| 273 |
{th("Mid", "Mid")}
|
| 274 |
{th("Hard", "Hard")}
|
|
|
|
| 340 |
if _submitted_today(submitter):
|
| 341 |
return "You have already submitted today. Please try again tomorrow.", render_lb(search_text, sort_col, sort_dir)
|
| 342 |
|
|
|
|
| 343 |
now = datetime.datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
| 344 |
nonce = uuid.uuid4().hex[:8]
|
| 345 |
safe_user = _slug(submitter)
|
|
|
|
| 382 |
|
| 383 |
|
| 384 |
CSS = r"""
|
| 385 |
+
/* 全宽 */
|
| 386 |
.gradio-container { max-width: 100% !important; }
|
| 387 |
+
#page { padding: 16px; }
|
| 388 |
|
| 389 |
+
/* 顶部一行:搜索弱化 */
|
| 390 |
+
#topbar { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom: 10px; }
|
| 391 |
+
#titleline { font-weight: 700; font-size: 18px; }
|
| 392 |
#searchbox { width: 280px; }
|
| 393 |
#searchbox label { display:none !important; }
|
| 394 |
#searchbox textarea, #searchbox input {
|
| 395 |
+
height: 34px !important;
|
| 396 |
+
border-radius: 8px !important;
|
| 397 |
+
border: 1px solid #e5e7eb !important;
|
| 398 |
+
background: #fff !important;
|
| 399 |
box-shadow: none !important;
|
| 400 |
}
|
| 401 |
+
#searchbox textarea::placeholder, #searchbox input::placeholder { color: #9ca3af; }
|
| 402 |
|
| 403 |
+
/* 表格:浅灰分割线风格 */
|
| 404 |
+
.table-wrap{
|
| 405 |
width: 100%;
|
| 406 |
+
border: 1px solid #e5e7eb;
|
| 407 |
+
border-radius: 8px;
|
| 408 |
+
background: #fff;
|
| 409 |
}
|
| 410 |
+
.table-scroll{ width: 100%; overflow-x: auto; }
|
| 411 |
+
table.table{
|
| 412 |
+
width: 100%;
|
| 413 |
+
border-collapse: separate;
|
| 414 |
+
border-spacing: 0;
|
| 415 |
+
min-width: 1100px;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
/* 表头 */
|
| 419 |
+
th.th{
|
| 420 |
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
|
| 421 |
+
font-weight: 600;
|
| 422 |
font-size: 13px;
|
| 423 |
+
color: #111827;
|
| 424 |
padding: 10px 12px;
|
| 425 |
text-align: center;
|
| 426 |
+
background: #f9fafb;
|
| 427 |
+
border-bottom: 1px solid #e5e7eb;
|
| 428 |
+
border-right: 1px solid #e5e7eb;
|
| 429 |
white-space: nowrap;
|
| 430 |
}
|
| 431 |
+
thead tr.r1 th.th, thead tr.r2 th.th { background: #f9fafb; }
|
| 432 |
+
thead tr.r3 th.th { background: #ffffff; }
|
| 433 |
+
|
| 434 |
+
th.th.left{ text-align:left; }
|
| 435 |
+
th.group{ color:#374151; font-weight:600; }
|
| 436 |
+
th.th:last-child{ border-right: none; }
|
|
|
|
| 437 |
|
| 438 |
+
/* body */
|
| 439 |
+
td.td{
|
| 440 |
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial;
|
| 441 |
font-size: 13px;
|
| 442 |
+
color: #111827;
|
| 443 |
padding: 10px 12px;
|
| 444 |
+
border-bottom: 1px solid #f0f1f3;
|
| 445 |
+
border-right: 1px solid #f0f1f3;
|
| 446 |
+
background: #fff;
|
| 447 |
}
|
| 448 |
+
td.td:last-child{ border-right: none; }
|
| 449 |
+
td.num{ text-align:right; }
|
| 450 |
+
td.model{ text-align:left; min-width: 280px; }
|
| 451 |
+
tr.tr:hover td.td{ background: #fafafa; }
|
| 452 |
|
| 453 |
+
/* 可点击排序 */
|
| 454 |
+
th.clickable{ cursor:pointer; user-select:none; }
|
| 455 |
+
th.clickable:hover{ background:#f3f4f6; }
|
| 456 |
|
| 457 |
+
/* 提交:全宽 */
|
| 458 |
#submit_card{
|
| 459 |
width: 100%;
|
| 460 |
+
border: 1px solid #e5e7eb;
|
| 461 |
+
border-radius: 8px;
|
| 462 |
+
padding: 12px;
|
| 463 |
+
background: #fff;
|
| 464 |
+
margin-top: 14px;
|
| 465 |
+
}
|
| 466 |
+
#submit_card .hint{
|
| 467 |
+
margin: 0 0 10px 0;
|
| 468 |
+
color: #6b7280;
|
| 469 |
+
font-size: 13px;
|
| 470 |
}
|
|
|
|
| 471 |
"""
|
| 472 |
|
| 473 |
with gr.Blocks(title=f"{APP_NAME} leaderboard") as demo:
|
| 474 |
with gr.Column(elem_id="page"):
|
|
|
|
| 475 |
with gr.Row(elem_id="topbar"):
|
| 476 |
gr.Markdown(f"<div id='titleline'>{APP_NAME} leaderboard</div>")
|
| 477 |
with gr.Row():
|
|
|
|
| 491 |
|
| 492 |
clicked_col = gr.Textbox(visible=False, elem_id="clicked_col")
|
| 493 |
|
|
|
|
| 494 |
gr.HTML(
|
| 495 |
"""
|
| 496 |
<script>
|
|
|
|
| 531 |
outputs=[sort_col, sort_dir, lb_html],
|
| 532 |
)
|
| 533 |
|
| 534 |
+
# 提交模块:全宽
|
| 535 |
gr.HTML(
|
| 536 |
"""
|
| 537 |
<div id="submit_card">
|
| 538 |
+
<div class="hint">
|
| 539 |
<b>Submission</b> — Submit <b>Model API URL</b> and <b>API key</b> only.
|
| 540 |
Requires login (Spaces). One submission per user per day. Account must be older than 4 months.
|
| 541 |
API key will <b>not</b> be stored.
|
|
|
|
| 544 |
"""
|
| 545 |
)
|
| 546 |
|
|
|
|
| 547 |
with gr.Column():
|
| 548 |
with gr.Row():
|
| 549 |
model_api = gr.Textbox(label="Model API URL", placeholder="https://...", scale=3)
|