Leen172 commited on
Commit
ecd3544
·
verified ·
1 Parent(s): 09c0b08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -18
app.py CHANGED
@@ -1,7 +1,7 @@
1
  # -*- coding: utf-8 -*-
2
  # صفحتان ثابتتان + Submit لكل سؤال يعمل فعليًا + منع تغيّر أبعاد صفحة الإدخال
3
 
4
- import os, json, uuid, random, unicodedata, difflib
5
  from dataclasses import dataclass
6
  from pathlib import Path
7
  from typing import List, Tuple, Optional
@@ -93,7 +93,7 @@ def norm_ar(t:str)->str:
93
  t = re2.sub(AR_DIAC, "", t)
94
  t = re2.sub(r"[إأآا]", "ا", t)
95
  t = re2.sub(r"[يى]", "ي", t)
96
- t = re2.sub(r"\س+", " ", t) if False else re2.sub(r"\s+", " ", t)
97
  t = re2.sub(r'(\p{L})\1{2,}', r'\1', t)
98
  t = re2.sub(r'(\p{L})\1', r'\1', t)
99
  return t.strip()
@@ -269,9 +269,7 @@ def sentence_score(s: str) -> float:
269
 
270
  # ================== (NEW) جودة المشتِّتات والتطويل ==================
271
 
272
- # كاش نص كامل لتحسين تقييم الجودة
273
  global_full_text_cache = ""
274
- # كاش عبارة صحيحة لتجنّب التطابق بعد التطويل
275
  ref_phrase_cache = {}
276
 
277
  ADJ_WHITELIST = {"التعليمية","الذكية","الرقمية","الافتراضية","التكيفية","الحديثة","المتقدمة"}
@@ -535,9 +533,7 @@ def make_mcqs(text:str, n:int=6)->List[MCQ]:
535
  ch = distracts + [kp]
536
 
537
  # ترتيب غير عشوائي: تدوير حتمي لموضع الصحيحة
538
- # 1) ضع الصحيحة مؤقتًا في النهاية
539
  ch_sorted = sorted(ch, key=lambda c: c != kp)
540
- # 2) تدوير بناءً على رقم السؤال (طول القائمة الحالية) وهاش العبارة
541
  rot = (len(items) + (hash(kp) & 3)) % 4
542
  ch = ch_sorted[-rot:] + ch_sorted[:-rot]
543
 
@@ -598,17 +594,56 @@ def render_quiz_html(records: List[dict]) -> str:
598
 
599
  # ------------------ توليد الامتحان وتبديل الصفحات ------------------
600
  def build_quiz(text_area, file_path, n, model_id, zoom):
601
- text_area = (text_area or "").strip()
602
- if not text_area and not file_path:
603
- return "", gr.update(visible=True), gr.update(visible=False), "🛈 الصق نصًا أو ارفع ملفًا أولًا."
604
- if text_area:
605
- raw = text_area
606
- else:
607
- raw, _ = file_to_text(file_path, model_id=model_id, zoom=float(zoom))
608
- cleaned = postprocess(raw)
609
- items = make_mcqs(cleaned, n=int(n))
610
- recs = to_records(items)
611
- return render_quiz_html(recs), gr.update(visible=False), gr.update(visible=True), ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
 
613
  # ------------------ CSS ------------------
614
  CSS = """
@@ -642,7 +677,7 @@ textarea{min-height:120px}
642
  .q-badge.ok{background:#0f2f22;color:#b6f4db;border:1px solid #145b44}
643
  .q-badge.err{background:#3a0d14;color:#ffd1d6;border:1px solid #6a1e2b}
644
 
645
- .q-text{color:#الtext;font-size:1.06rem;line-height:1.8;margin:8px 0 12px}
646
  .opts{display:flex;flex-direction:column;gap:8px}
647
  .opt{display:flex;gap:10px;align-items:center;background:#14161c;border:1px solid #2a2d3a;border-radius:12px;padding:10px;transition:background .15s,border-color .15s}
648
  .opt input{accent-color:var(--accent2)}
 
1
  # -*- coding: utf-8 -*-
2
  # صفحتان ثابتتان + Submit لكل سؤال يعمل فعليًا + منع تغيّر أبعاد صفحة الإدخال
3
 
4
+ import os, json, uuid, random, unicodedata, difflib, traceback
5
  from dataclasses import dataclass
6
  from pathlib import Path
7
  from typing import List, Tuple, Optional
 
93
  t = re2.sub(AR_DIAC, "", t)
94
  t = re2.sub(r"[إأآا]", "ا", t)
95
  t = re2.sub(r"[يى]", "ي", t)
96
+ t = re2.sub(r"\s+", " ", t)
97
  t = re2.sub(r'(\p{L})\1{2,}', r'\1', t)
98
  t = re2.sub(r'(\p{L})\1', r'\1', t)
99
  return t.strip()
 
269
 
270
  # ================== (NEW) جودة المشتِّتات والتطويل ==================
271
 
 
272
  global_full_text_cache = ""
 
273
  ref_phrase_cache = {}
274
 
275
  ADJ_WHITELIST = {"التعليمية","الذكية","الرقمية","الافتراضية","التكيفية","الحديثة","المتقدمة"}
 
533
  ch = distracts + [kp]
534
 
535
  # ترتيب غير عشوائي: تدوير حتمي لموضع الصحيحة
 
536
  ch_sorted = sorted(ch, key=lambda c: c != kp)
 
537
  rot = (len(items) + (hash(kp) & 3)) % 4
538
  ch = ch_sorted[-rot:] + ch_sorted[:-rot]
539
 
 
594
 
595
  # ------------------ توليد الامتحان وتبديل الصفحات ------------------
596
  def build_quiz(text_area, file_path, n, model_id, zoom):
597
+ try:
598
+ text_area = (text_area or "").strip()
599
+ if not text_area and not file_path:
600
+ return "", gr.update(visible=True), gr.update(visible=False), "🛈 الصق نصًا أو ارفع ملفًا أولًا."
601
+
602
+ if text_area:
603
+ raw = text_area
604
+ else:
605
+ if isinstance(file_path, (list, tuple)) and file_path:
606
+ file_path = file_path[0]
607
+ if not file_path or not os.path.exists(file_path):
608
+ return "", gr.update(visible=True), gr.update(visible=False), "⚠️ تعذّر الوصول للملف المرفوع."
609
+ raw, _ = file_to_text(str(file_path), model_id=model_id, zoom=float(zoom))
610
+
611
+ cleaned = postprocess(raw)
612
+
613
+ try:
614
+ items = make_mcqs(cleaned, n=int(n))
615
+ except Exception as inner_e:
616
+ # Fallback بسيط يضمن توليد أسئلة حتى لو تعطل المسار الذكي
617
+ sents = split_sents(cleaned)[:int(n)*2]
618
+ if not sents:
619
+ raise inner_e
620
+ recs_items = []
621
+ import itertools
622
+ for s in sents:
623
+ toks = [t for t in re2.findall(r"[\p{L}]{3,}", s) if t not in AR_STOP]
624
+ if len(toks) < 4:
625
+ continue
626
+ kw = toks[len(toks)//3]
627
+ q = re2.sub(rf"(?<!\p{{L}}){re2.escape(kw)}(?!\p{{L}})", "_____", s, count=1)
628
+ pool = [w for w in toks if w != kw][:30]
629
+ random.shuffle(pool)
630
+ dis = list(dict.fromkeys(pool))[:3]
631
+ while len(dis) < 3: dis.append("اختيار")
632
+ ch = dis + [kw]; random.shuffle(ch)
633
+ recs_items.append(MCQ(id=str(uuid.uuid4())[:8], question=q, choices=ch, answer_index=ch.index(kw)))
634
+ if len(recs_items) >= int(n):
635
+ break
636
+ if not recs_items:
637
+ raise inner_e
638
+ items = recs_items
639
+
640
+ recs = to_records(items)
641
+ html = render_quiz_html(recs)
642
+ return html, gr.update(visible=False), gr.update(visible=True), ""
643
+ except Exception as e:
644
+ err = f"❌ حدث خطأ أثناء التوليد:\n```\n{str(e)}\n```"
645
+ traceback.print_exc()
646
+ return "", gr.update(visible=True), gr.update(visible=False), err
647
 
648
  # ------------------ CSS ------------------
649
  CSS = """
 
677
  .q-badge.ok{background:#0f2f22;color:#b6f4db;border:1px solid #145b44}
678
  .q-badge.err{background:#3a0d14;color:#ffd1d6;border:1px solid #6a1e2b}
679
 
680
+ .q-text{color:var(--text);font-size:1.06rem;line-height:1.8;margin:8px 0 12px}
681
  .opts{display:flex;flex-direction:column;gap:8px}
682
  .opt{display:flex;gap:10px;align-items:center;background:#14161c;border:1px solid #2a2d3a;border-radius:12px;padding:10px;transition:background .15s,border-color .15s}
683
  .opt input{accent-color:var(--accent2)}