Spaces:
Running
Running
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -1,21 +1,28 @@
|
|
| 1 |
"""
|
| 2 |
Mnemo v2 - Interactive Demo (ZeroGPU Compatible)
|
| 3 |
Enhanced memory system with real embeddings, HNSW index, and temporal decay.
|
|
|
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
import gradio as gr
|
| 7 |
import spaces
|
| 8 |
import time
|
| 9 |
from datetime import datetime
|
| 10 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
def format_time(timestamp: float) -> str:
|
| 13 |
return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
| 14 |
|
| 15 |
def get_stats_text(user_id: str = "default") -> str:
|
| 16 |
-
|
| 17 |
-
stats = mnemo.get_stats(user_id=user_id or "default")
|
| 18 |
-
|
| 19 |
return f"""**System Stats**
|
| 20 |
- Total memories: {stats['total_memories']}
|
| 21 |
- User memories: {stats['user_memory_count']}
|
|
@@ -26,18 +33,29 @@ def get_stats_text(user_id: str = "default") -> str:
|
|
| 26 |
|
| 27 |
|
| 28 |
@spaces.GPU(duration=30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
def add_memory(content: str, importance: float, tags: str, user_id: str):
|
| 30 |
-
"""Add a memory -
|
| 31 |
if not content.strip():
|
| 32 |
return "❌ Please enter content", get_stats_text(user_id)
|
| 33 |
|
| 34 |
-
mnemo = get_mnemo()
|
| 35 |
tags_list = [t.strip() for t in tags.split(",") if t.strip()] if tags else []
|
| 36 |
|
| 37 |
-
# Compute embedding
|
| 38 |
-
embedding =
|
| 39 |
|
| 40 |
-
|
|
|
|
| 41 |
content=content,
|
| 42 |
embedding=embedding,
|
| 43 |
user_id=user_id or "default",
|
|
@@ -51,19 +69,18 @@ def add_memory(content: str, importance: float, tags: str, user_id: str):
|
|
| 51 |
return f"{icon} {result['message']} (ID: {result['id']})", get_stats_text(user_id)
|
| 52 |
|
| 53 |
|
| 54 |
-
@spaces.GPU(duration=30)
|
| 55 |
def search_memories(query: str, k: int, min_score: float, user_id: str):
|
| 56 |
-
"""Search memories -
|
| 57 |
if not query.strip():
|
| 58 |
return "❌ Please enter a search query"
|
| 59 |
|
| 60 |
-
mnemo = get_mnemo()
|
| 61 |
start = time.time()
|
| 62 |
|
| 63 |
-
# Compute query embedding
|
| 64 |
-
query_embedding =
|
| 65 |
|
| 66 |
-
|
|
|
|
| 67 |
query_embedding=query_embedding,
|
| 68 |
user_id=user_id or "default",
|
| 69 |
k=k,
|
|
@@ -94,9 +111,8 @@ def search_memories(query: str, k: int, min_score: float, user_id: str):
|
|
| 94 |
|
| 95 |
|
| 96 |
def list_memories_ui(user_id: str, limit: int):
|
| 97 |
-
"""List memories - no GPU needed."""
|
| 98 |
-
|
| 99 |
-
memories = mnemo.list_memories(user_id=user_id or "default", limit=limit)
|
| 100 |
|
| 101 |
if not memories:
|
| 102 |
return "No memories stored yet."
|
|
@@ -119,8 +135,7 @@ def delete_memory_ui(memory_id: str, user_id: str):
|
|
| 119 |
if not memory_id.strip():
|
| 120 |
return "❌ Please enter a memory ID", get_stats_text(user_id)
|
| 121 |
|
| 122 |
-
|
| 123 |
-
success = mnemo.delete(memory_id.strip(), user_id=user_id or "default")
|
| 124 |
|
| 125 |
if success:
|
| 126 |
return f"✅ Deleted memory: {memory_id}", get_stats_text(user_id)
|
|
@@ -129,16 +144,12 @@ def delete_memory_ui(memory_id: str, user_id: str):
|
|
| 129 |
|
| 130 |
def clear_memories_ui(user_id: str):
|
| 131 |
"""Clear all memories - no GPU needed."""
|
| 132 |
-
|
| 133 |
-
count = mnemo.clear(user_id=user_id or "default")
|
| 134 |
return f"🗑️ Cleared {count} memories", get_stats_text(user_id)
|
| 135 |
|
| 136 |
|
| 137 |
-
@spaces.GPU(duration=60)
|
| 138 |
def load_examples(user_id: str):
|
| 139 |
-
"""Load example memories -
|
| 140 |
-
mnemo = get_mnemo()
|
| 141 |
-
|
| 142 |
examples = [
|
| 143 |
("User prefers dark mode and VS Code for development", 1.0, ["preferences", "development"]),
|
| 144 |
("Project deadline is March 15th 2026 for the Q1 release", 0.9, ["project", "deadline"]),
|
|
@@ -150,13 +161,14 @@ def load_examples(user_id: str):
|
|
| 150 |
("Lives in San Francisco, timezone is PST", 0.6, ["personal", "location"]),
|
| 151 |
]
|
| 152 |
|
| 153 |
-
# Batch compute embeddings
|
| 154 |
texts = [ex[0] for ex in examples]
|
| 155 |
-
embeddings =
|
| 156 |
|
|
|
|
| 157 |
added = 0
|
| 158 |
for i, (content, importance, tags) in enumerate(examples):
|
| 159 |
-
result =
|
| 160 |
content=content,
|
| 161 |
embedding=embeddings[i],
|
| 162 |
user_id=user_id or "default",
|
|
|
|
| 1 |
"""
|
| 2 |
Mnemo v2 - Interactive Demo (ZeroGPU Compatible)
|
| 3 |
Enhanced memory system with real embeddings, HNSW index, and temporal decay.
|
| 4 |
+
|
| 5 |
+
Fixed: State persistence across ZeroGPU function calls
|
| 6 |
"""
|
| 7 |
|
| 8 |
import gradio as gr
|
| 9 |
import spaces
|
| 10 |
import time
|
| 11 |
from datetime import datetime
|
| 12 |
+
from typing import List
|
| 13 |
+
import numpy as np
|
| 14 |
+
|
| 15 |
+
# Import core components
|
| 16 |
+
from mnemo_core import MnemoV2, compute_embedding, compute_embeddings_batch
|
| 17 |
+
|
| 18 |
+
# Global persistent state (outside GPU functions)
|
| 19 |
+
MNEMO = MnemoV2()
|
| 20 |
|
| 21 |
def format_time(timestamp: float) -> str:
|
| 22 |
return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
| 23 |
|
| 24 |
def get_stats_text(user_id: str = "default") -> str:
|
| 25 |
+
stats = MNEMO.get_stats(user_id=user_id or "default")
|
|
|
|
|
|
|
| 26 |
return f"""**System Stats**
|
| 27 |
- Total memories: {stats['total_memories']}
|
| 28 |
- User memories: {stats['user_memory_count']}
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
@spaces.GPU(duration=30)
|
| 36 |
+
def compute_single_embedding(text: str) -> np.ndarray:
|
| 37 |
+
"""GPU function: compute embedding for single text."""
|
| 38 |
+
return compute_embedding(text)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@spaces.GPU(duration=60)
|
| 42 |
+
def compute_batch_embeddings(texts: List[str]) -> np.ndarray:
|
| 43 |
+
"""GPU function: compute embeddings for batch of texts."""
|
| 44 |
+
return compute_embeddings_batch(texts)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
def add_memory(content: str, importance: float, tags: str, user_id: str):
|
| 48 |
+
"""Add a memory - computes embedding on GPU, stores in persistent state."""
|
| 49 |
if not content.strip():
|
| 50 |
return "❌ Please enter content", get_stats_text(user_id)
|
| 51 |
|
|
|
|
| 52 |
tags_list = [t.strip() for t in tags.split(",") if t.strip()] if tags else []
|
| 53 |
|
| 54 |
+
# Compute embedding on GPU
|
| 55 |
+
embedding = compute_single_embedding(content)
|
| 56 |
|
| 57 |
+
# Store in persistent MNEMO instance (CPU operation)
|
| 58 |
+
result = MNEMO.add_with_embedding(
|
| 59 |
content=content,
|
| 60 |
embedding=embedding,
|
| 61 |
user_id=user_id or "default",
|
|
|
|
| 69 |
return f"{icon} {result['message']} (ID: {result['id']})", get_stats_text(user_id)
|
| 70 |
|
| 71 |
|
|
|
|
| 72 |
def search_memories(query: str, k: int, min_score: float, user_id: str):
|
| 73 |
+
"""Search memories - computes query embedding on GPU, searches persistent state."""
|
| 74 |
if not query.strip():
|
| 75 |
return "❌ Please enter a search query"
|
| 76 |
|
|
|
|
| 77 |
start = time.time()
|
| 78 |
|
| 79 |
+
# Compute query embedding on GPU
|
| 80 |
+
query_embedding = compute_single_embedding(query)
|
| 81 |
|
| 82 |
+
# Search in persistent MNEMO instance (CPU operation)
|
| 83 |
+
results = MNEMO.search_with_embedding(
|
| 84 |
query_embedding=query_embedding,
|
| 85 |
user_id=user_id or "default",
|
| 86 |
k=k,
|
|
|
|
| 111 |
|
| 112 |
|
| 113 |
def list_memories_ui(user_id: str, limit: int):
|
| 114 |
+
"""List memories - no GPU needed, uses persistent state."""
|
| 115 |
+
memories = MNEMO.list_memories(user_id=user_id or "default", limit=limit)
|
|
|
|
| 116 |
|
| 117 |
if not memories:
|
| 118 |
return "No memories stored yet."
|
|
|
|
| 135 |
if not memory_id.strip():
|
| 136 |
return "❌ Please enter a memory ID", get_stats_text(user_id)
|
| 137 |
|
| 138 |
+
success = MNEMO.delete(memory_id.strip(), user_id=user_id or "default")
|
|
|
|
| 139 |
|
| 140 |
if success:
|
| 141 |
return f"✅ Deleted memory: {memory_id}", get_stats_text(user_id)
|
|
|
|
| 144 |
|
| 145 |
def clear_memories_ui(user_id: str):
|
| 146 |
"""Clear all memories - no GPU needed."""
|
| 147 |
+
count = MNEMO.clear(user_id=user_id or "default")
|
|
|
|
| 148 |
return f"🗑️ Cleared {count} memories", get_stats_text(user_id)
|
| 149 |
|
| 150 |
|
|
|
|
| 151 |
def load_examples(user_id: str):
|
| 152 |
+
"""Load example memories - batch GPU embedding then store in persistent state."""
|
|
|
|
|
|
|
| 153 |
examples = [
|
| 154 |
("User prefers dark mode and VS Code for development", 1.0, ["preferences", "development"]),
|
| 155 |
("Project deadline is March 15th 2026 for the Q1 release", 0.9, ["project", "deadline"]),
|
|
|
|
| 161 |
("Lives in San Francisco, timezone is PST", 0.6, ["personal", "location"]),
|
| 162 |
]
|
| 163 |
|
| 164 |
+
# Batch compute embeddings on GPU
|
| 165 |
texts = [ex[0] for ex in examples]
|
| 166 |
+
embeddings = compute_batch_embeddings(texts)
|
| 167 |
|
| 168 |
+
# Store in persistent MNEMO instance (CPU operations)
|
| 169 |
added = 0
|
| 170 |
for i, (content, importance, tags) in enumerate(examples):
|
| 171 |
+
result = MNEMO.add_with_embedding(
|
| 172 |
content=content,
|
| 173 |
embedding=embeddings[i],
|
| 174 |
user_id=user_id or "default",
|