Spaces:
Sleeping
Sleeping
Commit
·
f82de34
1
Parent(s):
701f9bf
ok2
Browse files
app.py
CHANGED
@@ -85,21 +85,13 @@ MEMORY_DIR = "memory_snapshots"
|
|
85 |
os.makedirs(MEMORY_DIR, exist_ok=True)
|
86 |
|
87 |
class EmotionalContext:
|
88 |
-
"""
|
89 |
-
Implements Mem|8's emotional context structure as described in the paper.
|
90 |
-
|
91 |
-
Attributes:
|
92 |
-
valence (torch.Tensor): Emotional valence (-128 to 127: negative to positive)
|
93 |
-
arousal (torch.Tensor): Emotional arousal (0 to 255: intensity level)
|
94 |
-
context (torch.Tensor): Contextual flags (16-bit in paper)
|
95 |
-
safety (torch.Tensor): Psychological safety indicator
|
96 |
-
"""
|
97 |
def __init__(self, device_str="cpu"):
|
98 |
self.device = device_str
|
99 |
-
self.valence = torch.zeros(1, device=device_str)
|
100 |
-
self.arousal = torch.zeros(1, device=device_str)
|
101 |
-
self.context = torch.zeros(1, device=device_str)
|
102 |
-
self.safety = torch.ones(1, device=device_str)
|
103 |
|
104 |
# Track emotional history for visualization
|
105 |
self.history = {
|
@@ -109,18 +101,28 @@ class EmotionalContext:
|
|
109 |
}
|
110 |
|
111 |
def update(self, valence: float, arousal: Optional[float] = None):
|
112 |
-
"""Update emotional context with new values
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
-
# If arousal not provided, calculate based on valence
|
116 |
if arousal is None:
|
117 |
-
self.arousal = torch.abs(
|
118 |
else:
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
|
|
124 |
self.history['timestamps'].append(time.time())
|
125 |
|
126 |
# Keep history at a reasonable size
|
@@ -130,34 +132,36 @@ class EmotionalContext:
|
|
130 |
self.history['timestamps'] = self.history['timestamps'][-100:]
|
131 |
|
132 |
def get_color_mapping(self) -> Tuple[float, float, float]:
|
133 |
-
"""
|
134 |
-
|
|
|
|
|
135 |
|
136 |
-
Returns:
|
137 |
-
Tuple[float, float, float]: RGB color values (0-1 range)
|
138 |
-
"""
|
139 |
# Normalize valence to 0-1 range for hue
|
140 |
-
norm_valence = (
|
141 |
|
142 |
# Normalize arousal to 0-1 range for saturation
|
143 |
-
norm_arousal =
|
144 |
|
145 |
-
# Convert HSV to RGB
|
146 |
rgb = colorsys.hsv_to_rgb(norm_valence, norm_arousal, 1.0)
|
147 |
return rgb
|
148 |
|
149 |
-
def __str__(self) -> str:
|
150 |
-
"""String representation of emotional context."""
|
151 |
-
return f"EmotionalContext(valence={self.valence.item():.2f}, arousal={self.arousal.item():.2f})"
|
152 |
-
|
153 |
def to(self, device_str):
|
154 |
"""Move the context to a different device."""
|
|
|
|
|
|
|
155 |
self.device = device_str
|
156 |
self.valence = self.valence.to(device_str)
|
157 |
self.arousal = self.arousal.to(device_str)
|
158 |
self.context = self.context.to(device_str)
|
159 |
self.safety = self.safety.to(device_str)
|
160 |
return self
|
|
|
|
|
|
|
|
|
161 |
|
162 |
class MemoryWave:
|
163 |
"""
|
@@ -168,13 +172,13 @@ class MemoryWave:
|
|
168 |
"""
|
169 |
def __init__(self,
|
170 |
size: int = DEFAULT_GRID_SIZE,
|
171 |
-
device_str: str = "cpu"):
|
172 |
"""
|
173 |
Initialize a memory wave system.
|
174 |
|
175 |
Args:
|
176 |
size: Size of the memory grid (NxN)
|
177 |
-
device_str: Device to use for computations
|
178 |
"""
|
179 |
self.size = size
|
180 |
self.device = device_str
|
@@ -192,23 +196,35 @@ class MemoryWave:
|
|
192 |
# History of wave states for animation
|
193 |
self.history = []
|
194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
def create_wave(self,
|
196 |
frequency: float,
|
197 |
amplitude: float,
|
198 |
phase: float = 0.0,
|
199 |
direction: str = "radial") -> torch.Tensor:
|
200 |
-
"""
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
amplitude
|
206 |
-
|
207 |
-
|
208 |
|
209 |
-
Returns:
|
210 |
-
torch.Tensor: The generated wave pattern
|
211 |
-
"""
|
212 |
if direction == "radial":
|
213 |
# Radial waves emanating from center (like dropping a stone in water)
|
214 |
center_x, center_y = self.size/2, self.size/2
|
@@ -236,15 +252,11 @@ class MemoryWave:
|
|
236 |
return wave
|
237 |
|
238 |
def apply_emotional_modulation(self, wave: torch.Tensor) -> torch.Tensor:
|
239 |
-
"""
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
wave: The input wave pattern
|
244 |
|
245 |
-
Returns:
|
246 |
-
torch.Tensor: Emotionally modulated wave
|
247 |
-
"""
|
248 |
# Emotional modulation formula from paper: M = A·exp(iωt-kx)·D·E
|
249 |
# We implement a simplified version where E is based on valence
|
250 |
valence_factor = self.emotion.valence / 128 # Normalize to -1 to 1 range
|
@@ -264,17 +276,13 @@ class MemoryWave:
|
|
264 |
|
265 |
def create_interference(self, wave1: torch.Tensor, wave2: torch.Tensor,
|
266 |
interference_type: str = "constructive") -> torch.Tensor:
|
267 |
-
"""
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
wave2
|
273 |
-
interference_type: Type of interference ("constructive", "destructive", or "resonance")
|
274 |
|
275 |
-
Returns:
|
276 |
-
torch.Tensor: The resulting interference pattern
|
277 |
-
"""
|
278 |
if interference_type == "constructive":
|
279 |
# Simple addition for constructive interference
|
280 |
return wave1 + wave2
|
@@ -291,20 +299,13 @@ class MemoryWave:
|
|
291 |
raise ValueError(f"Unknown interference type: {interference_type}")
|
292 |
|
293 |
def apply_memory_blanket(self, wave: torch.Tensor, threshold: float = 0.5) -> torch.Tensor:
|
294 |
-
"""
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
Args:
|
302 |
-
wave: Input wave pattern
|
303 |
-
threshold: Importance threshold
|
304 |
|
305 |
-
Returns:
|
306 |
-
torch.Tensor: Filtered wave pattern
|
307 |
-
"""
|
308 |
# Calculate wave importance (amplitude)
|
309 |
importance = torch.abs(wave)
|
310 |
|
@@ -314,21 +315,16 @@ class MemoryWave:
|
|
314 |
return filtered_wave
|
315 |
|
316 |
def store_memory(self, wave: torch.Tensor, memory_type: int = 0) -> None:
|
317 |
-
"""
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
wave: Wave pattern to store
|
322 |
-
memory_type: Memory type (0-5) as described in the paper
|
323 |
-
"""
|
324 |
-
if memory_type not in self.memory_types:
|
325 |
-
raise ValueError(f"Invalid memory type: {memory_type}")
|
326 |
|
327 |
# Store the wave pattern
|
328 |
self.memory_types[memory_type] = wave
|
329 |
|
330 |
-
# Add to history for animation
|
331 |
-
self.history.append(wave.
|
332 |
|
333 |
# Keep history at a reasonable size
|
334 |
if len(self.history) > 100:
|
@@ -834,18 +830,6 @@ class MemoryWave:
|
|
834 |
print(f"❌ Error during processing: {e}")
|
835 |
return None
|
836 |
|
837 |
-
def to(self, device_str):
|
838 |
-
"""Move the wave system to a different device."""
|
839 |
-
self.device = device_str
|
840 |
-
self.grid = self.grid.to(device_str)
|
841 |
-
self.emotion = self.emotion.to(device_str)
|
842 |
-
self.x = self.x.to(device_str)
|
843 |
-
self.y = self.y.to(device_str)
|
844 |
-
self.X = self.X.to(device_str)
|
845 |
-
self.Y = self.Y.to(device_str)
|
846 |
-
self.memory_types = {k: v.to(device_str) for k, v in self.memory_types.items()}
|
847 |
-
return self
|
848 |
-
|
849 |
def generate_memory_prompt(operation: str, emotion_valence: float) -> str:
|
850 |
"""Generate an artistic prompt based on the memory operation and emotional context."""
|
851 |
|
|
|
85 |
os.makedirs(MEMORY_DIR, exist_ok=True)
|
86 |
|
87 |
class EmotionalContext:
|
88 |
+
"""Implements Mem|8's emotional context structure."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
def __init__(self, device_str="cpu"):
|
90 |
self.device = device_str
|
91 |
+
self.valence = torch.zeros(1, device=device_str)
|
92 |
+
self.arousal = torch.zeros(1, device=device_str)
|
93 |
+
self.context = torch.zeros(1, device=device_str)
|
94 |
+
self.safety = torch.ones(1, device=device_str)
|
95 |
|
96 |
# Track emotional history for visualization
|
97 |
self.history = {
|
|
|
101 |
}
|
102 |
|
103 |
def update(self, valence: float, arousal: Optional[float] = None):
|
104 |
+
"""Update emotional context with new values."""
|
105 |
+
# Convert inputs to tensors on the right device
|
106 |
+
if not isinstance(valence, torch.Tensor):
|
107 |
+
valence = torch.tensor([valence], device=self.device)
|
108 |
+
elif valence.device != self.device:
|
109 |
+
valence = valence.to(self.device)
|
110 |
+
|
111 |
+
self.valence = valence
|
112 |
|
113 |
+
# If arousal not provided, calculate based on valence
|
114 |
if arousal is None:
|
115 |
+
self.arousal = torch.abs(valence * 2)
|
116 |
else:
|
117 |
+
if not isinstance(arousal, torch.Tensor):
|
118 |
+
arousal = torch.tensor([arousal], device=self.device)
|
119 |
+
elif arousal.device != self.device:
|
120 |
+
arousal = arousal.to(self.device)
|
121 |
+
self.arousal = arousal
|
122 |
+
|
123 |
+
# Update history (use CPU values for storage)
|
124 |
+
self.history['valence'].append(float(self.valence.cpu().item()))
|
125 |
+
self.history['arousal'].append(float(self.arousal.cpu().item()))
|
126 |
self.history['timestamps'].append(time.time())
|
127 |
|
128 |
# Keep history at a reasonable size
|
|
|
132 |
self.history['timestamps'] = self.history['timestamps'][-100:]
|
133 |
|
134 |
def get_color_mapping(self) -> Tuple[float, float, float]:
|
135 |
+
"""Maps emotional state to RGB color values."""
|
136 |
+
# Get values from tensors (move to CPU for calculations)
|
137 |
+
valence = self.valence.cpu().item()
|
138 |
+
arousal = self.arousal.cpu().item()
|
139 |
|
|
|
|
|
|
|
140 |
# Normalize valence to 0-1 range for hue
|
141 |
+
norm_valence = (valence - EMOTION_RANGE[0]) / (EMOTION_RANGE[1] - EMOTION_RANGE[0])
|
142 |
|
143 |
# Normalize arousal to 0-1 range for saturation
|
144 |
+
norm_arousal = arousal / AROUSAL_RANGE[1]
|
145 |
|
146 |
+
# Convert HSV to RGB
|
147 |
rgb = colorsys.hsv_to_rgb(norm_valence, norm_arousal, 1.0)
|
148 |
return rgb
|
149 |
|
|
|
|
|
|
|
|
|
150 |
def to(self, device_str):
|
151 |
"""Move the context to a different device."""
|
152 |
+
if self.device == device_str:
|
153 |
+
return self
|
154 |
+
|
155 |
self.device = device_str
|
156 |
self.valence = self.valence.to(device_str)
|
157 |
self.arousal = self.arousal.to(device_str)
|
158 |
self.context = self.context.to(device_str)
|
159 |
self.safety = self.safety.to(device_str)
|
160 |
return self
|
161 |
+
|
162 |
+
def __str__(self) -> str:
|
163 |
+
"""String representation of emotional context."""
|
164 |
+
return f"EmotionalContext(valence={self.valence.cpu().item():.2f}, arousal={self.arousal.cpu().item():.2f})"
|
165 |
|
166 |
class MemoryWave:
|
167 |
"""
|
|
|
172 |
"""
|
173 |
def __init__(self,
|
174 |
size: int = DEFAULT_GRID_SIZE,
|
175 |
+
device_str: str = "cpu"):
|
176 |
"""
|
177 |
Initialize a memory wave system.
|
178 |
|
179 |
Args:
|
180 |
size: Size of the memory grid (NxN)
|
181 |
+
device_str: Device to use for computations (defaults to CPU)
|
182 |
"""
|
183 |
self.size = size
|
184 |
self.device = device_str
|
|
|
196 |
# History of wave states for animation
|
197 |
self.history = []
|
198 |
|
199 |
+
def to(self, device_str):
|
200 |
+
"""Move the wave system to a different device."""
|
201 |
+
if self.device == device_str:
|
202 |
+
return self
|
203 |
+
|
204 |
+
self.device = device_str
|
205 |
+
self.grid = self.grid.to(device_str)
|
206 |
+
self.emotion = self.emotion.to(device_str)
|
207 |
+
self.x = self.x.to(device_str)
|
208 |
+
self.y = self.y.to(device_str)
|
209 |
+
self.X = self.X.to(device_str)
|
210 |
+
self.Y = self.Y.to(device_str)
|
211 |
+
self.memory_types = {k: v.to(device_str) for k, v in self.memory_types.items()}
|
212 |
+
return self
|
213 |
+
|
214 |
def create_wave(self,
|
215 |
frequency: float,
|
216 |
amplitude: float,
|
217 |
phase: float = 0.0,
|
218 |
direction: str = "radial") -> torch.Tensor:
|
219 |
+
"""Create a wave pattern as described in Mem|8 paper."""
|
220 |
+
# Ensure we're on the right device
|
221 |
+
if not isinstance(frequency, torch.Tensor):
|
222 |
+
frequency = torch.tensor(frequency, device=self.device)
|
223 |
+
if not isinstance(amplitude, torch.Tensor):
|
224 |
+
amplitude = torch.tensor(amplitude, device=self.device)
|
225 |
+
if not isinstance(phase, torch.Tensor):
|
226 |
+
phase = torch.tensor(phase, device=self.device)
|
227 |
|
|
|
|
|
|
|
228 |
if direction == "radial":
|
229 |
# Radial waves emanating from center (like dropping a stone in water)
|
230 |
center_x, center_y = self.size/2, self.size/2
|
|
|
252 |
return wave
|
253 |
|
254 |
def apply_emotional_modulation(self, wave: torch.Tensor) -> torch.Tensor:
|
255 |
+
"""Apply emotional modulation to a wave pattern."""
|
256 |
+
# Ensure wave is on the right device
|
257 |
+
if wave.device != self.device:
|
258 |
+
wave = wave.to(self.device)
|
|
|
259 |
|
|
|
|
|
|
|
260 |
# Emotional modulation formula from paper: M = A·exp(iωt-kx)·D·E
|
261 |
# We implement a simplified version where E is based on valence
|
262 |
valence_factor = self.emotion.valence / 128 # Normalize to -1 to 1 range
|
|
|
276 |
|
277 |
def create_interference(self, wave1: torch.Tensor, wave2: torch.Tensor,
|
278 |
interference_type: str = "constructive") -> torch.Tensor:
|
279 |
+
"""Create interference between two memory waves."""
|
280 |
+
# Ensure waves are on the right device
|
281 |
+
if wave1.device != self.device:
|
282 |
+
wave1 = wave1.to(self.device)
|
283 |
+
if wave2.device != self.device:
|
284 |
+
wave2 = wave2.to(self.device)
|
|
|
285 |
|
|
|
|
|
|
|
286 |
if interference_type == "constructive":
|
287 |
# Simple addition for constructive interference
|
288 |
return wave1 + wave2
|
|
|
299 |
raise ValueError(f"Unknown interference type: {interference_type}")
|
300 |
|
301 |
def apply_memory_blanket(self, wave: torch.Tensor, threshold: float = 0.5) -> torch.Tensor:
|
302 |
+
"""Apply the memory blanket concept."""
|
303 |
+
# Ensure wave is on the right device
|
304 |
+
if wave.device != self.device:
|
305 |
+
wave = wave.to(self.device)
|
306 |
+
if not isinstance(threshold, torch.Tensor):
|
307 |
+
threshold = torch.tensor(threshold, device=self.device)
|
|
|
|
|
|
|
|
|
308 |
|
|
|
|
|
|
|
309 |
# Calculate wave importance (amplitude)
|
310 |
importance = torch.abs(wave)
|
311 |
|
|
|
315 |
return filtered_wave
|
316 |
|
317 |
def store_memory(self, wave: torch.Tensor, memory_type: int = 0) -> None:
|
318 |
+
"""Store a wave pattern in memory."""
|
319 |
+
# Ensure wave is on the right device
|
320 |
+
if wave.device != self.device:
|
321 |
+
wave = wave.to(self.device)
|
|
|
|
|
|
|
|
|
|
|
322 |
|
323 |
# Store the wave pattern
|
324 |
self.memory_types[memory_type] = wave
|
325 |
|
326 |
+
# Add to history for animation (move to CPU for numpy conversion)
|
327 |
+
self.history.append(wave.cpu().numpy())
|
328 |
|
329 |
# Keep history at a reasonable size
|
330 |
if len(self.history) > 100:
|
|
|
830 |
print(f"❌ Error during processing: {e}")
|
831 |
return None
|
832 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
833 |
def generate_memory_prompt(operation: str, emotion_valence: float) -> str:
|
834 |
"""Generate an artistic prompt based on the memory operation and emotional context."""
|
835 |
|