Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
# -*- coding: utf-8 -*-
|
| 2 |
-
# صفحتان
|
|
|
|
| 3 |
import os, json, uuid, random, unicodedata
|
| 4 |
from dataclasses import dataclass
|
| 5 |
from pathlib import Path
|
|
@@ -235,9 +236,16 @@ body{direction:rtl; font-family:system-ui,'Cairo','IBM Plex Arabic',sans-serif;
|
|
| 235 |
.gradio-container{max-width:980px;margin:0 auto;padding:12px 12px 40px;}
|
| 236 |
h2.top{color:#eaeaf2;margin:6px 0 16px}
|
| 237 |
|
| 238 |
-
|
|
|
|
|
|
|
| 239 |
.small{opacity:.9;color:#d9dee8}
|
| 240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
.button-primary>button{background:linear-gradient(180deg,var(--accent),var(--accent2));border:none;color:#0b0d10;font-weight:800}
|
| 242 |
.button-primary>button:hover{filter:brightness(.95)}
|
| 243 |
textarea{min-height:120px}
|
|
@@ -268,44 +276,50 @@ textarea{min-height:120px}
|
|
| 268 |
.q-note.warn{color:#ffd1d6}
|
| 269 |
"""
|
| 270 |
|
| 271 |
-
# ------------------ JS: ربط
|
| 272 |
ATTACH_LISTENERS_JS = """
|
| 273 |
() => {
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
}
|
| 310 |
"""
|
| 311 |
|
|
@@ -313,8 +327,8 @@ ATTACH_LISTENERS_JS = """
|
|
| 313 |
with gr.Blocks(title="Question Generator", css=CSS) as demo:
|
| 314 |
gr.Markdown("<h2 class='top'>Question Generator</h2>")
|
| 315 |
|
| 316 |
-
# الصفحة 1
|
| 317 |
-
page1 = gr.Group(visible=True, elem_classes=["panel"])
|
| 318 |
with page1:
|
| 319 |
gr.Markdown("اختر **أحد** الخيارين ثم اضغط الزر.", elem_classes=["small"])
|
| 320 |
text_area = gr.Textbox(lines=6, placeholder="ألصق نصك هنا...", label="لصق نص")
|
|
@@ -335,19 +349,19 @@ with gr.Blocks(title="Question Generator", css=CSS) as demo:
|
|
| 335 |
btn_build = gr.Button("generate quistion", elem_classes=["button-primary"])
|
| 336 |
warn = gr.Markdown("", elem_classes=["small"])
|
| 337 |
|
| 338 |
-
# الصفحة 2
|
| 339 |
page2 = gr.Group(visible=False)
|
| 340 |
with page2:
|
| 341 |
quiz_html = gr.HTML("")
|
|
|
|
| 342 |
|
| 343 |
-
# بناء الامتحان +
|
| 344 |
btn_build.click(
|
| 345 |
build_quiz,
|
| 346 |
inputs=[text_area, file_comp, num_q, trocr_model, trocr_zoom],
|
| 347 |
outputs=[quiz_html, page1, page2, warn]
|
| 348 |
-
).then(
|
| 349 |
-
None, inputs=None, outputs=[],
|
| 350 |
-
js=ATTACH_LISTENERS_JS
|
| 351 |
)
|
| 352 |
|
| 353 |
if __name__ == "__main__":
|
|
|
|
| 1 |
# -*- coding: utf-8 -*-
|
| 2 |
+
# صفحتان ثابتتان + Submit لكل سؤال يعمل فعليًا + منع تغيّر أبعاد صفحة الإدخال
|
| 3 |
+
|
| 4 |
import os, json, uuid, random, unicodedata
|
| 5 |
from dataclasses import dataclass
|
| 6 |
from pathlib import Path
|
|
|
|
| 236 |
.gradio-container{max-width:980px;margin:0 auto;padding:12px 12px 40px;}
|
| 237 |
h2.top{color:#eaeaf2;margin:6px 0 16px}
|
| 238 |
|
| 239 |
+
/* صفحة الإدخال ثابتة الارتفاع ولا تتغير بعد الرفع */
|
| 240 |
+
.input-panel{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:16px;
|
| 241 |
+
box-shadow:0 16px 38px rgba(0,0,0,.35); min-height:360px; display:flex; flex-direction:column; gap:12px;}
|
| 242 |
.small{opacity:.9;color:#d9dee8}
|
| 243 |
+
|
| 244 |
+
/* منع لوحة المعاينة الخاصة بالملفات التي تغيّر التخطيط */
|
| 245 |
+
[data-testid="file"] .file-preview, [data-testid="file"] .file-preview * { display:none !important; }
|
| 246 |
+
[data-testid="file"] .grid-wrap { display:block !important; }
|
| 247 |
+
.upload-like{border:2px dashed #3b3f52;background:#121318;border-radius:12px;padding:12px;color:#cfd5e3;min-height:90px}
|
| 248 |
+
|
| 249 |
.button-primary>button{background:linear-gradient(180deg,var(--accent),var(--accent2));border:none;color:#0b0d10;font-weight:800}
|
| 250 |
.button-primary>button:hover{filter:brightness(.95)}
|
| 251 |
textarea{min-height:120px}
|
|
|
|
| 276 |
.q-note.warn{color:#ffd1d6}
|
| 277 |
"""
|
| 278 |
|
| 279 |
+
# ------------------ JS: ربط Submit بعد الرندر (مع Output مخفي لضمان التنفيذ) ------------------
|
| 280 |
ATTACH_LISTENERS_JS = """
|
| 281 |
() => {
|
| 282 |
+
// تفويض عام على مستوى الوثيقة: يعمل حتى بعد أي إعادة إنشاء للعناصر
|
| 283 |
+
if (window.__q_submit_bound) { return 'already'; }
|
| 284 |
+
window.__q_submit_bound = true;
|
| 285 |
+
|
| 286 |
+
document.addEventListener('click', function(e){
|
| 287 |
+
if (!e.target || !e.target.classList) return;
|
| 288 |
+
if (!e.target.classList.contains('q-submit')) return;
|
| 289 |
+
|
| 290 |
+
const card = e.target.closest('.q-card');
|
| 291 |
+
if (!card) return;
|
| 292 |
+
|
| 293 |
+
const qid = card.getAttribute('data-qid');
|
| 294 |
+
const correct = card.getAttribute('data-correct');
|
| 295 |
+
const note = document.getElementById('n_'+qid);
|
| 296 |
+
const badge = document.getElementById('b_'+qid);
|
| 297 |
+
const chosen = card.querySelector('input[type="radio"]:checked');
|
| 298 |
+
|
| 299 |
+
if (!chosen) {
|
| 300 |
+
if (note){ note.textContent = 'اختر إجابة أولاً'; note.className='q-note warn'; }
|
| 301 |
+
return;
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
// تنظيف ألوان سابقة
|
| 305 |
+
card.querySelectorAll('.opt').forEach(l => l.classList.remove('ok','err'));
|
| 306 |
+
|
| 307 |
+
const chosenLabel = chosen.closest('.opt');
|
| 308 |
+
if (chosen.value === correct) {
|
| 309 |
+
chosenLabel.classList.add('ok');
|
| 310 |
+
if (badge){ badge.hidden=false; badge.className='q-badge ok'; badge.textContent='Correct!'; }
|
| 311 |
+
} else {
|
| 312 |
+
chosenLabel.classList.add('err');
|
| 313 |
+
if (badge){ badge.hidden=false; badge.className='q-badge err'; badge.textContent='Incorrect.'; }
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
// قفل هذا السؤال
|
| 317 |
+
card.querySelectorAll('input[type="radio"]').forEach(i => i.disabled = true);
|
| 318 |
+
e.target.disabled = true;
|
| 319 |
+
if (note) note.textContent = '';
|
| 320 |
+
});
|
| 321 |
+
|
| 322 |
+
return 'wired';
|
| 323 |
}
|
| 324 |
"""
|
| 325 |
|
|
|
|
| 327 |
with gr.Blocks(title="Question Generator", css=CSS) as demo:
|
| 328 |
gr.Markdown("<h2 class='top'>Question Generator</h2>")
|
| 329 |
|
| 330 |
+
# الصفحة 1: إدخال ثابت لا تتغير أبعاده
|
| 331 |
+
page1 = gr.Group(visible=True, elem_classes=["input-panel"])
|
| 332 |
with page1:
|
| 333 |
gr.Markdown("اختر **أحد** الخيارين ثم اضغط الزر.", elem_classes=["small"])
|
| 334 |
text_area = gr.Textbox(lines=6, placeholder="ألصق نصك هنا...", label="لصق نص")
|
|
|
|
| 349 |
btn_build = gr.Button("generate quistion", elem_classes=["button-primary"])
|
| 350 |
warn = gr.Markdown("", elem_classes=["small"])
|
| 351 |
|
| 352 |
+
# الصفحة 2: الأسئلة
|
| 353 |
page2 = gr.Group(visible=False)
|
| 354 |
with page2:
|
| 355 |
quiz_html = gr.HTML("")
|
| 356 |
+
js_wired = gr.Textbox(visible=False) # Output مخفي لضمان تنفيذ JS
|
| 357 |
|
| 358 |
+
# بناء الامتحان + تبديل الصفحات + ربط الـJS
|
| 359 |
btn_build.click(
|
| 360 |
build_quiz,
|
| 361 |
inputs=[text_area, file_comp, num_q, trocr_model, trocr_zoom],
|
| 362 |
outputs=[quiz_html, page1, page2, warn]
|
| 363 |
+
).then(
|
| 364 |
+
None, inputs=None, outputs=[js_wired], js=ATTACH_LISTENERS_JS
|
|
|
|
| 365 |
)
|
| 366 |
|
| 367 |
if __name__ == "__main__":
|