Leen172 commited on
Commit
66e335c
·
verified ·
1 Parent(s): 2eae76d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -46
app.py CHANGED
@@ -1,5 +1,6 @@
1
  # -*- coding: utf-8 -*-
2
- # صفحتان: إدخال بسيط + صفحة أسئلة مع Submit لكل سؤال
 
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
- .panel{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:16px;box-shadow:0 16px 38px rgba(0,0,0,.35)}
 
 
239
  .small{opacity:.9;color:#d9dee8}
240
- .upload-like{border:2px dashed #3b3f52;background:#121318;border-radius:12px;padding:10px;color:#cfd5e3}
 
 
 
 
 
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: ربط أزرار Submit بعد الرندر ------------------
272
  ATTACH_LISTENERS_JS = """
273
  () => {
274
- const bind = (btn) => {
275
- if (btn.dataset.bound === '1') return;
276
- btn.dataset.bound = '1';
277
- btn.addEventListener('click', (e) => {
278
- const card = e.target.closest('.q-card');
279
- const qid = card.getAttribute('data-qid');
280
- const correct= card.getAttribute('data-correct');
281
- const note = document.getElementById('n_'+qid);
282
- const badge = document.getElementById('b_'+qid);
283
- const chosen = card.querySelector('input[type="radio"]:checked');
284
-
285
- if (!chosen) {
286
- if (note){ note.textContent = 'اختر إجابة أولاً'; note.className='q-note warn'; }
287
- return;
288
- }
289
- // نظّف ألوان سابقة
290
- card.querySelectorAll('.opt').forEach(l => l.classList.remove('ok','err'));
291
-
292
- const chosenLabel = chosen.closest('.opt');
293
- if (chosen.value === correct) {
294
- chosenLabel.classList.add('ok');
295
- if (badge){ badge.hidden=false; badge.className='q-badge ok'; badge.textContent='Correct!'; }
296
- } else {
297
- chosenLabel.classList.add('err');
298
- if (badge){ badge.hidden=false; badge.className='q-badge err'; badge.textContent='Incorrect.'; }
299
- }
300
- // أقفل السؤال
301
- card.querySelectorAll('input[type="radio"]').forEach(i => i.disabled = true);
302
- e.target.disabled = true;
303
- if (note) note.textContent = '';
304
- });
305
- };
306
-
307
- document.querySelectorAll('.q-card .q-submit').forEach(bind);
308
- return [];
 
 
 
 
 
 
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
- # بناء الامتحان + إظهار الصفحة 2
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( # بعد عرض الـHTML اربط أزرار Submit
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__":