Update app.py
Browse files
app.py
CHANGED
|
@@ -18,9 +18,9 @@ DTYPE = torch.bfloat16 if torch.cuda.is_available() else torch.float32
|
|
| 18 |
base = AutoModelForCausalLM.from_pretrained(
|
| 19 |
BASE_MODEL,
|
| 20 |
torch_dtype=DTYPE,
|
| 21 |
-
device_map="cpu",
|
| 22 |
trust_remote_code=True,
|
| 23 |
-
low_cpu_mem_usage=False,
|
| 24 |
)
|
| 25 |
model = PeftModel.from_pretrained(
|
| 26 |
base,
|
|
@@ -79,6 +79,48 @@ SUBJECT_EXAMPLES = {
|
|
| 79 |
|
| 80 |
history_store = []
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
def generate_answer(question, opa, opb, opc, opd, temperature, max_tokens):
|
| 83 |
if not question.strip():
|
| 84 |
return "β οΈ Please enter a question.", "", "0.00s", str(query_count["total"])
|
|
@@ -112,15 +154,13 @@ def generate_answer(question, opa, opb, opc, opd, temperature, max_tokens):
|
|
| 112 |
|
| 113 |
query_count["total"] += 1
|
| 114 |
|
| 115 |
-
# Store in history
|
| 116 |
letter = result.strip()[0] if result.strip() else "?"
|
| 117 |
history_store.append({
|
| 118 |
-
"q":
|
| 119 |
-
"ans":
|
| 120 |
"time": f"{elapsed:.2f}s"
|
| 121 |
})
|
| 122 |
|
| 123 |
-
# Build confidence display
|
| 124 |
options_map = {"A": opa, "B": opb, "C": opc, "D": opd}
|
| 125 |
pred_letter = ""
|
| 126 |
for ch in result.upper():
|
|
@@ -143,7 +183,7 @@ def build_confidence(pred_letter, full_text):
|
|
| 143 |
for i, k in enumerate(others):
|
| 144 |
scores[k] = [remaining * 0.6, remaining * 0.25, remaining * 0.15][i] if i < 3 else 0
|
| 145 |
|
| 146 |
-
bars
|
| 147 |
colors = {"A": "#00c8f0", "B": "#00f0a0", "C": "#ff6030", "D": "#ffcc00"}
|
| 148 |
for letter in ["A", "B", "C", "D"]:
|
| 149 |
w = scores[letter]
|
|
@@ -180,8 +220,7 @@ def load_subject_examples(subject):
|
|
| 180 |
return gr.update(value=None)
|
| 181 |
examples = SUBJECT_EXAMPLES.get(subject, [])
|
| 182 |
if examples:
|
| 183 |
-
|
| 184 |
-
return gr.update(value=ex[0])
|
| 185 |
return gr.update(value=None)
|
| 186 |
|
| 187 |
|
|
@@ -214,8 +253,6 @@ body, .gradio-container {
|
|
| 214 |
margin: 0 auto !important;
|
| 215 |
padding: 0 20px 60px !important;
|
| 216 |
}
|
| 217 |
-
|
| 218 |
-
/* ββ Header ββ */
|
| 219 |
#header {
|
| 220 |
padding: 44px 0 28px;
|
| 221 |
border-bottom: 1px solid var(--border);
|
|
@@ -237,7 +274,6 @@ body, .gradio-container {
|
|
| 237 |
.b-rocm { color: var(--accent); border-color: #00c8f030; background: #00c8f008; }
|
| 238 |
.b-lora { color: var(--green); border-color: #00f0a030; background: #00f0a008; }
|
| 239 |
.b-live { color: #ffcc00; border-color: #ffcc0030; background: #ffcc0008; }
|
| 240 |
-
|
| 241 |
h1#title {
|
| 242 |
font-family: 'Syne', sans-serif !important;
|
| 243 |
font-size: 42px !important; font-weight: 800 !important;
|
|
@@ -246,8 +282,6 @@ h1#title {
|
|
| 246 |
}
|
| 247 |
h1#title em { color: var(--accent); font-style: normal; }
|
| 248 |
.subtitle { font-size: 14px; color: var(--muted); font-weight: 300; line-height: 1.6; max-width: 600px; }
|
| 249 |
-
|
| 250 |
-
/* ββ Stats ββ */
|
| 251 |
#stats {
|
| 252 |
display: flex; border: 1px solid var(--border);
|
| 253 |
border-radius: 12px; overflow: hidden;
|
|
@@ -259,8 +293,6 @@ h1#title em { color: var(--accent); font-style: normal; }
|
|
| 259 |
.sl { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
|
| 260 |
.dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--green); margin-right: 4px; animation: blink 2s infinite; }
|
| 261 |
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
| 262 |
-
|
| 263 |
-
/* ββ Inputs ββ */
|
| 264 |
label span, .label-wrap span {
|
| 265 |
font-family: 'DM Sans', sans-serif !important;
|
| 266 |
font-size: 11px !important; font-weight: 500 !important;
|
|
@@ -279,8 +311,6 @@ textarea:focus, input[type=text]:focus {
|
|
| 279 |
border-color: var(--accent) !important;
|
| 280 |
box-shadow: 0 0 0 3px #00c8f012 !important; outline: none !important;
|
| 281 |
}
|
| 282 |
-
|
| 283 |
-
/* ββ Section labels ββ */
|
| 284 |
.section-label {
|
| 285 |
font-size: 10px; font-weight: 600; letter-spacing: 0.12em;
|
| 286 |
text-transform: uppercase; color: var(--muted); margin-bottom: 10px;
|
|
@@ -290,11 +320,8 @@ textarea:focus, input[type=text]:focus {
|
|
| 290 |
content: ''; width: 5px; height: 5px; border-radius: 50%;
|
| 291 |
background: var(--accent); display: inline-block;
|
| 292 |
}
|
| 293 |
-
|
| 294 |
-
/* ββ Tabs ββ */
|
| 295 |
.tab-nav button {
|
| 296 |
-
background: transparent !important;
|
| 297 |
-
color: var(--muted) !important;
|
| 298 |
border: none !important; border-bottom: 2px solid transparent !important;
|
| 299 |
font-family: 'DM Sans', sans-serif !important;
|
| 300 |
font-size: 13px !important; font-weight: 500 !important;
|
|
@@ -305,8 +332,6 @@ textarea:focus, input[type=text]:focus {
|
|
| 305 |
color: var(--accent) !important;
|
| 306 |
border-bottom-color: var(--accent) !important;
|
| 307 |
}
|
| 308 |
-
|
| 309 |
-
/* ββ Buttons ββ */
|
| 310 |
button.lg.primary {
|
| 311 |
background: linear-gradient(135deg, var(--accent2), var(--accent)) !important;
|
| 312 |
border: none !important; border-radius: 10px !important;
|
|
@@ -317,7 +342,6 @@ button.lg.primary {
|
|
| 317 |
transition: opacity 0.2s, transform 0.15s !important;
|
| 318 |
}
|
| 319 |
button.lg.primary:hover { opacity: 0.85 !important; transform: translateY(-1px) !important; }
|
| 320 |
-
|
| 321 |
button.lg.secondary {
|
| 322 |
background: var(--surface2) !important;
|
| 323 |
border: 1px solid var(--border) !important;
|
|
@@ -328,8 +352,20 @@ button.lg.secondary {
|
|
| 328 |
transition: border-color 0.2s !important;
|
| 329 |
}
|
| 330 |
button.lg.secondary:hover { border-color: var(--accent) !important; color: var(--accent) !important; }
|
| 331 |
-
|
| 332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
.out-box textarea {
|
| 334 |
background: var(--surface2) !important;
|
| 335 |
border: 1px solid var(--border) !important;
|
|
@@ -337,15 +373,8 @@ button.lg.secondary:hover { border-color: var(--accent) !important; color: var(-
|
|
| 337 |
line-height: 1.8 !important; color: var(--text) !important;
|
| 338 |
min-height: 220px !important;
|
| 339 |
}
|
| 340 |
-
|
| 341 |
-
/* ββ Sliders ββ */
|
| 342 |
input[type=range] { accent-color: var(--accent) !important; }
|
| 343 |
-
|
| 344 |
-
/* ββ Dropdowns ββ */
|
| 345 |
.wrap-inner { background: var(--surface2) !important; border-color: var(--border) !important; }
|
| 346 |
-
.svelte-1gfkn6j { background: var(--surface) !important; color: var(--text) !important; }
|
| 347 |
-
|
| 348 |
-
/* ββ Examples ββ */
|
| 349 |
.examples-holder table {
|
| 350 |
background: var(--surface) !important;
|
| 351 |
border: 1px solid var(--border) !important;
|
|
@@ -357,14 +386,6 @@ input[type=range] { accent-color: var(--accent) !important; }
|
|
| 357 |
font-family: 'DM Sans', sans-serif !important;
|
| 358 |
}
|
| 359 |
.examples-holder tr:hover td { background: var(--surface2) !important; cursor: pointer; }
|
| 360 |
-
|
| 361 |
-
/* ββ Info cards ββ */
|
| 362 |
-
.info-card {
|
| 363 |
-
background: var(--surface); border: 1px solid var(--border);
|
| 364 |
-
border-radius: 12px; padding: 16px;
|
| 365 |
-
}
|
| 366 |
-
|
| 367 |
-
/* ββ Footer ββ */
|
| 368 |
#footer {
|
| 369 |
margin-top: 44px; padding-top: 22px;
|
| 370 |
border-top: 1px solid var(--border);
|
|
@@ -379,7 +400,6 @@ input[type=range] { accent-color: var(--accent) !important; }
|
|
| 379 |
|
| 380 |
with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
| 381 |
|
| 382 |
-
# ββ Header ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 383 |
gr.HTML("""
|
| 384 |
<div id="header">
|
| 385 |
<div class="badges">
|
|
@@ -404,14 +424,11 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 404 |
</div>
|
| 405 |
""")
|
| 406 |
|
| 407 |
-
# ββ Main Tabs βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 408 |
with gr.Tabs():
|
| 409 |
|
| 410 |
-
# ββ TAB 1: Ask a Question βββββββββββββββββββββββββββββββββββββββββββββ
|
| 411 |
with gr.Tab("Ask a Question"):
|
| 412 |
with gr.Row():
|
| 413 |
|
| 414 |
-
# Left column β inputs
|
| 415 |
with gr.Column(scale=5):
|
| 416 |
gr.HTML('<div class="section-label">Clinical Question</div>')
|
| 417 |
question = gr.Textbox(
|
|
@@ -419,19 +436,27 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 419 |
placeholder="e.g. A 45-year-old presents with sudden onset severe headache and neck stiffness...",
|
| 420 |
lines=4,
|
| 421 |
)
|
| 422 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 423 |
with gr.Row():
|
| 424 |
-
opa = gr.Textbox(label="Option A", placeholder="
|
| 425 |
-
opb = gr.Textbox(label="Option B", placeholder="
|
| 426 |
with gr.Row():
|
| 427 |
-
opc = gr.Textbox(label="Option C", placeholder="
|
| 428 |
-
opd = gr.Textbox(label="Option D", placeholder="
|
| 429 |
|
| 430 |
with gr.Row():
|
| 431 |
btn = gr.Button("β Analyze Question", variant="primary")
|
| 432 |
clr_btn = gr.Button("β Clear", variant="secondary")
|
| 433 |
|
| 434 |
-
# Settings accordion
|
| 435 |
with gr.Accordion("β Generation Settings", open=False):
|
| 436 |
temperature = gr.Slider(
|
| 437 |
minimum=0.1, maximum=1.5, value=0.7, step=0.05,
|
|
@@ -447,16 +472,15 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 447 |
Higher = more creative explanations.
|
| 448 |
</p>""")
|
| 449 |
|
| 450 |
-
# Right column β outputs
|
| 451 |
with gr.Column(scale=5):
|
| 452 |
gr.HTML('<div class="section-label">AI Answer & Reasoning</div>')
|
| 453 |
-
# AFTER β works on Gradio 6
|
| 454 |
output = gr.Textbox(
|
| 455 |
label="",
|
| 456 |
placeholder="Answer and clinical explanation will appear here...",
|
| 457 |
lines=10,
|
| 458 |
elem_classes=["out-box"],
|
| 459 |
-
|
|
|
|
| 460 |
|
| 461 |
gr.HTML('<div class="section-label" style="margin-top:16px">Answer Confidence</div>')
|
| 462 |
confidence = gr.HTML(
|
|
@@ -465,24 +489,22 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 465 |
|
| 466 |
with gr.Row():
|
| 467 |
inf_time = gr.Textbox(label="Inference Time", value="β", interactive=False, scale=1)
|
| 468 |
-
query_disp = gr.Textbox(label="Total Queries",
|
| 469 |
|
| 470 |
-
# ββ Examples ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 471 |
gr.HTML('<div class="section-label" style="margin-top:24px">Browse by Subject</div>')
|
| 472 |
with gr.Row():
|
| 473 |
subject_dd = gr.Dropdown(
|
| 474 |
choices=SUBJECTS, value="All Subjects", label="Filter by subject", scale=2
|
| 475 |
)
|
| 476 |
-
gr.HTML('<div style="flex:5"></div>')
|
| 477 |
|
| 478 |
gr.HTML('<div class="section-label" style="margin-top:12px">Sample Questions β click any to load</div>')
|
| 479 |
gr.Examples(
|
| 480 |
examples=EXAMPLES,
|
| 481 |
inputs=[question, opa, opb, opc, opd],
|
| 482 |
label="",
|
|
|
|
| 483 |
)
|
| 484 |
|
| 485 |
-
# ββ TAB 2: History ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 486 |
with gr.Tab("Query History"):
|
| 487 |
gr.HTML('<div class="section-label">Recent Queries</div>')
|
| 488 |
history_html = gr.HTML(
|
|
@@ -490,11 +512,9 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 490 |
)
|
| 491 |
refresh_btn = gr.Button("β» Refresh History", variant="secondary")
|
| 492 |
|
| 493 |
-
# ββ TAB 3: About ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 494 |
with gr.Tab("About"):
|
| 495 |
gr.HTML("""
|
| 496 |
<div style="max-width:800px;margin:0 auto;padding:24px 0;">
|
| 497 |
-
|
| 498 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:16px;padding:28px;margin-bottom:20px;">
|
| 499 |
<h2 style="font-family:'Syne',sans-serif;color:#deeeff;font-size:22px;margin-bottom:16px;">What is MedQA?</h2>
|
| 500 |
<p style="color:#4a6080;font-size:14px;line-height:1.8;">
|
|
@@ -504,33 +524,26 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 504 |
the clinical reasoning.
|
| 505 |
</p>
|
| 506 |
</div>
|
| 507 |
-
|
| 508 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px;">
|
| 509 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 510 |
<h3 style="color:#00c8f0;font-size:14px;margin-bottom:12px;">MODEL</h3>
|
| 511 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 512 |
-
Base: Qwen3-1.7B<br>
|
| 513 |
-
|
| 514 |
-
Trainable: 2.2M / 1.7B params<br>
|
| 515 |
-
Precision: bfloat16
|
| 516 |
</p>
|
| 517 |
</div>
|
| 518 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 519 |
<h3 style="color:#00f0a0;font-size:14px;margin-bottom:12px;">HARDWARE</h3>
|
| 520 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 521 |
-
AMD Instinct MI300X<br>
|
| 522 |
-
|
| 523 |
-
ROCm 7.2 on Ubuntu 24.04<br>
|
| 524 |
-
No CUDA required
|
| 525 |
</p>
|
| 526 |
</div>
|
| 527 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 528 |
<h3 style="color:#ff6030;font-size:14px;margin-bottom:12px;">TRAINING</h3>
|
| 529 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 530 |
-
Dataset: MedMCQA (500 samples)<br>
|
| 531 |
-
|
| 532 |
-
Optimizer: AdamW<br>
|
| 533 |
-
Scheduler: Constant + warmup
|
| 534 |
</p>
|
| 535 |
</div>
|
| 536 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
|
@@ -543,7 +556,6 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 543 |
</p>
|
| 544 |
</div>
|
| 545 |
</div>
|
| 546 |
-
|
| 547 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 548 |
<h3 style="color:#deeeff;font-size:14px;margin-bottom:12px;">BUILT BY</h3>
|
| 549 |
<p style="color:#4a6080;font-size:13px;">
|
|
@@ -551,11 +563,9 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 551 |
AMD Hackathon 2025 on lablab.ai
|
| 552 |
</p>
|
| 553 |
</div>
|
| 554 |
-
|
| 555 |
</div>
|
| 556 |
""")
|
| 557 |
|
| 558 |
-
# ββ Footer ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 559 |
gr.HTML("""
|
| 560 |
<div id="footer">
|
| 561 |
<div class="fl">
|
|
@@ -572,6 +582,12 @@ with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
|
| 572 |
""")
|
| 573 |
|
| 574 |
# ββ Events ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
btn.click(
|
| 576 |
fn=generate_answer,
|
| 577 |
inputs=[question, opa, opb, opc, opd, temperature, max_tokens],
|
|
|
|
| 18 |
base = AutoModelForCausalLM.from_pretrained(
|
| 19 |
BASE_MODEL,
|
| 20 |
torch_dtype=DTYPE,
|
| 21 |
+
device_map="cpu",
|
| 22 |
trust_remote_code=True,
|
| 23 |
+
low_cpu_mem_usage=False,
|
| 24 |
)
|
| 25 |
model = PeftModel.from_pretrained(
|
| 26 |
base,
|
|
|
|
| 79 |
|
| 80 |
history_store = []
|
| 81 |
|
| 82 |
+
|
| 83 |
+
def autogenerate_options(question):
|
| 84 |
+
if not question.strip():
|
| 85 |
+
return "", "", "", ""
|
| 86 |
+
|
| 87 |
+
prompt = (
|
| 88 |
+
f"Generate exactly 4 multiple choice options for this medical question. "
|
| 89 |
+
f"One must be correct, three must be plausible but wrong.\n"
|
| 90 |
+
f"Question: {question}\n\n"
|
| 91 |
+
f"Reply ONLY in this exact format, nothing else:\n"
|
| 92 |
+
f"A) <option>\n"
|
| 93 |
+
f"B) <option>\n"
|
| 94 |
+
f"C) <option>\n"
|
| 95 |
+
f"D) <option>"
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
| 99 |
+
with torch.no_grad():
|
| 100 |
+
out = model.generate(
|
| 101 |
+
**inputs,
|
| 102 |
+
max_new_tokens=120,
|
| 103 |
+
do_sample=True,
|
| 104 |
+
temperature=0.8,
|
| 105 |
+
top_p=0.9,
|
| 106 |
+
repetition_penalty=1.2,
|
| 107 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 108 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 109 |
+
)
|
| 110 |
+
new = out[0][inputs["input_ids"].shape[-1]:]
|
| 111 |
+
result = tokenizer.decode(new, skip_special_tokens=True).strip()
|
| 112 |
+
|
| 113 |
+
lines = result.split("\n")
|
| 114 |
+
opts = {"A": "", "B": "", "C": "", "D": ""}
|
| 115 |
+
for line in lines:
|
| 116 |
+
line = line.strip()
|
| 117 |
+
for letter in ["A", "B", "C", "D"]:
|
| 118 |
+
if line.upper().startswith(f"{letter})"):
|
| 119 |
+
opts[letter] = line[2:].strip()
|
| 120 |
+
|
| 121 |
+
return opts["A"], opts["B"], opts["C"], opts["D"]
|
| 122 |
+
|
| 123 |
+
|
| 124 |
def generate_answer(question, opa, opb, opc, opd, temperature, max_tokens):
|
| 125 |
if not question.strip():
|
| 126 |
return "β οΈ Please enter a question.", "", "0.00s", str(query_count["total"])
|
|
|
|
| 154 |
|
| 155 |
query_count["total"] += 1
|
| 156 |
|
|
|
|
| 157 |
letter = result.strip()[0] if result.strip() else "?"
|
| 158 |
history_store.append({
|
| 159 |
+
"q": question[:60] + "..." if len(question) > 60 else question,
|
| 160 |
+
"ans": letter,
|
| 161 |
"time": f"{elapsed:.2f}s"
|
| 162 |
})
|
| 163 |
|
|
|
|
| 164 |
options_map = {"A": opa, "B": opb, "C": opc, "D": opd}
|
| 165 |
pred_letter = ""
|
| 166 |
for ch in result.upper():
|
|
|
|
| 183 |
for i, k in enumerate(others):
|
| 184 |
scores[k] = [remaining * 0.6, remaining * 0.25, remaining * 0.15][i] if i < 3 else 0
|
| 185 |
|
| 186 |
+
bars = ""
|
| 187 |
colors = {"A": "#00c8f0", "B": "#00f0a0", "C": "#ff6030", "D": "#ffcc00"}
|
| 188 |
for letter in ["A", "B", "C", "D"]:
|
| 189 |
w = scores[letter]
|
|
|
|
| 220 |
return gr.update(value=None)
|
| 221 |
examples = SUBJECT_EXAMPLES.get(subject, [])
|
| 222 |
if examples:
|
| 223 |
+
return gr.update(value=examples[0][0])
|
|
|
|
| 224 |
return gr.update(value=None)
|
| 225 |
|
| 226 |
|
|
|
|
| 253 |
margin: 0 auto !important;
|
| 254 |
padding: 0 20px 60px !important;
|
| 255 |
}
|
|
|
|
|
|
|
| 256 |
#header {
|
| 257 |
padding: 44px 0 28px;
|
| 258 |
border-bottom: 1px solid var(--border);
|
|
|
|
| 274 |
.b-rocm { color: var(--accent); border-color: #00c8f030; background: #00c8f008; }
|
| 275 |
.b-lora { color: var(--green); border-color: #00f0a030; background: #00f0a008; }
|
| 276 |
.b-live { color: #ffcc00; border-color: #ffcc0030; background: #ffcc0008; }
|
|
|
|
| 277 |
h1#title {
|
| 278 |
font-family: 'Syne', sans-serif !important;
|
| 279 |
font-size: 42px !important; font-weight: 800 !important;
|
|
|
|
| 282 |
}
|
| 283 |
h1#title em { color: var(--accent); font-style: normal; }
|
| 284 |
.subtitle { font-size: 14px; color: var(--muted); font-weight: 300; line-height: 1.6; max-width: 600px; }
|
|
|
|
|
|
|
| 285 |
#stats {
|
| 286 |
display: flex; border: 1px solid var(--border);
|
| 287 |
border-radius: 12px; overflow: hidden;
|
|
|
|
| 293 |
.sl { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
|
| 294 |
.dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--green); margin-right: 4px; animation: blink 2s infinite; }
|
| 295 |
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
|
|
|
|
|
|
| 296 |
label span, .label-wrap span {
|
| 297 |
font-family: 'DM Sans', sans-serif !important;
|
| 298 |
font-size: 11px !important; font-weight: 500 !important;
|
|
|
|
| 311 |
border-color: var(--accent) !important;
|
| 312 |
box-shadow: 0 0 0 3px #00c8f012 !important; outline: none !important;
|
| 313 |
}
|
|
|
|
|
|
|
| 314 |
.section-label {
|
| 315 |
font-size: 10px; font-weight: 600; letter-spacing: 0.12em;
|
| 316 |
text-transform: uppercase; color: var(--muted); margin-bottom: 10px;
|
|
|
|
| 320 |
content: ''; width: 5px; height: 5px; border-radius: 50%;
|
| 321 |
background: var(--accent); display: inline-block;
|
| 322 |
}
|
|
|
|
|
|
|
| 323 |
.tab-nav button {
|
| 324 |
+
background: transparent !important; color: var(--muted) !important;
|
|
|
|
| 325 |
border: none !important; border-bottom: 2px solid transparent !important;
|
| 326 |
font-family: 'DM Sans', sans-serif !important;
|
| 327 |
font-size: 13px !important; font-weight: 500 !important;
|
|
|
|
| 332 |
color: var(--accent) !important;
|
| 333 |
border-bottom-color: var(--accent) !important;
|
| 334 |
}
|
|
|
|
|
|
|
| 335 |
button.lg.primary {
|
| 336 |
background: linear-gradient(135deg, var(--accent2), var(--accent)) !important;
|
| 337 |
border: none !important; border-radius: 10px !important;
|
|
|
|
| 342 |
transition: opacity 0.2s, transform 0.15s !important;
|
| 343 |
}
|
| 344 |
button.lg.primary:hover { opacity: 0.85 !important; transform: translateY(-1px) !important; }
|
|
|
|
| 345 |
button.lg.secondary {
|
| 346 |
background: var(--surface2) !important;
|
| 347 |
border: 1px solid var(--border) !important;
|
|
|
|
| 352 |
transition: border-color 0.2s !important;
|
| 353 |
}
|
| 354 |
button.lg.secondary:hover { border-color: var(--accent) !important; color: var(--accent) !important; }
|
| 355 |
+
.auto-btn button {
|
| 356 |
+
background: linear-gradient(135deg, #1a0055, #0055ff44) !important;
|
| 357 |
+
border: 1px solid var(--accent2) !important;
|
| 358 |
+
border-radius: 10px !important; color: var(--accent) !important;
|
| 359 |
+
font-family: 'DM Sans', sans-serif !important;
|
| 360 |
+
font-size: 13px !important; font-weight: 600 !important;
|
| 361 |
+
padding: 10px !important; width: 100% !important;
|
| 362 |
+
cursor: pointer !important; letter-spacing: 0.04em !important;
|
| 363 |
+
transition: opacity 0.2s, box-shadow 0.2s !important;
|
| 364 |
+
}
|
| 365 |
+
.auto-btn button:hover {
|
| 366 |
+
box-shadow: 0 0 12px #0055ff44 !important;
|
| 367 |
+
opacity: 0.9 !important;
|
| 368 |
+
}
|
| 369 |
.out-box textarea {
|
| 370 |
background: var(--surface2) !important;
|
| 371 |
border: 1px solid var(--border) !important;
|
|
|
|
| 373 |
line-height: 1.8 !important; color: var(--text) !important;
|
| 374 |
min-height: 220px !important;
|
| 375 |
}
|
|
|
|
|
|
|
| 376 |
input[type=range] { accent-color: var(--accent) !important; }
|
|
|
|
|
|
|
| 377 |
.wrap-inner { background: var(--surface2) !important; border-color: var(--border) !important; }
|
|
|
|
|
|
|
|
|
|
| 378 |
.examples-holder table {
|
| 379 |
background: var(--surface) !important;
|
| 380 |
border: 1px solid var(--border) !important;
|
|
|
|
| 386 |
font-family: 'DM Sans', sans-serif !important;
|
| 387 |
}
|
| 388 |
.examples-holder tr:hover td { background: var(--surface2) !important; cursor: pointer; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
#footer {
|
| 390 |
margin-top: 44px; padding-top: 22px;
|
| 391 |
border-top: 1px solid var(--border);
|
|
|
|
| 400 |
|
| 401 |
with gr.Blocks(css=CSS, title="MedQA β AMD ROCm") as demo:
|
| 402 |
|
|
|
|
| 403 |
gr.HTML("""
|
| 404 |
<div id="header">
|
| 405 |
<div class="badges">
|
|
|
|
| 424 |
</div>
|
| 425 |
""")
|
| 426 |
|
|
|
|
| 427 |
with gr.Tabs():
|
| 428 |
|
|
|
|
| 429 |
with gr.Tab("Ask a Question"):
|
| 430 |
with gr.Row():
|
| 431 |
|
|
|
|
| 432 |
with gr.Column(scale=5):
|
| 433 |
gr.HTML('<div class="section-label">Clinical Question</div>')
|
| 434 |
question = gr.Textbox(
|
|
|
|
| 436 |
placeholder="e.g. A 45-year-old presents with sudden onset severe headache and neck stiffness...",
|
| 437 |
lines=4,
|
| 438 |
)
|
| 439 |
+
|
| 440 |
+
auto_btn = gr.Button(
|
| 441 |
+
"β¨ Auto-generate Options A B C D from Question",
|
| 442 |
+
variant="secondary",
|
| 443 |
+
elem_classes=["auto-btn"],
|
| 444 |
+
)
|
| 445 |
+
gr.HTML("<p style='font-size:11px;color:#4a6080;margin-bottom:10px;'>"
|
| 446 |
+
"Type your question above then click to auto-fill all 4 options using AI.</p>")
|
| 447 |
+
|
| 448 |
+
gr.HTML('<div class="section-label">Answer Options</div>')
|
| 449 |
with gr.Row():
|
| 450 |
+
opa = gr.Textbox(label="Option A", placeholder="Auto-generated or type manually")
|
| 451 |
+
opb = gr.Textbox(label="Option B", placeholder="Auto-generated or type manually")
|
| 452 |
with gr.Row():
|
| 453 |
+
opc = gr.Textbox(label="Option C", placeholder="Auto-generated or type manually")
|
| 454 |
+
opd = gr.Textbox(label="Option D", placeholder="Auto-generated or type manually")
|
| 455 |
|
| 456 |
with gr.Row():
|
| 457 |
btn = gr.Button("β Analyze Question", variant="primary")
|
| 458 |
clr_btn = gr.Button("β Clear", variant="secondary")
|
| 459 |
|
|
|
|
| 460 |
with gr.Accordion("β Generation Settings", open=False):
|
| 461 |
temperature = gr.Slider(
|
| 462 |
minimum=0.1, maximum=1.5, value=0.7, step=0.05,
|
|
|
|
| 472 |
Higher = more creative explanations.
|
| 473 |
</p>""")
|
| 474 |
|
|
|
|
| 475 |
with gr.Column(scale=5):
|
| 476 |
gr.HTML('<div class="section-label">AI Answer & Reasoning</div>')
|
|
|
|
| 477 |
output = gr.Textbox(
|
| 478 |
label="",
|
| 479 |
placeholder="Answer and clinical explanation will appear here...",
|
| 480 |
lines=10,
|
| 481 |
elem_classes=["out-box"],
|
| 482 |
+
show_copy_button=True,
|
| 483 |
+
)
|
| 484 |
|
| 485 |
gr.HTML('<div class="section-label" style="margin-top:16px">Answer Confidence</div>')
|
| 486 |
confidence = gr.HTML(
|
|
|
|
| 489 |
|
| 490 |
with gr.Row():
|
| 491 |
inf_time = gr.Textbox(label="Inference Time", value="β", interactive=False, scale=1)
|
| 492 |
+
query_disp = gr.Textbox(label="Total Queries", value="0", interactive=False, scale=1)
|
| 493 |
|
|
|
|
| 494 |
gr.HTML('<div class="section-label" style="margin-top:24px">Browse by Subject</div>')
|
| 495 |
with gr.Row():
|
| 496 |
subject_dd = gr.Dropdown(
|
| 497 |
choices=SUBJECTS, value="All Subjects", label="Filter by subject", scale=2
|
| 498 |
)
|
|
|
|
| 499 |
|
| 500 |
gr.HTML('<div class="section-label" style="margin-top:12px">Sample Questions β click any to load</div>')
|
| 501 |
gr.Examples(
|
| 502 |
examples=EXAMPLES,
|
| 503 |
inputs=[question, opa, opb, opc, opd],
|
| 504 |
label="",
|
| 505 |
+
elem_classes=["examples-holder"],
|
| 506 |
)
|
| 507 |
|
|
|
|
| 508 |
with gr.Tab("Query History"):
|
| 509 |
gr.HTML('<div class="section-label">Recent Queries</div>')
|
| 510 |
history_html = gr.HTML(
|
|
|
|
| 512 |
)
|
| 513 |
refresh_btn = gr.Button("β» Refresh History", variant="secondary")
|
| 514 |
|
|
|
|
| 515 |
with gr.Tab("About"):
|
| 516 |
gr.HTML("""
|
| 517 |
<div style="max-width:800px;margin:0 auto;padding:24px 0;">
|
|
|
|
| 518 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:16px;padding:28px;margin-bottom:20px;">
|
| 519 |
<h2 style="font-family:'Syne',sans-serif;color:#deeeff;font-size:22px;margin-bottom:16px;">What is MedQA?</h2>
|
| 520 |
<p style="color:#4a6080;font-size:14px;line-height:1.8;">
|
|
|
|
| 524 |
the clinical reasoning.
|
| 525 |
</p>
|
| 526 |
</div>
|
|
|
|
| 527 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px;">
|
| 528 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 529 |
<h3 style="color:#00c8f0;font-size:14px;margin-bottom:12px;">MODEL</h3>
|
| 530 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 531 |
+
Base: Qwen3-1.7B<br>Fine-tuning: LoRA (r=4)<br>
|
| 532 |
+
Trainable: 2.2M / 1.7B params<br>Precision: bfloat16
|
|
|
|
|
|
|
| 533 |
</p>
|
| 534 |
</div>
|
| 535 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 536 |
<h3 style="color:#00f0a0;font-size:14px;margin-bottom:12px;">HARDWARE</h3>
|
| 537 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 538 |
+
AMD Instinct MI300X<br>192GB HBM3 memory<br>
|
| 539 |
+
ROCm 7.2 on Ubuntu 24.04<br>No CUDA required
|
|
|
|
|
|
|
| 540 |
</p>
|
| 541 |
</div>
|
| 542 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 543 |
<h3 style="color:#ff6030;font-size:14px;margin-bottom:12px;">TRAINING</h3>
|
| 544 |
<p style="color:#4a6080;font-size:13px;line-height:1.8;">
|
| 545 |
+
Dataset: MedMCQA (500 samples)<br>Time: ~5 minutes on MI300X<br>
|
| 546 |
+
Optimizer: AdamW<br>Scheduler: Constant + warmup
|
|
|
|
|
|
|
| 547 |
</p>
|
| 548 |
</div>
|
| 549 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
|
|
|
| 556 |
</p>
|
| 557 |
</div>
|
| 558 |
</div>
|
|
|
|
| 559 |
<div style="background:#0f1624;border:1px solid #1a3356;border-radius:12px;padding:20px;">
|
| 560 |
<h3 style="color:#deeeff;font-size:14px;margin-bottom:12px;">BUILT BY</h3>
|
| 561 |
<p style="color:#4a6080;font-size:13px;">
|
|
|
|
| 563 |
AMD Hackathon 2025 on lablab.ai
|
| 564 |
</p>
|
| 565 |
</div>
|
|
|
|
| 566 |
</div>
|
| 567 |
""")
|
| 568 |
|
|
|
|
| 569 |
gr.HTML("""
|
| 570 |
<div id="footer">
|
| 571 |
<div class="fl">
|
|
|
|
| 582 |
""")
|
| 583 |
|
| 584 |
# ββ Events ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 585 |
+
auto_btn.click(
|
| 586 |
+
fn=autogenerate_options,
|
| 587 |
+
inputs=[question],
|
| 588 |
+
outputs=[opa, opb, opc, opd],
|
| 589 |
+
)
|
| 590 |
+
|
| 591 |
btn.click(
|
| 592 |
fn=generate_answer,
|
| 593 |
inputs=[question, opa, opb, opc, opd, temperature, max_tokens],
|