antonypamo commited on
Commit
f4bbd6f
·
verified ·
1 Parent(s): 8c4f04b

Update engine.py

Browse files
Files changed (1) hide show
  1. engine.py +114 -285
engine.py CHANGED
@@ -1,334 +1,163 @@
1
- #engine.py
2
- #Orquestador principal del motor Savant Simbiótico RRF.
3
- #Expone:
4
- #- handle_query(text): detecta intención (map/resonance/music/chat) y responde
5
- #- access to SimpleTrainer, SelfImprover, MemoryStore for external control
6
-
7
- import time # Import time
 
 
 
 
8
  from mappings import IcosaMap, DodecaMap
9
  from resonance import ResonanceSimulator
10
  from music import MusicAdapter
11
  from memory import MemoryStore
12
  from self_improvement import SelfImprover
13
- # from .trainer import SimpleTrainer # Avoid circular import, trainer can be instantiated externally
14
  from api_helpers import chat_refine
15
- import os # Import os
16
- import pandas as pd # Import pandas
17
- import json # Import json
18
- import pickle # Import pickle
19
 
20
  class SavantEngine:
21
  def __init__(self, structured_data_paths=None):
22
  self.memory = MemoryStore("SAVANT_memory.jsonl")
23
- # Load structured data if paths are provided
24
  self.structured_data = {}
 
 
 
 
25
  if structured_data_paths:
26
  print("Engine: Loading structured data...")
27
  try:
28
- self.structured_data['equations'] = self._load_json_data(structured_data_paths.get('equations'))
29
- nodes_raw = self._load_json_data(structured_data_paths.get('icosahedron_nodes'))
30
- self.structured_data['icosahedron_nodes'] = nodes_raw.get('nodes', []) if isinstance(nodes_raw, dict) else []
31
- self.structured_data['frequencies'] = self._load_csv_data(structured_data_paths.get('frequencies'))
32
- self.structured_data['constants'] = self._load_csv_data(structured_data_paths.get('constants'))
33
-
34
- self.structured_data['physics_data'] = self._load_csv_data(structured_data_paths.get('physics_data'))
35
- self.structured_data['meta_data'] = self._load_csv_data(structured_data_paths.get('meta_data'))
36
- self.structured_data['language_data'] = self._load_csv_data(structured_data_paths.get('language_data'))
37
- self.structured_data['geometry_data'] = self._load_csv_data(structured_data_paths.get('geometry_data'))
38
- self.structured_data['cognition_data'] = self._load_csv_data(structured_data_paths.get('cognition_data'))
39
- self.structured_data['cmb_data'] = self._load_csv_data(structured_data_paths.get('cmb_data'))
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- print("Engine loaded structured data: Equations={}, Nodes={}, Frequencies={}, Constants={}".format(
42
- len(self.structured_data['equations']) if self.structured_data['equations'] else 0,
43
- len(self.structured_data['icosahedron_nodes']),
44
- len(self.structured_data['frequencies']),
45
- len(self.structured_data['constants'])
46
- ))
47
  except Exception as e:
48
  print(f"Engine: Error loading structured data: {e}")
49
- self.structured_data = {} # Reset if loading fails
50
-
51
-
52
- # Instantiate components, passing relevant structured data
53
- self.icosa = IcosaMap(node_data=self.structured_data.get('icosahedron_nodes')) # Pass node data
54
- self.dodeca = DodecaMap() # No dodecahedron data provided in list
55
- self.resonator = ResonanceSimulator(frequencies_data=self.structured_data.get('frequencies'), constants_data=self.structured_data.get('constants')) # Pass freq/const data
56
- self.music = MusicAdapter(frequencies_data=self.structured_data.get('frequencies')) # Pass frequencies data
57
- self.self_improver = SelfImprover(self.memory, structured_data=self.structured_data) # Pass structured data to SelfImprover
58
-
59
-
60
- self._interaction_count = 0 # Initialize interaction count for self-improvement trigger
61
-
62
-
63
- # Helper methods for loading data within the Engine (copied from Trainer for self-containment)
 
 
 
 
64
  def _load_json_data(self, file_path):
65
- """Loads data from a JSON file."""
66
  if not file_path or not os.path.exists(file_path):
67
- # print(f"JSON file not found or path not provided: {file_path}") # Suppress not found for optional files
68
  return None
69
  try:
70
  with open(file_path, "r", encoding="utf-8") as f:
71
- data = json.load(f)
72
- # print(f"Successfully loaded JSON data from {file_path}") # Suppress success for cleaner output
73
- return data
74
- except json.JSONDecodeError as e:
75
- print(f"Error decoding JSON from {file_path}: {e}")
76
- return None
77
  except Exception as e:
78
- print(f"An unexpected error occurred while loading JSON data: {e}")
79
  return None
80
 
81
  def _load_csv_data(self, file_path):
82
- """Loads data from a CSV file using pandas."""
83
  if not file_path or not os.path.exists(file_path):
84
- # print(f"CSV file not found or path not provided: {file_path}") # Suppress not found for optional files
85
- return []
86
  try:
87
  df = pd.read_csv(file_path)
88
- # print(f"Successfully loaded CSV data from {file_path}") # Suppress success for cleaner output
89
- return df.to_dict(orient='records')
90
  except Exception as e:
91
- print(f"An error occurred while loading CSV data from {file_path}: {e}")
92
  return []
93
 
94
-
 
 
95
  def _classify(self, text):
96
  t = text.lower()
97
- # Enhanced classification based on structured data keywords and patterns
98
- if any(k in t for k in ("equation", "ecuacion", "hamiltoniano", "dirac", "formula", "formulae", "formulas")): # Added formula variations
99
- return "equation_query"
100
- if any(k in t for k in ("node", "nodo", "icosahedron", "dodecahedron", "poly", "vertex", "point", "map")): # Added map keyword to node query
101
- # Check for patterns like "node X" where X is a number
102
- words = t.split()
103
- if len(words) > 1 and words[-1].isdigit() and words[-2] in ("node", "nodo"):
104
- return "node_query"
105
- return "node_query"
106
- if any(k in t for k in ("frecuen", "freq", "music", "nota", "melod", "tono", "pitch", "scale", "musical", "sound", "audio")): # Added sound, audio
107
- return "music_resonance" # Combine music and resonance intent for simplicity here
108
- if any(k in t for k in ("constant", "constante", "valor", "unidad", "define", "what is the value of")): # Added "what is the value of"
109
- return "constant_query"
110
- if any(k in t for k in ("resonance", "resonar", "resonant", "vibration", "oscilla")): # Specific keywords for resonance without music
111
- return "resonance_only"
112
-
113
- # Existing classifications (kept as fallbacks or for broader terms)
114
- # Removed redundant 'reson' and 'sinton' mapping to music_resonance as specific resonance_only added
115
- if any(k in t for k in ("chat", "hola", "qué", "como", "explica", "tell me", "what is", "describe", "info", "information")): # Added info, information
116
- return "chat"
117
- return "chat" # Default to chat
118
-
119
-
120
  def handle_query(self, text, base_model_output=None):
121
  kind = self._classify(text)
122
 
123
- # Handle query types based on structured data
124
- if kind == "equation_query":
125
- relevant_eqs = []
126
- if self.structured_data.get('equations'):
127
- # Find equations related to the query (more robust keyword matching)
128
- query_words = text.lower().split()
129
- relevant_eqs = [eq for eq in self.structured_data['equations'] if any(word in eq.get('nombre', '').lower() or word in eq.get('descripcion', '').lower() or any(comp.lower() in word for comp in eq.get('componentes', [])) for word in query_words)]
130
-
131
- if relevant_eqs:
132
- # Provide information about found equations
133
- response_parts = ["Based on the RRF Equations data, I found the following relevant equations:"]
134
- for eq in relevant_eqs[:3]: # Limit to first 3 for brevity
135
- response_parts.append(f"- '{eq.get('nombre', 'N/A')}' ({eq.get('tipo', 'Equation')}): {eq.get('ecuacion', 'N/A')} (Components: {', '.join(eq.get('componentes', []))})")
136
- if len(relevant_eqs) > 3:
137
- response_parts.append("...")
138
- response = "\n".join(response_parts)
139
- self._log_interaction(text, base_model_output, response, type="equation_query")
140
- return {"type": "equation_query", "query": text, "result": relevant_eqs, "response": response}
141
- else:
142
- response = "I couldn't find any relevant equations in the loaded data for that query."
143
- self._log_interaction(text, base_model_output, response, type="equation_query_not_found")
144
- return {"type": "equation_query", "query": text, "result": [], "response": response}
145
-
146
-
147
- if kind == "node_query":
148
- relevant_nodes = []
149
- if self.structured_data.get('icosahedron_nodes'):
150
- query_words = text.lower().split()
151
- # Try to find by ID first if query contains a number
152
- try:
153
- node_id = int(query_words[-1]) if query_words and query_words[-1].isdigit() else None
154
- if node_id is not None:
155
- relevant_nodes = [node for node in self.structured_data['icosahedron_nodes'] if node.get('id') == node_id]
156
- except (ValueError, IndexError):
157
- pass # Not a number query
158
-
159
- # If not found by ID or not a number query, search by keyword in description/name
160
- if not relevant_nodes:
161
- relevant_nodes = [node for node in self.structured_data['icosahedron_nodes'] if any(word in node.get('description', '').lower() or word in node.get('name', '').lower() for word in query_words)]
162
-
163
- if relevant_nodes:
164
- response_parts = ["Based on the Icosahedron Nodes data, I found the following relevant nodes:"]
165
- for node in relevant_nodes[:3]: # Limit to first 3
166
- response_parts.append(f"- Node {node.get('id', 'N/A')}: {node.get('description', node.get('name', 'No description'))} (Coords: ({node.get('x', 'N/A')}, {node.get('y', 'N/A')}, {node.get('z', 'N/A')}))") # Added N/A checks
167
- if len(relevant_nodes) > 3:
168
- response_parts.append("...")
169
- response = "\n".join(response_parts)
170
- self._log_interaction(text, base_model_output, response, type="node_query")
171
- return {"type": "node_query", "query": text, "result": relevant_nodes, "response": response}
172
- else:
173
- response = "I couldn't find any relevant nodes in the loaded data for that query."
174
- self._log_interaction(text, base_model_output, response, type="node_query_not_found")
175
- return {"type": "node_query", "query": text, "result": [], "response": response}
176
-
177
  if kind == "music_resonance":
178
- # Can still trigger resonance simulation and music adaptation
179
- # Enhance response with information from frequencies/constants if relevant keywords are used
180
- response_parts = []
181
- if self.structured_data.get('frequencies') and any(k in text.lower() for k in ("frecuen", "freq", "nota", "pitch", "scale", "musical", "sound", "audio")):
182
- query_words = text.lower().split()
183
- relevant_freqs = [f for f in self.structured_data['frequencies'] if any(word in f.get('note', '').lower() or word in f.get('role', '').lower() for word in query_words)]
184
- if relevant_freqs:
185
- response_parts.append("Based on the Frequencies data, I found:")
186
- for freq in relevant_freqs[:3]:
187
- response_parts.append(f"- Note: {freq.get('note', 'N/A')}, Frequency: {freq.get('frequency', 'N/A')} Hz, Role: {freq.get('role', 'N/A')}") # Added N/A checks
188
- if len(relevant_freqs) > 3: response_parts.append("...")
189
-
190
- if self.structured_data.get('constants') and any(k in text.lower() for k in ("constant", "constante")):
191
- query_words = text.lower().split()
192
- relevant_constants = [c for c in self.structured_data['constants'] if any(word in c.get('name', '').lower() for word in query_words)]
193
- if relevant_constants:
194
- response_parts.append("Based on the Constants data, I found:")
195
- for const in relevant_constants[:3]:
196
- response_parts.append(f"- Constant: {const.get('name', 'N/A')}, Value: {const.get('value', 'N/A')}, Units: {const.get('units', 'N/A')}") # Added N/A checks
197
- if len(relevant_constants) > 3: response_parts.append("...")
198
-
199
- # Always run resonance simulation and music adaptation for this type
200
  r = self.resonator.simulate(text)
201
  seq = self.music.adapt_text_to_music(text)
 
 
 
202
 
203
- response_parts.append(f"Resonance simulation summary: Dominant Frequency={r['summary'].get('dom_freq', 0.0):.4f} Hz, Max Power={r['summary'].get('max_power', 0.0):.4f}.") # Added default values
204
- response_parts.append(f"Adapted to music sequence (first 5 notes: pitch, duration): {seq[:5]}...")
205
-
206
- response = "\n".join(response_parts) if response_parts else "Processing music and resonance query..."
207
- self._log_interaction(text, base_model_output, response, type="music_resonance")
208
- return {"type":"music_resonance","query":text,"resonance_result":r,"music_result":seq, "response": response}
209
-
210
- if kind == "resonance_only": # New handler for resonance-only queries
211
- # Can still trigger resonance simulation
212
- response_parts = []
213
- if self.structured_data.get('constants') and any(k in text.lower() for k in ("constant", "constante")):
214
- query_words = text.lower().split()
215
- relevant_constants = [c for c in self.structured_data['constants'] if any(word in c.get('name', '').lower() for word in query_words)]
216
- if relevant_constants:
217
- response_parts.append("Based on the Constants data, I found:")
218
- for const in relevant_constants[:3]:
219
- response_parts.append(f"- Constant: {const.get('name', 'N/A')}, Value: {const.get('value', 'N/A')}, Units: {const.get('units', 'N/A')}") # Added N/A checks
220
- if len(relevant_constants) > 3: response_parts.append("...")
221
-
222
- r = self.resonator.simulate(text)
223
- response_parts.append(f"Resonance simulation summary: Dominant Frequency={r['summary'].get('dom_freq', 0.0):.4f} Hz, Max Power={r['summary'].get('max_power', 0.0):.4f}.") # Added default values
224
-
225
- response = "\n".join(response_parts) if response_parts else "Processing resonance query..."
226
- self._log_interaction(text, base_model_output, response, type="resonance_only")
227
- return {"type":"resonance_only","query":text,"resonance_result":r, "response": response}
228
-
229
-
230
- if kind == "constant_query":
231
- relevant_constants = []
232
- if self.structured_data.get('constants'):
233
- query_words = text.lower().split()
234
- relevant_constants = [c for c in self.structured_data['constants'] if any(word in c.get('name', '').lower() or word in c.get('units', '').lower() for word in query_words)]
235
-
236
- if relevant_constants:
237
- response_parts = ["Based on the RRF Constants data, I found the following relevant constants:"]
238
- for const in relevant_constants[:3]:
239
- response_parts.append(f"- Name: {const.get('name', 'N/A')}, Value: {const.get('value', 'N/A')}, Units: {const.get('units', 'N/A')}") # Added N/A checks
240
- if len(relevant_constants) > 3: response_parts.append("...")
241
- response = "\n".join(response_parts)
242
- self._log_interaction(text, base_model_output, response, type="constant_query")
243
- return {"type": "constant_query", "query": text, "result": relevant_constants, "response": response}
244
- else:
245
- response = "I couldn't find any relevant constants in the loaded data for that query."
246
- self._log_interaction(text, base_model_output, response, type="constant_query_not_found")
247
- return {"type": "constant_query", "query": text, "result": [], "response": response}
248
-
249
-
250
- if kind == "map":
251
- # Use icosahedron_nodes data in mapping (already done in IcosaMap)
252
  node_label = self.icosa.closest_node(text)
253
- response = f"Mapping query '{text}' to closest node: {node_label}"
254
- # If we have node data, try to find details about the mapped node
255
- if self.structured_data.get('icosahedron_nodes'):
256
- # Assuming node_label is the description or name from node_data used for embedding
257
- # A more robust mapping is needed here to link label back to original node dict by ID
258
- # For now, let's just find the node with a matching description/name if possible
259
- mapped_node_data = next((node for node in self.structured_data['icosahedron_nodes'] if node.get('description', '').lower() == node_label.lower() or node.get('name', '').lower() == node_label.lower()), None)
260
- if mapped_node_data:
261
- response += f" (ID: {mapped_node_data.get('id', 'N/A')}, Coords: ({mapped_node_data.get('x', 'N/A')}, {mapped_node_data.get('y', 'N/A')}, {mapped_node_data.get('z', 'N/A')}))" # Added N/A checks
262
 
 
 
 
 
263
 
264
- self._log_interaction(text, base_model_output, response, type="map")
265
- return {"type":"map","query":text,"node":node_label, "response": response}
 
 
266
 
267
- # chat fallback: if base_model_output provided, refine it using self_improver
268
  if kind == "chat":
269
- if base_model_output is None:
270
- # default echo
271
- base = "Echo: " + text
272
- else:
273
- base = base_model_output
274
-
275
- refined = chat_refine(text, base, self_improver=self.self_improver)
276
- response = refined # Use refined output as the main response for chat
277
- self._log_interaction(text, base_model_output, refined, type="chat_interaction") # Log chat interaction
278
-
279
- return {"type":"chat","query":text,"base":base,"refined":refined, "response": response}
280
-
281
- # Fallback for unhandled types (shouldn't be reached with current classify)
282
- response = "I'm not sure how to handle that query based on the available data and functions."
283
- self._log_interaction(text, base_model_output, response, type="unhandled_query")
284
- return {"type": "unhandled", "query": text, "response": response}
285
 
 
 
 
286
 
 
 
 
287
  def _log_interaction(self, user_input, base_output, final_output, type="interaction"):
288
- """Logs interaction details to memory and triggers self-improvement if needed."""
289
- interaction_record = {
290
- "type": type, # Use the specified type (e.g., chat_interaction, equation_query)
291
- "user_input": user_input,
292
- "base_model_output": base_output, # Might be None for non-chat types
293
- "final_output": final_output, # The response generated by handle_query
294
- "_ts": time.time() # Add timestamp
295
- }
296
- self.memory.add(interaction_record)
297
-
298
- # Periodically trigger self-improvement (e.g., every 10 interactions)
299
- self._interaction_count = getattr(self, '_interaction_count', 0) + 1
300
- if self._interaction_count % 10 == 0:
301
- print("SAVANT: Triggering self-improvement cycle...")
302
- try:
303
- proposal = self.self_improver.propose()
304
- accepted, metric = self.self_improver.evaluate_and_apply(proposal)
305
- print(f"SAVANT: Self-improvement proposal accepted: {accepted}, New metric: {metric}")
306
- self.memory.add({
307
- "type": "self_improvement_triggered",
308
- "proposal": proposal,
309
- "accepted": accepted,
310
- "metric": metric,
311
- "_ts": time.time()
312
- })
313
- except Exception as si_error:
314
- # Log the error and continue
315
- error_message = f"Error during self-improvement: {si_error}"
316
- print(f"SAVANT: {error_message}")
317
- self.memory.add({
318
- "type": "self_improvement_error",
319
- "error": error_message,
320
- "_ts": time.time()
321
- })
322
-
323
-
324
- # trainer helpers (these are now called externally via SimpleTrainer instance)
325
- # def run_training_epochs(self, stimuli, epochs=3):
326
- # return self.trainer.run_epochs(stimuli, epochs)
327
-
328
- def propose_improvement(self):
329
- return self.self_improver.propose()
330
-
331
- def apply_improvement(self, proposal):
332
- return self.self_improver.evaluate_and_apply(proposal)
333
-
334
-
 
1
+ """
2
+ engine.py
3
+ Núcleo simbiótico cognitivo del sistema SAVANT-RRF Φ₄.1∞+
4
+ Maneja:
5
+ - Memoria simbiótica
6
+ - Resonancia
7
+ - Mapas geométricos
8
+ - Auto-mejora resonante
9
+ """
10
+
11
+ import os, json, time, pandas as pd
12
  from mappings import IcosaMap, DodecaMap
13
  from resonance import ResonanceSimulator
14
  from music import MusicAdapter
15
  from memory import MemoryStore
16
  from self_improvement import SelfImprover
 
17
  from api_helpers import chat_refine
18
+
 
 
 
19
 
20
  class SavantEngine:
21
  def __init__(self, structured_data_paths=None):
22
  self.memory = MemoryStore("SAVANT_memory.jsonl")
 
23
  self.structured_data = {}
24
+
25
+ # ===============================
26
+ # Carga de datos estructurados
27
+ # ===============================
28
  if structured_data_paths:
29
  print("Engine: Loading structured data...")
30
  try:
31
+ self.structured_data["equations"] = self._load_json_data(structured_data_paths.get("equations"))
32
+ nodes_raw = self._load_json_data(structured_data_paths.get("icosahedron_nodes"))
33
+ self.structured_data["icosahedron_nodes"] = (
34
+ nodes_raw.get("nodes", []) if isinstance(nodes_raw, dict) else []
35
+ )
36
+ self.structured_data["frequencies"] = self._load_csv_data(structured_data_paths.get("frequencies"))
37
+ self.structured_data["constants"] = self._load_csv_data(structured_data_paths.get("constants"))
38
+
39
+ # Otros datasets opcionales
40
+ self.structured_data["physics_data"] = self._load_csv_data(structured_data_paths.get("physics_data"))
41
+ self.structured_data["meta_data"] = self._load_csv_data(structured_data_paths.get("meta_data"))
42
+ self.structured_data["language_data"] = self._load_csv_data(structured_data_paths.get("language_data"))
43
+ self.structured_data["geometry_data"] = self._load_csv_data(structured_data_paths.get("geometry_data"))
44
+ self.structured_data["cognition_data"] = self._load_csv_data(structured_data_paths.get("cognition_data"))
45
+ self.structured_data["cmb_data"] = self._load_csv_data(structured_data_paths.get("cmb_data"))
46
+
47
+ print(
48
+ "Engine loaded structured data: Equations={}, Nodes={}, Frequencies={}, Constants={}".format(
49
+ len(self.structured_data["equations"]) if self.structured_data["equations"] else 0,
50
+ len(self.structured_data["icosahedron_nodes"]),
51
+ len(self.structured_data["frequencies"]),
52
+ len(self.structured_data["constants"]),
53
+ )
54
+ )
55
 
 
 
 
 
 
 
56
  except Exception as e:
57
  print(f"Engine: Error loading structured data: {e}")
58
+ self.structured_data = {}
59
+
60
+ # ===============================
61
+ # Inicialización de subsistemas
62
+ # ===============================
63
+ self.icosa = IcosaMap(node_data=self.structured_data.get("icosahedron_nodes"))
64
+ self.dodeca = DodecaMap()
65
+ self.resonator = ResonanceSimulator(
66
+ frequencies_data=self.structured_data.get("frequencies"),
67
+ constants_data=self.structured_data.get("constants"),
68
+ )
69
+ self.music = MusicAdapter(frequencies_data=self.structured_data.get("frequencies"))
70
+ self.self_improver = SelfImprover(self.memory, structured_data=self.structured_data)
71
+
72
+ self._interaction_count = 0
73
+
74
+ # =====================================================
75
+ # Métodos de carga de datos auxiliares
76
+ # =====================================================
77
  def _load_json_data(self, file_path):
 
78
  if not file_path or not os.path.exists(file_path):
 
79
  return None
80
  try:
81
  with open(file_path, "r", encoding="utf-8") as f:
82
+ return json.load(f)
 
 
 
 
 
83
  except Exception as e:
84
+ print(f"Error loading JSON {file_path}: {e}")
85
  return None
86
 
87
  def _load_csv_data(self, file_path):
 
88
  if not file_path or not os.path.exists(file_path):
89
+ return []
 
90
  try:
91
  df = pd.read_csv(file_path)
92
+ return df.to_dict(orient="records")
 
93
  except Exception as e:
94
+ print(f"Error loading CSV {file_path}: {e}")
95
  return []
96
 
97
+ # =====================================================
98
+ # Clasificador de tipo de consulta
99
+ # =====================================================
100
  def _classify(self, text):
101
  t = text.lower()
102
+ if any(k in t for k in ["equation", "ecuacion", "hamiltoniano", "dirac", "formula"]):
103
+ return "equation_query"
104
+ if any(k in t for k in ["node", "nodo", "icosahedron", "dodecahedron", "vertex", "map"]):
105
+ return "node_query"
106
+ if any(k in t for k in ["music", "nota", "melod", "freq", "sound"]):
107
+ return "music_resonance"
108
+ if any(k in t for k in ["constant", "constante", "valor", "unidad"]):
109
+ return "constant_query"
110
+ if any(k in t for k in ["resonance", "resonar", "vibration"]):
111
+ return "resonance_only"
112
+ return "chat"
113
+
114
+ # =====================================================
115
+ # Motor principal de consulta
116
+ # =====================================================
 
 
 
 
 
 
 
 
117
  def handle_query(self, text, base_model_output=None):
118
  kind = self._classify(text)
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  if kind == "music_resonance":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  r = self.resonator.simulate(text)
122
  seq = self.music.adapt_text_to_music(text)
123
+ response = f"🎵 Resonancia dominante: {r['summary'].get('dom_freq', 0):.2f} Hz\n🎶 Secuencia: {seq[:5]}"
124
+ self._log_interaction(text, base_model_output, response, "music_resonance")
125
+ return {"type": kind, "response": response}
126
 
127
+ if kind == "node_query":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  node_label = self.icosa.closest_node(text)
129
+ response = f"Nodo más cercano al concepto '{text}': {node_label}"
130
+ self._log_interaction(text, base_model_output, response, "node_query")
131
+ return {"type": kind, "response": response}
 
 
 
 
 
 
132
 
133
+ if kind == "equation_query":
134
+ response = "Buscando ecuación relevante dentro del marco RRF..."
135
+ self._log_interaction(text, base_model_output, response, "equation_query")
136
+ return {"type": kind, "response": response}
137
 
138
+ if kind == "constant_query":
139
+ response = "Consultando constante física o resonante relevante..."
140
+ self._log_interaction(text, base_model_output, response, "constant_query")
141
+ return {"type": kind, "response": response}
142
 
 
143
  if kind == "chat":
144
+ refined = chat_refine(text, base_model_output or "", self_improver=self.self_improver)
145
+ self._log_interaction(text, base_model_output, refined, "chat")
146
+ return {"type": "chat", "response": refined}
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
+ response = "No puedo clasificar la consulta."
149
+ self._log_interaction(text, base_model_output, response, "unhandled")
150
+ return {"type": "unhandled", "response": response}
151
 
152
+ # =====================================================
153
+ # Registro de interacciones
154
+ # =====================================================
155
  def _log_interaction(self, user_input, base_output, final_output, type="interaction"):
156
+ record = {
157
+ "type": type,
158
+ "user_input": user_input,
159
+ "base_output": base_output,
160
+ "final_output": final_output,
161
+ "_ts": time.time(),
162
+ }
163
+ self.memory.add(record)