#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys import asyncio import secrets import sqlite3 import hashlib import time import json from pathlib import Path from datetime import datetime from typing import List, Dict, Any, Optional, Tuple import gradio as gr import aiohttp from bs4 import BeautifulSoup import numpy as np # ============================================================================= # 0. محاولة استيراد المكتبات القوية مع fallbacks # ============================================================================= GROQ_AVAILABLE = False CHROMA_AVAILABLE = False SENTENCE_AVAILABLE = False CRAWL4AI_AVAILABLE = False TAVILY_AVAILABLE = False try: from groq import Groq, AsyncGroq GROQ_AVAILABLE = True except ImportError: pass try: import chromadb from chromadb.utils import embedding_functions CHROMA_AVAILABLE = True except ImportError: pass try: from sentence_transformers import SentenceTransformer SENTENCE_AVAILABLE = True except ImportError: pass try: from crawl4ai import AsyncWebCrawler CRAWL4AI_AVAILABLE = True except ImportError: pass try: import tavily TAVILY_AVAILABLE = True except ImportError: pass # ============================================================================= # 1. التكوين والمفاتيح # ============================================================================= OWNER_SECRET = os.environ.get("OWNER_SECRET", "admin_giant_2026") GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "") TAVILY_API_KEY = os.environ.get("TAVILY_API_KEY", "") if GROQ_AVAILABLE and GROQ_API_KEY: groq_client = Groq(api_key=GROQ_API_KEY) async_groq = AsyncGroq(api_key=GROQ_API_KEY) else: groq_client = None async_groq = None # ============================================================================= # 2. الذاكرة المتجهية (ChromaDB إن أمكن، وإلا بديل بسيط) # ============================================================================= class VectorMemory: def __init__(self): self.use_chroma = False self.collection = None self.embed_fn = None self.simple_data = [] self.simple_embedder = None if CHROMA_AVAILABLE and SENTENCE_AVAILABLE: try: self.client = chromadb.PersistentClient(path="./chroma_db") self.embed_fn = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="all-MiniLM-L6-v2" ) self.collection = self.client.get_or_create_collection( name="giant_memory", embedding_function=self.embed_fn ) self.use_chroma = True print("✅ ChromaDB + SentenceTransformer active") except Exception as e: print(f"⚠️ ChromaDB init failed: {e}") if not self.use_chroma and SENTENCE_AVAILABLE: self.simple_embedder = SentenceTransformer("all-MiniLM-L6-v2") print("✅ Fallback memory (SentenceTransformer) active") elif not self.use_chroma: print("⚠️ No vector memory available, using simple list") def store(self, text: str, metadata: Dict = None): if self.use_chroma and self.collection: doc_id = hashlib.md5(f"{text}{time.time()}".encode()).hexdigest() self.collection.upsert( ids=[doc_id], documents=[text[:2000]], metadatas=[metadata or {}] ) elif self.simple_embedder: self.simple_data.append({"text": text[:2000], "metadata": metadata or {}}) else: self.simple_data.append({"text": text[:2000], "metadata": metadata or {}}) def retrieve(self, query: str, n: int = 5) -> List[Dict]: if self.use_chroma and self.collection: try: results = self.collection.query(query_texts=[query], n_results=n) docs = results.get("documents", [[]])[0] metas = results.get("metadatas", [[]])[0] dists = results.get("distances", [[]])[0] return [{"text": d, "metadata": m, "score": 1 - dist} for d, m, dist in zip(docs, metas, dists)] except: pass if self.simple_embedder and self.simple_data: q_emb = self.simple_embedder.encode(query) scores = [] for item in self.simple_data: emb = self.simple_embedder.encode(item["text"][:500]) sim = np.dot(q_emb, emb) / (np.linalg.norm(q_emb) * np.linalg.norm(emb) + 1e-8) scores.append(sim) indices = np.argsort(scores)[-n:][::-1] return [{"text": self.simple_data[i]["text"], "metadata": self.simple_data[i]["metadata"], "score": scores[i]} for i in indices] # آخر بديل: بحث نصي بسيط if self.simple_data: return [{"text": item["text"], "metadata": item["metadata"], "score": 0.5} for item in self.simple_data[:n]] return [] memory = VectorMemory() # ============================================================================= # 3. محرك البحث العميق (Tavily أو DuckDuckGo) # ============================================================================= class DeepSearchEngine: def __init__(self): self.session = None self.tavily_key = TAVILY_API_KEY async def _get_session(self): if self.session is None or self.session.closed: self.session = aiohttp.ClientSession() return self.session async def search_tavily(self, query: str) -> str: if not self.tavily_key: return "" try: session = await self._get_session() async with session.post( "https://api.tavily.com/search", json={"api_key": self.tavily_key, "query": query, "max_results": 4} ) as resp: if resp.status == 200: data = await resp.json() results = data.get("results", []) output = "🔍 **Tavily نتائج:**\n" for r in results[:3]: title = r.get("title", "") content = r.get("content", "")[:200] url = r.get("url", "") output += f"- **{title}**: {content}...\n 🔗 {url}\n" return output except Exception as e: print(f"Tavily error: {e}") return "" async def search_duckduckgo(self, query: str) -> str: try: session = await self._get_session() url = "https://html.duckduckgo.com/html/" async with session.get(url, params={"q": query}) as resp: if resp.status == 200: html = await resp.text() soup = BeautifulSoup(html, "html.parser") results = [] for r in soup.select(".result")[:4]: title = r.select_one(".result__a") snippet = r.select_one(".result__snippet") if title: t = title.get_text(strip=True) s = snippet.get_text(strip=True) if snippet else "" results.append(f"- **{t}**: {s[:200]}...") if results: return "🔍 **DuckDuckGo نتائج:**\n" + "\n".join(results) except Exception as e: print(f"DuckDuckGo error: {e}") return "" async def deep_search(self, query: str) -> str: # حاول Tavily أولاً res = await self.search_tavily(query) if res: return res # ثم DuckDuckGo res = await self.search_duckduckgo(query) if res: return res return "⚠️ لم يتم العثور على معلومات حديثة." deep_search = DeepSearchEngine() # ============================================================================= # 4. إدارة السياق # ============================================================================= class ConversationContext: def __init__(self): self.history = [] def add(self, user: str, assistant: str): self.history.append((user, assistant)) if len(self.history) > 10: self.history.pop(0) def get_prompt(self) -> str: if not self.history: return "" context = "\n[سِيَاقُ الْمُحَادَثَةِ]\n" for i, (u, a) in enumerate(self.history[-5:], 1): context += f"{i}. المستخدم: {u[:200]}\n المساعد: {a[:200]}\n" return context + "[/سِيَاقُ الْمُحَادَثَةِ]\n" context = ConversationContext() # ============================================================================= # 5. دوال المالك # ============================================================================= def read_local_files() -> str: count = 0 for root, _, files in os.walk("."): if any(x in root for x in ["chroma_db", "__pycache__", ".git", "venv"]): continue for f in files: if f.endswith((".txt", ".md", ".py", ".json", ".csv")): path = os.path.join(root, f) try: with open(path, "r", encoding="utf-8", errors="ignore") as fp: content = fp.read()[:3000] memory.store(f"ملف: {path}\n{content}", {"source": path}) count += 1 except: pass return f"✅ تم قراءة {count} ملف." async def learn_website(url: str) -> str: try: # استخدام Crawl4AI إذا متاح if CRAWL4AI_AVAILABLE: async with AsyncWebCrawler() as crawler: result = await crawler.arun(url=url, bypass_cache=True) if result and result.markdown: content = result.markdown[:5000] memory.store(f"محتوى {url}:\n{content}", {"source": url, "type": "website"}) return f"✅ تم تعلم الموقع {url} بنجاح (Crawl4AI)." # بديل: aiohttp + BeautifulSoup async with aiohttp.ClientSession() as session: async with session.get(url) as resp: if resp.status == 200: html = await resp.text() soup = BeautifulSoup(html, "html.parser") for s in soup(["script", "style"]): s.decompose() text = soup.get_text(separator="\n", strip=True)[:5000] memory.store(f"محتوى {url}:\n{text}", {"source": url, "type": "website"}) return f"✅ تم تعلم الموقع {url} بنجاح." except Exception as e: return f"❌ خطأ: {e}" return f"⚠️ فشل تعلم {url}" # ============================================================================= # 6. توليد الرد باستخدام Groq # ============================================================================= async def generate_response(user_message: str) -> str: # ردود سريعة if any(g in user_message.lower() for g in ["السلام", "اهلا", "مرحبا", "كيف حالك"]): return "وَعَلَيْكُمُ السَّلَامُ! أَنَا بِخَيْرٍ، شُكْرًا. كَيْفَ يُمْكِنُنِي مُسَاعَدَتُكَ؟" now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") ctx = context.get_prompt() memories = memory.retrieve(user_message, n=3) local = "\n".join([m["text"][:300] for m in memories]) if memories else "" needs_search = any(k in user_message.lower() for k in ["سعر", "دولار", "أخبار", "طقس"]) web_info = await deep_search.deep_search(user_message) if needs_search else "" if GROQ_AVAILABLE and async_groq: try: prompt = f"""الوقت الحالي: {now} {ctx} المعرفة المحلية: {local[:1000]} المعلومات الحديثة: {web_info[:1000]} سؤال المستخدم: {user_message} أجب بالعربية بدقة ووضوح، مستخدماً الوقت الحالي والمعلومات الحديثة.""" response = await async_groq.chat.completions.create( model="llama-3.3-70b-versatile", messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=1024 ) return response.choices[0].message.content except Exception as e: return f"⚠️ خطأ في Groq: {e}\n\nالسياق: {local[:300]}\n{web_info[:300]}" else: return f"الوقت: {now}\nالسياق: {ctx[:300]}\nالذاكرة: {local[:300]}\nالويب: {web_info[:300]}\nسؤالك: {user_message}" # ============================================================================= # 7. قاعدة بيانات الدردشة (SQLite) # ============================================================================= DB_PATH = Path("./chat_history.db") SESSION_ID = secrets.token_hex(16) def init_db(): conn = sqlite3.connect(str(DB_PATH)) conn.execute("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, role TEXT, content TEXT, session TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)") conn.close() def save_message(role: str, content: str): conn = sqlite3.connect(str(DB_PATH)) conn.execute("INSERT INTO messages (role, content, session) VALUES (?, ?, ?)", (role, content, SESSION_ID)) conn.commit() conn.close() def load_history(limit: int = 30) -> List[Tuple[str, str]]: conn = sqlite3.connect(str(DB_PATH)) cur = conn.execute("SELECT role, content FROM messages WHERE session=? ORDER BY id DESC LIMIT ?", (SESSION_ID, limit)) rows = cur.fetchall() conn.close() return [(r[0], r[1]) for r in reversed(rows)] def delete_history(): conn = sqlite3.connect(str(DB_PATH)) conn.execute("DELETE FROM messages WHERE session=?", (SESSION_ID,)) conn.commit() conn.close() init_db() # ============================================================================= # 8. معالج الدردشة # ============================================================================= async def chat_response(message: str, history: List[Tuple[str, str]]) -> str: if message.startswith("/"): parts = message.strip().split(maxsplit=2) cmd = parts[0].lower() if cmd == "/help": return """📖 **أوامر المالك**: /delete <المفتاح> - مسح الدردشة /learn <المفتاح> - قراءة الملفات /learnsite <المفتاح> <الرابط> - تعلم موقع /status <المفتاح> - حالة النظام /help - هذه المساعدة""" if len(parts) < 2: return f"⚠️ الأمر {cmd} يحتاج إلى المفتاح" if parts[1] != OWNER_SECRET: return "⛔ مفتاح غير صحيح" if cmd == "/delete": delete_history() return "🗑️ تم مسح الدردشة" elif cmd == "/learn": return read_local_files() elif cmd == "/learnsite": if len(parts) < 3: return "⚠️ الصيغة: /learnsite <المفتاح> <الرابط>" return await learn_website(parts[2]) elif cmd == "/status": return f"""**حالة النظام**: - Groq API: {'✅' if GROQ_AVAILABLE else '❌'} - ChromaDB: {'✅' if CHROMA_AVAILABLE else '❌'} - SentenceTransformers: {'✅' if SENTENCE_AVAILABLE else '❌'} - Crawl4AI: {'✅' if CRAWL4AI_AVAILABLE else '❌'} - Tavily: {'✅' if TAVILY_AVAILABLE else '❌'} - الوقت: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}""" else: return f"⚠️ أمر غير معروف: {cmd}" save_message("user", message) answer = await generate_response(message) save_message("assistant", answer) context.add(message, answer) return answer # ============================================================================= # 9. واجهة Gradio # ============================================================================= def create_interface(): async def respond(message, history): return await chat_response(message, history) demo = gr.ChatInterface( fn=respond, title="🦾 GIANT-AI ULTIMATE v52.0 - العملاق الكامل", description="مساعد ذكي عملاق - يدعم البحث العميق، الذاكرة المتجهية، وتعلم المواقع.\nللمالك: /help", examples=["السلام عليكم", "كم سعر الدولار اليوم؟", "/learnsite admin_giant_2026 https://example.com", "/status admin_giant_2026"] ) return demo if __name__ == "__main__": print("🦾 GIANT-AI ULTIMATE v52.0 - تشغيل...") print(f"Groq: {'متاح' if GROQ_AVAILABLE else 'غير متاح'}") print(f"ChromaDB: {'متاح' if CHROMA_AVAILABLE else 'غير متاح'}") print(f"Crawl4AI: {'متاح' if CRAWL4AI_AVAILABLE else 'غير متاح'}") demo = create_interface() demo.queue() demo.launch(server_name="0.0.0.0", server_port=7860)