import os import time import json import google.generativeai as genai from docx import Document import gradio as gr # --- قائمة النماذج --- USER_MODELS = [ "models/gemini-2.5-flash", "models/gemini-2.5-pro", "models/gemini-2.0-flash-exp", "models/gemini-2.0-flash", "models/gemini-2.0-flash-001", "models/gemini-2.0-flash-lite-preview-02-05", "models/gemini-1.5-flash", "models/gemini-1.5-pro", ] # --- كلاس إدارة المفاتيح والإحصائيات --- class KeyManager: def __init__(self, keys_list): # تخزين المفاتيح مع عداد لكل مفتاح self.keys_data = [{"key": k, "count": 0, "status": "active"} for k in keys_list] self.current_index = 0 self.total_requests = 0 def get_next_key(self): """جلب المفتاح التالي بنظام التدوير (Round Robin)""" if not self.keys_data: return None key_data = self.keys_data[self.current_index] current_key = key_data["key"] # تحديث المؤشر للمرة القادمة self.current_index = (self.current_index + 1) % len(self.keys_data) return current_key, self.keys_data.index(key_data) def increment_usage(self, index): """زيادة العداد للمفتاح المستخدم""" self.keys_data[index]["count"] += 1 self.total_requests += 1 def get_stats_html(self): """توليد جدول HTML للإحصائيات""" rows = "" max_usage = max([k["count"] for k in self.keys_data]) if self.keys_data else 1 for k in self.keys_data: # إخفاء جزء من المفتاح للأمان masked_key = k['key'][:6] + "..." + k['key'][-4:] if len(k['key']) > 10 else "KEY" count = k['count'] # شريط تقدم بسيط width_percent = (count / max_usage * 100) if max_usage > 0 else 0 rows += f""" {masked_key} {count}
""" html = f"""

📊 إحصائيات استهلاك المفاتيح

إجمالي الطلبات الناجحة: {self.total_requests}

{rows}
المفتاح الطلبات مؤشر الحمل
""" return html # --- دوال مساعدة --- def read_docx_and_chunk(file_obj, chunk_size=4000): try: if not file_obj: return [] doc = Document(file_obj.name) full_text = "\n".join([p.text for p in doc.paragraphs if p.text.strip()]) chunks = [] current_chunk = "" for paragraph in full_text.split('\n'): if len(current_chunk) + len(paragraph) < chunk_size: current_chunk += paragraph + "\n" else: chunks.append(current_chunk) current_chunk = paragraph + "\n" if current_chunk: chunks.append(current_chunk) return chunks except: return [] def clean_json_text(text): text = text.strip() if text.startswith('```json'): text = text[7:] if text.startswith('```'): text = text[3:] if text.endswith('```'): text = text[:-3] return text.strip() def parse_api_keys(api_text, api_file): keys = [] if api_file is not None: try: with open(api_file.name, 'r', encoding='utf-8') as f: content = f.read() keys = [line.split(',')[0].strip() for line in content.split('\n') if line.strip()] except: pass if not keys and api_text.strip(): keys = [k.strip() for k in api_text.split('\n') if k.strip()] return keys def generate_fiqh_system_instruction(author, madhab, field, book_type): base_prompt = f""" أنت باحث شرعي وخبير متخصص في تحويل التراث الإسلامي إلى بيانات هيكلية. النص من مذهب: ({madhab})، فن: ({field}). المؤلف: ({author}). النوع: ({book_type}). """ if "متن" in book_type: specific = 'استخرج القواعد والمسائل (المنطوق) بدقة.' else: specific = 'اربط الشرح بالمتن واستخرج المسألة مع التعليل والدليل.' output_format = """ المطلوب: JSON List فقط. كل عنصر: {"instruction": "السؤال/المسألة", "input": "السياق (اختياري)", "output": "الجواب المحرر", "source_meta": "المصدر"} """ return base_prompt + specific + output_format # --- المحرك الرئيسي --- def process_fiqh_book(file_obj, api_text, api_file, selected_model, author, madhab, field, book_type, delay): # 1. إعداد المفاتيح keys_list = parse_api_keys(api_text, api_file) if not keys_list: return None, None, "⚠️ يجب إدخال مفاتيح API." # إنشاء مدير المفاتيح key_manager = KeyManager(keys_list) if not file_obj: return None, key_manager.get_stats_html(), "⚠️ المرجو رفع ملف الكتاب." chunks = read_docx_and_chunk(file_obj) if not chunks: return None, key_manager.get_stats_html(), "⚠️ الملف فارغ أو معطوب." system_instruction = generate_fiqh_system_instruction(author, madhab, field, book_type) log_msg = f"🚀 تم تحميل {len(keys_list)} مفتاح.\nبدء المعالجة (توزيع الحمل المتساوي)...\n" yield None, key_manager.get_stats_html(), log_msg processed_data = [] for i, chunk in enumerate(chunks): # الحصول على المفتاح التالي في الدور current_key, key_index = key_manager.get_next_key() try: genai.configure(api_key=current_key) model = genai.GenerativeModel( model_name=selected_model, system_instruction=system_instruction, generation_config={"response_mime_type": "application/json"} ) response = model.generate_content(chunk) if not response.text: raise ValueError("رد فارغ") data = json.loads(clean_json_text(response.text)) for item in data: item['author'] = author item['madhab'] = madhab processed_data.extend(data) # تسجيل النجاح وتحديث الإحصائيات key_manager.increment_usage(key_index) log_msg += f"✅ جزء {i+1} تم ({len(data)} مسألة) -> مفتاح {current_key[:5]}...\n" # تحديث الواجهة (الجدول واللوج) yield None, key_manager.get_stats_html(), log_msg time.sleep(delay) except Exception as e: log_msg += f"❌ خطأ في جزء {i+1}: {str(e)}\n" yield None, key_manager.get_stats_html(), log_msg if processed_data: fname = "fiqh_data.json" with open(fname, 'w', encoding='utf-8') as f: json.dump(processed_data, f, ensure_ascii=False, indent=4) yield fname, key_manager.get_stats_html(), log_msg + "\n🎉 اكتملت المهمة." else: yield None, key_manager.get_stats_html(), log_msg + "\n⚠️ لم يتم استخراج بيانات." # --- الواجهة --- with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown("# 📚 محول الفقه (نظام توزيع الحمل المتوازن)") with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 1️⃣ المفاتيح والإعدادات") api_file = gr.File(label="ملف المفاتيح (txt)") api_text = gr.Textbox(label="أو لصق المفاتيح", lines=3, placeholder="KEY_1\nKEY_2", type="password") model_in = gr.Dropdown(USER_MODELS, value="models/gemini-2.5-flash", label="الموديل") with gr.Group(): author_in = gr.Textbox(label="المؤلف") madhab_in = gr.Dropdown(['المالكي', 'الشافعي', 'الحنفي', 'الحنبلي'], value='المالكي', label="المذهب") field_in = gr.Textbox(value="الفقه", label="الفن") type_in = gr.Dropdown(['متن', 'شرح'], value='شرح', label="النوع") delay_in = gr.Slider(0, 10, 1, label="تأخير (ث)") with gr.Column(scale=1): gr.Markdown("### 2️⃣ التشغيل والمراقبة") file_in = gr.File(label="ملف الكتاب (DOCX)") btn = gr.Button("🚀 ابدأ المعالجة", variant="primary") # مكون عرض الإحصائيات الجديد stats_view = gr.HTML(label="إحصائيات المفاتيح") logs = gr.Textbox(label="سجل العمليات", lines=8) f_out = gr.File(label="تحميل النتيجة") btn.click( fn=process_fiqh_book, inputs=[file_in, api_text, api_file, model_in, author_in, madhab_in, field_in, type_in, delay_in], outputs=[f_out, stats_view, logs] ) if __name__ == "__main__": demo.queue().launch()