Genisi-v3 / app.py
AnesKAM's picture
Update app.py
51fbd19 verified
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"))
# ==================== عميل Ollama ====================
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:
# الاحتفاظ بآخر 50 محادثة فقط
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
# ==================== واجهة Gradio 6.0 ====================
# تخصيص شكل Gradio - متوافق مع الإصدار 6.0
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;
}
"""
# إنشاء واجهة Gradio - متوافقة مع الإصدار 6.0
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}
==========================
""")
# تمرير theme و css إلى launch() كما هو مطلوب في Gradio 6.0
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=False,
theme=gr.themes.Soft(), # نقل theme هنا
css=custom_css # نقل css هنا
)