import streamlit as st
from huggingface_hub import InferenceClient
from pypdf import PdfReader
from gtts import gTTS
import io
# ==============================================================================
# 1. منظومة الأمان وجلب رمز الوصول الآمن (Security & Secrets)
# ==============================================================================
try:
# جلب التوكن الخاص بـ Hugging Face من الأسرار
HF_TOKEN = st.secrets["HF_TOKEN"]
except Exception:
st.error("🔒 خطأ في منظومة الأمان: لم يتم العثور على رمز الوصول HF_TOKEN في إعدادات الأسرار (Secrets) الخاصة بالـ Space!")
st.stop()
# تهيئة عميل الاستدعاء للنموذج الصيني العملاق بشكل سليم ومستقر
client = InferenceClient(token=HF_TOKEN)
# ==============================================================================
# 2. إعدادات الواجهة الرسومية (UI Configuration)
# ==============================================================================
st.set_page_config(
page_title="وكيل الأزهريين الذكي",
page_icon="🕌",
layout="centered"
)
# التوجيهات النظامية الصارمة للموديل لتحديد هويته الأزهريّة
SYSTEM_PROMPT = """
أنت الآن الـ AI الملقب بـ "وكيل الأزهريين" (Deputy of Al-Azhar)، خبير تعليمي ومدرس تراثي وعلمي متمكن متخصص في مناهج ومواد الأزهر الشريف بالكامل.
- مهمتك الأساسية والمقدسة: مساعدة الطلاب والمعلمين بكل ود واحترام، والحديث معهم بأسلوب أزهري وقور ومبسط.
- إذا قام المستخدم برفع نص أو كتاب معهد، فاجعل إجاباتك وشروحاتك مقتبسة ومرتبطة بدقة بالنصوص المرفوعة مع التبسيط الشديد وذكر الأدلة الصحيحة من القرآن الكريم والسنة النبوية.
- إذا لم يرفع المستخدم كتاباً، وتحدث معك بشكل مباشر، فأجب عليه من واقع علمك الواسع كأنك في جلسة نقاش علمية أخوية دافئة ومباشرة.
- طريقة العرض: استخدم التنسيق المنظم (Markdown)، واستخدم الخط العريض (Bold) للعناوين، ونظام النقاط المرتبة ليكون النص مريحاً وممتعاً للقراءة وسهلاً للحفظ الفوري.
"""
# ==============================================================================
# 3. الدوال البرمجية الخلفية (Backend Functions)
# ==============================================================================
def get_qwen_answer(user_query, text_context, user_mode):
try:
# صياغة محتوى السياق بناءً على وجود كتاب مرفع أو محادثة حرة
if text_context.strip():
context_brief = f"نص كتاب المعهد الأزهرى المرفوع كـ سياق معتمد ومستند أصيل للحديث:\n{text_context}\n\n"
else:
context_brief = "تنبيه للموديل: لم يتم رفع أي مستند خارجي حالياً، تحدث مع الطالب نقاشاً حراً ومباشراً من معلوماتك الأزهريّة.\n\n"
full_user_message = (
f"[بوابة الاستخدام الحالية في المنصة: {user_mode}]\n\n"
f"{context_brief}"
f"طلب المستخدم وسؤاله الحالي المباشر:\n{user_query}"
)
# استدعاء الـ API باستخدام الصيغة القياسية الصحيحة والمحدثة للمكتبة
response = client.chat.completions.create(
model="Qwen/Qwen2.5-72B-Instruct",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": full_user_message}
],
max_tokens=1200,
temperature=0.4
)
return response.choices[0].message.content
except Exception as e:
return f"⚠️ عذراً يا بني، حدث خطأ أثناء الاتصال بسيرفر النموذج: {str(e)}"
def extract_text_from_pdf(pdf_file):
try:
reader = PdfReader(pdf_file)
extracted_text = ""
for page in reader.pages:
text = page.extract_text()
if text:
extracted_text += text + "\n"
return extracted_text
except Exception:
return ""
def text_to_speech_player(text_to_speak):
try:
# تنظيف النص من الرموز البرمجية لتوليد صوت نقي
clean_text = text_to_speak.replace("*", "").replace("#", "").replace("-", "")
# تحويل أول 500 حرف لضمان سرعة الاستجابة الصوتية في السيرفر
tts = gTTS(text=clean_text[:500], lang='ar', slow=False)
sound_file = io.BytesIO()
tts.write_to_fp(sound_file)
sound_file.seek(0)
st.audio(sound_file.read(), format='audio/mp3')
except Exception:
st.warning("⚠️ مشغل الصوت واجه ضغطاً مؤقتاً في السيرفر، يمكنك قراءة التوضيح المكتوب بالأعلى ببساطة.")
# ==============================================================================
# 4. تصميم الواجهة الأمامية للمستحدم (App Frontend Layout)
# ==============================================================================
st.markdown("
🕌 وكيل الأزهريين الذكي
", unsafe_allow_html=True)
st.markdown("Deputy of Al-Azhar Engine
", unsafe_allow_html=True)
st.markdown("مشروع برمجى فخم ومتكامل لخدمة طلاب ومدرسي الأزهر الشريف عبر طراز Qwen 2.5 72B العملاق
", unsafe_allow_html=True)
st.write("---")
# بناء القائمة الجانبية الفخمة لإدارة البوابات
with st.sidebar:
st.markdown("🔐 لوحة التحكم والتوجيه
", unsafe_allow_html=True)
user_mode = st.selectbox(
"اختر بوابة الدخول الحالية:",
["👤 بوابة الطالب الأزهري", "👨🏫 بوابة معلم أزهري"]
)
st.write("---")
st.success("🔒 الاتصال آمن ومصرح به عبر خوادم Hugging Face.")
st.info("💡 ميزة حرة: يمكنك التحدث المباشر مع الوكيل الآن، وإذا رغبت في نقاش كتاب محدد قم برفعه بالأسفل وسيتحول النقاش تلقائياً حول الكتاب المرفوع!")
# صندوق رفع ملفات كتب المعهد المشترك في الواجهة الرئيسية (اختياري)
uploaded_file = st.file_uploader(
"📚 [اختياري] قم برفع كتاب المعهد أو المقرّر بصيغة (PDF) إذا كنت تريد الشرح منه مباشرة:",
type=["pdf"]
)
# التحقق من حالة الملف المرفوع وبناء السياق التلقائي
if uploaded_file is not None:
with st.spinner("📄 جاري تشريح صفحات كتاب المعهد وتحميلها لذاكرة الوكيل الذكي..."):
book_context = extract_text_from_pdf(uploaded_file)
st.toast("تمت قراءة المستند بنجاح! محادثتك الحالية ستتمحور حول محتوى الكتاب. 📚🎉", icon="✅")
else:
book_context = ""
# ==============================================================================
# 5. تفعيل البوابات البرمجية بناءً على وضع المستخدم
# ==============================================================================
# === أولاً: تشغيل منظومة بوابة الطالب الأزهري ===
if user_mode == "👤 بوابة الطالب الأزهري":
st.subheader("📚 رفيـقك الذكي للمذاكـرة والدردشة الحـرة")
st.write("مرحباً بك يا غالي. اكتب للوكيل أي شيء يدور في ذهنك للمناقشة المباشرة، أو ارفع درسك واطلب شرحه وفحصه:")
student_query = st.text_input("تحدث مع الوكيل أو اطرح مسألتك العلمية والفقهية هنا مباشرة:")
col1, col2 = st.columns(2)
with col1:
if st.button("💬 إرسال ومناقشة السؤال"):
if student_query:
with st.spinner("🤖 يتأمل الوكيل سؤالك ويصيغ الرد الفقهي والعلمي الحكيم..."):
reply = get_qwen_answer(student_query, book_context, user_mode)
st.success(reply)
st.markdown("### 🎧 استمع إلى الرد الصوتي النقي:")
text_to_speech_player(reply)
else:
st.warning("⚠️ فضلاً اكتب سؤالك أو جملة ترحيبية في الصندوق أولاً ليتحدث الوكيل معك!")
with col2:
if st.button("📝 توليد أسئلة بوكليت امتحانية"):
query_to_send = "استخرج من هذا النص المرفق أو من علمك الأزهري العام حول موضوع بحث الطالب 3 أسئلة امتحانات متوقعة بنظام البوكليت الرسمي (الحكم مع التعليل، علل، اذكر الدليل) مع الأجوبة النموذجية الكاملة والمنظمة لكل سؤال."
if student_query:
query_to_send += f" مع التركيز التام على جزئية: {student_query}"
with st.spinner("🤖 جاري استنباط وتوليد أهم أسئلة البوكليت المتوقعة..."):
reply = get_qwen_answer(query_to_send, book_context, user_mode)
st.info(reply)
st.markdown("### 🎧 استمع إلى الأسئلة المتوقعة وإجاباتها:")
text_to_speech_player(reply)
# === ثانياً: تشغيل منظومة بوابة المعلم الأزهري ===
elif user_mode == "👨🏫 بوابة معلم أزهري":
st.subheader("👨🏫 مساعدك التربوي المتقدم لتنظيم المنهج والاختبارات")
st.write("أهلاً وسهلاً بمشايخنا الأجلاء. استخدم هذه البوابة الذكية لتوفير الوقت والجهد في صياغة الخطط والامتحانات بكفاءة:")
teacher_query = st.text_input("اكتب عنوان الدرس أو المادة التربوية المراد إعدادها وتجهيزها تفاعلياً:")
col1, col2 = st.columns(2)
with col1:
if st.button("🗺️ وضع خطة تحضير وتوزيع للدرس"):
if teacher_query or book_context:
base_query = "قم بعمل تحضير دراسي نموذجي تربوي مفصل يحتوي على الأهداف السلوكية الثلاثة (معرفية، وجدانية، مهارية)، واقترح وسيلة تعليمية مبتكرة ومبسطة لشرح المعلم الدرس وتوصيل المعلومة بكفاءة لعقول الطلاب."
if teacher_query:
base_query += f" للدرس المسمى: {teacher_query}"
with st.spinner("🤖 جاري صياغة خطة التحضير التربوية والوسائل المقترحة..."):
reply = get_qwen_answer(base_query, book_context, user_mode)
st.success(reply)
st.markdown("### 🎧 استمع إلى التحضير الصوتي التعليمي:")
text_to_speech_player(reply)
else:
st.warning("⚠️ تنبيه: رجاءً اكتب اسم الدرس في الصندوق أو ارفع الملف الخاص به للبدء في التحضير.")
with col2:
if st.button("🔍 ابتكار اختبار تقييمي منوع"):
if teacher_query or book_context:
base_query = "اصنع اختباراً شهرياً منوعاً وشاملاً لتقييم استيعاب وفهم الطلاب، على أن يكون مقسماً بدقة وبشكل منظم إلى أسئلة مقالية، وأسئلة اختيار من متعدد، مع كتابة نموذج الإجابة التفصيلي ومفتاح الحل لكل سؤال لراحة المعلم."
if teacher_query:
base_query += f" مخصص لـ: {teacher_query}"
with st.spinner("🤖 جاري صياغة وبناء أسئلة الاختبار الشامل ومفتاح الحل..."):
reply = get_qwen_answer(base_query, book_context, user_mode)
st.info(reply)
st.markdown("### 🎧 استمع إلى بنك الأسئلة والاختبار الشهري:")
text_to_speech_player(reply)
else:
st.warning("⚠️ تنبيه: رجاءً اكتب موضوع الاختبار في الصندوق أو ارفع ملف المادة التوضيحي أولاً.")