SeaWolf-AI commited on
Commit
b8a5854
·
verified ·
1 Parent(s): cef481b

상단에 총 제출 수 · 참가는 한 부문이면 된다는 점 명시

Browse files
Files changed (3) hide show
  1. app.py +31 -0
  2. i18n.js +4 -2
  3. index.html +5 -0
app.py CHANGED
@@ -237,6 +237,36 @@ def _hdr():
237
  return {"Authorization": "Bearer " + HF_TOKEN, "User-Agent": "LEADBOARD/1.0"}
238
 
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  def ledger_read(path, default=None):
241
  try:
242
  with urllib.request.urlopen(urllib.request.Request(
@@ -370,6 +400,7 @@ def api_leaders():
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)}
 
237
  return {"Authorization": "Bearer " + HF_TOKEN, "User-Agent": "LEADBOARD/1.0"}
238
 
239
 
240
+ def submission_count():
241
+ """원장에 들어온 제출 수. **주최측 기준 제출도 포함한 전체다.**
242
+
243
+ 화면 상단에 올리는 값이라 매 요청마다 원장을 훑으면 안 된다 - 트리 조회는
244
+ 페이지당 1000건이고 부문이 46개다. 5분 캐시로 충분하다: 이 숫자는 사람이
245
+ 제출할 때만 움직이고, 5분 늦게 보인다고 잘못된 값이 되지는 않는다.
246
+ """
247
+ def build():
248
+ n, cursor = 0, ""
249
+ for _ in range(20): # 20페이지 = 2만 건. 그 위는 지금 없다.
250
+ url = (LEDGER_API + "/tree/main?recursive=1&limit=1000"
251
+ + ("&cursor=" + cursor if cursor else ""))
252
+ try:
253
+ with urllib.request.urlopen(
254
+ urllib.request.Request(url, headers=_hdr()), timeout=60) as r:
255
+ rows = json.loads(r.read())
256
+ link = r.headers.get("Link") or ""
257
+ except Exception:
258
+ return None # 🔴 실패는 0 이 아니다. 모르는 것이다.
259
+ n += sum(1 for x in rows
260
+ if str(x.get("path", "")).startswith("submissions/")
261
+ and str(x.get("path", "")).endswith(".json"))
262
+ m = re.search(r"cursor=([^&>]+)", link) if 'rel="next"' in link else None
263
+ if not m:
264
+ break
265
+ cursor = m.group(1)
266
+ return n
267
+ return cached("subcount", 300, build)
268
+
269
+
270
  def ledger_read(path, default=None):
271
  try:
272
  with urllib.request.urlopen(urllib.request.Request(
 
400
  "eligible": len(bs) >= n_boards})
401
  standing.sort(key=lambda x: (not x["eligible"], -x["firsts"], -x["submitted"]))
402
  return {"spec": SPEC, "n": len(rows), "rows": rows,
403
+ "submissions": submission_count(),
404
  "held": sum(1 for r in rows if r["leader"]),
405
  "prize": dict(PRIZE, n_boards=n_boards), "standing": standing,
406
  "host_accounts": sorted(HOST_ACCOUNTS)}
i18n.js CHANGED
@@ -30,7 +30,8 @@ ko: {
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 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
@@ -236,7 +237,8 @@ en: {
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.",
 
30
  secBrowse: "분야", secBrowseLead: "분야를 선택하면 소속 부문의 순위표와 제출 창구로 이동합니다.",
31
  prizeH: "상금",
32
  prizeLead: (amt,close)=>`마감일에 <b>한 분</b>에게 미화 ${amt}달러를 드립니다. 마감 ${close}.`,
33
+ prizeRule: (n)=>`<b>참가는 한 부문이면 됩니다.</b> 부문 하나에 예측을 내면 그 부문 순위표에 바로 오릅니다.<br><b>상금 자격만</b> ${n}개 전 부문 제출입니다 — 한 부문 특화가 아니라 전체를 감당하는 예측기에 드리는 상이기 때문입니다. 전 부문을 채운 분들 중 <b>1위 부문의 개수</b>로 정하고, 동수이면 먼저 도달한 분이 우선합니다.`,
34
+ statSubs: "제출",
35
  prizeElig: "자격 충족",
36
  prizeMissing: (n)=>`${n}개 부문 남음`,
37
  prizeHost: "주최측 계정(SeaWolf-AI 등)은 수상 대상이 아닙니다. 눈금 역할로 표에 남되 겨루지 않습니다.",
 
237
  secBrowse: "Disciplines",
238
  prizeH: "Prize",
239
  prizeLead: (amt,close)=>`At the closing date <b>one entrant</b> receives USD ${amt}. Closes ${close}.`,
240
+ prizeRule: (n)=>`<b>One board is enough to enter.</b> Submit predictions for a single board and you appear on that board's table straight away.<br><b>The prize alone</b> requires all ${n} boards — it goes to 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.`,
241
+ statSubs: "submissions",
242
  prizeElig: "qualified",
243
  prizeMissing: (n)=>`${n} to go`,
244
  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.",
index.html CHANGED
@@ -363,6 +363,7 @@ function hub(){
363
  <p class="tag">${t.heroTag}</p>
364
  <p class="lede">${t.heroLede}</p>
365
  <div class="stats">
 
366
  <div class="stat"><b>${T0.open}</b><span>${t.statBoards}</span></div>
367
  <div class="stat"><b>${bs.reduce((s,b)=>s+b.n_test,0).toLocaleString()}</b><span>${t.statCompounds}</span></div>
368
  <div class="stat"><b>${CATS.categories.filter(c=>c.open).length}</b><span>${t.statFields}</span></div>
@@ -446,6 +447,10 @@ async function paintLeaders(){
446
  const el=$("#leaders"); if(!el)return;
447
  let d; try{ d=await j("/api/leaders"); }catch(e){ el.innerHTML=""; return; }
448
  renderPrize(d);
 
 
 
 
449
  const rows=d.rows.map(r=>{
450
  const ld=r.leader; // 전역 L 은 언어다. 가리지 않는다
451
  // 점수는 부문마다 주지표가 다르다. 회귀 부문은 MAE, 분류 전용 부문은 AUROC.
 
363
  <p class="tag">${t.heroTag}</p>
364
  <p class="lede">${t.heroLede}</p>
365
  <div class="stats">
366
+ <div class="stat"><b id="st_subs">—</b><span>${t.statSubs}</span></div>
367
  <div class="stat"><b>${T0.open}</b><span>${t.statBoards}</span></div>
368
  <div class="stat"><b>${bs.reduce((s,b)=>s+b.n_test,0).toLocaleString()}</b><span>${t.statCompounds}</span></div>
369
  <div class="stat"><b>${CATS.categories.filter(c=>c.open).length}</b><span>${t.statFields}</span></div>
 
447
  const el=$("#leaders"); if(!el)return;
448
  let d; try{ d=await j("/api/leaders"); }catch(e){ el.innerHTML=""; return; }
449
  renderPrize(d);
450
+ // 제출 수는 원장을 훑어야 나오므로 순위 응답에 실려 온다. 실패하면 - 로 둔다.
451
+ // 0 으로 두면 "아무도 안 냈다"로 읽히는데, 그것과 "못 셌다"는 다르다.
452
+ const se = $("#st_subs");
453
+ if (se) se.textContent = (d.submissions==null) ? "—" : d.submissions.toLocaleString();
454
  const rows=d.rows.map(r=>{
455
  const ld=r.leader; // 전역 L 은 언어다. 가리지 않는다
456
  // 점수는 부문마다 주지표가 다르다. 회귀 부문은 MAE, 분류 전용 부문은 AUROC.