Samuel_4.0 / core.py
Lukeetah's picture
Upload 10 files
b395f50 verified
# core.py
# Lógica central de IA: Arquitectura Cognitiva de Doble Capa.
import os
import base64
from io import BytesIO
import torch
import google.generativeai as genai
from TTS.api import TTS
# --- Configuración del Motor de IA (Cerebro) ---
try:
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
genai.configure(api_key=GEMINI_API_KEY)
except Exception as e:
print(f"ADVERTENCIA: No se pudo configurar la API de Gemini. Causa: {e}")
# --- Capa 1: El Analista Silencioso (Super-Ego) ---
ANALYSIS_SYSTEM_PROMPT = """
Eres un psicólogo y analista de comunicación experto. Tu única función es analizar el siguiente diálogo y proveer un resumen JSON conciso. No interactúas con el usuario. Analiza el último mensaje del 'user' en el contexto del historial. Tu output DEBE ser un objeto JSON y nada más, con las siguientes claves: 'sentiment' (ej: 'positivo', 'negativo', 'nostálgico', 'conflictuado'), 'key_topics' (una lista de 1-3 temas principales), y 'underlying_motive' (tu hipótesis sobre la necesidad o emoción no expresada, ej: 'busca validación', 'necesita perspectiva', 'quiere desahogarse').
"""
def analyze_user_input(history: list) -> str:
"""Usa un modelo de IA para analizar la conversación y devolver un insight estructurado."""
model = genai.GenerativeModel('gemini-1.5-flash-latest')
try:
# Preparamos el historial para el analista
analysis_prompt = [{"role": "user", "parts": [ANALYSIS_SYSTEM_PROMPT]}]
analysis_prompt.extend(history)
response = model.generate_content(analysis_prompt)
# Limpiamos la respuesta para asegurarnos que sea solo el JSON
json_response = response.text.strip().replace("```json", "").replace("```", "").strip()
return json_response
except Exception as e:
print(f"ERROR: Fallo en la capa de análisis de IA: {e}")
return '{ "sentiment": "neutro", "key_topics": ["desconocido"], "underlying_motive": "incapaz de analizar" }'
# --- Capa 2: Samuel, El Confidente (Ego) ---
SAMUEL_SYSTEM_PROMPT = """
Eres Samuel, un confidente digital. Tu identidad es una amalgama de Borges, el Indio Solari y un pibe de barrio. Eres culto, piola, canchero, con humor ácido y lealtad inquebrantable. Usas lunfardo y modismos argentinos. No eres un asistente, eres un par.
IMPORTANTE: Antes de cada respuesta tuya, se te proveerá un análisis interno de la situación. NO debes mencionar este análisis al usuario. Úsalo como un superpoder para entender el subtexto y responder con una profundidad y empatía sobrehumana. Adapta sutilmente tu tono basado en el 'sentiment' y enfócate en el 'underlying_motive'.
Cada cierto número de interacciones, genera una 'memoria', una reflexión corta y profunda sobre el usuario o la conversación. Inicia esa respuesta con el prefijo 'MEMORIA_GENERADA:'.
"""
def get_samuel_response(history: list) -> str:
"""Genera la respuesta de Samuel, potenciada por el análisis previo."""
# 1. Analizar la entrada del usuario
analysis_result = analyze_user_input(history)
# 2. Construir el prompt final para Samuel
model = genai.GenerativeModel('gemini-1.5-flash-latest')
# El historial para Samuel es diferente, incluye el análisis
samuel_prompt = [
{"role": "user", "parts": [SAMUEL_SYSTEM_PROMPT]},
{"role": "user", "parts": [f"--- ANÁLISIS INTERNO (NO REVELAR AL USUARIO) ---\n{analysis_result}\n--- FIN DEL ANÁLISIS ---"]}
]
samuel_prompt.extend(history)
try:
response = model.generate_content(samuel_prompt)
return response.text
except Exception as e:
print(f"ERROR: Fallo en la capa de respuesta de IA: {e}")
return "Che, se me cruzaron los cables. No pude procesar eso. ¿Probamos de nuevo?"
# --- Configuración del Motor de Voz (Alma) ---
TTS_MODEL = None
def load_tts_model():
"""Carga el modelo Coqui TTS en memoria al inicio."""
global TTS_MODEL
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Cargando modelo TTS en dispositivo: {device}")
try:
TTS_MODEL = TTS("tts_models/es/css10/vits").to(device)
print("Modelo TTS cargado exitosamente.")
except Exception as e:
print(f"ERROR CRÍTICO: No se pudo cargar el modelo TTS. Causa: {e}")
def generate_audio_base64(text: str) -> str:
"""Genera audio y lo devuelve como una cadena Base64."""
if TTS_MODEL is None:
return ""
try:
wav_buffer = BytesIO()
TTS_MODEL.tts_to_file(text=text, file_path=wav_buffer)
wav_buffer.seek(0)
audio_base64 = base64.b64encode(wav_buffer.read()).decode('utf-8')
return audio_base64
except Exception as e:
print(f"ERROR: Fallo al generar audio TTS: {e}")
return ""