Spaces:
Sleeping
Sleeping
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import numpy as np
|
| 3 |
import torch
|
|
|
|
| 4 |
from transformers import AutoTokenizer, AutoModelForMultipleChoice
|
| 5 |
|
| 6 |
# ── Config ──────────────────────────────────────────────────────────────────
|
| 7 |
HF_MODEL_REPO = "Shitanshu06/mcq-deberta-v3-best-v2"
|
| 8 |
OPTION_LABELS = ["A", "B", "C", "D", "E"]
|
| 9 |
-
MAX_LENGTH =
|
| 10 |
|
| 11 |
# ── Model loader (cached globally) ──────────────────────────────────────────
|
| 12 |
_model = None
|
|
@@ -14,98 +15,42 @@ _tokenizer = None
|
|
| 14 |
_device = None
|
| 15 |
|
| 16 |
|
| 17 |
-
def load_model():
|
| 18 |
global _model, _tokenizer, _device
|
| 19 |
-
if _model is None:
|
| 20 |
_device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
|
|
| 21 |
_tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_REPO)
|
| 22 |
_model = AutoModelForMultipleChoice.from_pretrained(HF_MODEL_REPO)
|
| 23 |
_model.to(_device)
|
| 24 |
_model.eval()
|
|
|
|
| 25 |
return _model, _tokenizer, _device
|
| 26 |
|
| 27 |
|
| 28 |
-
# ── Example Questions ────────────────────────────────────────────────────────
|
| 29 |
-
EXAMPLES = [
|
| 30 |
-
{
|
| 31 |
-
"label": "🔬 Biology — Cell Organelle",
|
| 32 |
-
"question": "Which organelle is responsible for producing energy in the form of ATP through cellular respiration?",
|
| 33 |
-
"A": "Nucleus",
|
| 34 |
-
"B": "Ribosome",
|
| 35 |
-
"C": "Mitochondria",
|
| 36 |
-
"D": "Golgi apparatus",
|
| 37 |
-
"E": "Endoplasmic reticulum",
|
| 38 |
-
},
|
| 39 |
-
{
|
| 40 |
-
"label": "🧪 Chemistry — Periodic Table",
|
| 41 |
-
"question": "Which element has the highest electronegativity on the Pauling scale?",
|
| 42 |
-
"A": "Oxygen",
|
| 43 |
-
"B": "Chlorine",
|
| 44 |
-
"C": "Nitrogen",
|
| 45 |
-
"D": "Fluorine",
|
| 46 |
-
"E": "Bromine",
|
| 47 |
-
},
|
| 48 |
-
{
|
| 49 |
-
"label": "📐 Mathematics — Calculus",
|
| 50 |
-
"question": "What is the derivative of sin(x) with respect to x?",
|
| 51 |
-
"A": "-sin(x)",
|
| 52 |
-
"B": "cos(x)",
|
| 53 |
-
"C": "-cos(x)",
|
| 54 |
-
"D": "tan(x)",
|
| 55 |
-
"E": "sec²(x)",
|
| 56 |
-
},
|
| 57 |
-
{
|
| 58 |
-
"label": "💻 Computer Science — Data Structures",
|
| 59 |
-
"question": "Which data structure follows the Last-In-First-Out (LIFO) principle?",
|
| 60 |
-
"A": "Queue",
|
| 61 |
-
"B": "Linked List",
|
| 62 |
-
"C": "Stack",
|
| 63 |
-
"D": "Binary Tree",
|
| 64 |
-
"E": "Hash Table",
|
| 65 |
-
},
|
| 66 |
-
{
|
| 67 |
-
"label": "🌍 Geography — World Capitals",
|
| 68 |
-
"question": "Which city serves as the capital of Australia?",
|
| 69 |
-
"A": "Sydney",
|
| 70 |
-
"B": "Melbourne",
|
| 71 |
-
"C": "Brisbane",
|
| 72 |
-
"D": "Canberra",
|
| 73 |
-
"E": "Perth",
|
| 74 |
-
},
|
| 75 |
-
{
|
| 76 |
-
"label": "⚛️ Physics — Thermodynamics",
|
| 77 |
-
"question": "According to the second law of thermodynamics, which quantity always increases in an isolated system?",
|
| 78 |
-
"A": "Temperature",
|
| 79 |
-
"B": "Pressure",
|
| 80 |
-
"C": "Entropy",
|
| 81 |
-
"D": "Enthalpy",
|
| 82 |
-
"E": "Internal energy",
|
| 83 |
-
},
|
| 84 |
-
]
|
| 85 |
-
|
| 86 |
-
|
| 87 |
# ── Inference ────────────────────────────────────────────────────────────────
|
| 88 |
@torch.no_grad()
|
| 89 |
def predict(prompt, opt_a, opt_b, opt_c, opt_d, opt_e):
|
| 90 |
options = [opt_a, opt_b, opt_c, opt_d, opt_e]
|
| 91 |
|
| 92 |
-
if not prompt.strip():
|
| 93 |
return (
|
| 94 |
-
"⚠️ Please enter a question.",
|
| 95 |
-
"",
|
| 96 |
-
{lb: 0.
|
| 97 |
)
|
| 98 |
-
if not all(o.strip() for o in options):
|
| 99 |
return (
|
| 100 |
-
"⚠️ Please fill in all 5 options.",
|
| 101 |
-
"",
|
| 102 |
-
{lb: 0.
|
| 103 |
)
|
| 104 |
|
| 105 |
model, tokenizer, device = load_model()
|
| 106 |
|
|
|
|
| 107 |
encoded = tokenizer(
|
| 108 |
-
[prompt] *
|
| 109 |
options,
|
| 110 |
truncation=True,
|
| 111 |
padding="max_length",
|
|
@@ -113,285 +58,255 @@ def predict(prompt, opt_a, opt_b, opt_c, opt_d, opt_e):
|
|
| 113 |
return_tensors="pt",
|
| 114 |
)
|
| 115 |
inputs = {k: v.unsqueeze(0).to(device) for k, v in encoded.items()}
|
| 116 |
-
|
| 117 |
-
|
|
|
|
| 118 |
|
| 119 |
ranked_idx = np.argsort(probs)[::-1]
|
| 120 |
ranked_labels = [OPTION_LABELS[i] for i in ranked_idx]
|
| 121 |
|
| 122 |
top3_str = " → ".join(ranked_labels[:3])
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
return prediction_str, top3_str, prob_dict
|
| 135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
-
|
| 138 |
-
ex = examples_state[evt.index]
|
| 139 |
-
return ex["question"], ex["A"], ex["B"], ex["C"], ex["D"], ex["E"]
|
| 140 |
|
| 141 |
|
| 142 |
-
# ── CSS ────────────────────────────────────────────────
|
| 143 |
CUSTOM_CSS = """
|
| 144 |
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
| 145 |
|
| 146 |
* { font-family: 'Inter', sans-serif !important; }
|
| 147 |
|
| 148 |
-
/*
|
| 149 |
.gradio-container {
|
| 150 |
-
background:
|
| 151 |
-
|
| 152 |
}
|
| 153 |
|
| 154 |
-
/*
|
| 155 |
#hero-banner {
|
| 156 |
-
background: linear-gradient(135deg, #
|
| 157 |
border-radius: 16px;
|
| 158 |
-
padding:
|
| 159 |
-
margin-bottom:
|
| 160 |
text-align: center;
|
| 161 |
-
box-shadow: 0
|
| 162 |
}
|
| 163 |
#hero-banner h1 {
|
| 164 |
-
font-size: 2rem !important;
|
| 165 |
-
font-weight:
|
| 166 |
-
color:
|
| 167 |
margin: 0 0 6px 0 !important;
|
|
|
|
| 168 |
}
|
| 169 |
#hero-banner p {
|
| 170 |
-
color:
|
| 171 |
-
font-size:
|
| 172 |
margin: 0 !important;
|
|
|
|
| 173 |
}
|
| 174 |
|
| 175 |
-
/*
|
| 176 |
.section-card {
|
| 177 |
-
background:
|
| 178 |
-
border: 1px solid
|
| 179 |
border-radius: 14px !important;
|
| 180 |
padding: 20px !important;
|
| 181 |
-
|
| 182 |
}
|
| 183 |
|
| 184 |
-
/*
|
| 185 |
-
|
| 186 |
-
color: #
|
| 187 |
-
font-weight:
|
| 188 |
-
|
| 189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
}
|
| 191 |
|
| 192 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
textarea, input[type="text"] {
|
| 194 |
-
background:
|
| 195 |
-
border:
|
| 196 |
border-radius: 10px !important;
|
| 197 |
-
color: #
|
| 198 |
-
|
|
|
|
|
|
|
| 199 |
}
|
| 200 |
textarea:focus, input[type="text"]:focus {
|
| 201 |
border-color: #6366f1 !important;
|
| 202 |
-
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.
|
| 203 |
-
|
| 204 |
}
|
| 205 |
|
| 206 |
-
/*
|
| 207 |
#predict-btn {
|
| 208 |
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
|
| 209 |
border: none !important;
|
| 210 |
border-radius: 12px !important;
|
| 211 |
-
color:
|
| 212 |
font-weight: 700 !important;
|
| 213 |
-
font-size:
|
| 214 |
padding: 14px !important;
|
| 215 |
-
box-shadow: 0 4px
|
| 216 |
-
transition:
|
| 217 |
-
|
| 218 |
}
|
| 219 |
#predict-btn:hover {
|
| 220 |
transform: translateY(-2px) !important;
|
| 221 |
-
box-shadow: 0 8px
|
| 222 |
}
|
| 223 |
-
#predict-btn:active { transform: translateY(0) !important; }
|
| 224 |
|
| 225 |
-
/*
|
| 226 |
#result-box {
|
| 227 |
-
background:
|
| 228 |
-
border:
|
| 229 |
border-radius: 12px !important;
|
| 230 |
-
padding:
|
| 231 |
-
color: #
|
| 232 |
-
|
| 233 |
-
|
|
|
|
|
|
|
|
|
|
| 234 |
}
|
| 235 |
-
#result-box h2 { color: #6ee7b7 !important; }
|
| 236 |
|
| 237 |
-
/*
|
| 238 |
-
|
| 239 |
-
background:
|
| 240 |
-
border:
|
| 241 |
-
|
|
|
|
|
|
|
|
|
|
| 242 |
}
|
| 243 |
|
| 244 |
-
/*
|
| 245 |
-
|
| 246 |
-
background:
|
| 247 |
-
border: 1px solid
|
| 248 |
-
border-radius:
|
| 249 |
-
color: #
|
| 250 |
-
font-weight: 500 !important;
|
| 251 |
-
font-size: 0.83rem !important;
|
| 252 |
-
transition: background 0.2s, border-color 0.2s, transform 0.15s !important;
|
| 253 |
-
padding: 10px 14px !important;
|
| 254 |
-
cursor: pointer !important;
|
| 255 |
}
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
border-color: #6366f1 !important;
|
| 259 |
-
transform: translateY(-2px) !important;
|
| 260 |
}
|
| 261 |
|
| 262 |
-
/*
|
| 263 |
-
|
| 264 |
-
color: #
|
| 265 |
-
font-
|
| 266 |
-
font-size: 0.95rem !important;
|
| 267 |
-
letter-spacing: 0.06em !important;
|
| 268 |
-
text-transform: uppercase !important;
|
| 269 |
-
margin-bottom: 10px !important;
|
| 270 |
}
|
| 271 |
|
| 272 |
-
/*
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
}
|
| 283 |
"""
|
| 284 |
|
| 285 |
-
# ──
|
| 286 |
HERO_HTML = """
|
| 287 |
<div id="hero-banner">
|
| 288 |
<h1>🧠 Smart MCQ Solver</h1>
|
| 289 |
-
<p>
|
| 290 |
-
IIT Madras BS Data Science — DL & GenAI Project (T2-2026)</p>
|
| 291 |
</div>
|
| 292 |
"""
|
| 293 |
|
| 294 |
-
# ── Build
|
| 295 |
with gr.Blocks(
|
| 296 |
title="Smart MCQ Solver — DeBERTa-v3",
|
| 297 |
css=CUSTOM_CSS,
|
| 298 |
) as demo:
|
| 299 |
|
| 300 |
-
# Hidden state holding examples list
|
| 301 |
-
examples_state = gr.State(EXAMPLES)
|
| 302 |
-
|
| 303 |
-
# Hero
|
| 304 |
gr.HTML(HERO_HTML)
|
| 305 |
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
gr.Markdown("### 💡 Quick Examples — click any card to auto-fill", elem_classes=["section-heading"])
|
| 309 |
-
example_gallery = gr.Dataset(
|
| 310 |
-
components=["text"],
|
| 311 |
-
samples=[[ex["label"]] for ex in EXAMPLES],
|
| 312 |
-
label="",
|
| 313 |
-
elem_id="example-gallery",
|
| 314 |
-
samples_per_page=6,
|
| 315 |
-
)
|
| 316 |
-
|
| 317 |
-
gr.HTML("<div style='height:12px'></div>")
|
| 318 |
-
|
| 319 |
-
# ── Main body ─────────────────────────────────────────────────────────────
|
| 320 |
-
with gr.Row(equal_height=False):
|
| 321 |
-
|
| 322 |
-
# Left — Input
|
| 323 |
with gr.Column(scale=3, elem_classes=["section-card"]):
|
| 324 |
-
gr.Markdown("### 📝
|
| 325 |
|
| 326 |
prompt_input = gr.Textbox(
|
| 327 |
label="Question / Prompt",
|
| 328 |
-
placeholder="
|
| 329 |
lines=3,
|
| 330 |
elem_id="prompt",
|
| 331 |
)
|
| 332 |
|
| 333 |
with gr.Row():
|
| 334 |
-
opt_a = gr.Textbox(label="Option A", placeholder="
|
| 335 |
-
opt_b = gr.Textbox(label="Option B", placeholder="
|
| 336 |
|
| 337 |
with gr.Row():
|
| 338 |
-
opt_c = gr.Textbox(label="Option C", placeholder="
|
| 339 |
-
opt_d = gr.Textbox(label="Option D", placeholder="
|
| 340 |
|
| 341 |
-
opt_e = gr.Textbox(label="Option E", placeholder="
|
| 342 |
|
| 343 |
predict_btn = gr.Button("🔍 Predict Answer", variant="primary", size="lg", elem_id="predict-btn")
|
| 344 |
|
| 345 |
-
# Right —
|
| 346 |
with gr.Column(scale=2, elem_classes=["section-card"]):
|
| 347 |
-
gr.Markdown("### 📊
|
| 348 |
|
| 349 |
prediction_out = gr.Markdown(
|
| 350 |
-
value="*
|
| 351 |
-
label="Prediction",
|
| 352 |
elem_id="result-box",
|
| 353 |
)
|
| 354 |
|
| 355 |
top3_out = gr.Textbox(
|
| 356 |
-
label="Top-3 Ranking
|
| 357 |
interactive=False,
|
| 358 |
elem_id="top3-box",
|
| 359 |
)
|
| 360 |
|
| 361 |
prob_out = gr.Label(
|
| 362 |
-
label="Confidence Scores —
|
| 363 |
num_top_classes=5,
|
| 364 |
)
|
| 365 |
|
| 366 |
gr.Markdown(
|
| 367 |
-
""
|
| 368 |
-
> **How to read:** The bar chart shows normalised probabilities across all 5 options.
|
| 369 |
-
> A higher bar means the model is more confident about that choice.
|
| 370 |
-
""",
|
| 371 |
elem_id="hint-text",
|
| 372 |
)
|
| 373 |
|
| 374 |
-
#
|
| 375 |
-
gr.HTML("""
|
| 376 |
-
<div style="
|
| 377 |
-
margin-top:24px;
|
| 378 |
-
padding:18px 24px;
|
| 379 |
-
background:rgba(255,255,255,0.03);
|
| 380 |
-
border:1px solid rgba(255,255,255,0.08);
|
| 381 |
-
border-radius:12px;
|
| 382 |
-
color:#94a3b8;
|
| 383 |
-
font-size:0.82rem;
|
| 384 |
-
line-height:1.8;
|
| 385 |
-
text-align:center;
|
| 386 |
-
">
|
| 387 |
-
<strong style="color:#a5b4fc">Model:</strong> DeBERTa-v3-base — fine-tuned for 5-option MCQ |
|
| 388 |
-
<strong style="color:#a5b4fc">Architecture:</strong> DebertaV2ForMultipleChoice |
|
| 389 |
-
<strong style="color:#a5b4fc">Project:</strong> IIT Madras BS DS — DL & GenAI T2-2026 |
|
| 390 |
-
<strong style="color:#a5b4fc">Author:</strong> Shitanshu Chaurasiya · Roll No. 24F2006167
|
| 391 |
-
</div>
|
| 392 |
-
""")
|
| 393 |
-
|
| 394 |
-
# ── Examples ──────────────────────────────────────────────────────────────
|
| 395 |
gr.Examples(
|
| 396 |
examples=[
|
| 397 |
[
|
|
@@ -402,6 +317,14 @@ with gr.Blocks(
|
|
| 402 |
"Golgi apparatus",
|
| 403 |
"Endoplasmic reticulum",
|
| 404 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 405 |
[
|
| 406 |
"Which element has the highest electronegativity on the Pauling scale?",
|
| 407 |
"Oxygen",
|
|
@@ -426,20 +349,33 @@ with gr.Blocks(
|
|
| 426 |
"Canberra",
|
| 427 |
"Perth",
|
| 428 |
],
|
| 429 |
-
[
|
| 430 |
-
"What is the derivative of sin(x) with respect to x?",
|
| 431 |
-
"-sin(x)",
|
| 432 |
-
"cos(x)",
|
| 433 |
-
"-cos(x)",
|
| 434 |
-
"tan(x)",
|
| 435 |
-
"sec²(x)",
|
| 436 |
-
],
|
| 437 |
],
|
| 438 |
inputs=[prompt_input, opt_a, opt_b, opt_c, opt_d, opt_e],
|
| 439 |
-
|
|
|
|
|
|
|
|
|
|
| 440 |
)
|
| 441 |
|
| 442 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
predict_btn.click(
|
| 444 |
fn=predict,
|
| 445 |
inputs=[prompt_input, opt_a, opt_b, opt_c, opt_d, opt_e],
|
|
@@ -447,4 +383,5 @@ with gr.Blocks(
|
|
| 447 |
)
|
| 448 |
|
| 449 |
if __name__ == "__main__":
|
|
|
|
| 450 |
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import numpy as np
|
| 3 |
import torch
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
from transformers import AutoTokenizer, AutoModelForMultipleChoice
|
| 6 |
|
| 7 |
# ── Config ──────────────────────────────────────────────────────────────────
|
| 8 |
HF_MODEL_REPO = "Shitanshu06/mcq-deberta-v3-best-v2"
|
| 9 |
OPTION_LABELS = ["A", "B", "C", "D", "E"]
|
| 10 |
+
MAX_LENGTH = 256
|
| 11 |
|
| 12 |
# ── Model loader (cached globally) ──────────────────────────────────────────
|
| 13 |
_model = None
|
|
|
|
| 15 |
_device = None
|
| 16 |
|
| 17 |
|
| 18 |
+
def load_model(force_reload=False):
|
| 19 |
global _model, _tokenizer, _device
|
| 20 |
+
if _model is None or force_reload:
|
| 21 |
_device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 22 |
+
print(f"Loading tokenizer & model from '{HF_MODEL_REPO}' on {_device}...")
|
| 23 |
_tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_REPO)
|
| 24 |
_model = AutoModelForMultipleChoice.from_pretrained(HF_MODEL_REPO)
|
| 25 |
_model.to(_device)
|
| 26 |
_model.eval()
|
| 27 |
+
print("Model loaded successfully!")
|
| 28 |
return _model, _tokenizer, _device
|
| 29 |
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
# ── Inference ────────────────────────────────────────────────────────────────
|
| 32 |
@torch.no_grad()
|
| 33 |
def predict(prompt, opt_a, opt_b, opt_c, opt_d, opt_e):
|
| 34 |
options = [opt_a, opt_b, opt_c, opt_d, opt_e]
|
| 35 |
|
| 36 |
+
if not prompt or not prompt.strip():
|
| 37 |
return (
|
| 38 |
+
"⚠️ **Please enter a question.**",
|
| 39 |
+
"N/A",
|
| 40 |
+
{lb: 0.20 for lb in OPTION_LABELS},
|
| 41 |
)
|
| 42 |
+
if not all(o and o.strip() for o in options):
|
| 43 |
return (
|
| 44 |
+
"⚠️ **Please fill in all 5 options (A, B, C, D, E).**",
|
| 45 |
+
"N/A",
|
| 46 |
+
{lb: 0.20 for lb in OPTION_LABELS},
|
| 47 |
)
|
| 48 |
|
| 49 |
model, tokenizer, device = load_model()
|
| 50 |
|
| 51 |
+
# Pair prompt with each option
|
| 52 |
encoded = tokenizer(
|
| 53 |
+
[prompt] * 5,
|
| 54 |
options,
|
| 55 |
truncation=True,
|
| 56 |
padding="max_length",
|
|
|
|
| 58 |
return_tensors="pt",
|
| 59 |
)
|
| 60 |
inputs = {k: v.unsqueeze(0).to(device) for k, v in encoded.items()}
|
| 61 |
+
|
| 62 |
+
outputs = model(**inputs)
|
| 63 |
+
probs = F.softmax(outputs.logits, dim=1).cpu().numpy()[0]
|
| 64 |
|
| 65 |
ranked_idx = np.argsort(probs)[::-1]
|
| 66 |
ranked_labels = [OPTION_LABELS[i] for i in ranked_idx]
|
| 67 |
|
| 68 |
top3_str = " → ".join(ranked_labels[:3])
|
| 69 |
+
best_idx = ranked_idx[0]
|
| 70 |
+
best_label = OPTION_LABELS[best_idx]
|
| 71 |
+
best_text = options[best_idx]
|
| 72 |
+
best_prob = probs[best_idx] * 100
|
| 73 |
+
|
| 74 |
+
prediction_markdown = f"""### 🏆 Predicted Answer: **Option {best_label}** — *{best_text}*
|
| 75 |
+
|
| 76 |
+
**Confidence:** `{best_prob:.1f}%`
|
| 77 |
+
**Top-3 Order (MAP@3):** `{top3_str}`
|
| 78 |
+
"""
|
|
|
|
|
|
|
| 79 |
|
| 80 |
+
prob_dict = {
|
| 81 |
+
f"Option {OPTION_LABELS[i]} ({options[i][:25]}...)": float(probs[i])
|
| 82 |
+
for i in range(5)
|
| 83 |
+
}
|
| 84 |
|
| 85 |
+
return prediction_markdown, top3_str, prob_dict
|
|
|
|
|
|
|
| 86 |
|
| 87 |
|
| 88 |
+
# ── High-Contrast Readable CSS ────────────────────────────────────────────────
|
| 89 |
CUSTOM_CSS = """
|
| 90 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
| 91 |
|
| 92 |
* { font-family: 'Inter', sans-serif !important; }
|
| 93 |
|
| 94 |
+
/* Main Container */
|
| 95 |
.gradio-container {
|
| 96 |
+
background: #0f172a !important;
|
| 97 |
+
color: #f8fafc !important;
|
| 98 |
}
|
| 99 |
|
| 100 |
+
/* Hero Header Banner */
|
| 101 |
#hero-banner {
|
| 102 |
+
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #0284c7 100%);
|
| 103 |
border-radius: 16px;
|
| 104 |
+
padding: 24px 32px;
|
| 105 |
+
margin-bottom: 16px;
|
| 106 |
text-align: center;
|
| 107 |
+
box-shadow: 0 10px 25px -5px rgba(79, 70, 229, 0.4);
|
| 108 |
}
|
| 109 |
#hero-banner h1 {
|
| 110 |
+
font-size: 2.2rem !important;
|
| 111 |
+
font-weight: 800 !important;
|
| 112 |
+
color: #ffffff !important;
|
| 113 |
margin: 0 0 6px 0 !important;
|
| 114 |
+
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
| 115 |
}
|
| 116 |
#hero-banner p {
|
| 117 |
+
color: #f1f5f9 !important;
|
| 118 |
+
font-size: 1rem !important;
|
| 119 |
margin: 0 !important;
|
| 120 |
+
font-weight: 500;
|
| 121 |
}
|
| 122 |
|
| 123 |
+
/* Card Containers */
|
| 124 |
.section-card {
|
| 125 |
+
background: #1e293b !important;
|
| 126 |
+
border: 1px solid #334155 !important;
|
| 127 |
border-radius: 14px !important;
|
| 128 |
padding: 20px !important;
|
| 129 |
+
box-shadow: 0 4px 15px rgba(0,0,0,0.2) !important;
|
| 130 |
}
|
| 131 |
|
| 132 |
+
/* All Headings & Labels - Readable High Contrast */
|
| 133 |
+
h1, h2, h3, h4, h5, h6 {
|
| 134 |
+
color: #f8fafc !important;
|
| 135 |
+
font-weight: 700 !important;
|
| 136 |
+
}
|
| 137 |
+
.section-heading, .section-heading h3 {
|
| 138 |
+
color: #38bdf8 !important;
|
| 139 |
+
font-weight: 700 !important;
|
| 140 |
+
font-size: 1rem !important;
|
| 141 |
+
letter-spacing: 0.05em !important;
|
| 142 |
+
text-transform: uppercase !important;
|
| 143 |
}
|
| 144 |
|
| 145 |
+
/* Labels on Textboxes */
|
| 146 |
+
label, label span, .gr-form label span {
|
| 147 |
+
color: #93c5fd !important;
|
| 148 |
+
font-weight: 600 !important;
|
| 149 |
+
font-size: 0.88rem !important;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/* Input Fields - Deep contrasting background with crisp white text */
|
| 153 |
textarea, input[type="text"] {
|
| 154 |
+
background-color: #0f172a !important;
|
| 155 |
+
border: 1.5px solid #475569 !important;
|
| 156 |
border-radius: 10px !important;
|
| 157 |
+
color: #ffffff !important;
|
| 158 |
+
font-size: 0.95rem !important;
|
| 159 |
+
font-weight: 500 !important;
|
| 160 |
+
transition: all 0.2s ease !important;
|
| 161 |
}
|
| 162 |
textarea:focus, input[type="text"]:focus {
|
| 163 |
border-color: #6366f1 !important;
|
| 164 |
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.3) !important;
|
| 165 |
+
background-color: #1e1b4b !important;
|
| 166 |
}
|
| 167 |
|
| 168 |
+
/* Predict Button */
|
| 169 |
#predict-btn {
|
| 170 |
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
|
| 171 |
border: none !important;
|
| 172 |
border-radius: 12px !important;
|
| 173 |
+
color: #ffffff !important;
|
| 174 |
font-weight: 700 !important;
|
| 175 |
+
font-size: 1.05rem !important;
|
| 176 |
padding: 14px !important;
|
| 177 |
+
box-shadow: 0 4px 18px rgba(99, 102, 241, 0.4) !important;
|
| 178 |
+
transition: all 0.2s ease !important;
|
| 179 |
+
cursor: pointer !important;
|
| 180 |
}
|
| 181 |
#predict-btn:hover {
|
| 182 |
transform: translateY(-2px) !important;
|
| 183 |
+
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.6) !important;
|
| 184 |
}
|
|
|
|
| 185 |
|
| 186 |
+
/* Result Markdown Box */
|
| 187 |
#result-box {
|
| 188 |
+
background: rgba(16, 185, 129, 0.15) !important;
|
| 189 |
+
border: 1.5px solid #10b981 !important;
|
| 190 |
border-radius: 12px !important;
|
| 191 |
+
padding: 16px 20px !important;
|
| 192 |
+
color: #f0fdf4 !important;
|
| 193 |
+
}
|
| 194 |
+
#result-box h3 {
|
| 195 |
+
color: #4ade80 !important;
|
| 196 |
+
font-size: 1.2rem !important;
|
| 197 |
+
margin-top: 0 !important;
|
| 198 |
}
|
|
|
|
| 199 |
|
| 200 |
+
/* Top 3 Box */
|
| 201 |
+
#top3-box textarea {
|
| 202 |
+
background-color: #0c4a6e !important;
|
| 203 |
+
border-color: #0284c7 !important;
|
| 204 |
+
color: #7dd3fc !important;
|
| 205 |
+
font-size: 1.1rem !important;
|
| 206 |
+
font-weight: 700 !important;
|
| 207 |
+
text-align: center !important;
|
| 208 |
}
|
| 209 |
|
| 210 |
+
/* Confidence Score Widget */
|
| 211 |
+
.gr-label {
|
| 212 |
+
background: #0f172a !important;
|
| 213 |
+
border: 1px solid #334155 !important;
|
| 214 |
+
border-radius: 12px !important;
|
| 215 |
+
color: #ffffff !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
}
|
| 217 |
+
.gr-label .label-item {
|
| 218 |
+
color: #ffffff !important;
|
|
|
|
|
|
|
| 219 |
}
|
| 220 |
|
| 221 |
+
/* Helper Notes */
|
| 222 |
+
#hint-text, #hint-text p, blockquote, blockquote p {
|
| 223 |
+
color: #cbd5e1 !important;
|
| 224 |
+
font-size: 0.85rem !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
}
|
| 226 |
|
| 227 |
+
/* Native Examples Table */
|
| 228 |
+
.gr-examples {
|
| 229 |
+
background: #1e293b !important;
|
| 230 |
+
border: 1px solid #334155 !important;
|
| 231 |
+
border-radius: 14px !important;
|
| 232 |
+
padding: 16px !important;
|
| 233 |
+
margin-top: 16px !important;
|
| 234 |
+
}
|
| 235 |
+
.gr-examples table {
|
| 236 |
+
color: #e2e8f0 !important;
|
| 237 |
+
}
|
| 238 |
+
.gr-examples tr:hover {
|
| 239 |
+
background: #334155 !important;
|
| 240 |
+
cursor: pointer !important;
|
| 241 |
}
|
| 242 |
"""
|
| 243 |
|
| 244 |
+
# ── Header HTML ───────────────────────────────────────────────────────────────
|
| 245 |
HERO_HTML = """
|
| 246 |
<div id="hero-banner">
|
| 247 |
<h1>🧠 Smart MCQ Solver</h1>
|
| 248 |
+
<p>DeBERTa-v3 Multiple Choice Question Answering · IIT Madras BS DS Project</p>
|
|
|
|
| 249 |
</div>
|
| 250 |
"""
|
| 251 |
|
| 252 |
+
# ── Build Gradio App ──────────────────────────────────────────────────────────
|
| 253 |
with gr.Blocks(
|
| 254 |
title="Smart MCQ Solver — DeBERTa-v3",
|
| 255 |
css=CUSTOM_CSS,
|
| 256 |
) as demo:
|
| 257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
gr.HTML(HERO_HTML)
|
| 259 |
|
| 260 |
+
with gr.Row():
|
| 261 |
+
# Left Column — Question & Options Input
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
with gr.Column(scale=3, elem_classes=["section-card"]):
|
| 263 |
+
gr.Markdown("### 📝 QUESTION & OPTIONS", elem_classes=["section-heading"])
|
| 264 |
|
| 265 |
prompt_input = gr.Textbox(
|
| 266 |
label="Question / Prompt",
|
| 267 |
+
placeholder="Enter your multiple-choice question here...",
|
| 268 |
lines=3,
|
| 269 |
elem_id="prompt",
|
| 270 |
)
|
| 271 |
|
| 272 |
with gr.Row():
|
| 273 |
+
opt_a = gr.Textbox(label="Option A", placeholder="First choice", elem_id="opt_a")
|
| 274 |
+
opt_b = gr.Textbox(label="Option B", placeholder="Second choice", elem_id="opt_b")
|
| 275 |
|
| 276 |
with gr.Row():
|
| 277 |
+
opt_c = gr.Textbox(label="Option C", placeholder="Third choice", elem_id="opt_c")
|
| 278 |
+
opt_d = gr.Textbox(label="Option D", placeholder="Fourth choice", elem_id="opt_d")
|
| 279 |
|
| 280 |
+
opt_e = gr.Textbox(label="Option E", placeholder="Fifth choice", elem_id="opt_e")
|
| 281 |
|
| 282 |
predict_btn = gr.Button("🔍 Predict Answer", variant="primary", size="lg", elem_id="predict-btn")
|
| 283 |
|
| 284 |
+
# Right Column — Model Predictions & Confidence Scores
|
| 285 |
with gr.Column(scale=2, elem_classes=["section-card"]):
|
| 286 |
+
gr.Markdown("### 📊 MODEL OUTPUT", elem_classes=["section-heading"])
|
| 287 |
|
| 288 |
prediction_out = gr.Markdown(
|
| 289 |
+
value="*Select an example below or enter a question and click Predict Answer.*",
|
|
|
|
| 290 |
elem_id="result-box",
|
| 291 |
)
|
| 292 |
|
| 293 |
top3_out = gr.Textbox(
|
| 294 |
+
label="Top-3 Ranking (MAP@3 Order)",
|
| 295 |
interactive=False,
|
| 296 |
elem_id="top3-box",
|
| 297 |
)
|
| 298 |
|
| 299 |
prob_out = gr.Label(
|
| 300 |
+
label="Confidence Scores — All 5 Options",
|
| 301 |
num_top_classes=5,
|
| 302 |
)
|
| 303 |
|
| 304 |
gr.Markdown(
|
| 305 |
+
"> **Note:** Probabilities are calculated using softmax logits from `DebertaV2ForMultipleChoice`.",
|
|
|
|
|
|
|
|
|
|
| 306 |
elem_id="hint-text",
|
| 307 |
)
|
| 308 |
|
| 309 |
+
# Examples list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
gr.Examples(
|
| 311 |
examples=[
|
| 312 |
[
|
|
|
|
| 317 |
"Golgi apparatus",
|
| 318 |
"Endoplasmic reticulum",
|
| 319 |
],
|
| 320 |
+
[
|
| 321 |
+
"Which of the following is NOT a programming language?",
|
| 322 |
+
"Python",
|
| 323 |
+
"Java",
|
| 324 |
+
"HTML",
|
| 325 |
+
"C++",
|
| 326 |
+
"Ruby",
|
| 327 |
+
],
|
| 328 |
[
|
| 329 |
"Which element has the highest electronegativity on the Pauling scale?",
|
| 330 |
"Oxygen",
|
|
|
|
| 349 |
"Canberra",
|
| 350 |
"Perth",
|
| 351 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
],
|
| 353 |
inputs=[prompt_input, opt_a, opt_b, opt_c, opt_d, opt_e],
|
| 354 |
+
outputs=[prediction_out, top3_out, prob_out],
|
| 355 |
+
fn=predict,
|
| 356 |
+
cache_examples=False,
|
| 357 |
+
label="💡 Click any example question below to load & test immediately:",
|
| 358 |
)
|
| 359 |
|
| 360 |
+
# Footer
|
| 361 |
+
gr.HTML("""
|
| 362 |
+
<div style="
|
| 363 |
+
margin-top:20px;
|
| 364 |
+
padding:16px;
|
| 365 |
+
background:#1e293b;
|
| 366 |
+
border:1px solid #334155;
|
| 367 |
+
border-radius:12px;
|
| 368 |
+
color:#94a3b8;
|
| 369 |
+
font-size:0.85rem;
|
| 370 |
+
text-align:center;
|
| 371 |
+
">
|
| 372 |
+
<strong style="color:#38bdf8">Model:</strong> DeBERTa-v3-base |
|
| 373 |
+
<strong style="color:#38bdf8">Fine-tuned Repository:</strong> Shitanshu06/mcq-deberta-v3-best-v2 |
|
| 374 |
+
<strong style="color:#38bdf8">Author:</strong> Shitanshu Chaurasiya (24F2006167)
|
| 375 |
+
</div>
|
| 376 |
+
""")
|
| 377 |
+
|
| 378 |
+
# Event binding
|
| 379 |
predict_btn.click(
|
| 380 |
fn=predict,
|
| 381 |
inputs=[prompt_input, opt_a, opt_b, opt_c, opt_d, opt_e],
|
|
|
|
| 383 |
)
|
| 384 |
|
| 385 |
if __name__ == "__main__":
|
| 386 |
+
load_model(force_reload=True)
|
| 387 |
demo.launch()
|