Spaces:
Running
Running
LEADBOARD 상금: 자격을 전 부문 제출로. 46부문 전체를 감당하는 예측기를 가린다
Browse files- app.py +26 -8
- i18n.js +8 -4
- index.html +3 -2
app.py
CHANGED
|
@@ -50,8 +50,11 @@ PRIZE = {
|
|
| 50 |
"amount_usd": 1000,
|
| 51 |
"winners": 1,
|
| 52 |
"closes": "2026-11-30",
|
| 53 |
-
#
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
| 55 |
}
|
| 56 |
|
| 57 |
|
|
@@ -312,9 +315,14 @@ def api_leaders():
|
|
| 312 |
"""
|
| 313 |
def build():
|
| 314 |
out = []
|
|
|
|
| 315 |
for name, b in boards().items():
|
| 316 |
rolled = ledger_read("leaderboard/%s.json" % name.lower(), {}) or {}
|
| 317 |
ent = (rolled.get("entries") or [])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
top = ent[0] if ent else None
|
| 319 |
nf = (b.get("noise_floor") or {}).get("sd_single")
|
| 320 |
base = b.get("baselines") or {}
|
|
@@ -341,19 +349,29 @@ def api_leaders():
|
|
| 341 |
"verified": bool(top.get("verified")), "leak": top.get("leak")}
|
| 342 |
out.append(row)
|
| 343 |
out.sort(key=lambda r: (r["leader"] is None, -(r["n_test"] or 0)))
|
| 344 |
-
return out
|
| 345 |
-
|
| 346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
tally = {}
|
| 348 |
for r in rows:
|
| 349 |
u = (r.get("leader") or {}).get("user")
|
| 350 |
if u and not is_host(u):
|
| 351 |
tally[u] = tally.get(u, 0) + 1
|
| 352 |
-
standing =
|
| 353 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
return {"spec": SPEC, "n": len(rows), "rows": rows,
|
| 355 |
"held": sum(1 for r in rows if r["leader"]),
|
| 356 |
-
"prize": PRIZE, "standing": standing,
|
| 357 |
"host_accounts": sorted(HOST_ACCOUNTS)}
|
| 358 |
|
| 359 |
|
|
|
|
| 50 |
"amount_usd": 1000,
|
| 51 |
"winners": 1,
|
| 52 |
"closes": "2026-11-30",
|
| 53 |
+
# 🔴 자격은 **전 부문 제출**이다. 한 부문만 잘 맞히는 특화 모델이 아니라
|
| 54 |
+
# 46부문 전체를 감당하는 범용 예측기를 가리는 시험대이기 때문이다.
|
| 55 |
+
# 전 부문을 채운 사람들 중에서 1위 부문 수로 순위를 매긴다.
|
| 56 |
+
"rule": "all_boards_then_most_firsts",
|
| 57 |
+
"require_all_boards": True,
|
| 58 |
}
|
| 59 |
|
| 60 |
|
|
|
|
| 315 |
"""
|
| 316 |
def build():
|
| 317 |
out = []
|
| 318 |
+
cover = {} # 누가 어느 부문에 제출했나. 자격 판정에 쓴다.
|
| 319 |
for name, b in boards().items():
|
| 320 |
rolled = ledger_read("leaderboard/%s.json" % name.lower(), {}) or {}
|
| 321 |
ent = (rolled.get("entries") or [])
|
| 322 |
+
for e in ent:
|
| 323 |
+
u = e.get("user")
|
| 324 |
+
if u and not is_host(u):
|
| 325 |
+
cover.setdefault(u, set()).add(name)
|
| 326 |
top = ent[0] if ent else None
|
| 327 |
nf = (b.get("noise_floor") or {}).get("sd_single")
|
| 328 |
base = b.get("baselines") or {}
|
|
|
|
| 349 |
"verified": bool(top.get("verified")), "leak": top.get("leak")}
|
| 350 |
out.append(row)
|
| 351 |
out.sort(key=lambda r: (r["leader"] is None, -(r["n_test"] or 0)))
|
| 352 |
+
return {"rows": out, "cover": {u: sorted(s) for u, s in cover.items()}}
|
| 353 |
+
|
| 354 |
+
got = cached("leaders", 60, build)
|
| 355 |
+
rows, cover = got["rows"], got["cover"]
|
| 356 |
+
n_boards = len(rows)
|
| 357 |
+
|
| 358 |
+
# 수상 후보. 주최측은 세지 않는다.
|
| 359 |
+
# **자격 = 전 부문 제출.** 못 채운 사람도 표에는 올린다 - 몇 개 남았는지 보여야
|
| 360 |
+
# 채우러 온다. 감추면 왜 자기가 후보가 아닌지 알 수 없다.
|
| 361 |
tally = {}
|
| 362 |
for r in rows:
|
| 363 |
u = (r.get("leader") or {}).get("user")
|
| 364 |
if u and not is_host(u):
|
| 365 |
tally[u] = tally.get(u, 0) + 1
|
| 366 |
+
standing = []
|
| 367 |
+
for u, bs in cover.items():
|
| 368 |
+
standing.append({"user": u, "firsts": tally.get(u, 0),
|
| 369 |
+
"submitted": len(bs), "missing": n_boards - len(bs),
|
| 370 |
+
"eligible": len(bs) >= n_boards})
|
| 371 |
+
standing.sort(key=lambda x: (not x["eligible"], -x["firsts"], -x["submitted"]))
|
| 372 |
return {"spec": SPEC, "n": len(rows), "rows": rows,
|
| 373 |
"held": sum(1 for r in rows if r["leader"]),
|
| 374 |
+
"prize": dict(PRIZE, n_boards=n_boards), "standing": standing,
|
| 375 |
"host_accounts": sorted(HOST_ACCOUNTS)}
|
| 376 |
|
| 377 |
|
i18n.js
CHANGED
|
@@ -29,8 +29,10 @@ ko: {
|
|
| 29 |
leadersSome: (a, b) => `${b}개 부문 중 ${a}개에 선두가 있습니다.`,
|
| 30 |
secBrowse: "분야", secBrowseLead: "분야를 선택하면 소속 부문의 순위표와 제출 창구로 이동합니다.",
|
| 31 |
prizeH: "상금",
|
| 32 |
-
prizeLead: (amt,close)=>`마감일에 <b>
|
| 33 |
-
prizeRule:
|
|
|
|
|
|
|
| 34 |
prizeHost: "주최측 계정(SeaWolf-AI 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
|
| 35 |
prizeNone: "아직 수상 후보가 없습니다. 부문 하나에서 1위를 하면 이름이 여기 올라갑니다.",
|
| 36 |
prizeStanding: "현재 후보",
|
|
@@ -233,8 +235,10 @@ en: {
|
|
| 233 |
leadersSome: (a, b) => `${a} of ${b} boards have a leader.`,
|
| 234 |
secBrowse: "Disciplines",
|
| 235 |
prizeH: "Prize",
|
| 236 |
-
prizeLead: (amt,close)=>`At the closing date
|
| 237 |
-
prizeRule:
|
|
|
|
|
|
|
| 238 |
prizeHost: "Host accounts (SeaWolf-AI and others) are not eligible. They stay on the tables as a scale to read against, but they do not compete.",
|
| 239 |
prizeNone: "No contenders yet. Take first place on any board and your name appears here.",
|
| 240 |
prizeStanding: "Current contenders",
|
|
|
|
| 29 |
leadersSome: (a, b) => `${b}개 부문 중 ${a}개에 선두가 있습니다.`,
|
| 30 |
secBrowse: "분야", secBrowseLead: "분야를 선택하면 소속 부문의 순위표와 제출 창구로 이동합니다.",
|
| 31 |
prizeH: "상금",
|
| 32 |
+
prizeLead: (amt,close)=>`마감일에 <b>한 분</b>에게 미화 ${amt}달러를 드립니다. 마감 ${close}.`,
|
| 33 |
+
prizeRule: (n)=>`<b>자격은 ${n}개 전 부문 제출입니다.</b> 한 부문만 잘 맞히는 모델이 아니라 전체를 감당하는 예측기를 가리는 자리이기 때문입니다. 전 부문을 채운 분들 중에서 <b>1위 부문의 개수</b>로 순위를 매기고, 동수이면 먼저 도달한 분이 우선합니다.`,
|
| 34 |
+
prizeElig: "자격 충족",
|
| 35 |
+
prizeMissing: (n)=>`${n}개 부문 남음`,
|
| 36 |
prizeHost: "주최측 계정(SeaWolf-AI 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
|
| 37 |
prizeNone: "아직 수상 후보가 없습니다. 부문 하나에서 1위를 하면 이름이 여기 올라갑니다.",
|
| 38 |
prizeStanding: "현재 후보",
|
|
|
|
| 235 |
leadersSome: (a, b) => `${a} of ${b} boards have a leader.`,
|
| 236 |
secBrowse: "Disciplines",
|
| 237 |
prizeH: "Prize",
|
| 238 |
+
prizeLead: (amt,close)=>`At the closing date <b>one entrant</b> receives USD ${amt}. Closes ${close}.`,
|
| 239 |
+
prizeRule: (n)=>`<b>To qualify you must submit to all ${n} boards.</b> This is a test bench for a predictor that handles the whole range, not one that wins a single board. Among those who cover every board, ranking is by <b>the number of boards you lead</b>, ties going to whoever got there first.`,
|
| 240 |
+
prizeElig: "qualified",
|
| 241 |
+
prizeMissing: (n)=>`${n} to go`,
|
| 242 |
prizeHost: "Host accounts (SeaWolf-AI and others) are not eligible. They stay on the tables as a scale to read against, but they do not compete.",
|
| 243 |
prizeNone: "No contenders yet. Take first place on any board and your name appears here.",
|
| 244 |
prizeStanding: "Current contenders",
|
index.html
CHANGED
|
@@ -434,9 +434,10 @@ function renderPrize(d){
|
|
| 434 |
el.innerHTML=`<h2>${t.prizeH}</h2>
|
| 435 |
<div class="amt">$${p.amount_usd.toLocaleString()} <small>USD</small></div>
|
| 436 |
<p>${t.prizeLead(p.amount_usd.toLocaleString(), p.closes)}</p>
|
| 437 |
-
<p>${t.prizeRule}</p>
|
| 438 |
<div class="cand"><b>${t.prizeStanding}</b> — ${
|
| 439 |
-
s.length? s.slice(0,
|
|
|
|
| 440 |
: t.prizeNone}</div>
|
| 441 |
<div class="fine">${t.prizeHost}</div>`;
|
| 442 |
}
|
|
|
|
| 434 |
el.innerHTML=`<h2>${t.prizeH}</h2>
|
| 435 |
<div class="amt">$${p.amount_usd.toLocaleString()} <small>USD</small></div>
|
| 436 |
<p>${t.prizeLead(p.amount_usd.toLocaleString(), p.closes)}</p>
|
| 437 |
+
<p>${t.prizeRule(p.n_boards)}</p>
|
| 438 |
<div class="cand"><b>${t.prizeStanding}</b> — ${
|
| 439 |
+
s.length? s.slice(0,6).map(x=>`${esc(x.user)} <span class="dim">(${
|
| 440 |
+
x.eligible? t.prizeElig : t.prizeMissing(x.missing)} · ${t.prizeFirsts(x.firsts)})</span>`).join(" · ")
|
| 441 |
: t.prizeNone}</div>
|
| 442 |
<div class="fine">${t.prizeHost}</div>`;
|
| 443 |
}
|