| import os |
| import json |
| import time |
| import uuid |
| from datetime import datetime |
| from typing import List, Dict, Optional, Generator, Tuple, Any |
| from dataclasses import dataclass, asdict |
| from functools import lru_cache |
|
|
| import gradio as gr |
| import requests |
| from dotenv import load_dotenv |
| from ollama import Client |
| import markdown |
| import bleach |
|
|
| |
| load_dotenv() |
|
|
| |
|
|
| APP_NAME = "🧞 Genisi - المساعد الذكي" |
| APP_VERSION = "3.0.1" |
| CREATOR = "AnesNT" |
| MODEL_NAME = "gpt-oss:20b" |
| HF_SPACE = "AnesNT/Genisi-v3" |
|
|
| |
|
|
| OLLAMA_HOST = os.getenv("OLLAMA_HOST", "https://ollama.com") |
| MAX_HISTORY = int(os.getenv("MAX_HISTORY", "50")) |
| TEMPERATURE = float(os.getenv("TEMPERATURE", "0.8")) |
| MAX_TOKENS = int(os.getenv("MAX_TOKENS", "2048")) |
|
|
| |
|
|
| class GenisiModel: |
| """فئة Genisi للتعامل مع GPT-OSS 20B""" |
| |
| def __init__(self): |
| self.model = MODEL_NAME |
| self.fallback_model = "llama2:13b" |
| self.client = None |
| self.initialize() |
| |
| def initialize(self): |
| """تهيئة الاتصال بـ Ollama""" |
| try: |
| self.client = Client(host=OLLAMA_HOST) |
| print(f"✅ تم تهيئة Genisi باستخدام {self.model}") |
| except Exception as e: |
| print(f"⚠️ تحذير: {e}") |
| self.client = None |
| |
| def generate(self, |
| prompt: str, |
| system_prompt: Optional[str] = None, |
| temperature: float = TEMPERATURE, |
| max_tokens: int = MAX_TOKENS) -> str: |
| """توليد رد من النموذج""" |
| |
| if not self.client: |
| return "⚠️ عذراً، النموذج غير متاح حالياً. الرجاء المحاولة لاحقاً." |
| |
| try: |
| |
| messages = [] |
| |
| if system_prompt: |
| messages.append({ |
| 'role': 'system', |
| 'content': system_prompt |
| }) |
| |
| messages.append({ |
| 'role': 'user', |
| 'content': prompt |
| }) |
| |
| |
| options = { |
| "temperature": temperature, |
| "num_predict": max_tokens, |
| "top_p": 0.9, |
| "top_k": 40, |
| "repeat_penalty": 1.1 |
| } |
| |
| |
| try: |
| response = self.client.chat( |
| model=self.model, |
| messages=messages, |
| options=options |
| ) |
| except Exception as e: |
| print(f"⚠️ استخدام النموذج الاحتياطي: {e}") |
| response = self.client.chat( |
| model=self.fallback_model, |
| messages=messages, |
| options=options |
| ) |
| |
| |
| if response and 'message' in response: |
| return response['message']['content'] |
| else: |
| return "عذراً، لم أتمكن من توليد رد." |
| |
| except Exception as e: |
| error_msg = f"❌ خطأ: {str(e)}" |
| print(error_msg) |
| return error_msg |
|
|
| |
|
|
| class ChatHistory: |
| """إدارة سجل المحادثات""" |
| |
| def __init__(self): |
| self.history = [] |
| self.history_file = "chat_history.json" |
| self.load() |
| |
| def load(self): |
| """تحميل سجل المحادثات""" |
| try: |
| if os.path.exists(self.history_file): |
| with open(self.history_file, 'r', encoding='utf-8') as f: |
| self.history = json.load(f) |
| except Exception as e: |
| print(f"⚠️ خطأ في تحميل التاريخ: {e}") |
| self.history = [] |
| |
| def save(self): |
| """حفظ سجل المحادثات""" |
| try: |
| |
| if len(self.history) > MAX_HISTORY: |
| self.history = self.history[-MAX_HISTORY:] |
| |
| with open(self.history_file, 'w', encoding='utf-8') as f: |
| json.dump(self.history, f, ensure_ascii=False, indent=2) |
| except Exception as e: |
| print(f"⚠️ خطأ في حفظ التاريخ: {e}") |
| |
| def add(self, user_message: str, bot_response: str): |
| """إضافة محادثة جديدة""" |
| self.history.append({ |
| 'timestamp': datetime.now().isoformat(), |
| 'user': user_message, |
| 'bot': bot_response, |
| 'model': MODEL_NAME |
| }) |
| self.save() |
| |
| def get_recent(self, count: int = 5) -> List[Dict]: |
| """الحصول على آخر المحادثات""" |
| return self.history[-count:] |
|
|
| def get_system_prompt() -> str: |
| """الحصول على رسالة النظام""" |
| return f"""أنت Genisi، مساعد ذكي تم تطويره بواسطة AnesNT. |
| أنت تستخدم نموذج {MODEL_NAME} القوي. |
| تحدث باللغة العربية الفصحى دائماً. |
| كن مفيداً ومحترماً في ردودك. |
| قدم إجابات دقيقة ومفصلة.""" |
|
|
| |
|
|
| model = GenisiModel() |
| chat_history = ChatHistory() |
|
|
| |
|
|
| def respond(message: str, history: List[List[str]]) -> Tuple[str, List[List[str]]]: |
| """دالة الرد على الرسائل""" |
| if not message or not message.strip(): |
| return "", history |
| |
| |
| history.append([message, None]) |
| |
| try: |
| |
| response = model.generate( |
| prompt=message, |
| system_prompt=get_system_prompt(), |
| temperature=TEMPERATURE |
| ) |
| |
| |
| history[-1][1] = response |
| |
| |
| chat_history.add(message, response) |
| |
| except Exception as e: |
| history[-1][1] = f"❌ خطأ: {str(e)}" |
| |
| return "", history |
|
|
| def clear_chat() -> List: |
| """مسح المحادثة""" |
| return [] |
|
|
| def get_stats() -> str: |
| """الحصول على إحصائيات""" |
| stats = f"""### 📊 إحصائيات Genisi |
| |
| - **النموذج**: {MODEL_NAME} |
| - **عدد المحادثات**: {len(chat_history.history)} |
| - **آخر تحديث**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} |
| - **المطور**: {CREATOR} |
| - **الإصدار**: {APP_VERSION} |
| """ |
| return stats |
|
|
| def set_example(example: str) -> str: |
| """تعيين مثال للسؤال""" |
| return example |
|
|
| |
|
|
| |
| custom_css = """ |
| /* تنسيقات عامة */ |
| .gradio-container { |
| max-width: 1200px !important; |
| margin: auto !important; |
| direction: rtl !important; |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important; |
| } |
| |
| /* تنسيق العنوان */ |
| .title-container { |
| text-align: center; |
| margin-bottom: 30px; |
| padding: 20px; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| border-radius: 15px; |
| color: white; |
| } |
| |
| .title-container h1 { |
| font-size: 3em; |
| margin-bottom: 10px; |
| text-shadow: 2px 2px 4px rgba(0,0,0,0.2); |
| } |
| |
| .title-container p { |
| font-size: 1.2em; |
| opacity: 0.9; |
| } |
| |
| /* تنسيق الأزرار */ |
| button { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; |
| border: none !important; |
| color: white !important; |
| transition: transform 0.2s !important; |
| } |
| |
| button:hover { |
| transform: scale(1.02) !important; |
| } |
| |
| /* تنسيق مربع النص */ |
| textarea { |
| border-radius: 10px !important; |
| border: 2px solid #e0e0e0 !important; |
| font-size: 16px !important; |
| padding: 10px !important; |
| } |
| |
| /* تنسيق المحادثة */ |
| .chat-message { |
| border-radius: 15px !important; |
| margin: 10px 0 !important; |
| padding: 10px 15px !important; |
| } |
| |
| .user-message { |
| background-color: #667eea !important; |
| color: white !important; |
| } |
| |
| .bot-message { |
| background-color: #f0f0f0 !important; |
| color: #333 !important; |
| } |
| |
| /* تنسيق التذييل */ |
| .footer { |
| text-align: center; |
| margin-top: 30px; |
| padding: 20px; |
| color: #666; |
| border-top: 1px solid #e0e0e0; |
| } |
| |
| .footer a { |
| color: #667eea; |
| text-decoration: none; |
| } |
| |
| .footer a:hover { |
| text-decoration: underline; |
| } |
| """ |
|
|
| |
| with gr.Blocks() as demo: |
| |
| |
| gr.HTML(f""" |
| <div class="title-container"> |
| <h1>🧞 Genisi</h1> |
| <p>{APP_NAME} - المدعوم بـ {MODEL_NAME}</p> |
| <p>تم التطوير بواسطة <strong>{CREATOR}</strong></p> |
| </div> |
| """) |
| |
| with gr.Row(): |
| |
| with gr.Column(scale=3): |
| chatbot = gr.Chatbot( |
| label="المحادثة", |
| height=500, |
| show_label=True, |
| avatar_images=(None, "🧞") |
| ) |
| |
| with gr.Row(): |
| msg = gr.Textbox( |
| label="اكتب سؤالك هنا", |
| placeholder="اكتب سؤالك بالعربية...", |
| lines=2, |
| max_lines=5, |
| scale=4, |
| container=True |
| ) |
| |
| send_btn = gr.Button( |
| "إرسال 📤", |
| variant="primary", |
| scale=1, |
| size="lg" |
| ) |
| |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### ⚙️ الإعدادات") |
| |
| gr.Markdown(f""" |
| **النموذج:** {MODEL_NAME} |
| **درجة الحرارة:** {TEMPERATURE} |
| **الحد الأقصى:** {MAX_TOKENS} رمز |
| """) |
| |
| gr.Markdown("### 📝 أمثلة") |
| |
| examples = [ |
| ("📚 ما هو الذكاء الاصطناعي؟", "ما هو الذكاء الاصطناعي؟"), |
| ("💻 كيف أتعلم بايثون؟", "كيف أتعلم لغة بايثون من الصفر؟"), |
| ("🔬 اشرح نظرية النسبية", "اشرح نظرية النسبية لأينشتاين بطريقة مبسطة"), |
| ("🌍 ما هي عاصمة اليابان؟", "ما هي عاصمة اليابان وما هي أشهر معالمها؟") |
| ] |
| |
| for label, value in examples: |
| btn = gr.Button(label, size="sm") |
| btn.click(fn=lambda v=value: v, outputs=msg) |
| |
| gr.Markdown("### 🛠️ أدوات") |
| |
| with gr.Row(): |
| clear_btn = gr.Button("🗑️ مسح", size="sm") |
| stats_btn = gr.Button("📊 إحصائيات", size="sm") |
| |
| |
| gr.Markdown(""" |
| --- |
| ### ℹ️ معلومات |
| - **النموذج**: GPT-OSS 20B - نموذج قوي متعدد اللغات |
| - **اللغة**: العربية الفصحى |
| - **المطور**: AnesNT |
| - **الإصدار**: 3.0.1 |
| - **الترخيص**: MIT |
| """) |
| |
| |
| send_btn.click( |
| respond, |
| [msg, chatbot], |
| [msg, chatbot] |
| ) |
| |
| msg.submit( |
| respond, |
| [msg, chatbot], |
| [msg, chatbot] |
| ) |
| |
| clear_btn.click( |
| lambda: ([], ""), |
| None, |
| [chatbot, msg], |
| queue=False |
| ) |
| |
| stats_btn.click( |
| lambda: gr.Info(get_stats()), |
| None, |
| None |
| ) |
| |
| |
| gr.HTML(f""" |
| <div class="footer"> |
| <p>🧞 {APP_NAME} v{APP_VERSION} | تم التطوير بواسطة <a href="https://huggingface.co/{CREATOR}" target="_blank">{CREATOR}</a> | |
| <a href="https://github.com/AnesKAM" target="_blank">GitHub</a></p> |
| </div> |
| """) |
|
|
| |
|
|
| if __name__ == "__main__": |
| print(f""" |
| 🧞 Genisi v{APP_VERSION} |
| ========================== |
| 🤖 النموذج: {MODEL_NAME} |
| 👨💻 المطور: {CREATOR} |
| 🚀 التشغيل على: https://huggingface.co/spaces/{HF_SPACE} |
| ========================== |
| """) |
| |
| |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False, |
| debug=False, |
| theme=gr.themes.Soft(), |
| css=custom_css |
| ) |