import gradio as gr import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification import re model_path = "." tokenizer = AutoTokenizer.from_pretrained(model_path, local_files_only=True) model = AutoModelForSequenceClassification.from_pretrained(model_path, local_files_only=True) id2label = { 0: 'Fluency Disorder (تأتأة)', 1: 'Language Disorder (تأخر لغة)', 2: 'Motor Speech Disorder (اضطراب حركي)', 3: 'Other/Medical (أخرى/طبية)', 4: 'Social Communication/ASD (تواصل واجتماعي)', 5: 'Speech Sound Disorder (مخارج الحروف)' } # (Data Source: Amayreh & Dyson 1998 + ASHA) --- SOUND_NORMS = { # المجموعة الأولى (تكتمل حوالي 3 سنوات) 'ب': 3, 'م': 3, 'ن': 3, 'و': 3, 'ه': 3, 'د': 3, 'ت': 3, 'ك': 3, 'ف': 3, 'ل': 3, 'ي': 3, # المجموعة الثانية (تكتمل بين 4 - 5 سنوات) 'س': 5, 'ز': 5, 'ش': 5, 'ج': 5, # المجموعة الثالثة (تكتمل حوالي 6 سنوات) 'ر': 6, 'ث': 6, 'ذ': 6, 'ص': 6, 'ض': 6, 'ط': 6, 'ظ': 6, 'ع': 6, 'غ': 6, 'خ': 6 } # (Phonological Processes) PHONO_PROCESSES = { 'fronting': {'age': 3.5, 'keywords': ['كاف', 'قاف', 'غين', 'خاء'], 'desc': 'التقديم (Fronting): استبدال الأصوات الخلفية بأمامية (مثل: كتاب -> تتاب) طبيعي حتى 3.5 سنوات.'}, 'gliding': {'age': 6.0, 'keywords': ['راء', 'لام', 'واو', 'ياء'], 'desc': 'الانزلاق (Gliding): إبدال الراء أو اللام بـ (واو/ياء) عملية طبيعية قد تستمر حتى 6 سنوات.'}, 'final_deletion': {'age': 3.0, 'keywords': ['اخر الكلمة', 'يحذف', 'نهاية'], 'desc': 'حذف الحرف الأخير (Final Consonant Deletion) طبيعي حتى عمر 3 سنوات فقط.'}, 'stopping': {'age': 4.0, 'keywords': ['فاء', 'سين', 'شين', 'صاد'], 'desc': 'الوقف (Stopping): استبدال الأصوات الاحتكاكية بأصوات انفجارية طبيعي حتى 3-4 سنوات.'} } # (Logic Layer) def extract_age(text): text = text.replace('١', '1').replace('٢', '2').replace('٣', '3').replace('٤', '4').replace('٥', '5').replace('٦', '6') match_half = re.search(r'(\d+)\s*(ونصف|و نص)', text) if match_half: return float(match_half.group(1)) + 0.5 numbers = re.findall(r'\d+', text) if numbers: return float(numbers[0]) text = text.lower() if 'سنتين' in text or 'عامين' in text: return 2.0 if 'سنة' in text or 'عام' in text: return 1.0 if 'ثلاث' in text: return 3.0 if 'أربع' in text: return 4.0 if 'خمس' in text: return 5.0 if 'ست' in text: return 6.0 return None def check_clinical_logic(age, text, predicted_label): text = text.lower() if age is None: return predicted_label, None # Gliding if any(k in text for k in PHONO_PROCESSES['gliding']['keywords']) and ('يبدل' in text or 'يقلب' in text or 'ما يقول' in text): if age < PHONO_PROCESSES['gliding']['age']: return "Phonological Process (عملية نطقية)", PHONO_PROCESSES['gliding']['desc'] # Fronting if any(k in text for k in PHONO_PROCESSES['fronting']['keywords']) and ('يبدل' in text or 'تاء' in text or 'دال' in text): if age <= PHONO_PROCESSES['fronting']['age']: return "Phonological Process (عملية نطقية)", PHONO_PROCESSES['fronting']['desc'] # 2. Sound Norms for sound, norm_age in SOUND_NORMS.items(): patterns = [f"حرف ال{sound}", f"حرف {sound}", f"صوت ال{sound}", f"ال{sound}"] if any(p in text for p in patterns): if age < norm_age: return f"Age Appropriate Error (خطأ تطوري طبيعي)", f"حسب معايير (Amayreh & Dyson)، اكتساب صوت ({sound}) يكتمل عند {norm_age} سنوات. وعمر الطفل ({age}) سنوات، فالأمر طبيعي." if age < 4 and any(w in text for w in ['قصة', 'سالفة', 'يسرد']): return "Normal Development (تطور طبيعي)", "مهارة السرد القصصي تكتمل عادة بعد عمر 4 سنوات." if (2 <= age <= 4) and any(w in text for w in ['تأتأة', 'يعلق', 'يكرر']): return "Developmental Disfluency (تأتأة نمائية)", "التأتأة الطبيعية شائعة بين 2-4 سنوات وتختفي غالباً تلقائياً." return predicted_label, None # ----------------------------------------- def predict_speech_issue(text): if not text.strip(): return "الرجاء كتابة وصف الحالة" # AI Prediction inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True) with torch.no_grad(): outputs = model(**inputs) probs = torch.nn.functional.softmax(outputs.logits, dim=-1) pred_id = torch.argmax(probs).item() confidence = probs[0][pred_id].item() ai_label = id2label[pred_id] # Clinical Logic Check age = extract_age(text) final_label, logic_reason = check_clinical_logic(age, text, ai_label) # Formatting if logic_reason: advice = logic_reason color = "#27ae60" # Green badge = "✅ تحليل نمائي (Evidence-Based)" confidence_display = "استناداً للمعايير العلمية" else: # Default AI Recommendations recommendations = { 'Speech Sound Disorder (مخارج الحروف)': "ينصح بتقييم مخارج الحروف وفحص أعضاء النطق (Oral Motor Exam).", 'Language Disorder (تأخر لغة)': "ينصح بعمل اختبار لغة شامل (مثل PLS-4 أو معرب).", 'Social Communication/ASD (تواصل واجتماعي)': "ينصح بمراجعة طبيب نمو وسلوك وعمل مقياس كارز أو ADOS.", 'Fluency Disorder (تأتأة)': "ينصح بتقييم الطلاقة ومراقبة البيئة التواصلية.", 'Motor Speech Disorder (اضطراب حركي)': "يحتاج تقييم دقيق (Apraxia/Dysarthria) من قبل مختص.", 'Other/Medical (أخرى/طبية)': "⛔ يفضل استشارة طبيب أنف وأذن وحنجرة (ENT) لفحص السمع أو الحبال الصوتية." } advice = recommendations.get(final_label, "يرجى استشارة مختص.") color = "#c0392b" if "Medical" in final_label else "#2980b9" badge = "🤖 تصنيف الذكاء الاصطناعي" confidence_display = f"{confidence:.1%}" return f"""
الثقة: {confidence_display}
💡 الرأي المختص:
{advice}
* المصادر: Amayreh & Dyson (1998), ASHA Guidelines.