Instructions to use antonypamo/ProSavantRRF with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Adapters
How to use antonypamo/ProSavantRRF with Adapters:
from adapters import AutoAdapterModel model = AutoAdapterModel.from_pretrained("undefined") model.load_adapter("antonypamo/ProSavantRRF", set_active=True) - Notebooks
- Google Colab
- Kaggle
| """ | |
| engine.py | |
| Orquestador principal del motor Savant Simbiótico RRF. | |
| Expone: | |
| - handle_query(text): detecta intención (map/resonance/music/chat) y responde | |
| - access to SimpleTrainer, SelfImprover, MemoryStore for external control | |
| """ | |
| import time # Import time | |
| from .mappings import IcosaMap, DodecaMap | |
| from .resonance import ResonanceSimulator | |
| from .music import MusicAdapter | |
| from .memory import MemoryStore | |
| from .self_improvement import SelfImprover | |
| # from .trainer import SimpleTrainer # Avoid circular import, trainer can be instantiated externally | |
| from .api_helpers import chat_refine | |
| import os # Import os | |
| import pandas as pd # Import pandas | |
| import json # Import json | |
| import pickle # Import pickle | |
| class SavantEngine: | |
| def __init__(self, structured_data_paths=None): | |
| self.memory = MemoryStore("SAVANT_memory.jsonl") | |
| # Load structured data if paths are provided | |
| self.structured_data = {} | |
| if structured_data_paths: | |
| print("Engine: Loading structured data...") | |
| try: | |
| self.structured_data['equations'] = self._load_json_data(structured_data_paths.get('equations')) | |
| nodes_raw = self._load_json_data(structured_data_paths.get('icosahedron_nodes')) | |
| self.structured_data['icosahedron_nodes'] = nodes_raw.get('nodes', []) if isinstance(nodes_raw, dict) else [] | |
| self.structured_data['frequencies'] = self._load_csv_data(structured_data_paths.get('frequencies')) | |
| self.structured_data['constants'] = self._load_csv_data(structured_data_paths.get('constants')) | |
| print("Engine loaded structured data: Equations={}, Nodes={}, Frequencies={}, Constants={}".format( | |
| len(self.structured_data['equations']) if self.structured_data['equations'] else 0, | |
| len(self.structured_data['icosahedron_nodes']), | |
| len(self.structured_data['frequencies']), | |
| len(self.structured_data['constants']) | |
| )) | |
| except Exception as e: | |
| print(f"Engine: Error loading structured data: {e}") | |
| self.structured_data = {} # Reset if loading fails | |
| # Instantiate components, passing relevant structured data | |
| self.icosa = IcosaMap(node_data=self.structured_data.get('icosahedron_nodes')) # Pass node data | |
| self.dodeca = DodecaMap() # No dodecahedron data provided in list | |
| self.resonator = ResonanceSimulator(frequencies_data=self.structured_data.get('frequencies'), constants_data=self.structured_data.get('constants')) # Pass freq/const data | |
| self.music = MusicAdapter(frequencies_data=self.structured_data.get('frequencies')) # Pass frequencies data | |
| self.self_improver = SelfImprover(self.memory, structured_data=self.structured_data) # Pass structured data to SelfImprover | |
| self._interaction_count = 0 # Initialize interaction count for self-improvement trigger | |
| # Helper methods for loading data within the Engine (copied from Trainer for self-containment) | |
| def _load_json_data(self, file_path): | |
| """Loads data from a JSON file.""" | |
| if not file_path or not os.path.exists(file_path): | |
| # print(f"JSON file not found or path not provided: {file_path}") # Suppress not found for optional files | |
| return None | |
| try: | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| # print(f"Successfully loaded JSON data from {file_path}") # Suppress success for cleaner output | |
| return data | |
| except json.JSONDecodeError as e: | |
| print(f"Error decoding JSON from {file_path}: {e}") | |
| return None | |
| except Exception as e: | |
| print(f"An unexpected error occurred while loading JSON data: {e}") | |
| return None | |
| def _load_csv_data(self, file_path): | |
| """Loads data from a CSV file using pandas.""" | |
| if not file_path or not os.path.exists(file_path): | |
| # print(f"CSV file not found or path not provided: {file_path}") # Suppress not found for optional files | |
| return [] | |
| try: | |
| df = pd.read_csv(file_path) | |
| # print(f"Successfully loaded CSV data from {file_path}") # Suppress success for cleaner output | |
| return df.to_dict(orient='records') | |
| except Exception as e: | |
| print(f"An error occurred while loading CSV data from {file_path}: {e}") | |
| return [] | |
| def _classify(self, text): | |
| t = text.lower() | |
| # Enhanced classification based on structured data keywords and patterns | |
| if any(k in t for k in ("equation", "ecuacion", "hamiltoniano", "dirac", "formula", "formulae", "formulas")): # Added formula variations | |
| return "equation_query" | |
| if any(k in t for k in ("node", "nodo", "icosahedron", "dodecahedron", "poly", "vertex", "point", "map")): # Added map keyword to node query | |
| # Check for patterns like "node X" where X is a number | |
| words = t.split() | |
| if len(words) > 1 and words[-1].isdigit() and words[-2] in ("node", "nodo"): | |
| return "node_query" | |
| return "node_query" | |
| if any(k in t for k in ("frecuen", "freq", "music", "nota", "melod", "tono", "pitch", "scale", "musical", "sound", "audio")): # Added sound, audio | |
| return "music_resonance" # Combine music and resonance intent for simplicity here | |
| if any(k in t for k in ("constant", "constante", "valor", "unidad", "define", "what is the value of")): # Added "what is the value of" | |
| return "constant_query" | |
| if any(k in t for k in ("resonance", "resonar", "resonant", "vibration", "oscilla")): # Specific keywords for resonance without music | |
| return "resonance_only" | |
| # Existing classifications (kept as fallbacks or for broader terms) | |
| # Removed redundant 'reson' and 'sinton' mapping to music_resonance as specific resonance_only added | |
| if any(k in t for k in ("chat", "hola", "qué", "como", "explica", "tell me", "what is", "describe", "info", "information")): # Added info, information | |
| return "chat" | |
| return "chat" # Default to chat | |
| def handle_query(self, text, base_model_output=None): | |
| kind = self._classify(text) | |
| # Handle query types based on structured data | |
| if kind == "equation_query": | |
| relevant_eqs = [] | |
| if self.structured_data.get('equations'): | |
| # Find equations related to the query (more robust keyword matching) | |
| query_words = text.lower().split() | |
| 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)] | |
| if relevant_eqs: | |
| # Provide information about found equations | |
| response_parts = ["Based on the RRF Equations data, I found the following relevant equations:"] | |
| for eq in relevant_eqs[:3]: # Limit to first 3 for brevity | |
| response_parts.append(f"- '{eq.get('nombre', 'N/A')}' ({eq.get('tipo', 'Equation')}): {eq.get('ecuacion', 'N/A')} (Components: {', '.join(eq.get('componentes', []))})") | |
| if len(relevant_eqs) > 3: | |
| response_parts.append("...") | |
| response = "\n".join(response_parts) | |
| self._log_interaction(text, base_model_output, response, type="equation_query") | |
| return {"type": "equation_query", "query": text, "result": relevant_eqs, "response": response} | |
| else: | |
| response = "I couldn't find any relevant equations in the loaded data for that query." | |
| self._log_interaction(text, base_model_output, response, type="equation_query_not_found") | |
| return {"type": "equation_query", "query": text, "result": [], "response": response} | |
| if kind == "node_query": | |
| relevant_nodes = [] | |
| if self.structured_data.get('icosahedron_nodes'): | |
| query_words = text.lower().split() | |
| # Try to find by ID first if query contains a number | |
| try: | |
| node_id = int(query_words[-1]) if query_words and query_words[-1].isdigit() else None | |
| if node_id is not None: | |
| relevant_nodes = [node for node in self.structured_data['icosahedron_nodes'] if node.get('id') == node_id] | |
| except (ValueError, IndexError): | |
| pass # Not a number query | |
| # If not found by ID or not a number query, search by keyword in description/name | |
| if not relevant_nodes: | |
| 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)] | |
| if relevant_nodes: | |
| response_parts = ["Based on the Icosahedron Nodes data, I found the following relevant nodes:"] | |
| for node in relevant_nodes[:3]: # Limit to first 3 | |
| 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 | |
| if len(relevant_nodes) > 3: | |
| response_parts.append("...") | |
| response = "\n".join(response_parts) | |
| self._log_interaction(text, base_model_output, response, type="node_query") | |
| return {"type": "node_query", "query": text, "result": relevant_nodes, "response": response} | |
| else: | |
| response = "I couldn't find any relevant nodes in the loaded data for that query." | |
| self._log_interaction(text, base_model_output, response, type="node_query_not_found") | |
| return {"type": "node_query", "query": text, "result": [], "response": response} | |
| if kind == "music_resonance": | |
| # Can still trigger resonance simulation and music adaptation | |
| # Enhance response with information from frequencies/constants if relevant keywords are used | |
| response_parts = [] | |
| if self.structured_data.get('frequencies') and any(k in text.lower() for k in ("frecuen", "freq", "nota", "pitch", "scale", "musical", "sound", "audio")): | |
| query_words = text.lower().split() | |
| 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)] | |
| if relevant_freqs: | |
| response_parts.append("Based on the Frequencies data, I found:") | |
| for freq in relevant_freqs[:3]: | |
| 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 | |
| if len(relevant_freqs) > 3: response_parts.append("...") | |
| if self.structured_data.get('constants') and any(k in text.lower() for k in ("constant", "constante")): | |
| query_words = text.lower().split() | |
| relevant_constants = [c for c in self.structured_data['constants'] if any(word in c.get('name', '').lower() for word in query_words)] | |
| if relevant_constants: | |
| response_parts.append("Based on the Constants data, I found:") | |
| for const in relevant_constants[:3]: | |
| 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 | |
| if len(relevant_constants) > 3: response_parts.append("...") | |
| # Always run resonance simulation and music adaptation for this type | |
| r = self.resonator.simulate(text) | |
| seq = self.music.adapt_text_to_music(text) | |
| 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 | |
| response_parts.append(f"Adapted to music sequence (first 5 notes: pitch, duration): {seq[:5]}...") | |
| response = "\n".join(response_parts) if response_parts else "Processing music and resonance query..." | |
| self._log_interaction(text, base_model_output, response, type="music_resonance") | |
| return {"type":"music_resonance","query":text,"resonance_result":r,"music_result":seq, "response": response} | |
| if kind == "resonance_only": # New handler for resonance-only queries | |
| # Can still trigger resonance simulation | |
| response_parts = [] | |
| if self.structured_data.get('constants') and any(k in text.lower() for k in ("constant", "constante")): | |
| query_words = text.lower().split() | |
| relevant_constants = [c for c in self.structured_data['constants'] if any(word in c.get('name', '').lower() for word in query_words)] | |
| if relevant_constants: | |
| response_parts.append("Based on the Constants data, I found:") | |
| for const in relevant_constants[:3]: | |
| 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 | |
| if len(relevant_constants) > 3: response_parts.append("...") | |
| r = self.resonator.simulate(text) | |
| 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 | |
| response = "\n".join(response_parts) if response_parts else "Processing resonance query..." | |
| self._log_interaction(text, base_model_output, response, type="resonance_only") | |
| return {"type":"resonance_only","query":text,"resonance_result":r, "response": response} | |
| if kind == "constant_query": | |
| relevant_constants = [] | |
| if self.structured_data.get('constants'): | |
| query_words = text.lower().split() | |
| 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)] | |
| if relevant_constants: | |
| response_parts = ["Based on the RRF Constants data, I found the following relevant constants:"] | |
| for const in relevant_constants[:3]: | |
| 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 | |
| if len(relevant_constants) > 3: response_parts.append("...") | |
| response = "\n".join(response_parts) | |
| self._log_interaction(text, base_model_output, response, type="constant_query") | |
| return {"type": "constant_query", "query": text, "result": relevant_constants, "response": response} | |
| else: | |
| response = "I couldn't find any relevant constants in the loaded data for that query." | |
| self._log_interaction(text, base_model_output, response, type="constant_query_not_found") | |
| return {"type": "constant_query", "query": text, "result": [], "response": response} | |
| if kind == "map": | |
| # Use icosahedron_nodes data in mapping (already done in IcosaMap) | |
| node_label = self.icosa.closest_node(text) | |
| response = f"Mapping query '{text}' to closest node: {node_label}" | |
| # If we have node data, try to find details about the mapped node | |
| if self.structured_data.get('icosahedron_nodes'): | |
| # Assuming node_label is the description or name from node_data used for embedding | |
| # A more robust mapping is needed here to link label back to original node dict by ID | |
| # For now, let's just find the node with a matching description/name if possible | |
| 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) | |
| if mapped_node_data: | |
| 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 | |
| self._log_interaction(text, base_model_output, response, type="map") | |
| return {"type":"map","query":text,"node":node_label, "response": response} | |
| # chat fallback: if base_model_output provided, refine it using self_improver | |
| if kind == "chat": | |
| if base_model_output is None: | |
| # default echo | |
| base = "Echo: " + text | |
| else: | |
| base = base_model_output | |
| refined = chat_refine(text, base, self_improver=self.self_improver) | |
| response = refined # Use refined output as the main response for chat | |
| self._log_interaction(text, base_model_output, refined, type="chat_interaction") # Log chat interaction | |
| return {"type":"chat","query":text,"base":base,"refined":refined, "response": response} | |
| # Fallback for unhandled types (shouldn't be reached with current classify) | |
| response = "I'm not sure how to handle that query based on the available data and functions." | |
| self._log_interaction(text, base_model_output, response, type="unhandled_query") | |
| return {"type": "unhandled", "query": text, "response": response} | |
| def _log_interaction(self, user_input, base_output, final_output, type="interaction"): | |
| """Logs interaction details to memory and triggers self-improvement if needed.""" | |
| interaction_record = { | |
| "type": type, # Use the specified type (e.g., chat_interaction, equation_query) | |
| "user_input": user_input, | |
| "base_model_output": base_output, # Might be None for non-chat types | |
| "final_output": final_output, # The response generated by handle_query | |
| "_ts": time.time() # Add timestamp | |
| } | |
| self.memory.add(interaction_record) | |
| # Periodically trigger self-improvement (e.g., every 10 interactions) | |
| self._interaction_count = getattr(self, '_interaction_count', 0) + 1 | |
| if self._interaction_count % 10 == 0: | |
| print("SAVANT: Triggering self-improvement cycle...") | |
| try: | |
| proposal = self.self_improver.propose() | |
| accepted, metric = self.self_improver.evaluate_and_apply(proposal) | |
| print(f"SAVANT: Self-improvement proposal accepted: {accepted}, New metric: {metric}") | |
| self.memory.add({ | |
| "type": "self_improvement_triggered", | |
| "proposal": proposal, | |
| "accepted": accepted, | |
| "metric": metric, | |
| "_ts": time.time() | |
| }) | |
| except Exception as si_error: | |
| # Log the error and continue | |
| error_message = f"Error during self-improvement: {si_error}" | |
| print(f"SAVANT: {error_message}") | |
| self.memory.add({ | |
| "type": "self_improvement_error", | |
| "error": error_message, | |
| "_ts": time.time() | |
| }) | |
| # trainer helpers (these are now called externally via SimpleTrainer instance) | |
| # def run_training_epochs(self, stimuli, epochs=3): | |
| # return self.trainer.run_epochs(stimuli, epochs) | |
| def propose_improvement(self): | |
| return self.self_improver.propose() | |
| def apply_improvement(self, proposal): | |
| return self.self_improver.evaluate_and_apply(proposal) | |