kawkabelaloom commited on
Commit
4344aef
·
verified ·
1 Parent(s): 20aed75

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +265 -292
app.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- 🤖 نظام RAG لـ HuggingFace - نسخة معدلة لتعمل مع طريقة HuggingFace
3
  """
4
 
5
  import os
@@ -9,38 +9,16 @@ import faiss
9
  import nltk
10
  from pypdf import PdfReader
11
  from sentence_transformers import SentenceTransformer
12
- import streamlit as st
 
13
 
14
- # ==================== تهيئة النظام في حالة global ====================
15
- # بدلاً من الاعتماد على session_state فقط
16
-
17
- _rag_system = None
18
- _current_file = None
19
-
20
- def get_rag_system():
21
- """الحصول على أو إنشاء مثيل النظام"""
22
- global _rag_system
23
- if _rag_system is None:
24
- _rag_system = FlowRAGSystem()
25
- _rag_system.initialize()
26
- return _rag_system
27
-
28
- def get_current_file():
29
- """الحصول على الملف الحالي"""
30
- global _current_file
31
- return _current_file
32
-
33
- def set_current_file(filename):
34
- """تعيين الملف الحالي"""
35
- global _current_file
36
- _current_file = filename
37
-
38
- # ==================== فئة النظام ====================
39
  class FlowRAGSystem:
40
  def __init__(self):
41
  self.model = None
42
  self.index = None
43
  self.chunks = None
 
44
  self.is_ready = False
45
 
46
  def initialize(self):
@@ -59,322 +37,317 @@ class FlowRAGSystem:
59
  self.is_ready = True
60
  return True
61
  except Exception as e:
62
- st.error(f"خطأ في تحميل النموذج: {e}")
63
- return False
64
 
65
- def process_pdf(self, pdf_bytes, filename):
66
  """معالجة ملف PDF"""
67
  try:
 
 
68
  # حفظ الملف المؤقت
69
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
70
- tmp_file.write(pdf_bytes)
71
  pdf_path = tmp_file.name
72
 
73
  # قراءة PDF
74
- with st.spinner("📖 جاري قراءة المستند..."):
75
- reader = PdfReader(pdf_path)
76
- pages_data = []
77
-
78
- for i, page in enumerate(reader.pages):
79
- text = page.extract_text()
80
- if text and text.strip():
81
- pages_data.append({
82
- 'page': i + 1,
83
- 'text': text.strip()
84
- })
85
 
86
  if not pages_data:
87
- st.error("❌ لم يتم العثور على نص في الملف")
88
  os.unlink(pdf_path)
89
- return False
90
 
91
  # تقسيم النص
92
- with st.spinner("✂️ جاري تقسيم النص..."):
93
- self.chunks = []
94
- for page in pages_data:
95
- words = page['text'].split()
 
 
 
 
 
 
 
 
96
 
97
- # تقسيم إلى أجزاء 200 كلمة مع تداخل 40
98
- chunk_size = 200
99
- overlap = 40
 
 
 
100
 
101
- start = 0
102
- while start < len(words):
103
- end = start + chunk_size
104
- chunk_words = words[start:end]
105
-
106
- if chunk_words:
107
- self.chunks.append({
108
- 'text': ' '.join(chunk_words),
109
- 'page': page['page'],
110
- 'word_count': len(chunk_words)
111
- })
112
-
113
- start += chunk_size - overlap
114
 
115
  # إنشاء embeddings
116
- with st.spinner("🧠 جاري إنشاء Embeddings..."):
117
- if len(self.chunks) > 0:
118
- chunk_texts = [chunk['text'] for chunk in self.chunks]
119
- embeddings = self.model.encode(
120
- chunk_texts,
121
- normalize_embeddings=True,
122
- show_progress_bar=False
123
- )
124
-
125
- # بناء الفهرس
126
- dimension = embeddings.shape[1]
127
- self.index = faiss.IndexFlatIP(dimension)
128
- faiss.normalize_L2(embeddings)
129
- self.index.add(embeddings)
130
- else:
131
- st.error("❌ لم يتم إنشاء أي أجزاء نصية")
132
- os.unlink(pdf_path)
133
- return False
134
 
135
  # تنظيف الملف المؤقت
136
  os.unlink(pdf_path)
137
 
138
- st.success(f"✅ تم معالجة المستند بنجاح!")
139
- st.info(f"📊 {len(pages_data)} صفحة → {len(self.chunks)} جزء نصي")
140
- return True
141
 
142
  except Exception as e:
143
- st.error(f"❌ خطأ في معالجة PDF: {str(e)}")
144
- return False
145
 
146
  def search(self, query, top_k=3):
147
  """بحث في المستند"""
148
  if not self.is_ready or self.index is None:
149
- return []
150
 
151
  try:
152
  query_embedding = self.model.encode([query], normalize_embeddings=True)
153
  scores, indices = self.index.search(query_embedding, top_k)
154
 
155
  results = []
156
- for score, idx in zip(scores[0], indices[0]):
157
  if 0 <= idx < len(self.chunks):
158
  chunk = self.chunks[idx]
159
- results.append({
160
- 'score': float(score),
161
- 'similarity': f"{score * 100:.1f}%",
162
- 'text': chunk['text'],
163
- 'page': chunk['page'],
164
- 'words': chunk['word_count']
165
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
- return results
 
 
 
168
 
169
  except Exception as e:
170
- st.error(f"❌ خطأ في البحث: {e}")
171
- return []
172
 
173
- # ==================== الوظائف المساعدة ====================
174
- def create_sidebar():
175
- """إنشاء الشريط الجانبي"""
176
- with st.sidebar:
177
- st.header("📁 رفع المستند")
178
-
179
- uploaded_file = st.file_uploader(
180
- "اختر ملف PDF",
181
- type=["pdf"],
182
- help="يمكنك رفع أي ملف PDF للبحث فيه"
183
- )
184
-
185
- if uploaded_file is not None:
186
- if st.button("🚀 معالجة المستند", type="primary", use_container_width=True):
187
- rag_system = get_rag_system()
188
- if rag_system.process_pdf(uploaded_file.getvalue(), uploaded_file.name):
189
- set_current_file(uploaded_file.name)
190
- st.rerun()
191
-
192
- st.divider()
193
-
194
- st.header("🔍 إعدادات البحث")
195
- top_k = st.slider("عدد النتائج", 1, 5, 3)
196
-
197
- st.divider()
198
-
199
- st.header("💡 أسئلة سريعة")
200
-
201
- # أمثلة للأسئلة
202
- example_questions = [
203
- "ما هي حالة التدفق؟",
204
- "What is flow state?",
205
- "ما هي عناصر التجربة المثلى؟",
206
- "كيف يحقق الإنسان السعادة في العمل؟",
207
- "ما هو دور التركيز في التدفق؟"
208
- ]
209
-
210
- for question in example_questions:
211
- if st.button(question, use_container_width=True):
212
- # تخزين السؤال في query params بدلاً من session state
213
- st.query_params["question"] = question
214
- st.rerun()
215
-
216
- st.divider()
217
-
218
- # معلومات النظام
219
- rag_system = get_rag_system()
220
- if rag_system.chunks:
221
- st.header("📊 معلومات النظام")
222
- st.metric("الأجزاء النصية", len(rag_system.chunks))
223
- if rag_system.index:
224
- st.metric("المتجهات", rag_system.index.ntotal)
225
-
226
- return top_k
227
 
228
- def create_main_content(top_k):
229
- """إنشاء المحتوى الرئيسي"""
230
- rag_system = get_rag_system()
231
- current_file = get_current_file()
232
 
233
  # العنوان
234
- st.markdown("""
235
- <div style="text-align: center; padding: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
236
- color: white; border-radius: 15px; margin-bottom: 2rem;">
237
- <h1>🤖 نظام RAG الذكي للمستندات</h1>
238
- <p>بحث دلالي متقدم في ملفات PDF - يدعم العربية والإنجليزية</p>
239
- </div>
240
- """, unsafe_allow_html=True)
241
 
242
- col1, col2 = st.columns([3, 1])
 
 
 
 
243
 
244
- with col1:
245
- st.header("💬 اسأل عن المستند")
246
-
247
- # عرض اسم الملف الحالي
248
- if current_file:
249
- st.info(f"📄 الملف الحالي: **{current_file}**")
250
-
251
- # الحصول على السؤال من query params أو حقل الإدخال
252
- default_question = st.query_params.get("question", "")
253
- question = st.text_area(
254
- "اكتب سؤالك هنا",
255
- value=default_question,
256
- height=120,
257
- placeholder="مثال: ما هي حالة التدفق؟ أو What is flow state?\nيمكنك استخدام العربية أو الإنجليزية...",
258
- key="question_input"
259
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
- # زر البحث
262
- if st.button("🔍 ابحث في المستند", type="primary", use_container_width=True):
263
- if not question:
264
- st.warning("⚠️ يرجى إدخال سؤال")
265
- elif rag_system.index is None:
266
- st.error("❌ يرجى معالجة مستند أولاً (من الشريط الجانبي)")
267
- else:
268
- with st.spinner("جاري البحث في المستند..."):
269
- results = rag_system.search(question, top_k=top_k)
270
-
271
- if results:
272
- st.success(f"✅ تم العثور على {len(results)} نتيجة")
273
-
274
- for i, result in enumerate(results):
275
- # تحديد لون التشابه
276
- similarity_score = float(result['similarity'].replace('%', '')) / 100
277
- sim_class = "similarity-high" if similarity_score >= 0.5 else \
278
- "similarity-medium" if similarity_score >= 0.3 else \
279
- "similarity-low"
280
-
281
- # عرض البطاقة
282
- st.markdown(f"""
283
- <div style="background: #f8f9fa; border-radius: 10px; padding: 1.5rem;
284
- margin: 1rem 0; border-left: 5px solid #4CAF50; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
285
- <h4>🏆 النتيجة #{i+1}</h4>
286
- <p>
287
- <span style="color: {'#28a745' if similarity_score >= 0.5 else '#ffc107' if similarity_score >= 0.3 else '#dc3545'};
288
- font-weight: bold;">التشابه: {result['similarity']}</span> |
289
- 📖 الصفحة: {result['page']} |
290
- 🔢 الكلمات: {result['words']}
291
- </p>
292
- <hr>
293
- <p>{result['text'][:400]}...</p>
294
- </div>
295
- """, unsafe_allow_html=True)
296
- else:
297
- st.error("❌ لم أجد نتائج ذات صلة في المستند")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
- with col2:
300
- st.header("🎯 نصائح البحث")
301
-
302
- st.info("""
303
- **لأفضل النتائج:**
304
-
305
- 🔸 **استخدم مصطلحات محددة**
306
- ✅ "ما هي خصائص flow state؟"
307
- "اشرح لي"
308
-
309
- 🔸 **جرب اللغتين**
310
- النموذج يدعم العربية والإنجليزية معاً
311
-
312
- 🔸 **اطلب التفاصيل**
313
- "ما هي العناصر الثمانية للتدفق؟"
314
- """)
315
 
316
- st.divider()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
- st.header("📚 عن النظام")
319
- st.markdown("""
320
- **التقنيات المستخدمة:**
 
 
 
321
 
322
- 🤖 **Sentence Transformers**
323
- • ⚡ **FAISS**
324
- • 📄 **PyPDF**
325
- • 🌐 **Streamlit**
326
- """)
327
-
328
- # ==================== التطبيق الرئيسي ====================
329
- def main():
330
- """الدالة الرئيسية للتطبيق"""
331
- # إعداد الصفحة
332
- st.set_page_config(
333
- page_title="نظام RAG للمستندات",
334
- page_icon="🤖",
335
- layout="wide",
336
- initial_sidebar_state="expanded"
337
- )
338
 
339
- # CSS مخصص
340
- st.markdown("""
341
- <style>
342
- .stButton>button {
343
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
344
- color: white;
345
- border: none;
346
- padding: 0.75rem 1.5rem;
347
- border-radius: 8px;
348
- font-weight: bold;
349
- }
350
- .stButton>button:hover {
351
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
352
- }
353
- </style>
354
- """, unsafe_allow_html=True)
355
 
356
- # إنشاء الواجهة
357
- top_k = create_sidebar()
358
- create_main_content(top_k)
 
 
359
 
360
- # تذييل الصفحة
361
- st.divider()
362
- st.markdown("""
363
- <div style="text-align: center; color: #666; padding: 1rem;">
364
- <p>🤖 نظام RAG للمستندات | إصدار HuggingFace Spaces</p>
365
- <p>تقنية: FAISS + Sentence Transformers | يدعم العربية والإنجليزية</p>
366
- </div>
367
- """, unsafe_allow_html=True)
368
 
369
- # ==================== نقطة الدخول للتشغيل ====================
370
  if __name__ == "__main__":
371
- # هذا يحل مشكلة HuggingFace مع طريقة التشغيل
372
- import sys
373
-
374
- # تحقق إذا كان يعمل في HuggingFace
375
- if "huggingface" in sys.argv[0] or "spaces" in sys.argv[0]:
376
- # تشغيل التطبيق مباشرة
377
- main()
378
- else:
379
- # للتشغيل المحلي
380
- main()
 
1
  """
2
+ 🤖 نظام RAG للمستندات - إصدار Gradio لـ HuggingFace
3
  """
4
 
5
  import os
 
9
  import nltk
10
  from pypdf import PdfReader
11
  from sentence_transformers import SentenceTransformer
12
+ import gradio as gr
13
+ import time
14
 
15
+ # ==================== تهيئة النظام ====================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  class FlowRAGSystem:
17
  def __init__(self):
18
  self.model = None
19
  self.index = None
20
  self.chunks = None
21
+ self.current_file = None
22
  self.is_ready = False
23
 
24
  def initialize(self):
 
37
  self.is_ready = True
38
  return True
39
  except Exception as e:
40
+ return f"خطأ في تحميل النموذج: {str(e)}"
 
41
 
42
+ def process_pdf(self, pdf_file):
43
  """معالجة ملف PDF"""
44
  try:
45
+ self.current_file = pdf_file.name
46
+
47
  # حفظ الملف المؤقت
48
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
49
+ tmp_file.write(pdf_file.read())
50
  pdf_path = tmp_file.name
51
 
52
  # قراءة PDF
53
+ reader = PdfReader(pdf_path)
54
+ pages_data = []
55
+
56
+ for i, page in enumerate(reader.pages):
57
+ text = page.extract_text()
58
+ if text and text.strip():
59
+ pages_data.append({
60
+ 'page': i + 1,
61
+ 'text': text.strip()
62
+ })
 
63
 
64
  if not pages_data:
 
65
  os.unlink(pdf_path)
66
+ return "❌ لم يتم العثور على نص في الملف"
67
 
68
  # تقسيم النص
69
+ self.chunks = []
70
+ for page in pages_data:
71
+ words = page['text'].split()
72
+
73
+ # تقسيم إلى أجزاء 200 كلمة مع تداخل 40
74
+ chunk_size = 200
75
+ overlap = 40
76
+
77
+ start = 0
78
+ while start < len(words):
79
+ end = start + chunk_size
80
+ chunk_words = words[start:end]
81
 
82
+ if chunk_words:
83
+ self.chunks.append({
84
+ 'text': ' '.join(chunk_words),
85
+ 'page': page['page'],
86
+ 'word_count': len(chunk_words)
87
+ })
88
 
89
+ start += chunk_size - overlap
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
  # إنشاء embeddings
92
+ if len(self.chunks) > 0:
93
+ chunk_texts = [chunk['text'] for chunk in self.chunks]
94
+ embeddings = self.model.encode(
95
+ chunk_texts,
96
+ normalize_embeddings=True,
97
+ show_progress_bar=False
98
+ )
99
+
100
+ # بناء الفهرس
101
+ dimension = embeddings.shape[1]
102
+ self.index = faiss.IndexFlatIP(dimension)
103
+ faiss.normalize_L2(embeddings)
104
+ self.index.add(embeddings)
105
+ else:
106
+ os.unlink(pdf_path)
107
+ return "❌ لم يتم إنشاء أي أجزاء نصية"
 
 
108
 
109
  # تنظيف الملف المؤقت
110
  os.unlink(pdf_path)
111
 
112
+ return f"✅ تم معالجة المستند بنجاح!\n📊 {len(pages_data)} صفحة → {len(self.chunks)} جزء نصي"
 
 
113
 
114
  except Exception as e:
115
+ return f"❌ خطأ في معالجة PDF: {str(e)}"
 
116
 
117
  def search(self, query, top_k=3):
118
  """بحث في المستند"""
119
  if not self.is_ready or self.index is None:
120
+ return "❌ يرجى معالجة مستند أولاً"
121
 
122
  try:
123
  query_embedding = self.model.encode([query], normalize_embeddings=True)
124
  scores, indices = self.index.search(query_embedding, top_k)
125
 
126
  results = []
127
+ for i, (score, idx) in enumerate(zip(scores[0], indices[0])):
128
  if 0 <= idx < len(self.chunks):
129
  chunk = self.chunks[idx]
130
+
131
+ # تحديد لون التشابه
132
+ similarity_score = float(score)
133
+ if similarity_score >= 0.5:
134
+ sim_color = "#28a745" # أخضر
135
+ sim_text = "ممتاز"
136
+ elif similarity_score >= 0.3:
137
+ sim_color = "#ffc107" # أصفر
138
+ sim_text = "جيد"
139
+ else:
140
+ sim_color = "#dc3545" # أحمر
141
+ sim_text = "ضعيف"
142
+
143
+ results.append(f"""
144
+ <div style="background: #f8f9fa; border-radius: 10px; padding: 1.5rem;
145
+ margin: 1rem 0; border-left: 5px solid {sim_color}; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
146
+ <h4 style="margin-top: 0;">🏆 النتيجة #{i+1}</h4>
147
+ <p style="margin-bottom: 0.5rem;">
148
+ <span style="color: {sim_color}; font-weight: bold;">التشابه: {score*100:.1f}% ({sim_text})</span> |
149
+ 📖 الصفحة: {chunk['page']} |
150
+ 🔢 الكلمات: {chunk['word_count']}
151
+ </p>
152
+ <hr style="margin: 0.5rem 0;">
153
+ <p>{chunk['text'][:400]}...</p>
154
+ </div>
155
+ """)
156
 
157
+ if not results:
158
+ return "❌ لم أجد نتائج ذات صلة في المستند"
159
+
160
+ return f"<h3>🔍 تم ��لعثور على {len(results)} نتيجة:</h3>" + "".join(results)
161
 
162
  except Exception as e:
163
+ return f"❌ خطأ في البحث: {str(e)}"
 
164
 
165
+ # ==================== إنشاء النظام ====================
166
+ rag_system = FlowRAGSystem()
167
+ init_result = rag_system.initialize()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ # ==================== واجهة Gradio ====================
170
+ with gr.Blocks(title="🤖 نظام RAG الذكي للمستندات", theme=gr.themes.Soft()) as demo:
 
 
171
 
172
  # العنوان
173
+ gr.Markdown("""
174
+ # 🤖 نظام RAG الذكي للمستندات
175
+ ### بحث دلالي متقدم في ملفات PDF - يدعم العربية والإنجليزية
176
+ """)
 
 
 
177
 
178
+ # منطقة التنبيهات
179
+ if init_result is not True:
180
+ gr.Warning(f"⚠️ {init_result}")
181
+ else:
182
+ gr.Info("✅ النظام جاهز للاستخدام")
183
 
184
+ with gr.Row():
185
+ with gr.Column(scale=2):
186
+ # قسم رفع الملف
187
+ with gr.Group():
188
+ gr.Markdown("## 📁 رفع ومعالجة المستند")
189
+ file_input = gr.File(
190
+ label="اختر ملف PDF",
191
+ file_types=[".pdf"],
192
+ type="binary"
193
+ )
194
+ process_btn = gr.Button("🚀 معالجة المستند", variant="primary")
195
+ process_output = gr.Markdown(label="حالة المعالجة")
196
+
197
+ # قسم البحث
198
+ with gr.Group():
199
+ gr.Markdown("## 💬 اسأل عن المستند")
200
+ question_input = gr.Textbox(
201
+ label="اكتب سؤالك هنا",
202
+ placeholder="مثال: ما هي حالة التدفق؟ أو What is flow state?",
203
+ lines=3
204
+ )
205
+
206
+ with gr.Row():
207
+ top_k_slider = gr.Slider(
208
+ minimum=1, maximum=5, value=3,
209
+ label="عدد النتائج"
210
+ )
211
+ search_btn = gr.Button("🔍 ابحث في المستند", variant="primary")
212
+
213
+ search_output = gr.HTML(label="نتائج البحث")
214
 
215
+ with gr.Column(scale=1):
216
+ # الشريط الجانبي
217
+ with gr.Group():
218
+ gr.Markdown("## 💡 أسئلة سريعة")
219
+
220
+ example_questions = [
221
+ "ما هي حالة التدفق؟",
222
+ "What is flow state?",
223
+ "ما هي عناصر التجربة المثلى؟",
224
+ "كيف يحقق الإنسان السعادة في العمل؟",
225
+ "ما هو دور التركيز في التدفق؟"
226
+ ]
227
+
228
+ for question in example_questions:
229
+ gr.Button(
230
+ question,
231
+ size="sm",
232
+ ).click(
233
+ fn=lambda q=question: q,
234
+ inputs=[],
235
+ outputs=[question_input]
236
+ )
237
+
238
+ with gr.Group():
239
+ gr.Markdown("## 🎯 نصائح البحث")
240
+ gr.Markdown("""
241
+ **لأفضل النتائج:**
242
+
243
+ استخدم مصطلحات محددة
244
+ جرب اللغتين (عربي/إنجليزي)
245
+ • اطرح أسئلة واضحة
246
+
247
+ **مثال:**
248
+ ✅ "ما هي خصائص flow state؟"
249
+ "اشرح لي"
250
+ """)
251
+
252
+ with gr.Group():
253
+ gr.Markdown("## 📊 معلومات النظام")
254
+ status_text = gr.Markdown("📄 لم يتم معالجة أي مستند بعد")
255
+
256
+ # تحديث حالة النظام
257
+ def update_status():
258
+ if rag_system.current_file:
259
+ file_info = f"📄 الملف: {rag_system.current_file}"
260
+ if rag_system.chunks:
261
+ chunks_info = f" | 📊 الأجزاء: {len(rag_system.chunks)}"
262
+ if rag_system.index:
263
+ vectors_info = f" | 🧮 المتجهات: {rag_system.index.ntotal}"
264
+ return file_info + chunks_info + vectors_info
265
+ return file_info + chunks_info
266
+ return file_info
267
+ return "📄 لم يتم معالجة أي مستند بعد"
268
+
269
+ status_display = gr.Markdown(update_status())
270
 
271
+ # نصائح إضافية
272
+ gr.Markdown("---")
273
+ with gr.Row():
274
+ with gr.Column():
275
+ gr.Markdown("### 📚 عن النظام")
276
+ gr.Markdown("""
277
+ **التقنيات المستخدمة:**
278
+
279
+ 🤖 **Sentence Transformers** - نماذج embedding متعددة اللغات
280
+ • ⚡ **FAISS** - بحث سريع في المتجهات
281
+ 📄 **PyPDF** - معالجة ملفات PDF
282
+ 🌐 **Gradio** - واجهة مستخدم تفاعلية
283
+ """)
 
 
 
284
 
285
+ with gr.Column():
286
+ gr.Markdown("### 🌍 الدعم اللغوي")
287
+ gr.Markdown("""
288
+ **اللغات المدعومة:**
289
+
290
+ • العربية - البحث والنتائج
291
+ • الإنجليزية - البحث والنتائج
292
+ • الفرنسية، الإسبانية، الألمانية - البحث الأساسي
293
+
294
+ **المميزات:**
295
+ ✓ بحث دلالي ذكي
296
+ ✓ نتائج مرتبة حسب الصلة
297
+ ✓ دعم ملفات كبيرة
298
+ """)
299
+
300
+ # تذييل الصفحة
301
+ gr.Markdown("---")
302
+ gr.Markdown("""
303
+ <div style="text-align: center; color: #666;">
304
+ <p>🤖 نظام RAG للمستندات | إصدار HuggingFace Spaces</p>
305
+ <p>تقنية: FAISS + Sentence Transformers + Gradio | يدعم العربية والإنجليزية</p>
306
+ </div>
307
+ """)
308
+
309
+ # ==================== معالجة الأحداث ====================
310
+ def process_file(file):
311
+ if file is None:
312
+ return "⚠️ يرجى اختيار ملف PDF أولاً"
313
 
314
+ result = rag_system.process_pdf(file)
315
+ return result
316
+
317
+ def search_query(question, top_k):
318
+ if not question:
319
+ return "⚠️ يرجى إدخال سؤال"
320
 
321
+ return rag_system.search(question, int(top_k))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
+ # ربط الأحداث
324
+ process_btn.click(
325
+ fn=process_file,
326
+ inputs=[file_input],
327
+ outputs=[process_output]
328
+ ).then(
329
+ fn=update_status,
330
+ inputs=[],
331
+ outputs=[status_display]
332
+ )
 
 
 
 
 
 
333
 
334
+ search_btn.click(
335
+ fn=search_query,
336
+ inputs=[question_input, top_k_slider],
337
+ outputs=[search_output]
338
+ )
339
 
340
+ # معالجة ضغط Enter في حقل السؤال
341
+ question_input.submit(
342
+ fn=search_query,
343
+ inputs=[question_input, top_k_slider],
344
+ outputs=[search_output]
345
+ )
 
 
346
 
347
+ # ==================== تشغيل التطبيق ====================
348
  if __name__ == "__main__":
349
+ demo.launch(
350
+ server_name="0.0.0.0",
351
+ server_port=7860,
352
+ share=False
353
+ )