kawkabelaloom/app
0
1"""2🤖 نظام RAG للمستندات - إصدار Gradio لـ HuggingFace3"""4 5import os6import tempfile7import numpy as np8import faiss9import nltk10from pypdf import PdfReader11from sentence_transformers import SentenceTransformer12import gradio as gr13import time14 15# ==================== تهيئة النظام ====================16class FlowRAGSystem:17 def __init__(self):18 self.model = None19 self.index = None20 self.chunks = None21 self.current_file = None22 self.is_ready = False23 24 def initialize(self):25 """تهيئة النظام"""26 try:27 # تحميل موارد NLTK28 try:29 nltk.download('punkt', quiet=True)30 nltk.download('punkt_tab', quiet=True)31 except:32 pass33 34 self.model = SentenceTransformer(35 "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"36 )37 self.is_ready = True38 return True39 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.name46 47 # حفظ الملف المؤقت48 with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:49 tmp_file.write(pdf_file.read())50 pdf_path = tmp_file.name51 52 # قراءة PDF53 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 كلمة مع تداخل 4074 chunk_size = 20075 overlap = 4076 77 start = 078 while start < len(words):79 end = start + chunk_size80 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 - overlap90 91 # إنشاء embeddings92 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=False98 )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# ==================== إنشاء النظام ====================166rag_system = FlowRAGSystem()167init_result = rag_system.initialize()168 169# ==================== واجهة Gradio ====================170with 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=3204 )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_info265 return file_info + chunks_info266 return file_info267 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 result316 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# ==================== تشغيل التطبيق ====================348if __name__ == "__main__":349 demo.launch(350 server_name="0.0.0.0",351 server_port=7860,352 share=False353 )