File size: 4,439 Bytes
0f0b357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""

Vector Memory Module

Mem贸ria de longo prazo usando ChromaDB + Sentence Transformers

"""

import chromadb
from sentence_transformers import SentenceTransformer
from datetime import datetime
import hashlib

# Usar modelo leve para embeddings
EMBEDDING_MODEL = "all-MiniLM-L6-v2"  # ~80MB, r谩pido

# Singleton para evitar recarregar
_memory_instance = None


def get_memory():
    """Get or create memory instance."""
    global _memory_instance
    if _memory_instance is None:
        _memory_instance = VectorMemory()
    return _memory_instance


class VectorMemory:
    def __init__(self):
        print("Inicializando mem贸ria vetorial...")
        
        # Modelo de embeddings
        self.model = SentenceTransformer(EMBEDDING_MODEL)
        print(f"Modelo carregado: {EMBEDDING_MODEL}")
        
        # ChromaDB em mem贸ria (persiste enquanto o servidor estiver rodando)
        self.client = chromadb.Client()
        self.collection = self.client.get_or_create_collection(
            name="chat_memory",
            metadata={"hnsw:space": "cosine"}
        )
        
        print(f"Mem贸ria pronta. {self.collection.count()} mem贸rias existentes.")
    
    def _generate_id(self, text: str) -> str:
        """Generate unique ID for a memory."""
        timestamp = datetime.now().isoformat()
        content = f"{timestamp}:{text}"
        return hashlib.md5(content.encode()).hexdigest()
    
    def add_memory(self, user_message: str, bot_response: str):
        """

        Add a conversation exchange to memory.

        Stores the combined context for better retrieval.

        """
        # Combinar mensagem e resposta para contexto completo
        combined = f"Usu谩rio: {user_message}\nAssistente: {bot_response}"
        
        # Gerar embedding
        embedding = self.model.encode(combined).tolist()
        
        # Gerar ID 煤nico
        doc_id = self._generate_id(combined)
        
        # Metadados
        metadata = {
            "user_message": user_message[:500],  # Truncar se muito longo
            "bot_response": bot_response[:500],
            "timestamp": datetime.now().isoformat()
        }
        
        # Adicionar ao banco
        self.collection.add(
            ids=[doc_id],
            embeddings=[embedding],
            documents=[combined],
            metadatas=[metadata]
        )
        
        print(f"Mem贸ria adicionada. Total: {self.collection.count()}")
    
    def search_memories(self, query: str, k: int = 3) -> list[dict]:
        """

        Search for relevant memories based on the query.

        Returns list of {text, user_message, bot_response, score}

        """
        if self.collection.count() == 0:
            return []
        
        # Gerar embedding da query
        query_embedding = self.model.encode(query).tolist()
        
        # Buscar similares
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=min(k, self.collection.count())
        )
        
        memories = []
        if results and results['documents'] and results['documents'][0]:
            for i, doc in enumerate(results['documents'][0]):
                metadata = results['metadatas'][0][i] if results['metadatas'] else {}
                distance = results['distances'][0][i] if results['distances'] else 0
                
                memories.append({
                    "text": doc,
                    "user_message": metadata.get("user_message", ""),
                    "bot_response": metadata.get("bot_response", ""),
                    "score": 1 - distance,  # Converter dist芒ncia em similaridade
                    "timestamp": metadata.get("timestamp", "")
                })
        
        return memories
    
    def clear_memories(self):
        """Clear all memories."""
        # Recriar collection
        self.client.delete_collection("chat_memory")
        self.collection = self.client.get_or_create_collection(
            name="chat_memory",
            metadata={"hnsw:space": "cosine"}
        )
        print("Mem贸rias limpas.")
    
    def get_stats(self) -> dict:
        """Get memory statistics."""
        return {
            "total_memories": self.collection.count(),
            "model": EMBEDDING_MODEL
        }