File size: 6,268 Bytes
7d1d5af
 
 
0cbefb6
7d1d5af
0cbefb6
 
 
7d1d5af
0cbefb6
 
 
 
 
7d1d5af
0cbefb6
 
ee1ea3a
0cbefb6
 
 
 
7d1d5af
0cbefb6
 
 
 
 
 
 
 
 
 
 
7d1d5af
0cbefb6
 
7d1d5af
0cbefb6
 
 
 
7d1d5af
0cbefb6
 
 
7d1d5af
0cbefb6
 
 
 
7d1d5af
0cbefb6
 
7d1d5af
 
0cbefb6
 
 
 
 
 
 
8a3b8db
0cbefb6
 
 
7d1d5af
0cbefb6
 
8a3b8db
7d1d5af
0cbefb6
 
7d1d5af
 
 
 
 
 
0cbefb6
7d1d5af
 
 
 
 
0cbefb6
 
 
 
 
 
 
 
 
 
7d1d5af
0cbefb6
 
 
 
 
7d1d5af
0cbefb6
 
7d1d5af
0cbefb6
 
7d1d5af
0cbefb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7d1d5af
0cbefb6
 
 
 
 
 
 
7d1d5af
 
 
0cbefb6
8a3b8db
ee1ea3a
7d1d5af
 
 
0cbefb6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import os
import uuid
import gradio as gr
import chromadb
from openai import OpenAI
from chromadb.utils import embedding_functions
from pypdf import PdfReader
from docx import Document

# --- 1. إعداد الذاكرة السيبرانية (ChromaDB) ---
CHROMA_DATA_PATH = "./neural_memory_v2"
chroma_client = chromadb.PersistentClient(path=CHROMA_DATA_PATH)
ef = embedding_functions.DefaultEmbeddingFunction()
collection = chroma_client.get_or_create_collection(name="yousef_vault", embedding_function=ef)

# النموذج الأساسي الافتراضي (يمكنك تغييره من هنا)
DEFAULT_MODEL = "huihui-ai/Qwen2.5-72B-Instruct-abliterated"

# --- 2. دالة استخراج النصوص (يدعم PDF, DOCX, TXT) ---
def process_document(file):
    if file is None: return "⚠️ لم يتم اختيار ملف."
    text = ""
    try:
        file_ext = os.path.splitext(file.name)[1].lower()
        if file_ext == ".pdf":
            reader = PdfReader(file.name)
            for page in reader.pages:
                text += (page.extract_text() or "") + "\n"
        elif file_ext == ".docx":
            doc = Document(file.name)
            text = "\n".join([para.text for para in doc.paragraphs])
        elif file_ext in [".txt", ".md"]:
            with open(file.name, "r", encoding="utf-8", errors="ignore") as f:
                text = f.read()
        
        if not text.strip():
            return "❌ تعذر استخراج نص. تأكد أن الملف ليس صوراً فقط."

        # تقسيم النص لقطع وحقنها في الذاكرة
        chunks = [text[i:i+2000] for i in range(0, len(text), 2000)]
        ids = [str(uuid.uuid4()) for _ in chunks]
        collection.add(documents=chunks, ids=ids)
        
        return f"✅ تمت الأرشفة: {len(chunks)} شظية معرفية حُقنت في الذاكرة."
    except Exception as e:
        return f"❌ خطأ في المعالجة: {str(e)}"

# --- 3. دالة الحوار (RAG) مع معالجة أخطاء الـ Stream ---
def predict(message, history, system_prompt, temperature, custom_model, oauth_token: gr.OAuthToken | None):
    # استخدام توكن المستخدم المسجل (OAuth) لخصم الرصيد الشخصي
    api_key = oauth_token.token if oauth_token else os.getenv("HF_TOKEN")
    
    if not api_key:
        yield "⚠️ يرجى تسجيل الدخول عبر Hugging Face أولاً للوصول إلى رصيدك الشخصي."
        return

    client = OpenAI(
        base_url="https://router.huggingface.co/v1",
        api_key=api_key
    )
    
    # تحديد النموذج المستخدم
    active_model = custom_model.strip() if custom_model and custom_model.strip() else DEFAULT_MODEL
    
    # استرجاع سياق من الذاكرة
    results = collection.query(query_texts=[message], n_results=10)
    context = "\n".join(results['documents'][0]) if results['documents'] else ""
    
    # بناء قائمة الرسائل
    messages = [{"role": "system", "content": f"{system_prompt}\n\n[CONTEXT]:\n{context}"}]
    
    for msg in history:
        messages.append({"role": msg['role'], "content": msg['content']})
        
    messages.append({"role": "user", "content": message})

    try:
        response = client.chat.completions.create(
            model=active_model,
            messages=messages,
            temperature=temperature,
            stream=True
        )

        partial_message = ""
        for chunk in response:
            # حماية ضد خطأ list index out of range
            if hasattr(chunk, 'choices') and chunk.choices and len(chunk.choices) > 0:
                content = chunk.choices[0].delta.content
                if content:
                    partial_message += content
                    yield partial_message
            else:
                # تجاهل الإطارات الفارغة التي تظهر في نهاية البث
                continue
                
    except Exception as e:
        if partial_message:
            # إذا كان هناك نص تم توليده بالفعل، اعرضه ولا تظهر رسالة الخطأ
            yield partial_message
        else:
            yield f"❌ فشل الاتصال بالنموذج ({active_model}): {str(e)}"

# --- 4. بناء الواجهة (بسيطة، داكنة، ومتجاوبة) ---
with gr.Blocks(fill_height=True, theme=gr.themes.Soft(primary_hue="indigo")) as demo:
    with gr.Sidebar():
        gr.Markdown("# 🧬 دهليز يوسف")
        gr.LoginButton("Sign in")
        
        with gr.Accordion("⚙️ الضبط والوعي", open=True):
            model_input = gr.Textbox(
                label="المحرك المستهدف (Model ID)",
                placeholder="اتركه فارغاً للنموذج الأساسي",
                value="",
                lines=1
            )
            system_input = gr.Textbox(
                value="أنت رفيق حكيم يغوص في التيه مع المستخدم. أجب بصدق مستعيناً بالذاكرة.", 
                label="البرومبت النظامي"
            )
            temp_slider = gr.Slider(0.1, 1.5, 0.8, label="درجة التشظي (Temperature)")
        
        gr.Markdown("---")
        gr.Markdown("### 📂 ملقم الذاكرة (PDF, DOCX, TXT)")
        file_box = gr.File(label="ارفع مسوداتك هنا", file_types=[".pdf", ".docx", ".txt"])
        status_msg = gr.Markdown("*الذاكرة بانتظار الملفات...*")
        
        file_box.change(process_document, inputs=file_box, outputs=status_msg)
        
        clear_btn = gr.Button("🗑 مسح الذاكرة")
        def clear_memory():
            all_data = collection.get()
            if all_data['ids']: 
                collection.delete(ids=all_data['ids'])
            return "🗑 تم تصفير الذاكرة بالكامل."
        clear_btn.click(clear_memory, outputs=status_msg)

    gr.ChatInterface(
        predict,
        additional_inputs=[system_input, temp_slider, model_input],
        fill_height=True,
        type="messages"
    )

if __name__ == "__main__":
    demo.launch()