File size: 3,376 Bytes
85ff8b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
from typing import List

app = FastAPI(title="مدير ذاكرة المحادثة")

# تحميل نموذج تحويل النصوص إلى متجهات (Embedding) باللغة العربية
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

# أبعاد المتجه (حسب النموذج)
embedding_dim = 384

# إنشاء فهرس FAISS (بحث بالتشابه الداخلي) مع دعم المعرفات
index = faiss.IndexIDMap(faiss.IndexFlatIP(embedding_dim))

# قائمة لتخزين مدخلات الذاكرة (كل مدخل: سؤال وجواب ومعرف)
memory = []
next_id = 0

# عتبة التشابه الكوني (cosine similarity)
SIMILARITY_THRESHOLD = 0.7

class QAEntry(BaseModel):
    input: str
    output: str

class Query(BaseModel):
    input: str

# دالة لحساب متجه embedding لنص وإرجاعه بعد التطبيع
def get_embedding(text: str) -> np.ndarray:
    embed = model.encode([text])[0]
    embed = embed / np.linalg.norm(embed)
    return embed.astype('float32')

@app.post("/add")
def add_entry(entry: QAEntry):
    """
    إضافة مدخل جديد للذاكرة (سؤال + جواب).
    """
    global next_id
    embedding = get_embedding(entry.input)
    entry_id = next_id
    next_id += 1
    # إضافة المتجه إلى فهرس FAISS مع المعرف
    index.add_with_ids(np.array([embedding]), np.array([entry_id], dtype='int64'))
    # حفظ السؤال والجواب في القائمة
    memory.append({"id": entry_id, "input": entry.input, "output": entry.output})
    return {"status": "تم الإضافة", "id": entry_id}

@app.post("/query")
def query_memory(query: Query):
    """
    الاستعلام عن سؤال جديد ومحاولة إيجاد جواب من الذاكرة.
    """
    if not memory:
        return {"output": None, "info": "الذاكرة فارغة"}
    embedding = get_embedding(query.input)
    # البحث عن أقرب إجابة
    D, I = index.search(np.array([embedding]), k=1)
    if I[0][0] == -1:
        return {"output": None}
    similarity = float(D[0][0])
    matched_id = int(I[0][0])
    if similarity >= SIMILARITY_THRESHOLD:
        for entry in memory:
            if entry["id"] == matched_id:
                return {"output": entry["output"], "id": matched_id, "similarity": similarity}
    return {"output": None, "id": None, "similarity": similarity}

@app.get("/memory")
def get_memory():
    """
    استعراض جميع محتويات الذاكرة (الأسئلة المخزنة + الردود).
    """
    return {"memory": memory}

@app.delete("/delete/{entry_id}")
def delete_entry(entry_id: int):
    """
    حذف مدخل من الذاكرة حسب المعرف وإزالته من فهرس FAISS.
    """
    for idx, entry in enumerate(memory):
        if entry["id"] == entry_id:
            del memory[idx]
            # إزالة المتجه من فهرس FAISS باستخدام remove_ids
            index.remove_ids(np.array([entry_id], dtype='int64'))
            return {"status": "تم الحذف", "id": entry_id}
    raise HTTPException(status_code=404, detail="المعرف غير موجود")