Spaces:
Runtime error
Runtime error
| import sqlite3 | |
| import json | |
| import time | |
| import numpy as np | |
| from sentence_transformers import SentenceTransformer | |
| class Memory: | |
| def __init__( | |
| self, | |
| db_path="memory.db", | |
| embedding_model="intfloat/multilingual-e5-large" | |
| ): | |
| self.db = sqlite3.connect(db_path) | |
| self.db.row_factory = sqlite3.Row | |
| self.model = SentenceTransformer(embedding_model) | |
| self._create_tables() | |
| self._setup_prototypes() | |
| # --------------------------- | |
| # DB SETUP | |
| # --------------------------- | |
| def _create_tables(self): | |
| self.db.execute(""" | |
| CREATE TABLE IF NOT EXISTS memories( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| role TEXT, | |
| content TEXT, | |
| timestamp REAL, | |
| importance REAL, | |
| recalls INTEGER DEFAULT 0, | |
| last_accessed REAL DEFAULT 0, | |
| embedding TEXT | |
| ) | |
| """) | |
| self.db.commit() | |
| # --------------------------- | |
| # EMBEDDINGS | |
| # --------------------------- | |
| def embed(self, text): | |
| return self.model.encode( | |
| text, | |
| normalize_embeddings=True | |
| ).tolist() | |
| def cosine_similarity(self, a, b): | |
| a = np.array(a) | |
| b = np.array(b) | |
| return float(np.dot(a, b)) # normalized embeddings => dot = cosine | |
| # --------------------------- | |
| # PROTOTYPES (SEMANTIC TYPES) | |
| # --------------------------- | |
| def _setup_prototypes(self): | |
| self.prototype_categories = { | |
| "identity": [ | |
| "My name is John", | |
| "I am 25 years old", | |
| "I live in Berlin", | |
| "I work as a teacher" | |
| ], | |
| "preferences": [ | |
| "My favorite game is Minecraft", | |
| "I love pizza", | |
| "I prefer cats" | |
| ], | |
| "relationships": [ | |
| "I have a sister", | |
| "My wife is a doctor", | |
| "My best friend is Alex" | |
| ], | |
| "goals": [ | |
| "I want to learn Python", | |
| "I plan to move abroad", | |
| "I am saving money" | |
| ], | |
| "health": [ | |
| "I am allergic to peanuts", | |
| "I have diabetes", | |
| "I take medication" | |
| ], | |
| "temporary": [ | |
| "I ate pizza today", | |
| "I watched a movie", | |
| "The weather is nice" | |
| ] | |
| } | |
| self.prototype_embeddings = {} | |
| for cat, examples in self.prototype_categories.items(): | |
| self.prototype_embeddings[cat] = self.model.encode( | |
| examples, | |
| normalize_embeddings=True | |
| ) | |
| # --------------------------- | |
| # CATEGORY DETECTION | |
| # --------------------------- | |
| def detect_memory_category(self, text, embedding): | |
| best_category = "temporary" | |
| best_score = -1.0 | |
| for category, prototypes in self.prototype_embeddings.items(): | |
| sims = [ | |
| self.cosine_similarity(embedding, p) | |
| for p in prototypes | |
| ] | |
| score = max(sims) | |
| if score > best_score: | |
| best_score = score | |
| best_category = category | |
| return best_category, best_score | |
| # --------------------------- | |
| # NOVELTY | |
| # --------------------------- | |
| def novelty_score(self, embedding): | |
| rows = self.db.execute( | |
| "SELECT embedding FROM memories" | |
| ).fetchall() | |
| if not rows: | |
| return 1.0 | |
| max_sim = 0.0 | |
| for row in rows: | |
| stored = json.loads(row["embedding"]) | |
| sim = self.cosine_similarity(embedding, stored) | |
| if sim > max_sim: | |
| max_sim = sim | |
| return float(max(0.0, 1.0 - max_sim)) | |
| # --------------------------- | |
| # DUPLICATE CHECK | |
| # --------------------------- | |
| def is_duplicate(self, embedding, threshold=0.92): | |
| rows = self.db.execute( | |
| "SELECT embedding FROM memories" | |
| ).fetchall() | |
| for row in rows: | |
| stored = json.loads(row["embedding"]) | |
| sim = self.cosine_similarity(embedding, stored) | |
| if sim >= threshold: | |
| return True | |
| return False | |
| # --------------------------- | |
| # IMPORTANCE | |
| # --------------------------- | |
| def calculate_importance(self, text, embedding): | |
| category, confidence = self.detect_memory_category( | |
| text, | |
| embedding | |
| ) | |
| novelty = self.novelty_score(embedding) | |
| weights = { | |
| "identity": 1.0, | |
| "health": 1.0, | |
| "relationships": 0.95, | |
| "goals": 0.9, | |
| "preferences": 0.75, | |
| "temporary": 0.2 | |
| } | |
| semantic_importance = confidence * weights[category] | |
| importance = ( | |
| semantic_importance * 0.7 + | |
| novelty * 0.3 | |
| ) | |
| return float(np.clip(importance, 0.0, 1.0)) | |
| # --------------------------- | |
| # ADD MEMORY | |
| # --------------------------- | |
| def add(self, role, content): | |
| embedding = self.embed(content) | |
| if self.is_duplicate(embedding): | |
| return | |
| importance = self.calculate_importance(content, embedding) | |
| self.db.execute(""" | |
| INSERT INTO memories( | |
| role, | |
| content, | |
| timestamp, | |
| importance, | |
| embedding | |
| ) | |
| VALUES (?, ?, ?, ?, ?) | |
| """, ( | |
| role, | |
| content, | |
| time.time(), | |
| importance, | |
| json.dumps(embedding) | |
| )) | |
| self.db.commit() | |
| # --------------------------- | |
| # RETRIEVAL | |
| # --------------------------- | |
| def retrieve(self, query, top_k=10): | |
| query_embedding = self.embed(query) | |
| rows = self.db.execute( | |
| "SELECT * FROM memories" | |
| ).fetchall() | |
| now = time.time() | |
| scored = [] | |
| for row in rows: | |
| embedding = json.loads(row["embedding"]) | |
| similarity = self.cosine_similarity( | |
| query_embedding, | |
| embedding | |
| ) | |
| age_days = (now - row["timestamp"]) / 86400 | |
| recency = 1 / (1 + age_days * 0.05) | |
| recall_bonus = min(row["recalls"] * 0.02, 0.2) | |
| final_score = ( | |
| similarity | |
| * (1 + row["importance"]) | |
| * (1 + recency * 0.3) | |
| * (1 + recall_bonus) | |
| ) | |
| scored.append((final_score, row)) | |
| scored.sort(key=lambda x: x[0], reverse=True) | |
| memories = [] | |
| for _, row in scored[:top_k]: | |
| self.db.execute(""" | |
| UPDATE memories | |
| SET recalls = recalls + 1, | |
| last_accessed = ? | |
| WHERE id = ? | |
| """, (now, row["id"])) | |
| memories.append({ | |
| "id": row["id"], | |
| "role": row["role"], | |
| "content": row["content"], | |
| "importance": row["importance"] | |
| }) | |
| self.db.commit() | |
| return memories | |
| # --------------------------- | |
| # CONTEXT BUILDER | |
| # --------------------------- | |
| def build_context(self, query, top_k=10): | |
| memories = self.retrieve(query, top_k) | |
| return "\n".join( | |
| f"{m['role']}: {m['content']}" | |
| for m in memories | |
| ) | |
| # --------------------------- | |
| # UTILITIES | |
| # --------------------------- | |
| def recent(self, limit=20): | |
| rows = self.db.execute(""" | |
| SELECT * FROM memories | |
| ORDER BY id DESC | |
| LIMIT ? | |
| """, (limit,)).fetchall() | |
| return [dict(r) for r in rows] | |
| def count(self): | |
| return self.db.execute( | |
| "SELECT COUNT(*) FROM memories" | |
| ).fetchone()[0] | |
| def clear(self): | |
| self.db.execute("DELETE FROM memories") | |
| self.db.commit() | |
| def close(self): | |
| self.db.close() |