Spaces:
Sleeping
Sleeping
Commit
·
8f17704
1
Parent(s):
3855268
Enhance memo dir with context memoriser and rm duplications
Browse files- memo/context.py +1 -5
- memo/core.py +34 -4
- memo/history.py +21 -14
- memo/persistent.py +2 -9
memo/context.py
CHANGED
|
@@ -18,10 +18,6 @@ def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
|
|
| 18 |
denom = (np.linalg.norm(a) * np.linalg.norm(b)) or 1.0
|
| 19 |
return float(np.dot(a, b) / denom)
|
| 20 |
|
| 21 |
-
def as_text(block: str) -> str:
|
| 22 |
-
"""Convert block to text"""
|
| 23 |
-
return block.strip()
|
| 24 |
-
|
| 25 |
async def semantic_context(question: str, memories: List[str], embedder: EmbeddingClient, topk: int = 3) -> str:
|
| 26 |
"""
|
| 27 |
Get semantic context from memories using cosine similarity.
|
|
@@ -31,7 +27,7 @@ async def semantic_context(question: str, memories: List[str], embedder: Embeddi
|
|
| 31 |
|
| 32 |
try:
|
| 33 |
qv = np.array(embedder.embed([question])[0], dtype="float32")
|
| 34 |
-
mats = embedder.embed([
|
| 35 |
sims = [(cosine_similarity(qv, np.array(v, dtype="float32")), s) for v, s in zip(mats, memories)]
|
| 36 |
sims.sort(key=lambda x: x[0], reverse=True)
|
| 37 |
top = [s for (sc, s) in sims[:topk] if sc > 0.15] # small threshold
|
|
|
|
| 18 |
denom = (np.linalg.norm(a) * np.linalg.norm(b)) or 1.0
|
| 19 |
return float(np.dot(a, b) / denom)
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
async def semantic_context(question: str, memories: List[str], embedder: EmbeddingClient, topk: int = 3) -> str:
|
| 22 |
"""
|
| 23 |
Get semantic context from memories using cosine similarity.
|
|
|
|
| 27 |
|
| 28 |
try:
|
| 29 |
qv = np.array(embedder.embed([question])[0], dtype="float32")
|
| 30 |
+
mats = embedder.embed([s.strip() for s in memories])
|
| 31 |
sims = [(cosine_similarity(qv, np.array(v, dtype="float32")), s) for v, s in zip(mats, memories)]
|
| 32 |
sims.sort(key=lambda x: x[0], reverse=True)
|
| 33 |
top = [s for (sc, s) in sims[:topk] if sc > 0.15] # small threshold
|
memo/core.py
CHANGED
|
@@ -128,15 +128,16 @@ class MemorySystem:
|
|
| 128 |
|
| 129 |
async def get_conversation_context(self, user_id: str, question: str,
|
| 130 |
project_id: Optional[str] = None) -> Tuple[str, str]:
|
| 131 |
-
"""Get conversation context for chat continuity"""
|
| 132 |
try:
|
| 133 |
if self.enhanced_available:
|
| 134 |
-
# Use enhanced context retrieval
|
| 135 |
recent_context, semantic_context = await self._get_enhanced_context(user_id, question)
|
| 136 |
return recent_context, semantic_context
|
| 137 |
else:
|
| 138 |
-
#
|
| 139 |
-
|
|
|
|
| 140 |
except Exception as e:
|
| 141 |
logger.error(f"[CORE_MEMORY] Failed to get conversation context: {e}")
|
| 142 |
return "", ""
|
|
@@ -173,6 +174,35 @@ class MemorySystem:
|
|
| 173 |
"enhanced_available": False
|
| 174 |
}
|
| 175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
# ────────────────────────────── Private Helper Methods ──────────────────────────────
|
| 177 |
|
| 178 |
async def _add_enhanced_memory(self, user_id: str, question: str, answer: str):
|
|
|
|
| 128 |
|
| 129 |
async def get_conversation_context(self, user_id: str, question: str,
|
| 130 |
project_id: Optional[str] = None) -> Tuple[str, str]:
|
| 131 |
+
"""Get conversation context for chat continuity with enhanced memory ability"""
|
| 132 |
try:
|
| 133 |
if self.enhanced_available:
|
| 134 |
+
# Use enhanced context retrieval with better integration
|
| 135 |
recent_context, semantic_context = await self._get_enhanced_context(user_id, question)
|
| 136 |
return recent_context, semantic_context
|
| 137 |
else:
|
| 138 |
+
# Use legacy context with enhanced semantic selection
|
| 139 |
+
from memo.context import get_legacy_context
|
| 140 |
+
return await get_legacy_context(user_id, question, self, self.embedder, 3)
|
| 141 |
except Exception as e:
|
| 142 |
logger.error(f"[CORE_MEMORY] Failed to get conversation context: {e}")
|
| 143 |
return "", ""
|
|
|
|
| 174 |
"enhanced_available": False
|
| 175 |
}
|
| 176 |
|
| 177 |
+
async def get_smart_context(self, user_id: str, question: str,
|
| 178 |
+
nvidia_rotator=None, project_id: Optional[str] = None) -> Tuple[str, str]:
|
| 179 |
+
"""Get smart context using both NVIDIA and semantic similarity for optimal memory ability"""
|
| 180 |
+
try:
|
| 181 |
+
if self.enhanced_available:
|
| 182 |
+
# Use enhanced context with NVIDIA integration if available
|
| 183 |
+
recent_context, semantic_context = await self._get_enhanced_context(user_id, question)
|
| 184 |
+
|
| 185 |
+
# If NVIDIA rotator is available, enhance recent context selection
|
| 186 |
+
if nvidia_rotator and recent_context:
|
| 187 |
+
try:
|
| 188 |
+
from memo.nvidia import related_recent_context
|
| 189 |
+
recent_memories = self.legacy_memory.recent(user_id, 5)
|
| 190 |
+
if recent_memories:
|
| 191 |
+
nvidia_recent = await related_recent_context(question, recent_memories, nvidia_rotator)
|
| 192 |
+
if nvidia_recent:
|
| 193 |
+
recent_context = nvidia_recent
|
| 194 |
+
except Exception as e:
|
| 195 |
+
logger.warning(f"[CORE_MEMORY] NVIDIA context enhancement failed: {e}")
|
| 196 |
+
|
| 197 |
+
return recent_context, semantic_context
|
| 198 |
+
else:
|
| 199 |
+
# Use legacy context with NVIDIA enhancement if available
|
| 200 |
+
from memo.context import get_legacy_context
|
| 201 |
+
return await get_legacy_context(user_id, question, self, self.embedder, 3)
|
| 202 |
+
except Exception as e:
|
| 203 |
+
logger.error(f"[CORE_MEMORY] Failed to get smart context: {e}")
|
| 204 |
+
return "", ""
|
| 205 |
+
|
| 206 |
# ────────────────────────────── Private Helper Methods ──────────────────────────────
|
| 207 |
|
| 208 |
async def _add_enhanced_memory(self, user_id: str, question: str, answer: str):
|
memo/history.py
CHANGED
|
@@ -9,7 +9,7 @@ from typing import List, Dict, Any, Tuple, Optional
|
|
| 9 |
|
| 10 |
from utils.logger import get_logger
|
| 11 |
from memo.nvidia import summarize_qa, files_relevance, related_recent_context
|
| 12 |
-
from memo.context import semantic_context
|
| 13 |
from utils.embeddings import EmbeddingClient
|
| 14 |
|
| 15 |
logger = get_logger("HISTORY_MANAGER", __name__)
|
|
@@ -33,7 +33,7 @@ class HistoryManager:
|
|
| 33 |
|
| 34 |
async def related_recent_and_semantic_context(self, user_id: str, question: str,
|
| 35 |
embedder: EmbeddingClient,
|
| 36 |
-
topk_sem: int = 3) -> Tuple[str, str]:
|
| 37 |
"""Get related recent and semantic context (enhanced version)"""
|
| 38 |
try:
|
| 39 |
if self.memory_system and self.memory_system.is_enhanced_available():
|
|
@@ -43,14 +43,14 @@ class HistoryManager:
|
|
| 43 |
)
|
| 44 |
return recent_context, semantic_context
|
| 45 |
else:
|
| 46 |
-
# Fallback to original implementation
|
| 47 |
-
return await
|
| 48 |
except Exception as e:
|
| 49 |
logger.error(f"[HISTORY_MANAGER] Context retrieval failed: {e}")
|
| 50 |
return "", ""
|
| 51 |
|
| 52 |
async def _get_legacy_context(self, user_id: str, question: str, memory_system,
|
| 53 |
-
embedder: EmbeddingClient, topk_sem: int) -> Tuple[str, str]:
|
| 54 |
"""Get context using legacy method with enhanced semantic selection"""
|
| 55 |
if not memory_system:
|
| 56 |
return "", ""
|
|
@@ -61,15 +61,22 @@ class HistoryManager:
|
|
| 61 |
recent_text = ""
|
| 62 |
if recent3:
|
| 63 |
# Use NVIDIA to select most relevant recent memories (enhanced)
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
try:
|
| 70 |
recent_text = await semantic_context(question, recent3, embedder, 2)
|
| 71 |
-
except Exception as
|
| 72 |
-
logger.warning(f"[HISTORY_MANAGER] Semantic
|
| 73 |
|
| 74 |
sem_text = ""
|
| 75 |
if rest17:
|
|
@@ -87,11 +94,11 @@ async def files_relevance(question: str, file_summaries: List[Dict[str, str]], r
|
|
| 87 |
"""Legacy function - use HistoryManager.files_relevance() instead"""
|
| 88 |
return await files_relevance(question, file_summaries, rotator)
|
| 89 |
|
| 90 |
-
async def related_recent_and_semantic_context(user_id: str, question: str, memory, embedder: EmbeddingClient, topk_sem: int = 3) -> Tuple[str, str]:
|
| 91 |
"""Legacy function - use HistoryManager.related_recent_and_semantic_context() instead"""
|
| 92 |
# Create a temporary history manager for legacy compatibility
|
| 93 |
history_manager = HistoryManager(memory)
|
| 94 |
-
return await history_manager.related_recent_and_semantic_context(user_id, question, embedder, topk_sem)
|
| 95 |
|
| 96 |
# ────────────────────────────── Global Instance ──────────────────────────────
|
| 97 |
|
|
|
|
| 9 |
|
| 10 |
from utils.logger import get_logger
|
| 11 |
from memo.nvidia import summarize_qa, files_relevance, related_recent_context
|
| 12 |
+
from memo.context import semantic_context, get_legacy_context
|
| 13 |
from utils.embeddings import EmbeddingClient
|
| 14 |
|
| 15 |
logger = get_logger("HISTORY_MANAGER", __name__)
|
|
|
|
| 33 |
|
| 34 |
async def related_recent_and_semantic_context(self, user_id: str, question: str,
|
| 35 |
embedder: EmbeddingClient,
|
| 36 |
+
topk_sem: int = 3, nvidia_rotator=None) -> Tuple[str, str]:
|
| 37 |
"""Get related recent and semantic context (enhanced version)"""
|
| 38 |
try:
|
| 39 |
if self.memory_system and self.memory_system.is_enhanced_available():
|
|
|
|
| 43 |
)
|
| 44 |
return recent_context, semantic_context
|
| 45 |
else:
|
| 46 |
+
# Fallback to original implementation with NVIDIA support
|
| 47 |
+
return await self._get_legacy_context(user_id, question, self.memory_system, embedder, topk_sem, nvidia_rotator)
|
| 48 |
except Exception as e:
|
| 49 |
logger.error(f"[HISTORY_MANAGER] Context retrieval failed: {e}")
|
| 50 |
return "", ""
|
| 51 |
|
| 52 |
async def _get_legacy_context(self, user_id: str, question: str, memory_system,
|
| 53 |
+
embedder: EmbeddingClient, topk_sem: int, nvidia_rotator=None) -> Tuple[str, str]:
|
| 54 |
"""Get context using legacy method with enhanced semantic selection"""
|
| 55 |
if not memory_system:
|
| 56 |
return "", ""
|
|
|
|
| 61 |
recent_text = ""
|
| 62 |
if recent3:
|
| 63 |
# Use NVIDIA to select most relevant recent memories (enhanced)
|
| 64 |
+
if nvidia_rotator:
|
| 65 |
+
try:
|
| 66 |
+
recent_text = await related_recent_context(question, recent3, nvidia_rotator)
|
| 67 |
+
except Exception as e:
|
| 68 |
+
logger.warning(f"[HISTORY_MANAGER] NVIDIA recent context selection failed: {e}")
|
| 69 |
+
# Fallback to semantic similarity
|
| 70 |
+
try:
|
| 71 |
+
recent_text = await semantic_context(question, recent3, embedder, 2)
|
| 72 |
+
except Exception as e2:
|
| 73 |
+
logger.warning(f"[HISTORY_MANAGER] Semantic fallback failed: {e2}")
|
| 74 |
+
else:
|
| 75 |
+
# Use semantic similarity directly if no NVIDIA rotator
|
| 76 |
try:
|
| 77 |
recent_text = await semantic_context(question, recent3, embedder, 2)
|
| 78 |
+
except Exception as e:
|
| 79 |
+
logger.warning(f"[HISTORY_MANAGER] Semantic recent context failed: {e}")
|
| 80 |
|
| 81 |
sem_text = ""
|
| 82 |
if rest17:
|
|
|
|
| 94 |
"""Legacy function - use HistoryManager.files_relevance() instead"""
|
| 95 |
return await files_relevance(question, file_summaries, rotator)
|
| 96 |
|
| 97 |
+
async def related_recent_and_semantic_context(user_id: str, question: str, memory, embedder: EmbeddingClient, topk_sem: int = 3, nvidia_rotator=None) -> Tuple[str, str]:
|
| 98 |
"""Legacy function - use HistoryManager.related_recent_and_semantic_context() instead"""
|
| 99 |
# Create a temporary history manager for legacy compatibility
|
| 100 |
history_manager = HistoryManager(memory)
|
| 101 |
+
return await history_manager.related_recent_and_semantic_context(user_id, question, embedder, topk_sem, nvidia_rotator)
|
| 102 |
|
| 103 |
# ────────────────────────────── Global Instance ──────────────────────────────
|
| 104 |
|
memo/persistent.py
CHANGED
|
@@ -142,17 +142,10 @@ class PersistentMemory:
|
|
| 142 |
"""Calculate cosine similarity between two vectors"""
|
| 143 |
try:
|
| 144 |
import numpy as np
|
|
|
|
| 145 |
a_np = np.array(a)
|
| 146 |
b_np = np.array(b)
|
| 147 |
-
|
| 148 |
-
dot_product = np.dot(a_np, b_np)
|
| 149 |
-
norm_a = np.linalg.norm(a_np)
|
| 150 |
-
norm_b = np.linalg.norm(b_np)
|
| 151 |
-
|
| 152 |
-
if norm_a == 0 or norm_b == 0:
|
| 153 |
-
return 0.0
|
| 154 |
-
|
| 155 |
-
return float(dot_product / (norm_a * norm_b))
|
| 156 |
except Exception:
|
| 157 |
return 0.0
|
| 158 |
|
|
|
|
| 142 |
"""Calculate cosine similarity between two vectors"""
|
| 143 |
try:
|
| 144 |
import numpy as np
|
| 145 |
+
from memo.context import cosine_similarity
|
| 146 |
a_np = np.array(a)
|
| 147 |
b_np = np.array(b)
|
| 148 |
+
return cosine_similarity(a_np, b_np)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
except Exception:
|
| 150 |
return 0.0
|
| 151 |
|