BATUTO-ART commited on
Commit
9199563
·
verified ·
1 Parent(s): 2847d18

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +702 -0
app.py ADDED
@@ -0,0 +1,702 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import asyncio
3
+ import json
4
+ from typing import List, Dict, Any, Optional, Tuple, Generator
5
+ from datetime import datetime
6
+ from enum import Enum
7
+ import hashlib
8
+ import logging
9
+ from dataclasses import dataclass
10
+ from typing import Literal
11
+
12
+ # ==================== CONFIGURACIÓN DE LOGGING ESTRUCTURADO ====================
13
+ logging.basicConfig(
14
+ level=logging.INFO,
15
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
16
+ handlers=[
17
+ logging.FileHandler('chat_interface.log'),
18
+ logging.StreamHandler()
19
+ ]
20
+ )
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # ==================== TIPADO Y ESTRUCTURAS DE DATOS ====================
24
+ @dataclass
25
+ class ChatMessage:
26
+ """Estructura type-safe para mensajes de chat"""
27
+ role: Literal["user", "assistant", "system"]
28
+ content: str
29
+ timestamp: str
30
+ message_id: str
31
+
32
+ def to_dict(self) -> Dict[str, Any]:
33
+ return {
34
+ "role": self.role,
35
+ "content": self.content,
36
+ "timestamp": self.timestamp,
37
+ "id": self.message_id
38
+ }
39
+
40
+ class IntentType(Enum):
41
+ """Tipos de intención detectados"""
42
+ QUERY = "consulta"
43
+ CODE_GENERATION = "generacion_codigo"
44
+ SYSTEM_DIAGNOSTIC = "diagnostico_sistema"
45
+ OPTIMIZATION = "optimizacion"
46
+ UNKNOWN = "desconocido"
47
+
48
+ @dataclass
49
+ class IntentAnalysis:
50
+ """Resultado del análisis de intención"""
51
+ intent: IntentType
52
+ confidence: float
53
+ entities: Dict[str, Any]
54
+ requires_streaming: bool
55
+
56
+ # ==================== SERVICIO DE ANÁLISIS DE INTENCIÓN ====================
57
+ class IntentAnalyzer:
58
+ """Servicio para análisis de intención con validación robusta"""
59
+
60
+ @staticmethod
61
+ def analyze_intent_detailed(
62
+ message: str,
63
+ history: List[Dict[str, Any]]
64
+ ) -> Tuple[IntentType, Dict[str, Any]]:
65
+ """
66
+ Analiza la intención del mensaje con validación de inputs.
67
+
68
+ Args:
69
+ message: Mensaje del usuario (validado y sanitizado)
70
+ history: Historial de conversación en formato Gradio 4.x
71
+
72
+ Returns:
73
+ Tuple[IntentType, Dict]: Tipo de intención y metadatos
74
+
75
+ Raises:
76
+ ValueError: Si el mensaje está vacío o mal formado
77
+ """
78
+ # Validación de inputs
79
+ if not isinstance(message, str):
80
+ raise TypeError(f"Mensaje debe ser string, recibido: {type(message)}")
81
+
82
+ if not message.strip():
83
+ raise ValueError("Mensaje no puede estar vacío")
84
+
85
+ # Sanitización básica
86
+ sanitized_message = message.strip()[:2000] # Limitación de longitud
87
+
88
+ # Patrones de detección de intención
89
+ message_lower = sanitized_message.lower()
90
+
91
+ # Diccionario de palabras clave para cada intención
92
+ intent_patterns = {
93
+ IntentType.CODE_GENERATION: [
94
+ "código", "programa", "función", "clase", "implementa",
95
+ "desarrolla", "escribe un", "crea un", "genera código",
96
+ "python", "javascript", "java", "typescript", "html", "css"
97
+ ],
98
+ IntentType.SYSTEM_DIAGNOSTIC: [
99
+ "error", "falla", "problema", "debug", "depurar",
100
+ "solucionar", "arreglar", "no funciona", "bug",
101
+ "excepción", "traceback", "stack trace"
102
+ ],
103
+ IntentType.OPTIMIZATION: [
104
+ "optimizar", "mejorar", "rendimiento", "eficiencia",
105
+ "velocidad", "lento", "bottleneck", "cuello de botella",
106
+ "escalar", "scaling", "performance", "memoria", "cpu"
107
+ ],
108
+ IntentType.QUERY: [
109
+ "qué", "cómo", "cuándo", "dónde", "por qué",
110
+ "explica", "describe", "información", "ayuda",
111
+ "tutorial", "guía", "ejemplo"
112
+ ]
113
+ }
114
+
115
+ # Análisis de frecuencia y confianza
116
+ intent_scores = {intent: 0.0 for intent in IntentType}
117
+
118
+ for intent, patterns in intent_patterns.items():
119
+ for pattern in patterns:
120
+ if pattern in message_lower:
121
+ intent_scores[intent] += 1.0
122
+
123
+ # Ponderación por longitud de palabra clave
124
+ word_count = len(sanitized_message.split())
125
+ for intent in intent_scores:
126
+ if intent_scores[intent] > 0:
127
+ intent_scores[intent] = min(1.0, intent_scores[intent] / (word_count * 0.5))
128
+
129
+ # Determinación de intención principal
130
+ if max(intent_scores.values()) > 0:
131
+ main_intent = max(intent_scores, key=intent_scores.get)
132
+ confidence = intent_scores[main_intent]
133
+ else:
134
+ main_intent = IntentType.UNKNOWN
135
+ confidence = 0.0
136
+
137
+ # Metadatos adicionales
138
+ metadata = {
139
+ "confidence": round(confidence, 2),
140
+ "message_length": len(sanitized_message),
141
+ "word_count": word_count,
142
+ "has_code_snippet": "```" in sanitized_message,
143
+ "timestamp": datetime.now().isoformat(),
144
+ "intent_scores": {k.name: v for k, v in intent_scores.items()}
145
+ }
146
+
147
+ logger.info(f"Intención detectada: {main_intent.value} (confianza: {confidence:.2f})")
148
+
149
+ return main_intent, metadata
150
+
151
+ # ==================== SERVICIO DE GENERACIÓN DE RESPUESTAS ====================
152
+ class ResponseGenerator:
153
+ """Servicio para generación de respuestas con streaming"""
154
+
155
+ def __init__(self):
156
+ self.intent_analyzer = IntentAnalyzer()
157
+ self.response_templates = self._load_templates()
158
+
159
+ def _load_templates(self) -> Dict[IntentType, str]:
160
+ """Carga plantillas de respuesta según intención"""
161
+ return {
162
+ IntentType.CODE_GENERATION: """
163
+ **🔧 Generando solución de código...**
164
+
165
+ He analizado tu solicitud y procedo a generar una implementación robusta y lista para producción.
166
+
167
+ **Consideraciones técnicas aplicadas:**
168
+ • Type hints completos para mypy
169
+ • Logging estructurado con niveles apropiados
170
+ • Manejo de errores con excepciones específicas
171
+ • Principios SOLID y Clean Code
172
+ • Validación de inputs y sanitización
173
+
174
+ **Código generado:**
175
+ ```python
176
+ # Implementación específica basada en tu solicitud
177
+ """
178
+ ,
179
+ IntentType.SYSTEM_DIAGNOSTIC: """
180
+ **🔍 Analizando diagnóstico del sistema...**
181
+
182
+ Procedo a analizar el problema reportado con metodología sistemática:
183
+
184
+ 1. **Identificación del root cause**
185
+ 2. **Análisis de logs y métricas**
186
+ 3. **Propuesta de solución escalable**
187
+ 4. **Prevención de recurrencia**
188
+
189
+ """
190
+ ,
191
+ IntentType.OPTIMIZATION: """
192
+ **⚡ Iniciando proceso de optimización...**
193
+
194
+ Optimización aplicada con enfoque en:
195
+ • Complejidad algorítmica (Big O)
196
+ • Uso eficiente de memoria
197
+ • Paralelización y concurrencia
198
+ • Caching estratégico
199
+ • Minimización de I/O
200
+
201
+ """
202
+ ,
203
+ IntentType.QUERY: """
204
+ **📚 Proporcionando respuesta detallada...**
205
+
206
+ Basado en tu consulta, te proporciono información completa y verificada:
207
+
208
+ """
209
+ ,
210
+ IntentType.UNKNOWN: """
211
+ **🤖 Procesando tu solicitud...**
212
+
213
+ He recibido tu mensaje. Para brindarte la mejor asistencia:
214
+
215
+ • ¿Podrías especificar si necesitas generación de código?
216
+ • ¿O prefieres una explicación técnica detallada?
217
+ • ¿Estás enfrentando un problema específico del sistema?
218
+
219
+ Estoy listo para ayudarte en cualquiera de estas áreas.
220
+ """
221
+ }
222
+
223
+ async def generate_streaming_response(
224
+ self,
225
+ message: str,
226
+ history: List[Dict[str, Any]]
227
+ ) -> Generator[Tuple[List[Dict[str, Any]], str], None, None]:
228
+ """
229
+ Genera respuesta con streaming en tiempo real.
230
+
231
+ Args:
232
+ message: Mensaje del usuario
233
+ history: Historial de conversación
234
+
235
+ Yields:
236
+ Tupla[List[Dict], str]: Historial actualizado y texto de modo
237
+ """
238
+ try:
239
+ # 1. Análisis de intención
240
+ intent, metadata = self.intent_analyzer.analyze_intent_detailed(message, history)
241
+ mode_text = f"**Modo activo**: {intent.value.replace('_', ' ').title()}"
242
+
243
+ # 2. Crear historial temporal para streaming
244
+ temp_history = history.copy()
245
+
246
+ # 3. Añadir mensaje del usuario al historial
247
+ user_message = {
248
+ "role": "user",
249
+ "content": message,
250
+ "timestamp": datetime.now().isoformat()
251
+ }
252
+ temp_history.append(user_message)
253
+
254
+ # 4. Añadir placeholder de asistente
255
+ assistant_placeholder = {
256
+ "role": "assistant",
257
+ "content": "",
258
+ "timestamp": datetime.now().isoformat()
259
+ }
260
+ temp_history.append(assistant_placeholder)
261
+
262
+ yield temp_history, mode_text
263
+
264
+ # 5. Generar respuesta con streaming simulado
265
+ template = self.response_templates.get(intent, self.response_templates[IntentType.UNKNOWN])
266
+
267
+ # Streaming chunk por chunk
268
+ chunks = self._split_into_chunks(template)
269
+ accumulated_response = ""
270
+
271
+ for chunk in chunks:
272
+ await asyncio.sleep(0.05) # Simular procesamiento
273
+ accumulated_response += chunk
274
+
275
+ # Actualizar contenido del asistente en el historial
276
+ temp_history[-1]["content"] = accumulated_response
277
+ yield temp_history, mode_text
278
+
279
+ # 6. Añadir sección específica basada en el mensaje
280
+ specific_response = f"\n\n**📝 Detalles específicos para tu solicitud:**\n\n"
281
+ specific_response += f"• **Mensaje analizado:** `{message[:100]}{'...' if len(message) > 100 else ''}`\n"
282
+ specific_response += f"• **Confianza de intención:** {metadata['confidence'] * 100:.1f}%\n"
283
+ specific_response += f"• **Longitud del mensaje:** {metadata['message_length']} caracteres\n"
284
+
285
+ chunks_specific = self._split_into_chunks(specific_response)
286
+ for chunk in chunks_specific:
287
+ await asyncio.sleep(0.03)
288
+ accumulated_response += chunk
289
+ temp_history[-1]["content"] = accumulated_response
290
+ yield temp_history, mode_text
291
+
292
+ # 7. Añadir marca de finalización
293
+ completion_marker = "\n\n---\n*Respuesta generada con SISTEMA_PROTOCOLO_POTENCIACION_ACTIVO v2.0*"
294
+ temp_history[-1]["content"] = accumulated_response + completion_marker
295
+
296
+ yield temp_history, mode_text
297
+
298
+ except Exception as e:
299
+ logger.error(f"Error en generación de respuesta: {str(e)}", exc_info=True)
300
+
301
+ # Respuesta de error controlada
302
+ error_history = history.copy()
303
+ error_history.append({
304
+ "role": "user",
305
+ "content": message,
306
+ "timestamp": datetime.now().isoformat()
307
+ })
308
+ error_history.append({
309
+ "role": "assistant",
310
+ "content": f"**⚠️ Error en el procesamiento:**\n\n{str(e)}\n\nPor favor, intenta nuevamente o reformula tu solicitud.",
311
+ "timestamp": datetime.now().isoformat()
312
+ })
313
+
314
+ yield error_history, "**Modo activo**: Manejo de errores"
315
+
316
+ def _split_into_chunks(self, text: str, chunk_size: int = 20) -> List[str]:
317
+ """Divide texto en chunks para streaming"""
318
+ words = text.split()
319
+ chunks = []
320
+ current_chunk = []
321
+ current_length = 0
322
+
323
+ for word in words:
324
+ if current_length + len(word) + 1 > chunk_size and current_chunk:
325
+ chunks.append(" ".join(current_chunk) + " ")
326
+ current_chunk = [word]
327
+ current_length = len(word)
328
+ else:
329
+ current_chunk.append(word)
330
+ current_length += len(word) + 1
331
+
332
+ if current_chunk:
333
+ chunks.append(" ".join(current_chunk))
334
+
335
+ return chunks
336
+
337
+ # ==================== INTERFAZ GRADIO 4.x COMPATIBLE ====================
338
+ def create_advanced_interface():
339
+ """
340
+ Crea interfaz avanzada de chat compatible con Gradio 4.x.
341
+ Implementa formato correcto de mensajes: {"role": "rol", "content": "texto"}
342
+ """
343
+
344
+ # Instanciar servicios
345
+ intent_analyzer = IntentAnalyzer()
346
+ response_generator = ResponseGenerator()
347
+
348
+ # Cache para historiales de sesión
349
+ session_histories = {}
350
+
351
+ def get_session_history(session_id: str) -> List[Dict[str, Any]]:
352
+ """Obtiene o crea historial para sesión"""
353
+ if session_id not in session_histories:
354
+ # Mensaje inicial del sistema
355
+ session_histories[session_id] = [{
356
+ "role": "system",
357
+ "content": "Eres un asistente especializado en ingeniería de software, DevOps y arquitectura de sistemas distribuidos. Proporcionas soluciones técnicas precisas y listas para producción.",
358
+ "timestamp": datetime.now().isoformat()
359
+ }]
360
+ return session_histories[session_id]
361
+
362
+ def generate_session_id() -> str:
363
+ """Genera ID único de sesión"""
364
+ timestamp = datetime.now().isoformat()
365
+ hash_obj = hashlib.md5(timestamp.encode())
366
+ return hash_obj.hexdigest()[:12]
367
+
368
+ # ==================== FUNCIONES DE INTERACCIÓN ====================
369
+ def process_message(
370
+ message: str,
371
+ history: List[Dict[str, Any]],
372
+ session_id: str
373
+ ) -> Tuple[str, List[Dict[str, Any]], str]:
374
+ """
375
+ Procesa mensaje del usuario - FORMATO GRADIO 4.x CORRECTO
376
+
377
+ Args:
378
+ message: Mensaje del usuario
379
+ history: Historial en formato {"role": "rol", "content": "texto"}
380
+ session_id: ID de sesión para persistencia
381
+
382
+ Returns:
383
+ Tuple[str, List[Dict], str]: Mensaje vacío, historial actualizado, texto de modo
384
+ """
385
+ # Validación robusta
386
+ if not message or not isinstance(message, str):
387
+ return "", history, "**Modo**: Error - Mensaje inválido"
388
+
389
+ sanitized_message = message.strip()
390
+ if not sanitized_message:
391
+ return "", history, "**Modo**: Esperando entrada válida..."
392
+
393
+ # Obtener historial de sesión
394
+ session_history = get_session_history(session_id)
395
+
396
+ # Crear mensaje de usuario en formato Gradio 4.x
397
+ user_message = {
398
+ "role": "user",
399
+ "content": sanitized_message,
400
+ "timestamp": datetime.now().isoformat()
401
+ }
402
+
403
+ # Actualizar historiales
404
+ new_history = history + [user_message] if history else [user_message]
405
+ session_history.append(user_message)
406
+
407
+ try:
408
+ # Análisis de intención
409
+ intent, metadata = intent_analyzer.analyze_intent_detailed(
410
+ sanitized_message,
411
+ new_history
412
+ )
413
+
414
+ mode_text = (
415
+ f"**Modo activo**: {intent.value.replace('_', ' ').title()}\n"
416
+ f"**Confianza**: {metadata['confidence'] * 100:.1f}%\n"
417
+ f"**Tokens**: {metadata['word_count']}"
418
+ )
419
+
420
+ except Exception as e:
421
+ logger.warning(f"Error en análisis de intención: {e}")
422
+ mode_text = "**Modo activo**: Procesamiento directo"
423
+
424
+ # Limpiar input
425
+ return "", new_history, mode_text
426
+
427
+ async def generate_response_stream(
428
+ message: str,
429
+ history: List[Dict[str, Any]],
430
+ session_id: str
431
+ ):
432
+ """
433
+ Genera respuesta con streaming - FORMATO GRADIO 4.x CORRECTO
434
+
435
+ Args:
436
+ message: Mensaje del usuario
437
+ history: Historial en formato correcto
438
+ session_id: ID de sesión
439
+
440
+ Yields:
441
+ Historial actualizado y texto de modo
442
+ """
443
+ async for updated_history, mode_text in response_generator.generate_streaming_response(
444
+ message,
445
+ history
446
+ ):
447
+ # Actualizar historial de sesión
448
+ session_histories[session_id] = updated_history.copy()
449
+ yield updated_history, mode_text
450
+
451
+ # ==================== INTERFAZ GRADIO ====================
452
+ with gr.Blocks(
453
+ title="🧠 SISTEMA_PROTOCOLO_POTENCIACION_ACTIVO v2.0",
454
+ theme=gr.themes.Soft(),
455
+ css="""
456
+ .gradio-container {
457
+ max-width: 1200px !important;
458
+ margin: 0 auto !important;
459
+ }
460
+ .chatbot {
461
+ height: 600px !important;
462
+ overflow-y: auto !important;
463
+ border: 1px solid #e0e0e0 !important;
464
+ border-radius: 10px !important;
465
+ padding: 20px !important;
466
+ }
467
+ .status-panel {
468
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
469
+ color: white !important;
470
+ padding: 15px !important;
471
+ border-radius: 10px !important;
472
+ margin-bottom: 20px !important;
473
+ }
474
+ """
475
+ ) as interface:
476
+
477
+ # Estado de sesión
478
+ session_state = gr.State(value=generate_session_id())
479
+
480
+ gr.Markdown("""
481
+ # 🧠 SISTEMA_PROTOCOLO_POTENCIACION_ACTIVO v2.0
482
+ ### *Asistente de IA Senior en Ingeniería de Software y DevOps*
483
+
484
+ ---
485
+
486
+ **Especialidades:**
487
+ • Arquitectura de Sistemas Distribuidos • Microservicios • DevOps • Cloud Security
488
+ • Optimización de Rendimiento • Code Review Profesional • Soluciones Production-Ready
489
+
490
+ **Modo actual:** `OPTIMIZACION_ASCENDENTE_EXCLUSIVA`
491
+ """)
492
+
493
+ with gr.Row():
494
+ with gr.Column(scale=3):
495
+ # Chatbot con formato correcto para Gradio 4.x
496
+ chatbot = gr.Chatbot(
497
+ label="Conversación",
498
+ height=600,
499
+ show_label=False,
500
+ bubble_full_width=False,
501
+ avatar_images=(
502
+ "https://cdn-icons-png.flaticon.com/512/3135/3135715.png", # User
503
+ "https://cdn-icons-png.flaticon.com/512/4712/4712035.png" # Assistant
504
+ ),
505
+ sanitize_html=False,
506
+ show_copy_button=True
507
+ )
508
+
509
+ # Panel de estado
510
+ status_display = gr.Markdown(
511
+ "**Modo**: Inicializando sistema...",
512
+ elem_classes="status-panel"
513
+ )
514
+
515
+ # Input con validación
516
+ msg_input = gr.Textbox(
517
+ label="Escribe tu mensaje técnico",
518
+ placeholder="Ejemplo: 'Optimiza este microservicio Python para alta concurrencia...'",
519
+ lines=3,
520
+ max_lines=6,
521
+ show_label=False
522
+ )
523
+
524
+ with gr.Row():
525
+ submit_btn = gr.Button(
526
+ "🚀 Enviar Consulta Técnica",
527
+ variant="primary",
528
+ scale=2
529
+ )
530
+ clear_btn = gr.Button(
531
+ "🧹 Limpiar Chat",
532
+ variant="secondary",
533
+ scale=1
534
+ )
535
+
536
+ with gr.Column(scale=1):
537
+ # Panel de información técnica
538
+ gr.Markdown("### 📊 Métricas del Sistema")
539
+
540
+ session_id_display = gr.Textbox(
541
+ label="ID de Sesión",
542
+ value=session_state.value,
543
+ interactive=False
544
+ )
545
+
546
+ message_count = gr.Number(
547
+ label="Mensajes en sesión",
548
+ value=0,
549
+ interactive=False
550
+ )
551
+
552
+ gr.Markdown("""
553
+ ### ⚙️ Configuración
554
+
555
+ - **Formato:** Gradio 4.x Compatible
556
+ - **Streaming:** Activado
557
+ - **Persistencia:** Por sesión
558
+ - **Logging:** Estructurado
559
+ - **Seguridad:** Input Sanitization
560
+ """)
561
+
562
+ # ==================== EVENT HANDLERS ====================
563
+
564
+ def update_message_count(history):
565
+ """Actualiza contador de mensajes"""
566
+ user_messages = [m for m in history if m.get("role") == "user"]
567
+ return len(user_messages)
568
+
569
+ # Submit handler
570
+ submit_event = msg_input.submit(
571
+ fn=process_message,
572
+ inputs=[msg_input, chatbot, session_state],
573
+ outputs=[msg_input, chatbot, status_display],
574
+ queue=True
575
+ ).then(
576
+ fn=update_message_count,
577
+ inputs=[chatbot],
578
+ outputs=[message_count]
579
+ ).then(
580
+ fn=generate_response_stream,
581
+ inputs=[msg_input, chatbot, session_state],
582
+ outputs=[chatbot, status_display]
583
+ )
584
+
585
+ # Button click handler
586
+ submit_btn.click(
587
+ fn=process_message,
588
+ inputs=[msg_input, chatbot, session_state],
589
+ outputs=[msg_input, chatbot, status_display],
590
+ queue=True
591
+ ).then(
592
+ fn=update_message_count,
593
+ inputs=[chatbot],
594
+ outputs=[message_count]
595
+ ).then(
596
+ fn=generate_response_stream,
597
+ inputs=[msg_input, chatbot, session_state],
598
+ outputs=[chatbot, status_display]
599
+ )
600
+
601
+ # Clear handler
602
+ def clear_chat():
603
+ """Limpia el chat y genera nueva sesión"""
604
+ new_session_id = generate_session_id()
605
+ initial_message = [{
606
+ "role": "system",
607
+ "content": "Sesión reiniciada. Listo para asistencia técnica.",
608
+ "timestamp": datetime.now().isoformat()
609
+ }]
610
+ return (
611
+ initial_message, # chatbot
612
+ "**Modo**: Sistema reiniciado - Esperando consulta técnica", # status
613
+ new_session_id, # session_state
614
+ 0, # message_count
615
+ new_session_id # session_id_display
616
+ )
617
+
618
+ clear_btn.click(
619
+ fn=clear_chat,
620
+ outputs=[chatbot, status_display, session_state, message_count, session_id_display]
621
+ )
622
+
623
+ # ==================== CONFIGURACIÓN ADICIONAL ====================
624
+
625
+ # Ejemplos de consultas
626
+ gr.Examples(
627
+ examples=[
628
+ ["Optimiza este endpoint REST para manejar 10K RPS con Python async/await"],
629
+ ["Diseña una arquitectura de microservicios con auto-scaling y circuit breaker"],
630
+ ["Implementa un sistema de logging distribuido con OpenTelemetry y Grafana"],
631
+ ["Genera un Dockerfile production-ready para aplicación Python con seguridad hardening"],
632
+ ["Crea un sistema de CI/CD con GitHub Actions para despliegue blue-green en Kubernetes"]
633
+ ],
634
+ inputs=msg_input,
635
+ label="📋 Ejemplos de consultas técnicas"
636
+ )
637
+
638
+ # Footer
639
+ gr.Markdown("""
640
+ ---
641
+
642
+ **🔒 Seguridad activa:** Todas las consultas son procesadas con sanitización de inputs y validación de tipos.
643
+ **📈 Logging:** Todas las interacciones son registradas para mejora continua del sistema.
644
+ **⚡ Performance:** Respuestas optimizadas con streaming en tiempo real.
645
+
646
+ *Sistema compatible con Gradio 4.x - Formato de mensajes: `{"role": "rol", "content": "texto"}`*
647
+ """)
648
+
649
+ return interface
650
+
651
+ # ==================== PUNTO DE ENTRADA ====================
652
+ if __name__ == "__main__":
653
+ # Validación de entorno
654
+ try:
655
+ import gradio as gr
656
+ GRADIO_VERSION = gr.__version__
657
+ logger.info(f"Gradio versión detectada: {GRADIO_VERSION}")
658
+
659
+ if not GRADIO_VERSION.startswith("4."):
660
+ logger.warning(
661
+ f"Esta interfaz está optimizada para Gradio 4.x. "
662
+ f"Versión actual: {GRADIO_VERSION}. "
663
+ f"Puede haber incompatibilidades."
664
+ )
665
+
666
+ # Crear e iniciar interfaz
667
+ interface = create_advanced_interface()
668
+
669
+ # Configuración para Hugging Face Spaces
670
+ interface.queue(
671
+ max_size=20,
672
+ default_concurrency_limit=10,
673
+ api_open=True
674
+ ).launch(
675
+ server_name="0.0.0.0" if "SPACE_ID" in os.environ else None,
676
+ server_port=7860,
677
+ share=False,
678
+ debug=False,
679
+ show_error=True,
680
+ favicon_path="https://cdn-icons-png.flaticon.com/512/4712/4712035.png"
681
+ )
682
+
683
+ except Exception as e:
684
+ logger.critical(f"Error crítico al iniciar la aplicación: {str(e)}", exc_info=True)
685
+
686
+ # Interfaz de fallback mínima
687
+ with gr.Blocks() as fallback:
688
+ gr.Markdown(f"""
689
+ # ⚠️ Error en la inicialización del sistema
690
+
691
+ **Detalles técnicos:**
692
+ ```python
693
+ {str(e)}
694
+ ```
695
+
696
+ Por favor, verifica:
697
+ 1. Dependencias de Gradio 4.x instaladas
698
+ 2. Formato de mensajes correcto
699
+ 3. Logs del sistema para diagnóstico
700
+ """)
701
+
702
+ fallback.launch()