SeaWolf-AI commited on
Commit
cc9fd51
Β·
verified Β·
1 Parent(s): c6f4734

Say what each board measures; link entrants to their profile

Browse files

A board name and a target symbol only read to specialists. Each board now carries a one-line description in both languages, shown on the leader table, the board cards and the board header. Entrant names link to their Hugging Face profile.

Files changed (3) hide show
  1. app.py +14 -0
  2. board_meta.json +29 -0
  3. index.html +14 -3
app.py CHANGED
@@ -87,7 +87,17 @@ def _sha(path):
87
  return h.hexdigest()[:16]
88
 
89
 
 
 
 
 
 
 
 
 
 
90
  def _load_boards():
 
91
  out = {}
92
  for p in sorted(glob.glob(os.path.join(DATA, "*_card.json"))):
93
  try:
@@ -120,6 +130,9 @@ def _load_boards():
120
  d["beats_constant"] = base["Morgan+LightGBM"]["mae"] < base["μƒμˆ˜ 예츑"]["mae"]
121
  if d.get("n_test"):
122
  d["near_pct"] = round(100.0 * d.get("near_threshold", 0) / d["n_test"], 1)
 
 
 
123
  d["open"] = True
124
  out[d["board"]] = d
125
  return out
@@ -254,6 +267,7 @@ def api_leaders():
254
  nf = (b.get("noise_floor") or {}).get("sd_single")
255
  base = b.get("baselines") or {}
256
  row = {"board": name, "n_test": b.get("n_test"),
 
257
  "split_grade": b.get("split_grade"), "answer_grade": b.get("answer_grade"),
258
  "noise_floor": nf, "entries": len(ent),
259
  "baseline_best": (min((v["mae"] for v in base.values() if v.get("mae") is not None),
 
87
  return h.hexdigest()[:16]
88
 
89
 
90
+ def _board_meta():
91
+ """λΆ€λ¬Έ ν•œ 쀄 μ„€λͺ…. 이름과 ν‘œμ  κΈ°ν˜Έλ§ŒμœΌλ‘œλŠ” 무엇을 μž¬λŠ”μ§€ μ•Œ 수 μ—†λ‹€."""
92
+ p = os.path.join(HERE, "board_meta.json")
93
+ try:
94
+ return json.load(io.open(p, encoding="utf-8")).get("boards", {})
95
+ except Exception:
96
+ return {}
97
+
98
+
99
  def _load_boards():
100
+ meta = _board_meta()
101
  out = {}
102
  for p in sorted(glob.glob(os.path.join(DATA, "*_card.json"))):
103
  try:
 
130
  d["beats_constant"] = base["Morgan+LightGBM"]["mae"] < base["μƒμˆ˜ 예츑"]["mae"]
131
  if d.get("n_test"):
132
  d["near_pct"] = round(100.0 * d.get("near_threshold", 0) / d["n_test"], 1)
133
+ m = meta.get(d["board"]) or {}
134
+ d["blurb"] = m.get("ko", "")
135
+ d["blurb_en"] = m.get("en", "")
136
  d["open"] = True
137
  out[d["board"]] = d
138
  return out
 
267
  nf = (b.get("noise_floor") or {}).get("sd_single")
268
  base = b.get("baselines") or {}
269
  row = {"board": name, "n_test": b.get("n_test"),
270
+ "blurb": b.get("blurb"), "blurb_en": b.get("blurb_en"),
271
  "split_grade": b.get("split_grade"), "answer_grade": b.get("answer_grade"),
272
  "noise_floor": nf, "entries": len(ent),
273
  "baseline_best": (min((v["mae"] for v in base.values() if v.get("mae") is not None),
board_meta.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "note": "λΆ€λ¬Έ μ΄λ¦„λ§ŒμœΌλ‘œλŠ” 무엇을 μž¬λŠ”μ§€ μ•Œ 수 μ—†λ‹€. ν‘œμ  κΈ°ν˜ΈλŠ” 이 λΆ„μ•Ό μ‚¬λžŒμ—κ²Œλ§Œ μ½νžŒλ‹€.",
3
+ "boards": {
4
+ "hERG": {"ko": "심μž₯독성 β€” μΉΌλ₯¨μ±„널 차단", "en": "Cardiotoxicity β€” hERG channel block"},
5
+ "Solubility": {"ko": "μˆ˜μš©ν•΄λ„ β€” 물에 λ…ΉλŠ” 정도", "en": "Aqueous solubility"},
6
+ "Withdrawal": {"ko": "μ‹œνŒ ν›„ ν‡΄μΆœ νŒμ •", "en": "Post-marketing withdrawal"},
7
+ "Phenotype": {"ko": "세포 ν˜•νƒœ λ³€ν™” 예츑", "en": "Cell morphology response"},
8
+
9
+ "CYP3A4": {"ko": "λŒ€μ‚¬ μ €ν•΄ β€” μ•½λ¬Ό μƒν˜Έμž‘μš© μ΅œλŒ€ 원인", "en": "CYP3A4 inhibition β€” main cause of drug interaction"},
10
+ "CYP2D6": {"ko": "λŒ€μ‚¬ μ €ν•΄ β€” κ°œμΈμ°¨κ°€ 큰 νš¨μ†Œ", "en": "CYP2D6 inhibition β€” highly polymorphic enzyme"},
11
+ "CYP2C9": {"ko": "λŒ€μ‚¬ μ €ν•΄ β€” μ™€νŒŒλ¦° 계열", "en": "CYP2C9 inhibition β€” warfarin class"},
12
+
13
+ "EGFR": {"ko": "폐암 ν‘œμ  β€” 상피성μž₯인자 수용체", "en": "Lung cancer target β€” EGF receptor"},
14
+ "JAK2": {"ko": "κ³¨μˆ˜μ¦μ‹μ§ˆν™˜ ν‘œμ ", "en": "Myeloproliferative disease target"},
15
+ "PI3Ka": {"ko": "μ’…μ–‘ μ‹ ν˜Έμ „λ‹¬ ν‘œμ ", "en": "Tumour signalling target"},
16
+ "FLT3": {"ko": "κΈ‰μ„±κ³¨μˆ˜λ°±ν˜ˆλ³‘ ν‘œμ ", "en": "Acute myeloid leukaemia target"},
17
+ "VEGFR2": {"ko": "ν˜ˆκ΄€μ‹ μƒ ν‘œμ  β€” μ’…μ–‘ ν˜ˆκ΄€ 차단", "en": "Angiogenesis target"},
18
+ "CDK2": {"ko": "세포주기 ν‘œμ ", "en": "Cell cycle target"},
19
+ "HER2": {"ko": "μœ λ°©μ•” ν‘œμ ", "en": "Breast cancer target"},
20
+ "ABL1": {"ko": "λ§Œμ„±κ³¨μˆ˜λ°±ν˜ˆλ³‘ ν‘œμ ", "en": "Chronic myeloid leukaemia target"},
21
+ "BRAF": {"ko": "흑색쒅 ν‘œμ ", "en": "Melanoma target"},
22
+ "KIT": {"ko": "μœ„μž₯κ΄€κΈ°μ§ˆμ’…μ–‘ ν‘œμ ", "en": "GIST target"},
23
+ "ALK": {"ko": "폐암 μœ΅ν•© ν‘œμ ", "en": "Lung cancer fusion target"},
24
+
25
+ "AChE": {"ko": "μ•ŒμΈ ν•˜μ΄λ¨Έ ν‘œμ  β€” μ•„μ„Έν‹Έμ½œλ¦° λΆ„ν•΄νš¨μ†Œ", "en": "Alzheimer target β€” acetylcholinesterase"},
26
+ "MAOB": {"ko": "νŒŒν‚¨μŠ¨ ν‘œμ  β€” λͺ¨λ…Έμ•„λ―Ό μ‚°ν™”νš¨μ†Œ B", "en": "Parkinson target β€” monoamine oxidase B"},
27
+ "COX2": {"ko": "μ†Œμ—Όμ§„ν†΅ ν‘œμ ", "en": "Anti-inflammatory target"}
28
+ }
29
+ }
index.html CHANGED
@@ -173,6 +173,9 @@
173
  .rk.g3{background:#c9885526;color:#95612f}
174
  .gain{color:var(--good);font-weight:700}
175
  .loss{color:var(--bad);font-weight:700}
 
 
 
176
  .mini{display:inline-block;height:6px;border-radius:3px;background:var(--acc);opacity:.5;
177
  vertical-align:middle;margin-right:7px}
178
 
@@ -239,6 +242,10 @@ const $=s=>document.querySelector(s), app=$("#app");
239
  const f=(x,d=3)=>(x==null||isNaN(x))?"β€”":Number(x).toFixed(d);
240
  const esc=s=>String(s??"").replace(/[&<>"]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c]));
241
  const W=h=>`<div class="wrap">${h}</div>`;
 
 
 
 
242
  let CATS=null, ME={user:null}, BOARDS={}, L=null, t=null;
243
 
244
  /* μ–Έμ–΄ κ²°μ • μˆœμ„œ: μ €μž₯된 선택 β†’ λΈŒλΌμš°μ € μ„€μ • β†’ μ˜μ–΄.
@@ -290,6 +297,7 @@ function terrain(items,link){
290
  }
291
  /* λΆ„λ₯˜ μ „μš© 뢀문은 MAE 기쀀선이 μ—†λ‹€. 그런 뢀문을 0 으둜 μ²˜λ¦¬ν•˜λ©΄ μ§€ν˜•λ„ 맨 μ™Όμͺ½μ—
292
  λΆ™μ–΄ "μΈ‘μ • ν•œκ³„μ— λ„λ‹¬ν–ˆλ‹€"둜 보인닀. μž¬μ§€ λͺ»ν•œ 것과 μž¬μ„œ μž‘μ€ 것은 λ‹€λ₯΄λ―€λ‘œ λΉ„μš΄λ‹€. */
 
293
  const ratioOf=b=>{
294
  const nf=(b.noise_floor||{}).sd_single;
295
  const maes=Object.values(b.baselines||{}).map(v=>v.mae).filter(v=>v!=null);
@@ -408,9 +416,10 @@ async function paintLeaders(){
408
  }
409
  return `<tr>
410
  <td style="text-align:left"><a href="#/b/${encodeURIComponent(r.board)}">${esc(r.board)}</a>
411
- <span class="chip g" style="margin-left:6px">${r.split_grade}/${r.answer_grade}</span></td>
 
412
  <td style="text-align:left">${L?esc(L.method):`<span class="dim">${t.noLeader}</span>`}</td>
413
- <td style="text-align:left">${L?esc(L.user):"β€”"}</td>
414
  <td>${score!=null?f(score):"β€”"}</td>
415
  <td>${vs}</td>
416
  <td>${(r.n_test||0).toLocaleString()}</td></tr>`;}).join("");
@@ -459,6 +468,7 @@ function boardMini(b){
459
  const bl=b.baselines[b.best_baseline]||{};
460
  return `<a class="cc" href="#/b/${encodeURIComponent(b.board)}">
461
  <div class="nm">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></div>
 
462
  <div class="ds">${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} ${f((b.noise_floor||{}).sd_single)}<br>
463
  ${esc(b.best_baseline)} ${bl.mae!=null?f(bl.mae):f(bl.auroc)}</div>
464
  <div class="mt"><span>${esc(b.source)}</span><span>${ratioOf(b)==null?"β€”":f(ratioOf(b),2)+"Γ—"}</span></div></a>`;
@@ -473,6 +483,7 @@ async function board(name,tab){
473
  app.innerHTML=W(`
474
  <div class="crumb"><a href="#/">${t.all}</a> β€Ί <a href="#/c/${cat?cat.id:""}">${esc(cn)}</a> β€Ί ${esc(b.board)}</div>
475
  <h1 class="ttl">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></h1>
 
476
  <p class="lede">${esc(b.source)} Β· ${esc(b.type)} Β·
477
  ${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} <b>${f(b.noise_floor.sd_single)}</b></p>
478
  <div class="pills">${TT.map(([k,l])=>
@@ -495,7 +506,7 @@ async function paneRank(b){
495
  const w=Math.max(4,58*(r.mae||0)/worst);
496
  return `<tr class="${r.kind!=="entry"?"base":""}">
497
  <td>${r.rank?`<span class="rk${g}">${r.rank}</span>`:"Β·"}</td>
498
- <td>${esc(r.method)}</td><td>${esc(r.user)}</td>
499
  <td><span class="mini" style="width:${w}px"></span>${f(r.mae)}</td>
500
  <td>${f(r.auroc)}</td><td>${f(r.prauc)}</td>
501
  <td>${r.kind==="baseline"?`<span class="chip g">${t.baseline}</span>`:leak(r.leak)}</td>
 
173
  .rk.g3{background:#c9885526;color:#95612f}
174
  .gain{color:var(--good);font-weight:700}
175
  .loss{color:var(--bad);font-weight:700}
176
+ .sub2{font-size:11.5px;color:var(--muted);font-family:inherit;font-weight:400;margin-top:3px}
177
+ .cc .bl{font-size:12.5px;color:var(--acc);font-weight:600;margin:-1px 0 6px}
178
+ .blurbig{font-size:17px;color:var(--ink2);font-weight:600;margin:2px 0 8px}
179
  .mini{display:inline-block;height:6px;border-radius:3px;background:var(--acc);opacity:.5;
180
  vertical-align:middle;margin-right:7px}
181
 
 
242
  const f=(x,d=3)=>(x==null||isNaN(x))?"β€”":Number(x).toFixed(d);
243
  const esc=s=>String(s??"").replace(/[&<>"]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c]));
244
  const W=h=>`<div class="wrap">${h}</div>`;
245
+ /* μ œμΆœμžλŠ” ν—ˆκΉ…νŽ˜μ΄μŠ€ 계정이닀. μ΄λ¦„λ§Œ 적으면 λˆ„κ΅¬μΈμ§€ 확인할 길이 μ—†λ‹€. */
246
+ const hfUser=u=>u&&u!=="β€”"
247
+ ?`<a href="https://huggingface.co/${encodeURIComponent(u)}" target="_blank" rel="noopener">${esc(u)}</a>`
248
+ :"β€”";
249
  let CATS=null, ME={user:null}, BOARDS={}, L=null, t=null;
250
 
251
  /* μ–Έμ–΄ κ²°μ • μˆœμ„œ: μ €μž₯된 선택 β†’ λΈŒλΌμš°μ € μ„€μ • β†’ μ˜μ–΄.
 
297
  }
298
  /* λΆ„λ₯˜ μ „μš© 뢀문은 MAE 기쀀선이 μ—†λ‹€. 그런 뢀문을 0 으둜 μ²˜λ¦¬ν•˜λ©΄ μ§€ν˜•λ„ 맨 μ™Όμͺ½μ—
299
  λΆ™μ–΄ "μΈ‘μ • ν•œκ³„μ— λ„λ‹¬ν–ˆλ‹€"둜 보인닀. μž¬μ§€ λͺ»ν•œ 것과 μž¬μ„œ μž‘μ€ 것은 λ‹€λ₯΄λ―€λ‘œ λΉ„μš΄λ‹€. */
300
+ const blurb=b=>esc(L==="ko"?(b.blurb||""):(b.blurb_en||b.blurb||""));
301
  const ratioOf=b=>{
302
  const nf=(b.noise_floor||{}).sd_single;
303
  const maes=Object.values(b.baselines||{}).map(v=>v.mae).filter(v=>v!=null);
 
416
  }
417
  return `<tr>
418
  <td style="text-align:left"><a href="#/b/${encodeURIComponent(r.board)}">${esc(r.board)}</a>
419
+ <span class="chip g" style="margin-left:6px">${r.split_grade}/${r.answer_grade}</span>
420
+ <div class="sub2">${esc(L==="ko"?(r.blurb||""):(r.blurb_en||r.blurb||""))}</div></td>
421
  <td style="text-align:left">${L?esc(L.method):`<span class="dim">${t.noLeader}</span>`}</td>
422
+ <td style="text-align:left">${L?hfUser(L.user):"β€”"}</td>
423
  <td>${score!=null?f(score):"β€”"}</td>
424
  <td>${vs}</td>
425
  <td>${(r.n_test||0).toLocaleString()}</td></tr>`;}).join("");
 
468
  const bl=b.baselines[b.best_baseline]||{};
469
  return `<a class="cc" href="#/b/${encodeURIComponent(b.board)}">
470
  <div class="nm">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></div>
471
+ <div class="bl">${blurb(b)}</div>
472
  <div class="ds">${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} ${f((b.noise_floor||{}).sd_single)}<br>
473
  ${esc(b.best_baseline)} ${bl.mae!=null?f(bl.mae):f(bl.auroc)}</div>
474
  <div class="mt"><span>${esc(b.source)}</span><span>${ratioOf(b)==null?"β€”":f(ratioOf(b),2)+"Γ—"}</span></div></a>`;
 
483
  app.innerHTML=W(`
484
  <div class="crumb"><a href="#/">${t.all}</a> β€Ί <a href="#/c/${cat?cat.id:""}">${esc(cn)}</a> β€Ί ${esc(b.board)}</div>
485
  <h1 class="ttl">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></h1>
486
+ <p class="blurbig">${blurb(b)}</p>
487
  <p class="lede">${esc(b.source)} Β· ${esc(b.type)} Β·
488
  ${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} <b>${f(b.noise_floor.sd_single)}</b></p>
489
  <div class="pills">${TT.map(([k,l])=>
 
506
  const w=Math.max(4,58*(r.mae||0)/worst);
507
  return `<tr class="${r.kind!=="entry"?"base":""}">
508
  <td>${r.rank?`<span class="rk${g}">${r.rank}</span>`:"Β·"}</td>
509
+ <td>${esc(r.method)}</td><td>${r.kind==="entry"?hfUser(r.user):esc(r.user)}</td>
510
  <td><span class="mini" style="width:${w}px"></span>${f(r.mae)}</td>
511
  <td>${f(r.auroc)}</td><td>${f(r.prauc)}</td>
512
  <td>${r.kind==="baseline"?`<span class="chip g">${t.baseline}</span>`:leak(r.leak)}</td>