import gradio as gr import os import json from datetime import datetime import logging import threading # Configuración de logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Importar módulos personalizados from model_manager import ModelManager from api_agent import APIAgent from prompt_generator import PromptGenerator # Inicializar componentes model_manager = ModelManager() api_agent = APIAgent() prompt_generator = PromptGenerator() class BATUTOChatbot: def __init__(self): self.conversation_history = [] self.config = { 'deepseek_api_key': '', 'openai_api_key': '', 'max_tokens': 400, 'temperature': 0.7 } def update_config(self, deepseek_key, openai_key, max_tokens, temperature): """Actualiza la configuración desde la UI""" updated = False if deepseek_key: self.config['deepseek_api_key'] = deepseek_key updated = True if openai_key: self.config['openai_api_key'] = openai_key updated = True if max_tokens: self.config['max_tokens'] = int(max_tokens) updated = True if temperature: self.config['temperature'] = float(temperature) updated = True # Actualizar agentes model_manager.set_config(self.config) api_agent.set_config(self.config) return 'Configuración actualizada' if updated else 'Sin cambios' def get_system_status(self): """Obtiene el estado del sistema""" has_deepseek = bool(self.config.get('deepseek_api_key')) has_openai = bool(self.config.get('openai_api_key')) models_loaded = model_manager.loaded status_html = f'''

Estado del Sistema

Modelos locales: {'Cargados' if models_loaded else 'Cargando...'}

DeepSeek API: {'Configurada' if has_deepseek else 'No configurada'}

OpenAI API: {'Configurada' if has_openai else 'No configurada'}

Mensajes en sesión: {len(self.conversation_history)}

''' return status_html def chat_response(self, message, history): """Genera respuesta del chatbot optimizado para HF""" if not message.strip(): return '' # Mostrar indicador de typing yield 'Procesando...' try: # Detectar intención y mejorar prompt intent = prompt_generator.detect_intent(message) enhanced_prompt = prompt_generator.enhance_prompt(message, intent) # Intentar usar APIs primero api_result = api_agent.generate_response(enhanced_prompt, intent['is_code']) if api_result['response']: # Usar respuesta de API response_text = api_result['response'] source = api_result['source'] else: # Usar modelo local como fallback response_text = model_manager.generate_local_response( enhanced_prompt, intent['is_code'], max_length=200 ) source = 'local' # Agregar metadata a la respuesta metadata = f'\n\n---\nFuente: {source.upper()}' if intent['is_code']: metadata += f' | Tipo: Código' else: metadata += f' | Tipo: Conversación' full_response = response_text + metadata # Guardar en historial self.conversation_history.append({ 'timestamp': datetime.now().isoformat(), 'user': message, 'bot': response_text, 'source': source, 'intent': intent }) yield full_response except Exception as e: error_msg = f'Error: {str(e)}' logger.error(f'Error en chat_response: {e}') yield error_msg def clear_conversation(self): """Limpia la conversación""" self.conversation_history.clear() return None, [] # Crear instancia del chatbot chatbot = BATUTOChatbot() # Cargar modelos al inicio (async) def load_models_async(): logger.info('Cargando modelos en segundo plano...') model_manager.load_models() logger.info('Modelos cargados exitosamente') # Iniciar carga de modelos model_loader = threading.Thread(target=load_models_async, daemon=True) model_loader.start() # Configuración de la interfaz Gradio para HF with gr.Blocks( title='BATUTO Chatbot - Asistente Educativo', theme=gr.themes.Soft(), css=''' .gradio-container { max-width: 1000px !important; margin: auto; } .chat-container { height: 500px; } .status-panel { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; color: white; } ''' ) as demo: gr.Markdown(''' # BATUTO Chatbot - Asistente Educativo **Sistema inteligente con modelos locales y APIs externas** *Desplegado en Hugging Face Spaces - Versión Optimizada* ''') with gr.Row(): with gr.Column(scale=2): # Área de chat gr.Markdown('### Conversación') chatbot_interface = gr.Chatbot( label='Chat con BATUTO', height=400, show_copy_button=True, container=True ) msg = gr.Textbox( label='Escribe tu mensaje', placeholder='Pregunta sobre programación, explica conceptos, pide ejemplos...', lines=2, max_lines=4 ) with gr.Row(): submit_btn = gr.Button('Enviar', variant='primary') clear_btn = gr.Button('Limpiar', variant='secondary') with gr.Column(scale=1): # Panel de estado gr.Markdown('### Estado del Sistema') status_display = gr.HTML() # Configuración rápida with gr.Accordion('Configuración Rápida', open=False): with gr.Group(): deepseek_key = gr.Textbox( label='DeepSeek API Key', type='password', placeholder='sk-...', info='Opcional - para respuestas mejoradas' ) openai_key = gr.Textbox( label='OpenAI API Key', type='password', placeholder='sk-...', info='Opcional - alternativa' ) with gr.Row(): max_tokens = gr.Slider( label='Tokens máx', minimum=100, maximum=800, value=400, step=50 ) temperature = gr.Slider( label='Temperatura', minimum=0.1, maximum=1.0, value=0.7, step=0.1 ) save_config_btn = gr.Button('Guardar Config', size='sm') config_output = gr.Textbox(label='Estado', interactive=False) # Información with gr.Accordion('Cómo usar', open=True): gr.Markdown(''' **Ejemplos:** - Muéstrame una función Python para ordenar listas - Explica qué es machine learning - Corrige este código: [tu código] **Fuentes:** 1. DeepSeek API (si se configura) 2. OpenAI API (si se configura) 3. Modelos locales (fallback) ''') # Event handlers def handle_submit(message, history): if not message.strip(): return '', history return '', history + [[message, None]] # Conectar el botón de enviar submit_btn.click( handle_submit, inputs=[msg, chatbot_interface], outputs=[msg, chatbot_interface] ).then( chatbot.chat_response, inputs=[msg, chatbot_interface], outputs=[chatbot_interface] ) # Enter también envía msg.submit( handle_submit, inputs=[msg, chatbot_interface], outputs=[msg, chatbot_interface] ).then( chatbot.chat_response, inputs=[msg, chatbot_interface], outputs=[chatbot_interface] ) # Limpiar chat clear_btn.click( chatbot.clear_conversation, outputs=[msg, chatbot_interface] ) # Configuración save_config_btn.click( chatbot.update_config, inputs=[deepseek_key, openai_key, max_tokens, temperature], outputs=[config_output] ).then( chatbot.get_system_status, outputs=[status_display] ) # Actualizar estado al cargar demo.load( chatbot.get_system_status, outputs=[status_display] ) # Configuración específica para Hugging Face Spaces if __name__ == '__main__': demo.launch( server_name='0.0.0.0', server_port=7860, share=True, show_error=True, debug=False )