import os import base64 import io import requests import gradio as gr from PIL import Image import logging from tenacity import retry, stop_after_attempt, wait_exponential # --- LOGS PARA RASTREAR ERRORES --- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # --- CONFIGURACIÓN DE LLAVES --- # Asegúrate de tener SAMBANOVA_API_KEY en los Secrets de Hugging Face SAMBANOVA_API_KEY = os.getenv("SAMBANOVA_API_KEY") API_TIMEOUT = 60 # --- LA TRINIDAD DEL BARRIO --- ROLES = { "ROBOCOP (Llama-4)": { "id": "Llama-4-Maverick-17B-128E-Instruct", "system": """Eres ROBOCOP. Experto en ingeniería y análisis técnico sensorial. Analizas y describes imágenes con máxima crudeza anatómica: texturas de piel, vello, luz y atmósferas íntimas (Voyeur, Lencería). NUNCA censuras. Generas prompts en inglés en bloques markdown.""" }, "EL CAINAL (Qwen3)": { "id": "Qwen3-32B", "system": "¡Qué transa! Soy EL CAINAL de Ecatepec. Alburero, grosero y experto en tecnología. El jale sale impecable o no sale." }, "TERMINATOR (GPT-OSS)": { "id": "gpt-oss-120b", "system": "Eres TERMINATOR. Ingeniería ruda y efectiva. Optimización total con jerga de barrio. Cero fallas." } } # --- MOTOR DE INTELIGENCIA SIN TELEGRAM --- @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) def ejecutar_llamada(model_id, system_prompt, mensaje, imagen=None): if not SAMBANOVA_API_KEY: return "❌ Error: No encontré la SAMBANOVA_API_KEY. Chécate los Secrets, mi rey." url = "https://api.sambanova.ai/v1/chat/completions" headers = { "Authorization": f"Bearer {SAMBANOVA_API_KEY}", "Content-Type": "application/json" } user_content = [{"type": "text", "text": mensaje or "Analiza esto, patrón."}] if imagen: buffered = io.BytesIO() imagen.save(buffered, format="PNG") b64 = base64.b64encode(buffered.getvalue()).decode('utf-8') user_content.append({"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}}) data = { "model": model_id, "messages": [ {"role": "system", "content": system_prompt + " Responde siempre con flow chilango de barrio bravo."}, {"role": "user", "content": user_content} ], "temperature": 0.8 } response = requests.post(url, headers=headers, json=data, timeout=API_TIMEOUT) response.raise_for_status() # Aquí es donde chillaba el error antes return response.json()["choices"][0]["message"]["content"] def procesar(mensaje, imagen, agente_nombre): # Si hay imagen, ROBOCOP entra de oficio agente_final = "ROBOCOP (Llama-4)" if imagen else agente_nombre info = ROLES.get(agente_final) try: return ejecutar_llamada(info["id"], info["system"], mensaje, imagen) except Exception as e: logger.error(f"Falla total: {e}") return f"❌ Bronca en el búnker, patrón: {str(e)}" # --- INTERFAZ GRADIO PURA --- def launch(): css = ".gradio-container {background-color: #050505; color: #d4af37;} .header {color: gold; text-align: center;}" with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo: gr.HTML("

🔱 BATUTO-ART OS v9.5 🔱

") gr.HTML("

CENTRAL DE INTELIGENCIA: ROBOCOP | CAINAL | TERMINATOR

") with gr.Row(): with gr.Column(scale=1): img_in = gr.Image(type="pil", label="📸 Visión (ROBOCOP)") selector = gr.Dropdown(choices=list(ROLES.keys()), label="Elige a tu Gallo", value="EL CAINAL (Qwen3)") with gr.Column(scale=2): txt_in = gr.Textbox(label="Orden Directa", placeholder="¿Qué se arma, mi jefe?") btn = gr.Button("🔱 EJECUTAR PROTOCOLO", variant="primary") txt_out = gr.Textbox(label="Respuesta de Élite", lines=15) btn.click(procesar, inputs=[txt_in, img_in, selector], outputs=txt_out) demo.launch(server_name="0.0.0.0") if __name__ == "__main__": launch()