File size: 17,306 Bytes
fab7968
bea6ca0
9fa42d2
 
 
 
 
 
420f982
9ec3758
fab7968
bea6ca0
9fa42d2
bea6ca0
 
f0c6cae
9fa42d2
 
f0c6cae
9fa42d2
 
f0c6cae
9fa42d2
f0c6cae
9fa42d2
 
 
 
99910fe
9fa42d2
 
 
 
 
 
 
 
bea6ca0
99910fe
9fa42d2
 
 
 
 
 
 
 
 
bea6ca0
 
9fa42d2
 
 
 
 
 
bea6ca0
 
9fa42d2
 
 
 
 
 
bea6ca0
 
 
9fa42d2
bea6ca0
 
9fa42d2
 
9ec3758
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9fa42d2
420f982
9fa42d2
 
9ec3758
9fa42d2
9ec3758
 
9fa42d2
9ec3758
 
 
 
 
 
9fa42d2
 
9ec3758
420f982
9ec3758
420f982
 
 
 
 
 
9ec3758
 
 
 
420f982
 
9ec3758
9fa42d2
 
bea6ca0
9ec3758
9fa42d2
 
 
 
 
f1282e5
 
 
 
 
 
 
 
 
 
d483990
f1282e5
9d27658
f1282e5
9d27658
f1282e5
9d27658
 
 
 
 
 
 
f1282e5
 
 
 
 
9fa42d2
9ec3758
 
 
 
 
 
 
9fa42d2
 
 
9ec3758
9fa42d2
9ec3758
 
 
 
 
 
 
 
 
 
9fa42d2
 
 
 
 
 
 
9ec3758
9fa42d2
9ec3758
 
 
9fa42d2
9ec3758
 
9fa42d2
9ec3758
 
 
9fa42d2
9ec3758
 
 
9fa42d2
 
 
9ec3758
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9fa42d2
 
 
 
9ec3758
9fa42d2
 
 
9ec3758
9fa42d2
9ec3758
9fa42d2
 
 
 
9ec3758
9fa42d2
9ec3758
9fa42d2
9ec3758
9fa42d2
9ec3758
9fa42d2
9ec3758
 
 
 
 
9fa42d2
9ec3758
9fa42d2
 
 
9ec3758
9fa42d2
 
 
f0c6cae
9fa42d2
 
 
bea6ca0
9fa42d2
 
 
 
 
9ec3758
9fa42d2
 
 
 
 
bea6ca0
9ec3758
bea6ca0
 
9ec3758
bea6ca0
 
019a63c
9ec3758
019a63c
 
5c2504e
 
 
 
 
420f982
 
 
019a63c
420f982
 
 
f0c6cae
019a63c
 
f1d6136
9fa42d2
f1d6136
 
019a63c
9fa42d2
 
9ec3758
9fa42d2
 
 
 
9ec3758
 
9fa42d2
 
 
 
 
 
9ec3758
9fa42d2
9ec3758
 
9fa42d2
 
9ec3758
9fa42d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ec3758
9fa42d2
9ec3758
 
 
 
 
 
9fa42d2
9ec3758
9fa42d2
 
 
 
 
9ec3758
9fa42d2
 
 
9ec3758
 
 
 
9fa42d2
 
 
9ec3758
 
9fa42d2
 
 
9ec3758
9fa42d2
9ec3758
9fa42d2
bea6ca0
 
 
9fa42d2
bea6ca0
fab7968
 
9fa42d2
 
 
9ec3758
 
 
 
9fa42d2
bea6ca0
 
5c2504e
9ec3758
 
bea6ca0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
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
    )