Spaces:
Runtime error
Runtime error
File size: 10,891 Bytes
1cb13bf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
from flask import Flask
from tts_utils import TTSUtils
from inference import InferenceManager
from huggingface_utils import HuggingFaceUtils
from flow_bot import FlowBot
from tunnel_manager import TunnelManager
from routes import Routes
from session_manager import SessionManager
from data_manager import DataManager
import yaml
import os
import webbrowser
import threading
import time
import sys
from datetime import timedelta
import logging
from colorama import init, Fore, Back, Style
# Inicializar colorama para Windows
init()
def print_startup_checklist():
"""Muestra el checklist de inicio con colores"""
print(f"\n{Fore.CYAN}{'='*50}")
print(f"{Fore.YELLOW}🤖 Iniciando Asistente Virtual...")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}\n")
# Checklist de Modelos
print(f"{Fore.MAGENTA}📋 Modelos de IA:{Style.RESET_ALL}")
print(f"{Fore.GREEN}✓ {Fore.WHITE}Principal: {Fore.YELLOW}Gemini 8b 🧠")
print(f"{Fore.GREEN}✓ {Fore.WHITE}Respaldo: {Fore.YELLOW}Mixtral 7b ⚡\n")
# Checklist de TTS
print(f"{Fore.MAGENTA}🎤 Motores TTS:{Style.RESET_ALL}")
print(f"{Fore.GREEN}✓ {Fore.WHITE}EDGE (Principal)")
print(f" {Fore.CYAN}└─ Voz: Jorge (MX) 📢")
print(f"{Fore.GREEN}✓ {Fore.WHITE}EDGE_ES")
print(f" {Fore.CYAN}└─ Voz: Álvaro (ES) 🌐")
print(f"{Fore.GREEN}✓ {Fore.WHITE}VITS")
print(f" {Fore.CYAN}└─ Modelo Local 🔊\n")
# Checklist de Modos
print(f"{Fore.MAGENTA}📋 Modos Disponibles:{Style.RESET_ALL}")
print(f"{Fore.GREEN}✓ {Fore.WHITE}Créditos 💰")
print(f"{Fore.GREEN}✓ {Fore.WHITE}Seguros 🛡️")
print(f"{Fore.GREEN}✓ {Fore.WHITE}Cobranza 💵\n")
# Estado del Sistema
print(f"{Fore.MAGENTA}🔄 Estado del Sistema:{Style.RESET_ALL}")
class WebChatbotApp:
def __init__(self):
# Mostrar checklist inicial
print_startup_checklist()
self.flask_app = Flask(__name__)
self.flask_app.config['SECRET_KEY'] = os.urandom(24)
self.flask_app.config['SESSION_TYPE'] = 'filesystem'
self.flask_app.config['SESSION_FILE_DIR'] = './flask_session'
self.flask_app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=2)
self.tunnel_url = None
self.load_config()
self.init_components()
self.routes = Routes(self.flask_app, self)
# Inicializar DataManager
self.data_manager = DataManager()
print(f"{Fore.GREEN}✓ {Fore.WHITE}Aplicación inicializada correctamente{Style.RESET_ALL}")
def load_config(self):
try:
config_path = os.path.join(os.path.dirname(__file__), 'config.yaml')
with open(config_path, 'r', encoding='utf-8') as f:
self.config = yaml.safe_load(f)
print(f"{Fore.GREEN}✓ {Fore.WHITE}Configuración cargada")
except Exception as e:
print(f"{Fore.RED}✗ Error cargando config.yaml: {e}{Style.RESET_ALL}")
self.config = {}
def init_components(self):
try:
print(f"{Fore.CYAN}⚙️ Iniciando componentes...{Style.RESET_ALL}")
elevenlabs_key = self.config.get('ELEVENLABS_API_KEY', '')
huggingface_token = self.config.get('api_keys', {}).get('HUGGINGFACE_TOKEN', '')
self.tts = TTSUtils(
model_name='EDGE',
elevenlabs_api_key=elevenlabs_key
)
self.inference = InferenceManager(self.config)
self.hf_utils = HuggingFaceUtils(huggingface_token)
self.flow_bot = FlowBot()
self.session_manager = SessionManager()
print(f"{Fore.GREEN}✓ {Fore.WHITE}Componentes iniciados correctamente{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}✗ Error iniciando componentes: {e}{Style.RESET_ALL}")
raise
def reinit_components(self):
try:
self.load_config()
elevenlabs_key = self.config.get('ELEVENLABS_API_KEY', '')
huggingface_token = self.config.get('api_keys', {}).get('HUGGINGFACE_TOKEN', '')
print(f"{Fore.CYAN}⚙️ Reiniciando componentes...{Style.RESET_ALL}")
self.tts = TTSUtils(
model_name='EDGE',
elevenlabs_api_key=elevenlabs_key
)
self.inference = InferenceManager(self.config)
self.hf_utils = HuggingFaceUtils(huggingface_token)
print(f"{Fore.GREEN}✓ {Fore.WHITE}Componentes reiniciados correctamente{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}✗ Error reiniciando componentes: {e}{Style.RESET_ALL}")
raise
def procesar_mensaje(self, mensaje):
"""Procesa un mensaje de texto y retorna la respuesta"""
try:
# Obtener el modo actual de la sesión
session_id = self.session_manager.get_session()
current_mode = self.session_manager.get_session_data(session_id, 'mode')
# Verificar si estamos en proceso de recolección de datos
if self.data_manager.is_collecting_data():
respuesta = self.data_manager.handle_data_collection(
mensaje,
current_mode,
self.flow_bot.get_data_collection_steps
)
if respuesta:
return respuesta
# Obtener contexto del flow_bot usando el modo actual
contexto = self.flow_bot.get_context(current_mode, mensaje)
# Obtener respuesta usando el inference manager
respuesta = self.inference.get_response(
prompt=mensaje,
context=contexto
)
# Verificar que la respuesta no sea un mensaje de error o predeterminado
mensajes_error = [
"No se proporcionó un mensaje",
"Lo siento, hubo un error",
"Error de autenticación",
"El servicio está ocupado",
"No se pudo generar una respuesta coherente",
"¡Hola! Soy tu asistente virtual"
]
if not respuesta or any(msg in respuesta for msg in mensajes_error):
print("Respuesta no válida del modelo, usando contexto directo")
respuesta = self.flow_bot.get_success_message(current_mode)
# Iniciar recolección de datos si es necesario
if "nombre" in respuesta.lower():
self.data_manager.start_data_collection()
return respuesta
except Exception as e:
print(f"Error procesando mensaje: {e}")
return self.flow_bot.get_negative_response(current_mode)
def procesar_audio(self, audio_path):
"""Procesa un archivo de audio y retorna mensaje y audio de respuesta"""
try:
# Transcribir audio a texto
mensaje = self.inference.transcribe_audio(audio_path)
print(f"Audio transcrito: {mensaje}")
# Obtener respuesta
respuesta = self.procesar_mensaje(mensaje)
print(f"Respuesta generada: {respuesta}")
# Convertir respuesta a audio
audio_path = self.tts.text_to_speech(respuesta)
return mensaje, audio_path
except Exception as e:
print(f"Error procesando audio: {e}")
return "Error al procesar el audio", None
def open_browser(self, url):
time.sleep(2)
webbrowser.open(url)
def run(self, host='127.0.0.1', port=5000, debug=False, use_tunnel=True):
try:
if use_tunnel:
try:
tunnel_manager = TunnelManager()
# Primero intentar obtener un túnel activo
self.tunnel_url = tunnel_manager.get_active_tunnel()
if not self.tunnel_url:
# Si no hay túnel activo, limpiar y crear uno nuevo
tunnel_manager.setup_ngrok()
tunnel_manager.cleanup()
self.tunnel_url = tunnel_manager.start(port)
if self.tunnel_url:
print(f"{Fore.GREEN}✓ {Fore.WHITE}Túnel iniciado en: {Fore.CYAN}{self.tunnel_url}{Style.RESET_ALL}")
threading.Thread(target=self.open_browser, args=(self.tunnel_url,)).start()
else:
print(f"{Fore.YELLOW}⚠️ No se pudo iniciar el túnel, continuando en modo local{Style.RESET_ALL}")
except Exception as tunnel_error:
print(f"{Fore.YELLOW}⚠️ Continuando en modo local{Style.RESET_ALL}")
print(f"\n{Fore.GREEN}✓ {Fore.WHITE}Servidor iniciado en: {Fore.CYAN}http://{host}:{port}{Style.RESET_ALL}\n")
self.flask_app.run(host=host, port=port, debug=debug, threaded=True)
except Exception as e:
print(f"{Fore.RED}✗ Error iniciando el servidor: {e}{Style.RESET_ALL}")
raise
@property
def app(self):
return self.flask_app
if __name__ == '__main__':
import os
import psutil
import socket
def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
return s.connect_ex(('localhost', port)) == 0
def kill_process_on_port(port):
for proc in psutil.process_iter(['pid', 'name', 'connections']):
try:
for conn in proc.connections():
if conn.laddr.port == port:
print(f"Terminando proceso anterior en puerto {port}")
proc.terminate()
proc.wait()
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False
try:
port = 5000
if is_port_in_use(port):
print(f"Puerto {port} en uso. Intentando liberar...")
if kill_process_on_port(port):
print("Proceso anterior terminado")
else:
print(f"No se pudo liberar el puerto {port}. Por favor, cierre la aplicación anterior manualmente.")
exit(1)
print("Iniciando nueva instancia de la aplicación...")
app = WebChatbotApp()
app.run()
except Exception as e:
print(f"Error al iniciar la aplicación: {e}")
exit(1)
|