ivanoctaviogaitansantos commited on
Commit
a308962
·
verified ·
1 Parent(s): 9c651ed

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +305 -0
app.py ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from datetime import datetime
5
+ import logging
6
+
7
+ # Configuración de logging
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # Importar módulos personalizados
12
+ from model_manager import ModelManager
13
+ from api_agent import APIAgent
14
+ from prompt_generator import PromptGenerator
15
+
16
+ # Inicializar componentes
17
+ model_manager = ModelManager()
18
+ api_agent = APIAgent()
19
+ prompt_generator = PromptGenerator()
20
+
21
+ class BATUTOChatbot:
22
+ def __init__(self):
23
+ self.conversation_history = []
24
+ self.config = {
25
+ "deepseek_api_key": "",
26
+ "openai_api_key": "",
27
+ "max_tokens": 400,
28
+ "temperature": 0.7
29
+ }
30
+
31
+ def update_config(self, deepseek_key, openai_key, max_tokens, temperature):
32
+ """Actualiza la configuración desde la UI"""
33
+ updated = False
34
+
35
+ if deepseek_key:
36
+ self.config["deepseek_api_key"] = deepseek_key
37
+ updated = True
38
+ if openai_key:
39
+ self.config["openai_api_key"] = openai_key
40
+ updated = True
41
+ if max_tokens:
42
+ self.config["max_tokens"] = int(max_tokens)
43
+ updated = True
44
+ if temperature:
45
+ self.config["temperature"] = float(temperature)
46
+ updated = True
47
+
48
+ # Actualizar agentes
49
+ model_manager.set_config(self.config)
50
+ api_agent.set_config(self.config)
51
+
52
+ return "✅ Configuración actualizada" if updated else "ℹ️ Sin cambios"
53
+
54
+ def get_system_status(self):
55
+ """Obtiene el estado del sistema"""
56
+ has_deepseek = bool(self.config.get("deepseek_api_key"))
57
+ has_openai = bool(self.config.get("openai_api_key"))
58
+ models_loaded = model_manager.loaded
59
+
60
+ status_html = f"""
61
+ <div style='padding: 15px; border-radius: 10px; background: #f8f9fa; border: 2px solid #e9ecef;'>
62
+ <h4 style='margin-top: 0;'>🔧 Estado del Sistema</h4>
63
+ <p><strong>Modelos locales:</strong> {'✅ Cargados' if models_loaded else '🔄 Cargando...'}</p>
64
+ <p><strong>DeepSeek API:</strong> {'✅ Configurada' if has_deepseek else '❌ No configurada'}</p>
65
+ <p><strong>OpenAI API:</strong> {'✅ Configurada' if has_openai else '❌ No configurada'}</p>
66
+ <p><strong>Mensajes en sesión:</strong> {len(self.conversation_history)}</p>
67
+ </div>
68
+ """
69
+ return status_html
70
+
71
+ def chat_response(self, message, history):
72
+ """Genera respuesta del chatbot optimizado para HF"""
73
+ if not message.strip():
74
+ return ""
75
+
76
+ # Mostrar indicador de typing
77
+ yield "🔄 Procesando..."
78
+
79
+ try:
80
+ # Detectar intención y mejorar prompt
81
+ intent = prompt_generator.detect_intent(message)
82
+ enhanced_prompt = prompt_generator.enhance_prompt(message, intent)
83
+
84
+ # Intentar usar APIs primero
85
+ api_result = api_agent.generate_response(enhanced_prompt, intent["is_code"])
86
+
87
+ if api_result["response"]:
88
+ # Usar respuesta de API
89
+ response_text = api_result["response"]
90
+ source = api_result["source"]
91
+ else:
92
+ # Usar modelo local como fallback
93
+ response_text = model_manager.generate_local_response(
94
+ enhanced_prompt,
95
+ intent["is_code"],
96
+ max_length=200 # Reducido para HF
97
+ )
98
+ source = "local"
99
+
100
+ # Agregar metadata a la respuesta
101
+ metadata = f"\n\n---\n*🔧 Fuente: {source.upper()}*"
102
+ if intent["is_code"]:
103
+ metadata += f" | 💻 *Tipo: Código*"
104
+ else:
105
+ metadata += f" | 💬 *Tipo: Conversación*"
106
+
107
+ full_response = response_text + metadata
108
+
109
+ # Guardar en historial
110
+ self.conversation_history.append({
111
+ "timestamp": datetime.now().isoformat(),
112
+ "user": message,
113
+ "bot": response_text,
114
+ "source": source,
115
+ "intent": intent
116
+ })
117
+
118
+ yield full_response
119
+
120
+ except Exception as e:
121
+ error_msg = f"❌ Error: {str(e)}"
122
+ logger.error(f"Error en chat_response: {e}")
123
+ yield error_msg
124
+
125
+ def clear_conversation(self):
126
+ """Limpia la conversación"""
127
+ self.conversation_history.clear()
128
+ return None, []
129
+
130
+ # Crear instancia del chatbot
131
+ chatbot = BATUTOChatbot()
132
+
133
+ # Cargar modelos al inicio (async)
134
+ def load_models_async():
135
+ logger.info("🔄 Cargando modelos en segundo plano...")
136
+ model_manager.load_models()
137
+ logger.info("✅ Modelos cargados exitosamente")
138
+
139
+ # Iniciar carga de modelos
140
+ import threading
141
+ model_loader = threading.Thread(target=load_models_async, daemon=True)
142
+ model_loader.start()
143
+
144
+ # Configuración de la interfaz Gradio para HF
145
+ with gr.Blocks(
146
+ title="BATUTO Chatbot - Asistente Educativo",
147
+ theme=gr.themes.Soft(),
148
+ css="""
149
+ .gradio-container {
150
+ max-width: 1000px !important;
151
+ margin: auto;
152
+ }
153
+ .chat-container {
154
+ height: 500px;
155
+ }
156
+ .status-panel {
157
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
158
+ padding: 20px;
159
+ border-radius: 10px;
160
+ color: white;
161
+ }
162
+ """
163
+ ) as demo:
164
+
165
+ gr.Markdown("""
166
+ # 🤖 BATUTO Chatbot - Asistente Educativo
167
+ **Sistema inteligente con modelos locales y APIs externas**
168
+ *Desplegado en Hugging Face Spaces - Versión Optimizada*
169
+ """)
170
+
171
+ with gr.Row():
172
+ with gr.Column(scale=2):
173
+ # Área de chat
174
+ gr.Markdown("### 💬 Conversación")
175
+ chatbot_interface = gr.Chatbot(
176
+ label="Chat con BATUTO",
177
+ height=400,
178
+ show_copy_button=True,
179
+ container=True
180
+ )
181
+ msg = gr.Textbox(
182
+ label="Escribe tu mensaje",
183
+ placeholder="Pregunta sobre programación, explica conceptos, pide ejemplos...",
184
+ lines=2,
185
+ max_lines=4
186
+ )
187
+
188
+ with gr.Row():
189
+ submit_btn = gr.Button("🚀 Enviar", variant="primary")
190
+ clear_btn = gr.Button("🧹 Limpiar", variant="secondary")
191
+
192
+ with gr.Column(scale=1):
193
+ # Panel de estado
194
+ gr.Markdown("### 📊 Estado del Sistema")
195
+ status_display = gr.HTML()
196
+
197
+ # Configuración rápida
198
+ with gr.Accordion("⚙️ Configuración Rápida", open=False):
199
+ with gr.Group():
200
+ deepseek_key = gr.Textbox(
201
+ label="DeepSeek API Key",
202
+ type="password",
203
+ placeholder="sk-...",
204
+ info="Opcional - para respuestas mejoradas"
205
+ )
206
+ openai_key = gr.Textbox(
207
+ label="OpenAI API Key",
208
+ type="password",
209
+ placeholder="sk-...",
210
+ info="Opcional - alternativa"
211
+ )
212
+
213
+ with gr.Row():
214
+ max_tokens = gr.Slider(
215
+ label="Tokens máx",
216
+ minimum=100,
217
+ maximum=800,
218
+ value=400,
219
+ step=50
220
+ )
221
+ temperature = gr.Slider(
222
+ label="Temperatura",
223
+ minimum=0.1,
224
+ maximum=1.0,
225
+ value=0.7,
226
+ step=0.1
227
+ )
228
+
229
+ save_config_btn = gr.Button("💾 Guardar Config", size="sm")
230
+ config_output = gr.Textbox(label="Estado", interactive=False)
231
+
232
+ # Información
233
+ with gr.Accordion("ℹ️ Cómo usar", open=True):
234
+ gr.Markdown("""
235
+ **Ejemplos:**
236
+ - 💻 *"Muéstrame una función Python para ordenar listas"*
237
+ - 💬 *"Explica qué es machine learning"*
238
+ - 🔧 *"Corrige este código: [tu código]"*
239
+
240
+ **Fuentes:**
241
+ 1. 🚀 DeepSeek API (si se configura)
242
+ 2. ⚡ OpenAI API (si se configura)
243
+ 3. 🤖 Modelos locales (fallback)
244
+ """)
245
+
246
+ # Event handlers
247
+ def handle_submit(message, history):
248
+ if not message.strip():
249
+ return "", history
250
+ return "", history + [[message, None]]
251
+
252
+ # Conectar el botón de enviar
253
+ submit_btn.click(
254
+ handle_submit,
255
+ inputs=[msg, chatbot_interface],
256
+ outputs=[msg, chatbot_interface]
257
+ ).then(
258
+ chatbot.chat_response,
259
+ inputs=[msg, chatbot_interface],
260
+ outputs=[chatbot_interface]
261
+ )
262
+
263
+ # Enter también envía
264
+ msg.submit(
265
+ handle_submit,
266
+ inputs=[msg, chatbot_interface],
267
+ outputs=[msg, chatbot_interface]
268
+ ).then(
269
+ chatbot.chat_response,
270
+ inputs=[msg, chatbot_interface],
271
+ outputs=[chatbot_interface]
272
+ )
273
+
274
+ # Limpiar chat
275
+ clear_btn.click(
276
+ chatbot.clear_conversation,
277
+ outputs=[msg, chatbot_interface]
278
+ )
279
+
280
+ # Configuración
281
+ save_config_btn.click(
282
+ chatbot.update_config,
283
+ inputs=[deepseek_key, openai_key, max_tokens, temperature],
284
+ outputs=[config_output]
285
+ ).then(
286
+ chatbot.get_system_status,
287
+ outputs=[status_display]
288
+ )
289
+
290
+ # Actualizar estado al cargar
291
+ demo.load(
292
+ chatbot.get_system_status,
293
+ outputs=[status_display]
294
+ )
295
+
296
+ # Configuración específica para Hugging Face Spaces
297
+ if __name__ == "__main__":
298
+ demo.launch(
299
+ server_name="0.0.0.0",
300
+ server_port=7860,
301
+ share=True,
302
+ show_error=True,
303
+ debug=False,
304
+ favicon_path=None
305
+ )