mohamedlabed's picture
Upload 4 files
fad1af7 verified
# -*- 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 = """
<div style="text-align: center; margin-bottom: 1rem">
<h1>مساعد الطالب الذكي</h1>
<p>أداة تعليمية متكاملة للطلاب باستخدام الذكاء الاصطناعي</p>
</div>
"""
# إنشاء واجهة المستخدم
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()