# -*- coding: utf-8 -*- """ مساعد الطالب الذكي - نسخة محسنة تطبيق تعليمي متكامل للطلاب باللغة العربية """ import gradio as gr import torch import random import datetime import json from datetime import datetime, timedelta # تحقق من توفر المكتبات وتثبيتها إذا لزم الأمر try: from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM except ImportError: import subprocess import sys subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'transformers']) from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM # ---------------------- وظائف معالجة النصوص ---------------------- # def summarize_text(text, max_length=150): """تلخيص النص العربي باستخدام نموذج مناسب""" if not text or len(text.strip()) < 50: return "النص قصير جداً أو فارغ. يرجى إدخال نص أطول للتلخيص." try: # استخدام نموذج خفيف للتلخيص summarizer = pipeline( "summarization", model="yalsaffar/mt5-small-Arabic-Summarization", device=0 if torch.cuda.is_available() else -1 ) # تقسيم النص إلى أجزاء إذا كان طويلاً max_chunk_length = 512 chunks = [text[i:i+max_chunk_length] for i in range(0, len(text), max_chunk_length)] summaries = [] for chunk in chunks[:3]: # نأخذ أول 3 أجزاء فقط لتجنب استهلاك الموارد if len(chunk.strip()) > 50: # تجاهل الأجزاء القصيرة جداً summary = summarizer(chunk, max_length=max_length, min_length=30, do_sample=False) summaries.append(summary[0]['summary_text']) if not summaries: return "لم نتمكن من تلخيص النص. يرجى التأكد من أن النص مكتوب باللغة العربية وأنه يحتوي على معلومات كافية." return " ".join(summaries) except Exception as e: return f"حدث خطأ أثناء التلخيص: {str(e)}" def generate_questions(text, num_questions=3): """توليد أسئلة من النص العربي""" if not text or len(text.strip()) < 50: return "النص قصير جداً أو فارغ. يرجى إدخال نص أطول لتوليد الأسئلة." try: # استخدام نموذج خفيف لتوليد الأسئلة # نظراً لأن النماذج المتخصصة قد تكون ثقيلة، نستخدم نهجاً مبسطاً sentences = text.split('.') questions = [] # اختيار جمل عشوائية وتحويلها إلى أسئلة selected_sentences = random.sample(sentences, min(num_questions + 2, len(sentences))) for sentence in selected_sentences: sentence = sentence.strip() if len(sentence) > 15: # تجاهل الجمل القصيرة جداً # تحويل الجملة إلى سؤال بطريقة بسيطة if "هو" in sentence: question = sentence.replace("هو", "ما هو") + "؟" elif "هي" in sentence: question = sentence.replace("هي", "ما هي") + "؟" elif "كان" in sentence: question = sentence.replace("كان", "ماذا كان") + "؟" elif "يمكن" in sentence: question = sentence.replace("يمكن", "كيف يمكن") + "؟" else: # إضافة كلمة استفهام في بداية الجملة question_starters = ["ما هو", "كيف", "لماذا", "متى", "أين"] question = random.choice(question_starters) + " " + sentence + "؟" questions.append(question) if len(questions) >= num_questions: break if not questions: return "لم نتمكن من توليد أسئلة من هذا النص. يرجى تجربة نص آخر." return "\n\n".join(questions) except Exception as e: return f"حدث خطأ أثناء توليد الأسئلة: {str(e)}" def extract_keywords(text, num_keywords=10): """استخراج الكلمات المفتاحية من النص العربي""" if not text or len(text.strip()) < 50: return "النص قصير جداً أو فارغ. يرجى إدخال نص أطول لاستخراج الكلمات المفتاحية." try: # تنظيف النص text = text.replace('\n', ' ').replace('\r', ' ') words = text.split() # إزالة الكلمات القصيرة والحروف stop_words = ["في", "من", "على", "إلى", "عن", "مع", "هذا", "هذه", "ذلك", "تلك", "هو", "هي", "أنا", "نحن", "أنت", "أنتم", "هم", "و", "أو", "ثم", "لكن", "ف", "ب", "ل", "ك", "و", "ا", "ال", "إن", "أن", "لا", "ما", "لم"] filtered_words = [word for word in words if len(word) > 2 and word not in stop_words] # حساب تكرار الكلمات word_freq = {} for word in filtered_words: if word in word_freq: word_freq[word] += 1 else: word_freq[word] = 1 # ترتيب الكلمات حسب التكرار sorted_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True) # اختيار الكلمات الأكثر تكراراً top_keywords = sorted_words[:num_keywords] if not top_keywords: return "لم نتمكن من استخراج كلمات مفتاحية من هذا النص. يرجى تجربة نص آخر." # تنسيق النتيجة result = "الكلمات المفتاحية:\n\n" for i, (word, freq) in enumerate(top_keywords, 1): result += f"{i}. {word} (التكرار: {freq})\n" return result except Exception as e: return f"حدث خطأ أثناء استخراج الكلمات المفتاحية: {str(e)}" def generate_mind_map(text): """إنشاء خريطة ذهنية بسيطة من النص العربي""" if not text or len(text.strip()) < 50: return "النص قصير جداً أو فارغ. يرجى إدخال نص أطول لإنشاء الخريطة الذهنية." try: # تقسيم النص إلى فقرات وجمل paragraphs = text.split('\n') sentences = text.split('.') # استخراج العنوان الرئيسي (أول جملة أو أول 50 حرف) main_title = sentences[0].strip() if sentences and len(sentences[0]) > 5 else text[:50] + "..." # استخراج العناوين الفرعية (بداية كل فقرة أو جمل مختارة) subtitles = [] # من الفقرات for para in paragraphs: if len(para.strip()) > 20: first_sentence = para.split('.')[0].strip() if first_sentence and len(first_sentence) > 15 and first_sentence not in subtitles: subtitles.append(first_sentence) # إذا لم نجد عناوين فرعية كافية، نأخذ من الجمل if len(subtitles) < 3: for sentence in sentences[1:]: if len(sentence.strip()) > 15 and sentence.strip() not in subtitles: subtitles.append(sentence.strip()) if len(subtitles) >= 5: break # إنشاء الخريطة الذهنية بتنسيق Markdown mind_map = f"# {main_title}\n\n" for i, subtitle in enumerate(subtitles[:5], 1): mind_map += f"## {subtitle}\n" # إضافة بعض النقاط تحت كل عنوان فرعي related_sentences = [s.strip() for s in sentences if subtitle not in s and len(s.strip()) > 10] for j, related in enumerate(random.sample(related_sentences, min(3, len(related_sentences))), 1): if len(related) > 10: mind_map += f" - {related}\n" mind_map += "\n" return mind_map except Exception as e: return f"حدث خطأ أثناء إنشاء الخريطة الذهنية: {str(e)}" def create_flashcards(text, num_cards=5): """إنشاء بطاقات تعليمية من النص العربي""" if not text or len(text.strip()) < 50: return "النص قصير جداً أو فارغ. يرجى إدخال نص أطول لإنشاء البطاقات التعليمية." try: # تقسيم النص إلى جمل sentences = [s.strip() for s in text.split('.') if len(s.strip()) > 15] if len(sentences) < 2: return "النص لا يحتوي على جمل كافية لإنشاء البطاقات التعليمية. يرجى إدخال نص أطول." # إنشاء البطاقات التعليمية flashcards = [] # اختيار جمل عشوائية selected_sentences = random.sample(sentences, min(num_cards * 2, len(sentences))) for i in range(0, len(selected_sentences) - 1, 2): if i + 1 < len(selected_sentences): question = selected_sentences[i] answer = selected_sentences[i + 1] # تحويل الجملة الأولى إلى سؤال إذا لم تكن كذلك if not question.endswith('?') and not question.endswith('؟'): question_starters = ["ما هو", "كيف", "لماذا", "اشرح", "وضح"] question = random.choice(question_starters) + " " + question + "؟" flashcards.append({"question": question, "answer": answer}) if len(flashcards) >= num_cards: break if not flashcards: return "لم نتمكن من إنشاء بطاقات تعليمية من هذا النص. يرجى تجربة نص آخر." # تنسيق النتيجة كنص بدلاً من JSON result = "البطاقات التعليمية:\n\n" for i, card in enumerate(flashcards, 1): result += f"بطاقة {i}:\n" result += f"السؤال: {card['question']}\n" result += f"الإجابة: {card['answer']}\n\n" return result except Exception as e: return f"حدث خطأ أثناء إنشاء البطاقات التعليمية: {str(e)}" def create_study_schedule(subject_name, start_date_str, exam_date_str, importance=3): """إنشاء جدول مراجعة باستخدام تقنية المراجعة المتباعدة""" try: # تحويل التواريخ من نص إلى كائنات datetime try: start_date = datetime.strptime(start_date_str, "%Y-%m-%d") exam_date = datetime.strptime(exam_date_str, "%Y-%m-%d") except ValueError: return "صيغة التاريخ غير صحيحة. يرجى استخدام الصيغة YYYY-MM-DD (مثال: 2025-06-20)." if start_date >= exam_date: return "تاريخ بدء المراجعة يجب أن يكون قبل تاريخ الامتحان." # حساب عدد الأيام المتاحة للمراجعة days_available = (exam_date - start_date).days if days_available < 1: return "لا توجد أيام كافية للمراجعة. يرجى اختيار تاريخ بدء أبكر." # تحديد عدد جلسات المراجعة بناءً على الأهمية وعدد الأيام المتاحة if importance <= 1: num_sessions = min(3, days_available) elif importance == 2: num_sessions = min(5, days_available) else: # importance >= 3 num_sessions = min(7, days_available) # إنشاء جدول المراجعة باستخدام تقنية المراجعة المتباعدة schedule = [] # الجلسة الأولى تكون في يوم البدء current_date = start_date schedule.append({ "session": 1, "date": current_date.strftime("%Y-%m-%d"), "day": ["الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"][current_date.weekday()], "focus": "مراجعة شاملة للمادة" }) # توزيع باقي الجلسات بشكل متباعد intervals = [1, 2, 4, 7, 12, 20] # فترات المراجعة المتباعدة بالأيام for i in range(1, num_sessions): # حساب تاريخ الجلسة التالية if i < len(intervals): days_to_add = intervals[i-1] else: days_to_add = intervals[-1] current_date = current_date + timedelta(days=days_to_add) # التأكد من أن تاريخ الجلسة قبل تاريخ الامتحان if current_date >= exam_date: # إذا تجاوزنا تاريخ الامتحان، نضع الجلسة قبل يوم من الامتحان current_date = exam_date - timedelta(days=1) # تحديد التركيز لكل جلسة if i == num_sessions - 1: focus = "مراجعة نهائية وحل أسئلة سابقة" elif i == 1: focus = "مراجعة المفاهيم الأساسية" elif i == 2: focus = "حل تمارين وأمثلة" else: focus = "مراجعة النقاط الصعبة" schedule.append({ "session": i + 1, "date": current_date.strftime("%Y-%m-%d"), "day": ["الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"][current_date.weekday()], "focus": focus }) # إذا وصلنا إلى يوم قبل الامتحان، نتوقف if current_date >= exam_date - timedelta(days=1): break # إضافة يوم الامتحان schedule.append({ "session": "الامتحان", "date": exam_date.strftime("%Y-%m-%d"), "day": ["الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"][exam_date.weekday()], "focus": "يوم الامتحان" }) # تنسيق النتيجة كنص result = f"جدول المراجعة لمادة: {subject_name}\n\n" for session in schedule: if session["session"] == "الامتحان": result += f"📝 {session['date']} ({session['day']}): {session['focus']}\n" else: result += f"📚 جلسة {session['session']}: {session['date']} ({session['day']}) - {session['focus']}\n" return result except Exception as e: return f"حدث خطأ أثناء إنشاء جدول المراجعة: {str(e)}" def analyze_exam_questions(questions_text): """تحليل أنماط أسئلة الامتحانات""" if not questions_text or len(questions_text.strip()) < 20: return "النص قصير جداً أو فارغ. يرجى إدخال أسئلة امتحانات سابقة للتحليل." try: # تقسيم النص إلى أسئلة منفصلة questions = [q.strip() for q in questions_text.split('\n') if len(q.strip()) > 5 and ('؟' in q or '?' in q)] if len(questions) < 2: return "لم نتمكن من تحديد أسئلة كافية للتحليل. يرجى التأكد من فصل كل سؤال بسطر جديد وإنهاء الأسئلة بعلامة استفهام." # تحليل أنواع الأسئلة question_types = { "تعريف": 0, "شرح": 0, "مقارنة": 0, "تحليل": 0, "تطبيق": 0, "أخرى": 0 } for q in questions: q_lower = q.lower() if any(word in q_lower for word in ["عرف", "ما هو", "ما هي", "من هو"]): question_types["تعريف"] += 1 elif any(word in q_lower for word in ["اشرح", "وضح", "بين", "فسر"]): question_types["شرح"] += 1 elif any(word in q_lower for word in ["قارن", "الفرق", "الاختلاف"]): question_types["مقارنة"] += 1 elif any(word in q_lower for word in ["حلل", "ناقش", "قيم"]): question_types["تحليل"] += 1 elif any(word in q_lower for word in ["طبق", "استخدم", "احسب"]): question_types["تطبيق"] += 1 else: question_types["أخرى"] += 1 # تحليل الكلمات المفتاحية all_words = " ".join(questions).split() word_freq = {} stop_words = ["ما", "هو", "هي", "كيف", "لماذا", "متى", "أين", "من", "في", "على", "إلى", "عن", "مع"] for word in all_words: if len(word) > 2 and word not in stop_words: if word in word_freq: word_freq[word] += 1 else: word_freq[word] = 1 # ترتيب الكلمات حسب التكرار sorted_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True) top_keywords = sorted_words[:10] # تنسيق النتيجة result = f"تحليل {len(questions)} سؤال:\n\n" result += "أنواع الأسئلة:\n" for q_type, count in question_types.items(): if count > 0: percentage = (count / len(questions)) * 100 result += f"- {q_type}: {count} ({percentage:.1f}%)\n" result += "\nالمواضيع الأكثر تكراراً:\n" for word, freq in top_keywords: result += f"- {word}: {freq} مرات\n" result += "\nتوصيات للمراجعة:\n" # تحديد نوع السؤال الأكثر تكراراً most_common_type = max(question_types.items(), key=lambda x: x[1])[0] result += f"1. التركيز على الإجابة على أسئلة {most_common_type}\n" # توصيات بناءً على الكلمات المفتاحية result += f"2. مراجعة المواضيع المتعلقة بـ: {', '.join([w for w, _ in top_keywords[:5]])}\n" # توصية عامة result += "3. التدرب على الإجابة على الأسئلة بأسلوب منظم ومختصر\n" return result except Exception as e: return f"حدث خطأ أثناء تحليل أسئلة الامتحانات: {str(e)}" # ---------------------- واجهة المستخدم ---------------------- # def create_interface(): """إنشاء واجهة المستخدم باستخدام Gradio""" # الشعار والعنوان title = """

مساعد الطالب الذكي

أداة تعليمية متكاملة للطلاب باستخدام الذكاء الاصطناعي

""" # إنشاء واجهة المستخدم with gr.Blocks(css="footer {visibility: hidden}") as demo: gr.HTML(title) with gr.Tabs(): # علامة تبويب تلخيص النصوص with gr.Tab("تلخيص النصوص"): with gr.Row(): with gr.Column(): summarize_input = gr.Textbox( label="أدخل النص المراد تلخيصه", placeholder="أدخل النص هنا...", lines=10 ) summarize_length = gr.Slider( label="طول التلخيص", minimum=50, maximum=300, value=150, step=10 ) summarize_button = gr.Button("تلخيص النص") with gr.Column(): summarize_output = gr.Textbox( label="نتيجة التلخيص", lines=10 ) summarize_button.click( fn=summarize_text, inputs=[summarize_input, summarize_length], outputs=summarize_output ) # علامة تبويب توليد الأسئلة with gr.Tab("توليد الأسئلة"): with gr.Row(): with gr.Column(): questions_input = gr.Textbox( label="أدخل النص المراد توليد أسئلة منه", placeholder="أدخل النص هنا...", lines=10 ) questions_count = gr.Slider( label="عدد الأسئلة", minimum=1, maximum=10, value=3, step=1 ) questions_button = gr.Button("توليد الأسئلة") with gr.Column(): questions_output = gr.Textbox( label="الأسئلة المولدة", lines=10 ) questions_button.click( fn=generate_questions, inputs=[questions_input, questions_count], outputs=questions_output ) # علامة تبويب استخراج الكلمات المفتاحية with gr.Tab("استخراج الكلمات المفتاحية"): with gr.Row(): with gr.Column(): keywords_input = gr.Textbox( label="أدخل النص المراد استخراج الكلمات المفتاحية منه", placeholder="أدخل النص هنا...", lines=10 ) keywords_count = gr.Slider( label="عدد الكلمات المفتاحية", minimum=5, maximum=20, value=10, step=1 ) keywords_button = gr.Button("استخراج الكلمات المفتاحية") with gr.Column(): keywords_output = gr.Textbox( label="الكلمات المفتاحية", lines=10 ) keywords_button.click( fn=extract_keywords, inputs=[keywords_input, keywords_count], outputs=keywords_output ) # علامة تبويب الخرائط الذهنية with gr.Tab("الخرائط الذهنية"): with gr.Row(): with gr.Column(): mindmap_input = gr.Textbox( label="أدخل النص المراد إنشاء خريطة ذهنية له", placeholder="أدخل النص هنا...", lines=10 ) mindmap_button = gr.Button("إنشاء الخريطة الذهنية") with gr.Column(): mindmap_output = gr.Markdown( label="الخريطة الذهنية" ) mindmap_button.click( fn=generate_mind_map, inputs=mindmap_input, outputs=mindmap_output ) # علامة تبويب البطاقات التعليمية with gr.Tab("البطاقات التعليمية"): with gr.Row(): with gr.Column(): flashcards_input = gr.Textbox( label="أدخل النص المراد إنشاء بطاقات تعليمية منه", placeholder="أدخل النص هنا...", lines=10 ) flashcards_count = gr.Slider( label="عدد البطاقات", minimum=3, maximum=10, value=5, step=1 ) flashcards_button = gr.Button("إنشاء البطاقات التعليمية") with gr.Column(): flashcards_output = gr.Textbox( label="البطاقات التعليمية", lines=15 ) flashcards_button.click( fn=create_flashcards, inputs=[flashcards_input, flashcards_count], outputs=flashcards_output ) # علامة تبويب منظم المراجعات with gr.Tab("منظم المراجعات"): with gr.Row(): with gr.Column(): subject_name = gr.Textbox( label="اسم المادة", placeholder="مثال: الرياضيات" ) start_date = gr.Textbox( label="تاريخ بدء المراجعة (YYYY-MM-DD)", placeholder="مثال: 2025-06-20", value=datetime.now().strftime("%Y-%m-%d") ) exam_date = gr.Textbox( label="تاريخ الامتحان (YYYY-MM-DD)", placeholder="مثال: 2025-07-10", value=(datetime.now() + timedelta(days=14)).strftime("%Y-%m-%d") ) importance = gr.Slider( label="أهمية المادة", minimum=1, maximum=5, value=3, step=1 ) schedule_button = gr.Button("إنشاء جدول المراجعة") with gr.Column(): schedule_output = gr.Textbox( label="جدول المراجعة", lines=15 ) schedule_button.click( fn=create_study_schedule, inputs=[subject_name, start_date, exam_date, importance], outputs=schedule_output ) # علامة تبويب تحليل أسئلة الامتحانات with gr.Tab("تحليل أسئلة الامتحانات"): with gr.Row(): with gr.Column(): exam_questions = gr.Textbox( label="أدخل أسئلة الامتحانات السابقة (سؤال واحد في كل سطر)", placeholder="مثال:\nما هو تعريف الخلية؟\nاشرح نظرية فيثاغورس؟\nقارن بين الخلية النباتية والخلية الحيوانية؟", lines=10 ) analyze_button = gr.Button("تحليل الأسئلة") with gr.Column(): analysis_output = gr.Textbox( label="نتائج التحليل", lines=15 ) analyze_button.click( fn=analyze_exam_questions, inputs=exam_questions, outputs=analysis_output ) # معلومات إضافية gr.Markdown(""" ### كيفية الاستخدام 1. اختر الميزة التي تريد استخدامها من علامات التبويب أعلاه 2. أدخل النص المطلوب واضبط الإعدادات حسب الحاجة 3. انقر على الزر المناسب للحصول على النتيجة ### ملاحظات - يعمل التطبيق بشكل أفضل مع النصوص العربية الفصحى - قد يستغرق تحميل النماذج بعض الوقت عند أول استخدام - للحصول على أفضل النتائج، استخدم نصوصًا واضحة وخالية من الأخطاء """) return demo # إنشاء واجهة المستخدم demo = create_interface() # نقطة الدخول الرئيسية لـ Hugging Face Spaces if __name__ == "__main__": demo.launch()