import gradio as gr import google.generativeai as genai import os import re from typing import List, Tuple # --- Configuración Mejorada con Manejo de Errores --- def configurar_gemini(): try: # Opción 1: Variable de entorno en Hugging Face api_key = os.environ.get("GOOGLE_API_KEY") # Opción 2: Fallback para desarrollo local if not api_key: from dotenv import load_dotenv load_dotenv() api_key = os.environ.get("GOOGLE_API_KEY") if not api_key: return None, "❌ **ERROR**: GOOGLE_API_KEY no encontrada. Configúrala en los Secrets de Hugging Face." # Configurar con manejo de versión genai.configure(api_key=api_key) # Verificar modelos disponibles try: models = genai.list_models() model_names = [model.name for model in models] # Priorizar modelos disponibles preferred_models = [ 'models/gemini-1.5-pro', 'models/gemini-1.5-flash', 'models/gemini-pro', 'models/gemini-pro-vision' ] for model_name in preferred_models: if model_name in model_names: model = genai.GenerativeModel(model_name.split('/')[-1]) return model, f"✅ **Conectado**: Usando {model_name}" # --- Modificación en tu función configurar_gemini (Alrededor de la línea 42) --- # 💡 Nueva Lógica: Priorizar los modelos 2.5 más recientes # Lista de modelos a buscar, en orden de preferencia (más potente/nuevo primero) preferred_prefixes = [ 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-pro', # Fallback a nombres base 'gemini-flash' ] selected_model_name = None # Buscar el modelo más potente disponible for prefix in preferred_prefixes: # Buscamos la versión más reciente del modelo con ese prefijo matching_models = [name for name in model_names if prefix in name] if matching_models: # Seleccionar el modelo que contenga el prefijo y que esté disponible # A menudo, los más largos son las versiones preview selected_model_name = sorted(matching_models, key=len, reverse=True)[0] break # Encontramos el mejor, salimos del bucle if selected_model_name: # Obtener solo el nombre corto del modelo (lo que va después de 'models/') model_alias = selected_model_name.split('/')[-1] model = genai.GenerativeModel(model_alias) return model, f"✅ **Conectado**: Usando {selected_model_name}" # Si no se encontró ninguno de los preferidos return None, f"❌ **ERROR**: No se encontraron modelos Gemini compatibles. Disponibles: {', '.join(model_names[:5])}..." # Mostrar solo los primeros 5 except Exception as e: return None, f"❌ **ERROR**: No se encontraron modelos Gemini. Disponibles: {', '.join(model_names)}" except Exception as e: return None, f"❌ **ERROR al conectar con Gemini**: {str(e)}" except Exception as e: return None, f"❌ **ERROR de configuración**: {str(e)}" # Inicializar modelo model, status_message = configurar_gemini() # --- CSS Futurista Mejorado --- futurista_css = """ :root { --primary: #00ff88; --secondary: #0088ff; --accent: #ff0088; --dark-bg: #0a0a0f; --darker-bg: #050508; --card-bg: #111122; --text: #e0e0ff; --text-secondary: #a0a0c0; --border: #222244; } .gradio-container { background: linear-gradient(135deg, var(--dark-bg) 0%, var(--darker-bg) 100%) !important; min-height: 100vh !important; font-family: 'Segoe UI', system-ui, sans-serif; } .dark-bg { background: var(--darker-bg) !important; } .contain { background: var(--card-bg) !important; border: 1px solid var(--border) !important; border-radius: 15px !important; box-shadow: 0 0 20px rgba(0, 255, 136, 0.1) !important; } .chatbot { background: var(--darker-bg) !important; border: none !important; min-height: 400px !important; } .message { margin: 8px 0 !important; border: none !important; padding: 12px 16px !important; } .message.user { background: linear-gradient(135deg, #0088ff, #00ff88) !important; color: white !important; border-radius: 18px 18px 4px 18px !important; margin-left: 20% !important; } .message.bot { background: var(--card-bg) !important; color: var(--text) !important; border: 1px solid var(--border) !important; border-radius: 18px 18px 18px 4px !important; margin-right: 20% !important; } .textbox { background: var(--card-bg) !important; border: 1px solid var(--border) !important; border-radius: 25px !important; color: var(--text) !important; padding: 12px 20px !important; } .textbox:focus { border-color: var(--primary) !important; box-shadow: 0 0 10px var(--primary) !important; } .button { background: linear-gradient(135deg, var(--primary), var(--secondary)) !important; border: none !important; border-radius: 20px !important; color: white !important; font-weight: 600 !important; transition: all 0.3s ease !important; } .button:hover { transform: translateY(-2px) !important; box-shadow: 0 5px 15px rgba(0, 255, 136, 0.3) !important; } .button-secondary { background: var(--card-bg) !important; border: 1px solid var(--border) !important; color: var(--text) !important; } .header-gradient { background: linear-gradient(135deg, var(--primary), var(--secondary), var(--accent)) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; text-align: center !important; font-weight: 800 !important; font-size: 2.2em !important; margin-bottom: 10px !important; text-shadow: 0 0 20px rgba(0, 255, 136, 0.3); } .status-banner { background: linear-gradient(135deg, #ff0088, #ff4444) !important; color: white !important; padding: 10px 15px !important; border-radius: 10px !important; margin: 10px 0 !important; text-align: center !important; font-weight: bold !important; } .status-success { background: linear-gradient(135deg, #00ff88, #00aaff) !important; } .code-block { background: var(--darker-bg) !important; border: 1px solid var(--border) !important; border-radius: 10px !important; padding: 15px !important; margin: 10px 0 !important; font-family: 'Courier New', monospace !important; color: var(--primary) !important; border-left: 4px solid var(--primary) !important; overflow-x: auto !important; } .examples-box { background: var(--card-bg) !important; border: 1px solid var(--border) !important; border-radius: 10px !important; padding: 15px !important; margin: 10px 0 !important; } """ # --- Funciones del Asistente --- def detectar_lenguaje(codigo: str) -> str: """Detecta el lenguaje de programación del código.""" patrones = { 'python': [r'^def\s+', r'^class\s+', r'^import\s+', r'^from\s+', r'print\('], 'javascript': [r'function\s*\w*\s*\(', r'const\s+|let\s+|var\s+', r'=>', r'console\.log'], 'java': [r'public\s+class', r'private\s+', r'protected\s+', r'System\.out\.print'], 'cpp': [r'#include\s+<', r'using\s+namespace', r'std::', r'cout\s*<<'], 'html': [r'', r'', r'
', r''], } for lenguaje, patrones_list in patrones.items(): for patron in patrones_list: if re.search(patron, codigo, re.MULTILINE | re.IGNORECASE): return lenguaje return 'desconocido' def analizar_codigo_basico(codigo: str) -> dict: """Análisis básico del código.""" problemas = [] sugerencias = [] lenguaje = detectar_lenguaje(codigo) # Análisis básico lineas = codigo.split('\n') if len(lineas) > 50: problemas.append("Código potencialmente muy largo") sugerencias.append("Considera dividir en funciones más pequeñas") for i, linea in enumerate(lineas): if len(linea.strip()) > 0 and len(linea) > 100: problemas.append(f"Línea {i+1} muy larga ({len(linea)} caracteres)") sugerencias.append("Divide la línea para mejorar legibilidad") return { 'lenguaje': lenguaje, 'problemas': problemas, 'sugerencias': sugerencias, 'lineas': len(lineas), 'caracteres': len(codigo) } def formatear_respuesta(respuesta: str) -> str: """Formatea la respuesta con estilos HTML.""" # Detectar bloques de código respuesta = re.sub( r'```(\w+)?\n(.*?)```', r'\2