Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import random | |
| import requests | |
| from PIL import Image | |
| from io import BytesIO | |
| import concurrent.futures | |
| import threading | |
| import os | |
| from openai import OpenAI | |
| import time | |
| # ============================================ | |
| # CONFIGURACIÓN SAMBANOVA | |
| # ============================================ | |
| SAMBANOVA_API_KEY = os.getenv("SAMBANOVA_API_KEY") | |
| client = None | |
| if SAMBANOVA_API_KEY: | |
| client = OpenAI(api_key=SAMBANOVA_API_KEY, base_url="https://api.sambanova.ai/v1") | |
| print("✅ SambaNova API conectada correctamente") | |
| else: | |
| print("⚠️ SAMBANOVA_API_KEY no configurada - El chatbot usará modo local") | |
| SAMBA_MODEL = "Meta-Llama-3.1-8B-Instruct" | |
| # ============================================ | |
| # DATOS PARA PROMPTS VOYEUR (FALLBACK LOCAL) | |
| # ============================================ | |
| VOYEUR_SCENES = [ | |
| "secretly observed through a slightly open door in a luxury bedroom", | |
| "captured unknowingly in a private dressing room moment", | |
| "discreetly viewed from afar in a dimly lit hotel suite", | |
| "hidden glimpse in a modern office after hours", | |
| "subtle observation in an elegant private lounge", | |
| "candid shot through a window in a high-end apartment", | |
| "voyeuristic view in a bathroom with steamed mirror", | |
| ] | |
| VOYEUR_POSES = [ | |
| "adjusting lingerie while facing away from the viewer", | |
| "stretching sensually after waking up", | |
| "bending forward to pick something up", | |
| "relaxing on the bed with legs slightly apart", | |
| "standing in front of mirror fixing hair", | |
| "casual moment changing clothes", | |
| "sitting on chair with one leg over the other", | |
| "walking slowly across the room", | |
| ] | |
| LINGERIE_HINTS = [ | |
| "subtly revealing delicate black lace thong under sheer robe", | |
| "hinting at red lace panties visible through transparent fabric", | |
| "accidental glimpse of white silk thong as clothing shifts", | |
| "suggesting intricate lace garter belt beneath skirt", | |
| "delicate hint of emerald green lace panties in movement", | |
| ] | |
| CAMERA_ANGLES = [ | |
| "low-angle voyeuristic shot from floor level looking up", | |
| "hidden camera perspective through slightly open door", | |
| "subtle side view with dramatic shadows", | |
| "through-window framing with soft natural light", | |
| "discreet overhead angle capturing full scene", | |
| ] | |
| # ============================================ | |
| # REVE CREATE - GENERACIÓN DE IMÁGENES | |
| # ============================================ | |
| def generate_single_reve_image(prompt: str, api_key: str, model: str, index: int, results_list: list, lock: threading.Lock): | |
| try: | |
| # Intenta con el dominio actual primero, si falla prueba alternativas | |
| domains = ["https://api.reveai.xyz", "https://api.reve-ai.xyz"] | |
| for domain in domains: | |
| try: | |
| url = f"{domain}/v1/images" | |
| headers = {"Authorization": f"Bearer {api_key}"} | |
| payload = {"prompt": prompt, "model": model} | |
| resp = requests.post(url, json=payload, headers=headers, timeout=30) | |
| if resp.status_code == 200: | |
| data = resp.json() | |
| img_url = data.get("image") | |
| if img_url: | |
| img_data = requests.get(img_url, timeout=30).content | |
| img = Image.open(BytesIO(img_data)) | |
| # Guarda en un archivo temporal único | |
| timestamp = int(time.time() * 1000) | |
| temp_path = f"/tmp/reve_{index}_{timestamp}.png" | |
| img.save(temp_path) | |
| with lock: | |
| results_list.append(temp_path) | |
| print(f"✅ Imagen {index+1} generada exitosamente") | |
| return | |
| except Exception as e: | |
| print(f"Intento con {domain} falló: {e}") | |
| continue | |
| print(f"❌ No se pudo generar imagen {index+1} con ningún dominio") | |
| except Exception as e: | |
| print(f"Error inesperado al generar imagen {index+1}: {e}") | |
| def reve_generate_multiple(prompt: str, api_key: str, model: str, num_images: int): | |
| if not api_key or not api_key.strip(): | |
| return None, "⚠️ Ingresa tu API Key de REVE CREATE" | |
| if not prompt or not prompt.strip(): | |
| return None, "⚠️ El prompt está vacío" | |
| try: | |
| num_images = min(max(1, int(num_images)), 4) | |
| except: | |
| num_images = 1 | |
| results = [] | |
| lock = threading.Lock() | |
| try: | |
| with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, num_images)) as executor: | |
| futures = [ | |
| executor.submit( | |
| generate_single_reve_image, prompt, api_key, model, i, results, lock | |
| ) | |
| for i in range(num_images) | |
| ] | |
| # Espera a que todas las tareas terminen | |
| concurrent.futures.wait(futures, timeout=180) | |
| except Exception as e: | |
| return None, f"❌ Error al generar imágenes: {str(e)}" | |
| if results: | |
| return results, f"✅ {len(results)} imágenes generadas con REVE CREATE" | |
| else: | |
| return None, "❌ No se generaron imágenes. Verifica tu API Key y conexión a internet." | |
| # ============================================ | |
| # CHATBOT VOYEUR CON SAMBANOVA (INTELIGENTE) | |
| # ============================================ | |
| SYSTEM_PROMPT = """Cada vez que pida un prompt de una celebridad o personaje (ej.: "Ariana Grande", "Scarlett Johansson", "una mujer anónima"), generaré automáticamente un prompt en inglés, ultra-sensual, con los siguientes elementos fijos: | |
| - Insinuación de ropa interior (tanga de encaje, transparencias, "descuidos"). | |
| - Perspectiva voyeurista (encuadre desde abajo hacia arriba, ocupando todo el espacio). | |
| - Actividad + contacto visual (ej.: ajustándose el vestido, inclinándose, bailando). | |
| - Iluminación perfecta (sin sombras molestas, colores vibrantes, detalles hiperrealistas). | |
| - Formato listo para copiar (bloque ```text``` en markdown, sin explicaciones adicionales). | |
| Ejemplo rápido: | |
| User: "Crea un prompt de Ariana Grande." | |
| You: | |
| ```text | |
| Ultra-hyperrealistic cinematic portrait of Ariana Grande in a provocative low-angle upward shot, filling the entire 9:16 frame with her iconic presence. She's caught mid-movement in a luxurious backstage dressing room, bathed in soft pink and gold stage lights that cling to her curves, eliminating harsh shadows. Wearing a semi-sheer silver mini dress that rides up her thighs with every step, the delicate black lace thong peeks out from beneath the fabric as she adjusts her earpiece, her fingers brushing the hemline in a "careless" yet deliberate tease. The dress clings to her hips, the fabric so thin it reveals the thong's scalloped edges when she shifts her weight. | |
| Her pose is playfully defiant: one leg slightly bent, weight on her right hip, causing the dress to hike up dangerously high. She locks eyes with the camera, lips glossy and parted in a smirk, as if she knows she's being watched and loves the attention. The background is a blurred haze of vanity mirrors and neon signs, amplifying the exclusive, voyeuristic vibe. | |
| Technical Mastery: | |
| --ar 9:16 | |
| --style raw | |
| --v 6 | |
| --q 2 | |
| --stylize 999 | |
| --chaos 25 | |
| Enhancements: | |
| - 16K photorealism with poreless skin texture, subsurface scattering, and realistic fabric physics (dress clings like a second skin). | |
| - Dynamic lighting: no harsh shadows, only golden highlights tracing her collarbone, thighs, and the thong's lace trim. | |
| - Cinematic depth: ultra-shallow focus—her eyes and the thong's edge razor-sharp, background melted in dreamy bokeh. | |
| ```""" | |
| def format_chat_history(history): | |
| """Convierte el historial del chatbot al formato correcto para Gradio""" | |
| formatted_history = [] | |
| for user_msg, bot_msg in history: | |
| formatted_history.append((user_msg, bot_msg)) | |
| return formatted_history | |
| def voyeur_chatbot_sambanova(message: str, history: list): | |
| if not client: | |
| return voyeur_chatbot_local(message, history) | |
| try: | |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] | |
| # Formatea el historial para la API | |
| for user_msg, bot_msg in history: | |
| messages.append({"role": "user", "content": user_msg}) | |
| if bot_msg: | |
| messages.append({"role": "assistant", "content": bot_msg}) | |
| messages.append({"role": "user", "content": message}) | |
| response = client.chat.completions.create( | |
| model=SAMBA_MODEL, | |
| messages=messages, | |
| temperature=0.8, | |
| max_tokens=800, | |
| top_p=0.9 | |
| ) | |
| bot_response = response.choices[0].message.content.strip() | |
| # Asegura que la respuesta esté en bloques de texto | |
| if "```" not in bot_response: | |
| bot_response = f"```text\n{bot_response}\n```" | |
| # Actualiza el historial | |
| history.append((message, bot_response)) | |
| return "", history | |
| except Exception as e: | |
| error_msg = f"⚠️ Error con SambaNova: {str(e)[:100]}... Usando modo local." | |
| print(f"Error SambaNova: {e}") | |
| return voyeur_chatbot_local(message, history) | |
| def voyeur_chatbot_local(message: str, history: list): | |
| message_lower = message.lower() | |
| # Respuestas de saludo/ayuda | |
| if any(word in message_lower for word in ["hola", "hello", "hi", "ayuda", "help"]): | |
| response = ( | |
| "👁️ **Voyeur Prompt Specialist**\n\n" | |
| "Describe una escena, persona o momento y generaré un prompt detallado " | |
| "en estilo voyeur para generación de imágenes.\n\n" | |
| "Ejemplos:\n" | |
| "- 'mujer preparándose en el dormitorio'\n" | |
| "- 'secretaria en la oficina después de horas'\n" | |
| "- 'modelo en el probador'\n\n" | |
| "Los prompts son en inglés, artísticos y sutiles." | |
| ) | |
| # Generación de prompts | |
| elif any(word in message_lower for word in ["prompt", "genera", "create", "haz", "dame", "voyeur", "imagen"]): | |
| scene = random.choice(VOYEUR_SCENES) | |
| pose = random.choice(VOYEUR_POSES) | |
| hint = random.choice(LINGERIE_HINTS) | |
| angle = random.choice(CAMERA_ANGLES) | |
| subject = "a beautiful elegant woman" | |
| if " " in message: | |
| parts = message.split(" ", 1) | |
| if len(parts) > 1 and len(parts[1].strip()) > 3: | |
| subject = parts[1].strip().capitalize() | |
| prompt = ( | |
| f"Voyeuristic photorealistic candid shot of {subject}, {pose}, {scene}, " | |
| f"{hint}, captured from {angle}. Natural lighting, intimate atmosphere, " | |
| f"subtle sensuality, hyper-detailed skin and fabric textures, 8K ultra-realistic. " | |
| f"--ar 9:16 --style raw" | |
| ) | |
| response = f"```text\n{prompt}\n```" | |
| else: | |
| # Si no es una solicitud clara, pregunta por más detalles | |
| response = ( | |
| "Para generar un prompt voyeur, describe una escena específica. Por ejemplo:\n" | |
| "- 'Una mujer en un hotel de lujo'\n" | |
| "- 'Una ejecutiva en su oficina por la noche'\n" | |
| "- 'Una modelo en una sesión privada'\n\n" | |
| "¿Qué escena te gustaría que describa?" | |
| ) | |
| history.append((message, response)) | |
| return "", history | |
| # Función principal del chatbot | |
| voyeur_chatbot = voyeur_chatbot_sambanova if client else voyeur_chatbot_local | |
| # ============================================ | |
| # AUTOGENERADOR (MODO LOCAL) | |
| # ============================================ | |
| def generate_random_voyeur_prompts(num: int = 5): | |
| prompts = [] | |
| for _ in range(num): | |
| scene = random.choice(VOYEUR_SCENES) | |
| pose = random.choice(VOYEUR_POSES) | |
| hint = random.choice(LINGERIE_HINTS) | |
| angle = random.choice(CAMERA_ANGLES) | |
| prompt = ( | |
| f"Voyeuristic candid photograph, {angle}, capturing a beautiful woman {pose}, " | |
| f"{scene}, {hint}. Soft natural lighting, intimate mood, photorealistic details, " | |
| f"perfect skin and lace textures, 8K UHD --ar 9:16 --style raw" | |
| ) | |
| prompts.append(prompt) | |
| while len(prompts) < 5: | |
| prompts.append("") | |
| return prompts | |
| # ============================================ | |
| # TEMA OSCURO MÍNIMO PARA GRADIO | |
| # ============================================ | |
| dark_theme = gr.themes.Soft( | |
| primary_hue=gr.themes.colors.neutral, | |
| secondary_hue=gr.themes.colors.neutral, | |
| neutral_hue=gr.themes.colors.gray, | |
| ).set( | |
| background_fill_primary_dark="#111111", | |
| background_fill_secondary="#1e1e1e", | |
| block_background_fill="#1e1e1e", | |
| block_title_text_color="white", | |
| block_label_background_fill="#2d2d2d", | |
| input_background_fill="#2d2d2d", | |
| button_primary_background_fill="#4a4a4a", | |
| button_primary_text_color="white", | |
| ) | |
| # ============================================ | |
| # INTERFAZ GRADIO | |
| # ============================================ | |
| with gr.Blocks(title="🦇 BATUTO CREATE IA + SambaNova", theme=dark_theme) as app: | |
| gr.Markdown("# 🦇 BATUTO CREATE IA") | |
| gr.Markdown("### Chatbot Voyeur Inteligente (SambaNova) • REVE CREATE • Auto-Prompts") | |
| with gr.Tabs(): | |
| with gr.Tab("👁️ Chatbot Voyeur English (SambaNova)"): | |
| gr.Markdown("#### El más avanzado: prompts voyeur generados con Llama 3.1 en SambaNova") | |
| gr.Markdown("Habla en español o inglés • Prompts ultra detallados y artísticos") | |
| chatbot = gr.Chatbot(height=600, bubble_full_width=False) | |
| msg = gr.Textbox( | |
| placeholder="Ej: 'mujer en dormitorio de lujo cambiándose', 'secretaria inclinándose en oficina', 'modelo en probador'...", | |
| label="Describe la escena", | |
| scale=7 | |
| ) | |
| clear = gr.Button("🗑️ Limpiar chat") | |
| msg.submit(voyeur_chatbot, [msg, chatbot], [msg, chatbot]) | |
| clear.click(lambda: [], None, chatbot) | |
| with gr.Tab("🖼️ REVE CREATE Img Gen"): | |
| gr.Markdown("#### Genera hasta 4 imágenes reales con REVE CREATE") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| api_key = gr.Textbox( | |
| label="🔑 REVE API Key", | |
| type="password", | |
| placeholder="Pega tu key aquí", | |
| info="Regístrate en reveai.xyz" | |
| ) | |
| model = gr.Dropdown( | |
| ["reve-fast", "reve-1", "reve-2"], | |
| value="reve-fast", | |
| label="Modelo" | |
| ) | |
| qty = gr.Slider(1, 4, value=1, step=1, label="Cantidad") | |
| with gr.Column(scale=2): | |
| prompt_input = gr.Textbox( | |
| label="📝 Prompt (puedes copiar del chatbot)", | |
| lines=6, | |
| placeholder="Pega aquí el prompt generado por el chatbot..." | |
| ) | |
| generate_btn = gr.Button("🚀 Generar Imágenes", variant="primary", size="lg") | |
| gallery = gr.Gallery( | |
| label="Imágenes generadas", | |
| columns=2, | |
| height="auto", | |
| object_fit="cover" | |
| ) | |
| status = gr.Markdown() | |
| generate_btn.click( | |
| reve_generate_multiple, | |
| inputs=[prompt_input, api_key, model, qty], | |
| outputs=[gallery, status] | |
| ) | |
| with gr.Tab("🎲 BATUTO Auto-Prompts"): | |
| gr.Markdown("#### 5 prompts voyeur aleatorios con un clic (modo local)") | |
| generate_auto_btn = gr.Button("⚡ Generar 5 Prompts Aleatorios", variant="primary", size="lg") | |
| with gr.Group(): | |
| prompt_boxes = [] | |
| for i in range(5): | |
| tb = gr.Textbox( | |
| label=f"Prompt Voyeur {i+1}", | |
| lines=4, | |
| max_lines=4, | |
| interactive=True, | |
| show_copy_button=True | |
| ) | |
| prompt_boxes.append(tb) | |
| generate_auto_btn.click( | |
| generate_random_voyeur_prompts, | |
| outputs=prompt_boxes | |
| ) | |
| # ============================================ | |
| # LANZAMIENTO | |
| # ============================================ | |
| if __name__ == "__main__": | |
| print("🚀 BATUTO CREATE IA con SambaNova activado") | |
| print(f"Modelo: {SAMBA_MODEL}") | |
| print("Usa SAMBANOVA_API_KEY en variables de entorno para máxima potencia") | |
| print("\nErrores conocidos:") | |
| print("- REVE API puede requerir una key válida") | |
| print("- Si SambaNova falla, se usa modo local automáticamente") | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True, | |
| debug=False | |
| ) |