BATUTO-ART commited on
Commit
3ef4fa8
Β·
verified Β·
1 Parent(s): 3473a6b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -550
app.py CHANGED
@@ -20,23 +20,21 @@ CARPETA_SALIDA = "bat_art_generaciones"
20
  os.makedirs(CARPETA_SALIDA, exist_ok=True)
21
 
22
  # Cambia por tus claves reales o usa variables de entorno
23
- SAMBA_API_KEY = os.getenv("SAMBA_API_KEY", "tu-clave-sambanova-aqui")
24
  REVE_API_KEY_DEFAULT = os.getenv("REVE_API_KEY", "")
25
 
26
  # ────────────────────────────────────────────────
27
- # CLASE UNIFICADA Y PERFECCIONADA
28
  # ────────────────────────────────────────────────
29
 
30
  class BatArtPromptGenerator:
31
  def __init__(self):
32
- # Colores
33
  self.colors = [
34
  "jet black", "blood red", "deep emerald", "royal purple", "neon hot pink",
35
  "wet crimson", "bruised plum", "glistening obsidian", "sweaty caramel",
36
  "midnight charcoal", "smoky burgundy", "electric violet"
37
  ]
38
 
39
- # Thongs ultra explΓ­citos
40
  self.thongs = [
41
  "extremely thin sheer {color} lace thong soaked transparent clinging to swollen engorged labia majora",
42
  "crotchless {color} mesh thong with puffy labia majora spilling out both sides",
@@ -44,10 +42,9 @@ class BatArtPromptGenerator:
44
  "{color} string thong pulled painfully tight outlining erect clitoris and glistening vaginal folds",
45
  "open-crotch {color} lace thong leaving dripping vaginal entrance and swollen clitoral hood completely exposed",
46
  "wet-look {color} latex thong vacuum-molded to every vulvar fold and crease",
47
- "see-through nude {color} mesh thong darkened and sticky from thick natural lubrication and dense pubic hair shadow"
48
  ]
49
 
50
- # Minifaldas con crudeza
51
  self.miniskirts = [
52
  "micro pleated black leather skirt violently hiked to waist exposing entire soaked thong and wet inner thighs",
53
  "ultra-short red vinyl skirt rolled up revealing extreme cameltoe and glistening lubrication trails down thighs",
@@ -56,7 +53,6 @@ class BatArtPromptGenerator:
56
  "pink satin micro skirt flipped up exposing ass cheeks and dripping thong string disappeared between buttocks"
57
  ]
58
 
59
- # Poses hardcore explΓ­citas
60
  self.poses_hardcore = [
61
  "legs spread obscenely wide, hips thrust forward, thong soaked dark showing asymmetric protruding inner labia and erect clitoris outline",
62
  "squatting low knees far apart, fingers pulling thong aside exposing slick gaping vaginal opening and thick arousal strings",
@@ -65,7 +61,6 @@ class BatArtPromptGenerator:
65
  "on all fours back arched extremely, vulva and anus fully exposed, swollen labia hanging and glistening with fluids"
66
  ]
67
 
68
- # Poses boudoir office mΓ‘s elegantes
69
  self.poses_boudoir_office = [
70
  "standing legs slightly apart with torso twist, skirt delicately lifted revealing lace thong cameltoe, seductive direct gaze",
71
  "sitting on desk edge one leg crossed high, skirt raised showing intricate thong texture and wet spot, confident sultry look",
@@ -74,7 +69,6 @@ class BatArtPromptGenerator:
74
  "reclining on office sofa, knees bent and apart, thong clearly displayed with glistening fluids, eyes conveying subtle ecstasy"
75
  ]
76
 
77
- # Ángulos (muy bajos y centrados en crotch)
78
  self.angles = [
79
  "extreme ultra-low worm’s eye view camera 15–25 cm from vulva filling most of frame with soaked thong and exposed anatomy",
80
  "dramatic floor-level macro crotch shot looking straight up between widely parted thighs, razor focus on wet cameltoe and clit",
@@ -82,7 +76,6 @@ class BatArtPromptGenerator:
82
  "contrapicado extremo casi pegado al suelo, vulva ocupando 60–75% del encuadre, tanga hundida mostrando clΓ­toris hinchado y labios asimΓ©tricos"
83
  ]
84
 
85
- # IluminaciΓ³n mixta
86
  self.lighting = [
87
  "hard directional window light creating strong specular highlights on vaginal lubrication and sweat beads on inner thighs",
88
  "soft diffuse natural daylight + subtle rim light outlining swollen labia and erect nipples through sheer fabric",
@@ -90,7 +83,6 @@ class BatArtPromptGenerator:
90
  "dramatic chiaroscuro with deep shadows accentuating wetness, clitoral hood contour and labia volume"
91
  ]
92
 
93
- # Fondos office
94
  self.backgrounds = [
95
  "modern executive office with floor-to-ceiling windows flooding natural daylight and city views",
96
  "minimalist chic office, large windows creating soft reflections on glass and marble",
@@ -98,7 +90,6 @@ class BatArtPromptGenerator:
98
  "sophisticated executive room with polished wood desk and huge windows"
99
  ]
100
 
101
- # Elementos boudoir adicionales (para modo no-hardcore)
102
  self.hairstyles = [
103
  "long loose tousled hair sensually framing the face and falling over shoulders",
104
  "elegant waves cascading seductively down the back",
@@ -107,45 +98,36 @@ class BatArtPromptGenerator:
107
  ]
108
 
109
  self.expressions = [
110
- "seductive heavy-lidded gaze full of desire, lips slightly parted",
111
- "confident sultry smirk with intense direct eye contact",
112
  "subtle ecstasy expression, eyes half-closed, tongue grazing lower lip",
113
- "playful yet hungry look, eyebrow raised, lips wet"
114
  ]
115
 
116
- def build_prompt(
117
- self,
118
- celebrity: str,
119
- hardcore: bool = True,
120
- use_boudoir_poses: bool = False
121
- ) -> Tuple[str, str]:
122
  color = random.choice(self.colors)
123
  thong = random.choice(self.thongs).format(color=color)
 
 
 
 
124
 
125
  if hardcore:
126
  pose = random.choice(self.poses_hardcore)
127
- skirt = random.choice(self.miniskirts)
128
  bg_weight = "subtle"
129
- detail_focus = "razor sharp focus on vulva and soaked thong texture"
 
130
  else:
131
  pose = random.choice(self.poses_boudoir_office) if use_boudoir_poses else random.choice(self.poses_hardcore)
132
- skirt = random.choice(self.miniskirts)
133
  bg_weight = "prominent"
134
  hairstyle = random.choice(self.hairstyles)
135
  expression = random.choice(self.expressions)
136
- detail_focus = "sharp focus on intricate lace thong texture, wet cameltoe and facial expression"
137
-
138
- angle = random.choice(self.angles)
139
- light = random.choice(self.lighting)
140
- background = random.choice(self.backgrounds)
141
-
142
- extra_desc = ""
143
- if not hardcore:
144
- extra_desc = f"""
145
  Hairstyle: {hairstyle}.
146
- Expression: {expression}, flushed cheeks, wet lips."""
147
 
148
- core = f"""Ultra-detailed hyperrealistic erotic office photograph of {celebrity},
149
 
150
  {pose},
151
 
@@ -166,7 +148,7 @@ visible anatomical details:
166
  β€’ sweat beads collecting in inguinal creases, perineum and between buttocks
167
  β€’ visible stretch marks, subtle cellulite and open pores on inner thighs
168
  β€’ erect hard nipples pressing against thin blouse or bra
169
- β€’ arousal fluid strands connecting vulva to pulled thong fabric{extra_desc}
170
 
171
  photorealistic raw photo, 16K, Canon EOS R5 + RF 85mm f/1.2 @ f/1.4, extremely shallow depth of field, {detail_focus}, cinematic warm grading, visible natural skin imperfections, subsurface scattering on moist skin, (masterpiece, ultra-detailed anatomy, best quality:1.45), (watermark BATUTO-ART:0.4)
172
 
@@ -174,21 +156,16 @@ Negative prompt: blurry, deformed, bad anatomy, extra limbs, fused fingers, poor
174
 
175
  caption = f"{celebrity} β€’ {color} soaked thong β€’ {'ultra-close hardcore crotch macro' if hardcore else 'boudoir office explicit visible thong'}"
176
 
177
- return core.strip(), caption
178
 
179
- def generate_five(
180
- self,
181
- celebrity: str,
182
- hardcore: bool = True,
183
- use_boudoir_poses: bool = False
184
- ) -> List[Tuple[str, str]]:
185
  return [self.build_prompt(celebrity, hardcore, use_boudoir_poses) for _ in range(5)]
186
 
187
  # ────────────────────────────────────────────────
188
- # FUNCIONES REVE (sin cambios)
189
  # ────────────────────────────────────────────────
190
 
191
- def save_image_locally(img: Image.Image, prefix: str = "batart_reve") -> str:
192
  ts = int(time.time() * 1000)
193
  fname = f"{prefix}_{ts}.png"
194
  path = os.path.join(CARPETA_SALIDA, fname)
@@ -196,32 +173,38 @@ def save_image_locally(img: Image.Image, prefix: str = "batart_reve") -> str:
196
  img.save(path, "PNG", optimize=True)
197
  return path
198
  except Exception as e:
199
- print(f"Error guardando: {e}")
200
  return None
201
 
202
  def call_reve_api(prompt: str, api_key: str, aspect_ratio: str = "9:16", version: str = "latest", timeout: int = 120):
203
- if not api_key.strip():
204
- return None, "API Key de REVE no proporcionada", 0
205
 
206
  payload = {"prompt": prompt.strip(), "aspect_ratio": aspect_ratio, "version": version}
207
- headers = {"Authorization": f"Bearer {api_key.strip()}", "Content-Type": "application/json", "Accept": "application/json"}
 
 
 
 
208
 
209
  try:
210
- response = requests.post(REVE_API_URL, headers=headers, json=payload, timeout=timeout)
211
- if response.status_code != 200:
212
- return None, f"HTTP {response.status_code} - {response.text[:300]}", 0
213
 
214
- data = response.json()
215
  if "image" not in data or not data["image"]:
216
- return None, "Respuesta sin campo 'image' vΓ‘lido", 0
217
 
218
  img_bytes = base64.b64decode(data["image"])
219
  img = Image.open(BytesIO(img_bytes)).convert("RGB")
220
- credits = data.get("credits_used", 0) or data.get("credits_consumed", 0)
221
- return img, "", int(credits)
222
 
 
 
223
  except Exception as e:
224
- return None, str(e), 0
225
 
226
  def generate_reve_batch(prompt: str, api_key: str, ratio: str, count: int, progress=gr.Progress()):
227
  count = max(1, min(count, 6))
@@ -231,28 +214,32 @@ def generate_reve_batch(prompt: str, api_key: str, ratio: str, count: int, progr
231
  futures = [exe.submit(call_reve_api, prompt, api_key, ratio) for _ in range(count)]
232
 
233
  for i, future in enumerate(concurrent.futures.as_completed(futures)):
234
- progress((i + 1) / count, desc=f"Generando {i+1}/{count}")
235
- img, err, credits = future.result()
236
  if img:
237
  path = save_image_locally(img)
238
  if path:
239
  images.append(img)
240
  paths.append(path)
241
- total_credits += credits
242
  if err:
243
  errors.append(err)
244
 
245
- status_lines = [f"**Resultado:** {len(images)} OK β€’ {len(errors)} errores"]
246
- if total_credits: status_lines.append(f"CrΓ©ditos β‰ˆ {total_credits}")
 
247
  if errors:
248
- status_lines.append("**Errores:**")
249
- status_lines.extend([f"β€’ {e}" for e in errors[:3]])
250
- if len(errors) > 3: status_lines.append(f"… y {len(errors)-3} mΓ‘s")
 
251
 
252
- return images, "\n".join(status_lines) or "No se generaron imΓ‘genes", paths
 
 
253
 
254
  # ────────────────────────────────────────────────
255
- # CHAT + VISIΓ“N (sin cambios mayores)
256
  # ────────────────────────────────────────────────
257
 
258
  def chat_with_samba(messages: list, image_base64: str = None):
@@ -277,7 +264,7 @@ def chat_with_samba(messages: list, image_base64: str = None):
277
  r.raise_for_status()
278
  return r.json()["choices"][0]["message"]["content"]
279
  except Exception as e:
280
- return f"Error SambaNova: {str(e)}"
281
 
282
  def analyze_uploaded_image(image: Image.Image, user_prompt: str):
283
  buffered = BytesIO()
@@ -285,10 +272,12 @@ def analyze_uploaded_image(image: Image.Image, user_prompt: str):
285
  img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
286
 
287
  system_msg = (
288
- "Eres BATUTO: describes imΓ‘genes con mΓ‘xima crudeza anatΓ³mica explΓ­cita sin censura. "
289
- "Detallas genitales, fluidos, texturas, vello pΓΊbico, sudor, lubricaciΓ³n, hinchazones, pliegues, "
290
- "ano, perinΓ©, pezones, areolas, cameltoe, clΓ­toris, labios mayores/menores asimΓ©tricos, etc. "
291
- "Usa vocabulario tΓ©cnico preciso y sin eufemismos jamΓ‘s."
 
 
292
  )
293
 
294
  messages = [
@@ -299,13 +288,12 @@ def analyze_uploaded_image(image: Image.Image, user_prompt: str):
299
  respuesta = chat_with_samba(messages, img_str)
300
 
301
  prompt_en = f"""Hyperrealistic raw extreme close-up erotic photograph based on the described image,
302
- photorealistic, 16K, Canon EOS R5 + RF 85mm f/1.2, shallow depth of field, visible pores, dense natural pubic hair, sweat beads in inguinal creases, glistening thick vaginal lubrication dripping, asymmetric swollen labia minora protruding, erect prominent clitoris, detailed skin textures and imperfections, subsurface scattering on wet skin, cinematic warm grading, (masterpiece, ultra-detailed anatomy:1.5), no censorship, (watermark BATUTO-ART:0.4)
303
 
304
  Negative prompt: blurry, deformed, bad anatomy, censored, mosaic censor, bar censor, cartoon, plastic skin, airbrushed, modest pose, covered genitals, dry skin, no pubic hair, symmetrical labia, safe for work"""
305
 
306
  return respuesta, prompt_en
307
-
308
- # ────────────────────────────────────────────────
309
  # INTERFAZ GRADIO FINAL
310
  # ────────────────────────────────────────────────
311
 
@@ -313,519 +301,155 @@ def main():
313
  generator = BatArtPromptGenerator()
314
 
315
  with gr.Blocks(
316
- title="BAT_ART β€’ Ultra-Explicit Fusion 2026",
317
  theme=gr.themes.Default(primary_hue="red", neutral_hue="slate"),
318
  css="""
319
- body { background-color: #0d1117; color: #c9d1d9; }
320
- .gradio-container { max-width: 1280px; margin: auto; }
321
- .prompt-box { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 14px; }
 
322
  """
323
  ) as demo:
324
 
325
  gr.Markdown("# BAT_ART β€’ Generador Ultra-ExplΓ­cito + Chat IA + REVE")
326
 
327
  with gr.Tabs():
328
- # ─── 1. Generador Prompts ───
329
  with gr.Tab("Generador Prompts ExplΓ­citos"):
330
- celebrity_input = gr.Textbox(
331
- label="Celebridad", placeholder="Ana de Armas, Sydney Sweeney...",
332
- value="Ana de Armas"
333
- )
334
- hardcore_checkbox = gr.Checkbox(label="Modo Ultra-Hardcore Close-up (vulva explΓ­cita)", value=True)
335
- boudoir_poses_checkbox = gr.Checkbox(label="Usar poses boudoir elegantes", value=False)
336
-
337
- btn_gen = gr.Button("Generar 5 Prompts", variant="primary")
 
 
 
 
 
 
338
 
339
  prompt_gallery = gr.Gallery(
340
- label="Prompts generados (selecciona uno)",
341
- columns=1, height=420, show_label=False
342
  )
 
343
  selected_prompt = gr.Textbox(
344
- label="Prompt seleccionado (editable)",
345
- lines=12, max_lines=25, show_copy_button=True,
346
- elem_classes="prompt-box"
347
  )
348
 
349
- def generate_prompts_fn(name, hardcore, boudoir_poses):
350
  if not name.strip():
351
- return [], ""
352
- prompts = generator.generate_five(name.strip(), hardcore=hardcore, use_boudoir_poses=boudoir_poses)
353
  return [[p[0], p[1]] for p in prompts], prompts[0][0] if prompts else ""
354
 
355
- btn_gen.click(
356
- generate_prompts_fn,
357
- [celebrity_input, hardcore_checkbox, boudoir_poses_checkbox],
358
- [prompt_gallery, selected_prompt]
359
  )
360
 
361
  prompt_gallery.select(
362
- lambda evt: evt.value[0] if evt.value else "",
363
- None, selected_prompt
364
  )
365
 
366
- # ─── 2. Chat + AnΓ‘lisis ───
367
- with gr.Tab("Chat BATUTO + AnΓ‘lisis ImΓ‘genes"):
368
- chatbot = gr.Chatbot(height=580, show_copy_button=True)
369
- msg_input = gr.Textbox(placeholder="Pregunta o describe quΓ© analizar...")
370
- img_upload = gr.Image(type="pil", label="Sube imagen para descripciΓ³n explΓ­cita")
371
- send_btn = gr.Button("Enviar / Analizar", variant="primary")
 
 
 
 
 
372
 
373
- def respond(message, image, history):
374
  history = history or []
375
  if image:
376
  desc, prompt_en = analyze_uploaded_image(image, message)
377
- response = f"**DescripciΓ³n explΓ­cita (BATUTO):**\n{desc}\n\n```prompt\n{prompt_en}\n```"
378
  else:
379
  messages = [{"role": "user", "content": message}]
380
  response = chat_with_samba(messages)
381
  history.append((message, response))
382
  return "", history
383
 
384
- send_btn.click(
385
- respond, [msg_input, img_upload, chatbot], [msg_input, chatbot], queue=False
 
 
 
386
  )
387
 
388
- # ─── 3. Generador REVE ───
389
  with gr.Tab("Generar ImΓ‘genes REVE"):
390
  with gr.Row():
391
  with gr.Column(scale=3):
392
- api_key_reve = gr.Textbox(label="REVE API Key", type="password", value=REVE_API_KEY_DEFAULT)
393
- prompt_reve = gr.Textbox(label="Prompt para REVE", lines=8, interactive=True, show_copy_button=True)
 
 
 
 
 
 
394
  with gr.Column(scale=1):
395
- ratio = gr.Dropdown(["9:16", "2:3", "3:4", "1:1", "16:9"], value="9:16", label="Aspect Ratio")
396
- count = gr.Slider(1, 4, value=2, step=1, label="Cantidad")
397
-
398
- btn_reve = gr.Button("πŸš€ Generar con REVE", variant="primary", size="lg")
399
- galle
400
-
401
- # Dataset con elementos mejorados para mayor variedad
402
- fashion_elements = {
403
- "hairstyles": [
404
- "long wavy auburn hair with elegant curls",
405
- "long straight platinum blonde hair flowing down",
406
- "long curly deep brown hair with soft waves",
407
- "long layered red hair with voluminous style",
408
- "long sleek black hair with glossy finish",
409
- "long beach wave golden blonde hair",
410
- "long braided chestnut hair with loose ends",
411
- "intricate updo with honey highlights",
412
- "long messy mahogany hair",
413
- "long straight cherry red hair",
414
- "long braided platinum hair with twists",
415
- "long updo with strawberry blonde",
416
- "long ponytail with sandy blonde"
417
- ],
418
- "discovery_moments": [
419
- "momentarily revealing lingerie as she adjusts her posture",
420
- "subtly exposing lingerie while shifting weight between legs",
421
- "accidentally revealing intimate details during a natural movement",
422
- "playfully teasing the visibility of lingerie through fabric movement",
423
- "unintentionally showing lingerie while reaching for an object",
424
- "delicately revealing underwear as she crosses and uncrosses legs",
425
- "offering a fleeting glimpse of lingerie during a graceful turn",
426
- "exposing intimate apparel through the sheer fabric of her clothing",
427
- "revealing lingerie edges while sitting down or standing up",
428
- "showing subtle hints of underwear through strategic posing",
429
- "creating an intimate reveal as the fabric clings to her form",
430
- "allowing a private view of her lingerie during an unguarded moment",
431
- "exposing delicate details through the transparency of her garment",
432
- "revealing hidden layers through calculated body movements",
433
- "creating sensual tension through partial concealment and revelation"
434
- ],
435
- "voyeuristic_angles": [
436
- "extreme low angle from floor level, tilted upward to capture intimate details",
437
- "worm's-eye view focusing on the revealing moment from below",
438
- "low angle emphasizing the voyeuristic perspective of discovered lingerie",
439
- "camera positioned as if secretly observing from a hidden vantage point",
440
- "upward angle creating the sensation of an unauthorized glimpse",
441
- "shot from knee level capturing the accidental exposure",
442
- "perspective from below simulating a hidden camera view",
443
- "low vantage point emphasizing the forbidden nature of the view",
444
- "angle that suggests the viewer is discovering something intimate",
445
- "camera placement that enhances the feeling of witnessing a private moment",
446
- "view from beneath creating a sense of intimate discovery",
447
- "low-angle shot that makes the reveal feel more personal and intrusive",
448
- "perspective that captures the moment as if by chance observation",
449
- "angle that emphasizes the vulnerability of the exposed moment",
450
- "shot composition that feels like a secret being uncovered"
451
- ],
452
- "lingerie_reveal_actions": [
453
- "adjusting her stockings while revealing the thong underneath",
454
- "smoothing her skirt only to expose more lingerie accidentally",
455
- "reaching up high causing her outfit to ride up and show underwear",
456
- "bending over to pick something up, offering a view of her thong",
457
- "crossing her legs in a way that pulls the fabric taut against lingerie",
458
- "stretching languidly, causing her clothing to shift and reveal",
459
- "turning quickly, creating a momentary flash of intimate apparel",
460
- "sitting down with a graceful motion that exposes lingerie edges",
461
- "standing up from a chair, her skirt riding up to show the thong",
462
- "playing with her hair while her other hand accidentally lifts her skirt",
463
- "leaning forward to examine something, revealing her lingerie line",
464
- "arching her back in a stretch that lifts her clothing",
465
- "shifting position on a sofa, causing her dress to hike up",
466
- "bending at the waist to tie her shoe, exposing her underwear",
467
- "reclining back with legs slightly parted, hinting at her thong"
468
- ],
469
- "lingerie_sets": [
470
- "black lace set with push-up bra, floral thong, and sheer thigh-high stockings with a lace top",
471
- "red satin set with underwire bra, bow accents thong, and fishnet thigh-high stockings with a pattern",
472
- "white mesh set with sheer-cup bra, transparent thong, and silk thigh-high stockings with a smooth finish",
473
- "pink lace set with demi-cup bra, scalloped-edge thong, and thigh-high stockings with a garter",
474
- "blue silk set with smooth-cup bra, a sleek thong, and velvet thigh-high stockings with a soft texture",
475
- "green velvet set with padded bra, a textured thong, and satin thigh-high stockings with a subtle shine",
476
- "purple satin set with balconette bra, a glossy thong, and mesh thigh-high stockings with a net pattern",
477
- "yellow chiffon set with a light-coverage bra, a light thong, and thigh-high stockings with a light, airy feel",
478
- "black mesh set with transparent-strap bra, a net-pattern thong, and opaque thigh-high stockings with a matte look",
479
- "red lace set with embroidered bra, an embroidered thong, and sheer thigh-high stockings with a red tint",
480
- "white satin set with pearl-accented bra, a pearl-detailed thong, and fishnet thigh-high stockings with a diamond pattern",
481
- "pink silk set with delicate-lace-trim bra, a delicate-strap thong, and shiny silk thigh-high stockings",
482
- "blue velvet set with a plush bra, a plush thong, and lace thigh-high stockings with a floral design",
483
- "green lace set with a floral-pattern bra, a leaf-motif thong, and plush velvet thigh-high stockings",
484
- "purple mesh set with sheer-panel bra, sheer-panel thong, and luxurious satin thigh-high stockings",
485
- "yellow satin set with a shiny bra, a glossy thong, and transparent mesh thigh-high stockings",
486
- "black chiffon set with a flowy-edged bra, a flowy-edged thong, and flowy chiffon thigh-high stockings",
487
- "red mesh set with a bold bra, a bold-line thong, and opaque thigh-high stockings with a bold look",
488
- "white lace set with a romantic bra, a romantic thong, and sheer thigh-high stockings for a subtle touch",
489
- "pink velvet set with a soft-textured bra, a soft-pile thong, and fun fishnet thigh-high stockings",
490
- "blue satin set with a sleek-line bra, a sleek thong, and elegant silk thigh_high stockings",
491
- "green silk set with an elegant-feel bra, an elegant-drape thong, and romantic lace thigh_high stockings",
492
- "purple chiffon set with an airy bra, an airy thong, and deep velvet thigh_high stockings",
493
- "yellow lace set with a bright bra, a bright thong, and bright satin thigh_high stockings",
494
- "black satin set with a luxurious bra, a luxurious thong, and edgy mesh thigh_high stockings",
495
- "red velvet set with a deep-hued bra, a deep-colored thong, and airy chiffon thigh_high stockings",
496
- "white mesh set with a modern bra, a modern-grid thong, and clean opaque thigh_high stockings",
497
- "pink chiffon set with a feminine bra, a feminine-ruffle thong, and blush-pink sheer thigh_high stockings",
498
- "blue lace set with a wave-pattern bra, a wave-pattern thong, and playful fishnet thigh_high stockings",
499
- "green satin set with a natural-color bra, a natural-hued thong, and natural-color silk thigh_high stockings",
500
- "purple velvet set with a royal-style bra, a royal-vibe thong, and ornate lace thigh_high stockings",
501
- "yellow mesh set with a sunny-transparency bra, a sunny thong, and sunny velvet thigh_high stockings",
502
- "black lace set with a gothic bra, a gothic-element thong, and thigh-high stockings with a shadow-black lace top",
503
- "red silk set with a passionate bra, a passionate thong, and passionate-red mesh thigh-high stockings",
504
- "white chiffon set with a pure-white bra, a pure-white thong, and pure-white chiffon thigh-high stockings",
505
- "pink satin set with a blush-pink bra, a blush-pink thong, and soft opaque thigh-high stockings",
506
- "blue velvet set with a deep-blue bra, a deep-blue thong, and sheer thigh-high stockings in a calm blue",
507
- "green lace set with an envious-green bra, an envious-green thong, and green fishnet thigh-high stockings",
508
- "purple mesh set with a mysterious bra, a mysterious thong, and lavender fishnet thigh-high stockings",
509
- "yellow chiffon set with a joyful-yellow bra, a joyful-yellow thong, and sunny-yellow silk thigh-high stockings",
510
- "black silk set with a night-black bra, a night-black thong, and shadow-black lace thigh-high stockings",
511
- "red satin set with a fire-red bra, a fire-red thong, and deep-red velvet thigh-high stockings",
512
- "white velvet set with a snow-white bra, a snow-white thong, and white-sheer thigh-high stockings",
513
- "pink lace set with a rose-pink bra, a rose-pink thong, and pink-rose lace thigh-high stockings",
514
- "blue mesh set with a sky-blue bra, a sky-blue thong, and sky-blue mesh thigh-high stockings",
515
- "green chiffon set with a forest-green bra, a forest-green thong, and forest-green chiffon thigh-high stockings",
516
- "purple satin set with a lavender bra, a lavender thong, and lavender lace thigh-high stockings",
517
- "yellow velvet set with a sun-yellow bra, a sun-yellow thong, and sun-yellow velvet thigh-high stockings",
518
- "black mesh set with a shadow-black bra, a shadow-black thong, and shadow-black mesh thigh-high stockings",
519
- "red chiffon set with a sunset-red bra, a sunset-red thong, and sunset-red chiffon thigh-high stockings"
520
- ],
521
- "colors": [
522
- "deep ruby red", "classic black", "emerald green", "sapphire blue", "royal purple",
523
- "champagne gold", "silver metallic", "burgundy wine", "chocolate brown", "ivory white",
524
- "hot pink", "electric blue", "vibrant orange", "forest green", "midnight navy",
525
- "soft lavender", "peachy coral", "platinum silver", "rose gold", "caramel nude"
526
- ],
527
- "outfits": [
528
- "a sleek fitted mini dress with a subtle texture",
529
- "a stylish A-line mini skirt paired with a delicate blouse",
530
- "a form-fitting bodycon dress with elegant draping",
531
- "a sophisticated sheath mini dress with unique detailing",
532
- "a playful skater dress with a flattering silhouette",
533
- "a chic wrap mini dress that accentuates the waist",
534
- "a trendy slip dress with a luxurious satin finish",
535
- "a tailored pencil mini skirt with a modern cut",
536
- "a flowing chiffon mini dress with intricate patterns",
537
- "a form-fitting leather mini skirt with bold accents",
538
- ],
539
- "expressions": [
540
- "unaware of being observed, natural and relaxed",
541
- "slightly self-conscious but continuing her actions",
542
- "lost in thought, completely natural in her movements",
543
- "playfully teasing but pretending not to notice the camera",
544
- "focused on her task, unaware of the revealing moment",
545
- "exuding quiet confidence while her lingerie becomes visible",
546
- "appearing distracted, allowing natural exposure to occur",
547
- "maintaining composure while her clothing shifts revealingly",
548
- "exhibiting casual elegance despite the intimate exposure",
549
- "completely absorbed in the moment, natural and unposed",
550
- "displaying innocent unawareness of the camera's presence",
551
- "showing subtle confidence in her accidental revelation",
552
- "maintaining natural grace during the unintentional exposure",
553
- "expressing quiet contemplation while partially exposed",
554
- "radiating natural beauty in the unguarded moment"
555
- ],
556
- "backgrounds": [
557
- "a luxurious bedroom with soft ambient lighting",
558
- "a modern office space during after-hours",
559
- "a chic studio apartment with intimate atmosphere",
560
- "a dimly lit lounge with moody shadows",
561
- "a stylish hotel room with elegant decor",
562
- "an industrial loft with dramatic lighting",
563
- "a minimalist living space with clean lines",
564
- "a Parisian balcony with romantic ambiance",
565
- "a vintage boudoir with ornate details",
566
- "a serene garden setting with natural beauty"
567
- ],
568
- "lighting": [
569
- "soft natural window light creating intimate shadows",
570
- "dramatic chiaroscuro lighting emphasizing curves and reveals",
571
- "warm golden hour glow enhancing skin tones",
572
- "studio lighting with softboxes for a polished look",
573
- "ambient moody lighting adding mystery and depth",
574
- "rim lighting to accentuate silhouette and intimate details",
575
- "cinematic lighting with subtle color grading",
576
- "ethereal backlight creating a halo effect",
577
- "dynamic spotlighting focusing on the revealed areas",
578
- "low-key lighting enhancing the voyeuristic atmosphere"
579
- ],
580
- "stockings": [
581
- "sheer thigh-high stockings with a lace top",
582
- "fishnet thigh-high stockings with a pattern",
583
- "silk thigh-high stockings with a smooth finish",
584
- "thigh-high stockings with a garter",
585
- "velvet thigh-high stockings with a soft texture",
586
- "satin thigh-high stockings with a subtle shine",
587
- "mesh thigh-high stockings with a net pattern",
588
- "thigh-high stockings with a light, airy feel",
589
- "opaque thigh-high stockings with a matte look",
590
- "sheer thigh-high stockings with a red tint",
591
- "fishnet thigh-high stockings with a diamond pattern",
592
- "shiny silk thigh-high stockings",
593
- "lace thigh-high stockings with a floral design",
594
- "plush velvet thigh-high stockings",
595
- "luxurious satin thigh-high stockings",
596
- "transparent mesh thigh-high stockings",
597
- "flowy chiffon thigh-high stockings",
598
- "opaque thigh-high stockings with a bold look",
599
- "sheer thigh-high stockings for a subtle touch",
600
- "fun fishnet thigh-high stockings",
601
- "elegant silk thigh-high stockings",
602
- "romantic lace thigh-high stockings",
603
- "deep velvet thigh-high stockings",
604
- "bright satin thigh-high stockings",
605
- "edgy mesh thigh-high stockings",
606
- "airy chiffon thigh-high stockings",
607
- "clean opaque thigh-high stockings",
608
- "blush-pink sheer thigh-high stockings",
609
- "playful fishnet thigh-high stockings",
610
- "natural-color silk thigh-high stockings",
611
- "ornate lace thigh-high stockings",
612
- "sunny velvet thigh-high stockings",
613
- "thigh-high stockings with a shadow-black lace top",
614
- "passionate-red mesh thigh-high stockings",
615
- "pure-white chiffon thigh-high stockings",
616
- "soft opaque thigh-high stockings",
617
- "sheer thigh-high stockings in a calm blue",
618
- "green fishnet thigh-high stockings",
619
- "lavender fishnet thigh-high stockings",
620
- "sunny-yellow silk thigh-high stockings",
621
- "shadow-black lace thigh-high stockings",
622
- "deep-red velvet thigh-high stockings",
623
- "white-sheer thigh-high stockings",
624
- "pink-rose lace thigh-high stockings",
625
- "sky-blue mesh thigh-high stockings",
626
- "forest-green chiffon thigh-high stockings",
627
- "lavender lace thigh-high stockings",
628
- "sun-yellow velvet thigh-high stockings",
629
- "shadow-black mesh thigh-high stockings",
630
- "sunset-red chiffon thigh-high stockings"
631
- ],
632
- "lingerie_thongs": [
633
- "floral thong", "bow accents thong", "transparent thong", "scalloped-edge thong",
634
- "a sleek thong", "a textured thong", "a glossy thong", "a light thong",
635
- "a net-pattern thong", "an embroidered thong", "a pearl-detailed thong",
636
- "a delicate-strap thong", "a plush thong", "a leaf-motif thong",
637
- "sheer-panel thong", "a shiny thong", "a flowy-edged thong", "a bold-line thong",
638
- "a romantic thong", "a soft-pile thong", "a sleek thong", "an elegant-drape thong",
639
- "an airy thong", "a bright thong", "a luxurious thong", "a deep-colored thong",
640
- "a modern-grid thong", "a feminine-ruffle thong", "a wave-pattern thong",
641
- "a natural-hued thong", "a royal-vibe thong", "a sunny thong", "a gothic-element thong",
642
- "a passionate thong", "a pure-white thong", "a blush-pink thong", "a deep-blue thong",
643
- "an envious-green thong", "a mysterious thong", "a joyful-yellow thong",
644
- "a night-black thong", "a fire-red thong", "a snow-white thong", "a rose-pink thong",
645
- "a sky-blue thong", "a sky-blue thong", "a forest-green thong", "a lavender thong", "a sun-yellow thong",
646
- "a shadow-black thong", "a sunset-red thong"
647
- ],
648
- "lingerie_bras": [
649
- "push-up bra", "underwire bra", "sheer-cup bra", "demi-cup bra", "smooth-cup bra",
650
- "padded bra", "balconette bra", "a light-coverage bra", "transparent-strap bra",
651
- "embroidered bra", "pearl-accented bra", "delicate-lace-trim bra", "a plush bra",
652
- "a floral-pattern bra", "sheer-panel bra", "a shiny bra", "a flowy-edged bra",
653
- "a bold bra", "a romantic bra", "a soft-textured bra", "a sleek-line bra",
654
- "an elegant-feel bra", "an airy bra", "a bright bra", "a luxurious bra",
655
- "a deep-hued bra", "a modern bra", "a feminine bra", "a wave-pattern bra",
656
- "a natural-color bra", "a royal-style bra", "a sunny-transparency bra", "a gothic bra",
657
- "a passionate bra", "a pure-white bra", "a blush-pink bra", "a deep-blue bra",
658
- "an envious-green bra", "a mysterious bra", "a joyful-yellow bra", "a night-black bra",
659
- "a fire-red bra", "a snow-white bra", "a rose-pink bra", "a sky-blue bra",
660
- "a forest-green bra", "a lavender bra", "a sun-yellow bra", "a shadow-black bra",
661
- "a sunset-red bra"
662
- ]
663
- }
664
- class FashionPromptGenerator:
665
- def __init__(self):
666
- self.fashion_elements = fashion_elements
667
- self.previous_prompts = set()
668
-
669
- def generate_unique_prompt(self, celebrity_name):
670
- """Genera un prompt ΓΊnico evitando repeticiones"""
671
- max_attempts = 10
672
- for attempt in range(max_attempts):
673
- prompt = self._build_prompt(celebrity_name)
674
- prompt_hash = hash(prompt)
675
- if prompt_hash not in self.previous_prompts:
676
- self.previous_prompts.add(prompt_hash)
677
- return prompt
678
- # Si no encuentra ΓΊnico despuΓ©s de varios intentos, devuelve igual
679
- return self._build_prompt(celebrity_name)
680
-
681
- def _build_prompt(self, celebrity_name):
682
- primary_color = random.choice(self.fashion_elements["colors"])
683
- secondary_color = random.choice([c for c in self.fashion_elements["colors"] if c != primary_color])
684
-
685
- outfit = random.choice(self.fashion_elements["outfits"])
686
- thong = random.choice(self.fashion_elements["lingerie_thongs"])
687
- bra = random.choice(self.fashion_elements["lingerie_bras"]) if random.random() > 0.3 else None
688
-
689
- lingerie_item = f"{primary_color} {thong}"
690
- if bra:
691
- lingerie_item += f" and {secondary_color} {bra}"
692
-
693
- discovery_moment = random.choice(self.fashion_elements["discovery_moments"])
694
- reveal_action = random.choice(self.fashion_elements["lingerie_reveal_actions"])
695
- voyeur_angle = random.choice(self.fashion_elements["voyeuristic_angles"])
696
- hairstyle = random.choice(self.fashion_elements["hairstyles"])
697
- background = random.choice(self.fashion_elements["backgrounds"])
698
- lighting = random.choice(self.fashion_elements["lighting"])
699
- expression = random.choice(self.fashion_elements["expressions"])
700
- stocking = f"{primary_color} {random.choice(self.fashion_elements['stockings'])}"
701
-
702
- prompt = f"""
703
- Voyeuristic fashion photograph of {celebrity_name}, captured from {voyeur_angle}.
704
- The composition creates an intimate, almost forbidden viewing experience, {discovery_moment}.
705
- She is {reveal_action}, creating a natural and unposed moment of exposure.
706
-
707
- She wears a {primary_color} {outfit} that subtly reveals her {lingerie_item} during movement.
708
- Complemented by {stocking}. Her {hairstyle} frames her face as she maintains {expression}.
709
-
710
- **Scene & Atmosphere:**
711
- - **Setting:** {background} with {lighting}
712
- - **Composition:** Full-body shot from below, maintaining complete figure visibility while emphasizing the intimate reveal
713
- - **Mood:** Sensual, voyeuristic, natural, and subtly erotic
714
- - **Focus:** Sharp detail on the revealed lingerie and facial expression, with soft background blur
715
-
716
- **Technical Details:**
717
- - Shot on professional DSLR with 85mm prime lens
718
- - Shallow depth of field focusing on the intimate moment
719
- - Natural skin tones with warm color grading
720
- - Ultra HD resolution, professional retouching
721
-
722
- The image captures a fleeting, intimate moment that feels both spontaneous and beautifully composed, emphasizing the sensual discovery of hidden lingerie through natural movement and expert framing.
723
-
724
- Negative prompt: cropped body, cut off limbs, out of frame, border, harsh shadows, uneven lighting, (bad anatomy, deformed, ugly), blurry, noisy, oversaturated, text, watermark, signature, (anime, cartoon, 3d, painting), monochrome, low quality, plastic, doll, airbrushed, photoshopped, fake, surreal, explicit nudity, vulgar
725
- """
726
- return prompt.strip()
727
-
728
- def generate_five_prompts(self, celebrity_name):
729
- """Genera 5 prompts ΓΊnicos"""
730
- self.previous_prompts.clear() # Limpiar historial para nueva generaciΓ³n
731
- return [self.generate_unique_prompt(celebrity_name) for _ in range(5)]
732
-
733
-
734
- def create_gradio_interface():
735
- generator = FashionPromptGenerator()
736
-
737
- with gr.Blocks(title="Voyeuristic Fashion Prompt Generator", theme=gr.themes.Soft(), css="""
738
- .prompt-box {
739
- border: 1px solid #e2e8f0;
740
- border-radius: 8px;
741
- padding: 16px;
742
- margin-bottom: 16px;
743
- background-color: #f8fafc;
744
- }
745
- .prompt-title {
746
- font-weight: bold;
747
- margin-bottom: 8px;
748
- color: #4a5568;
749
- }
750
- .dark .prompt-box {
751
- background-color: #2d3748;
752
- border-color: #4a5568;
753
- }
754
- .dark .prompt-title {
755
- color: #e2e8f0;
756
- }
757
- .header {
758
- text-align: center;
759
- margin-bottom: 20px;
760
- }
761
- """) as demo:
762
-
763
- gr.Markdown("""
764
- # πŸ” Voyeuristic Fashion Prompt Generator
765
- *Create intimate, discovery-focused fashion prompts with sensual lingerie reveals*
766
- """)
767
-
768
- with gr.Row():
769
- with gr.Column(scale=4):
770
- celebrity_input = gr.Textbox(
771
- label="Celebrity Name",
772
- placeholder="Enter celebrity name (e.g., Scarlett Johansson, Zendaya, Ana de Armas...)",
773
- info="The celebrity who will appear in the sensual fashion prompts"
774
  )
775
- with gr.Column(scale=1):
776
- generate_btn = gr.Button("✨ Generate 5 Unique Prompts", variant="primary", size="lg")
777
- clear_btn = gr.Button("πŸ—‘οΈ Clear All", variant="secondary")
778
-
779
- gr.Markdown("## Generated Prompts")
780
- gr.Markdown("*Each prompt features unique angles, discovery moments, and lingerie reveals*")
781
-
782
- output_prompts = []
783
- prompt_columns = []
784
-
785
- for i in range(5):
786
- with gr.Column(visible=False) as prompt_col:
787
- gr.Markdown(f"### 🎯 Prompt {i+1}", elem_classes="prompt-title")
788
- prompt_output = gr.Textbox(
789
- label="",
790
- lines=12,
791
- max_lines=15,
792
- interactive=False,
793
- elem_id=f"prompt_output_{i}",
794
- show_copy_button=True,
795
- elem_classes="prompt-box"
796
  )
797
- output_prompts.append(prompt_output)
798
- prompt_columns.append(prompt_col)
799
-
800
- def generate_and_display_prompts(celebrity_name):
801
- if not celebrity_name.strip():
802
- return [gr.update(visible=False)] * 5 + [""] * 5
803
- prompts = generator.generate_five_prompts(celebrity_name)
804
- return [gr.update(visible=True)] * 5 + prompts
805
-
806
- def clear_all():
807
- generator.previous_prompts.clear()
808
- return [gr.update(visible=False)] * 5 + [""] * 5
809
-
810
- generate_btn.click(
811
- fn=generate_and_display_prompts,
812
- inputs=celebrity_input,
813
- outputs=prompt_columns + output_prompts
814
- )
815
-
816
- clear_btn.click(
817
- fn=clear_all,
818
- inputs=None,
819
- outputs=prompt_columns + output_prompts
820
- )
821
-
822
- gr.Markdown("---")
823
- gr.Markdown("### πŸ’‘ Try these examples:")
824
- gr.Examples(
825
- examples=["Zendaya", "Ana de Armas", "Florence Pugh", "Sydney Sweeney", "Margot Robbie"],
826
- inputs=celebrity_input,
827
- outputs=prompt_columns + output_prompts,
828
- fn=generate_and_display_prompts,
829
- cache_examples=False,
830
- label="Click any example to generate prompts"
831
- )
 
20
  os.makedirs(CARPETA_SALIDA, exist_ok=True)
21
 
22
  # Cambia por tus claves reales o usa variables de entorno
23
+ SAMBA_API_KEY = os.getenv("SAMBA_API_KEY", "")
24
  REVE_API_KEY_DEFAULT = os.getenv("REVE_API_KEY", "")
25
 
26
  # ────────────────────────────────────────────────
27
+ # BATARTO PROMPT GENERATOR – MÁXIMA CRUDEZA
28
  # ────────────────────────────────────────────────
29
 
30
  class BatArtPromptGenerator:
31
  def __init__(self):
 
32
  self.colors = [
33
  "jet black", "blood red", "deep emerald", "royal purple", "neon hot pink",
34
  "wet crimson", "bruised plum", "glistening obsidian", "sweaty caramel",
35
  "midnight charcoal", "smoky burgundy", "electric violet"
36
  ]
37
 
 
38
  self.thongs = [
39
  "extremely thin sheer {color} lace thong soaked transparent clinging to swollen engorged labia majora",
40
  "crotchless {color} mesh thong with puffy labia majora spilling out both sides",
 
42
  "{color} string thong pulled painfully tight outlining erect clitoris and glistening vaginal folds",
43
  "open-crotch {color} lace thong leaving dripping vaginal entrance and swollen clitoral hood completely exposed",
44
  "wet-look {color} latex thong vacuum-molded to every vulvar fold and crease",
45
+ "see-through nude {color} mesh thong darkened and sticky from thick natural lubrication and dense curly pubic hair shadow"
46
  ]
47
 
 
48
  self.miniskirts = [
49
  "micro pleated black leather skirt violently hiked to waist exposing entire soaked thong and wet inner thighs",
50
  "ultra-short red vinyl skirt rolled up revealing extreme cameltoe and glistening lubrication trails down thighs",
 
53
  "pink satin micro skirt flipped up exposing ass cheeks and dripping thong string disappeared between buttocks"
54
  ]
55
 
 
56
  self.poses_hardcore = [
57
  "legs spread obscenely wide, hips thrust forward, thong soaked dark showing asymmetric protruding inner labia and erect clitoris outline",
58
  "squatting low knees far apart, fingers pulling thong aside exposing slick gaping vaginal opening and thick arousal strings",
 
61
  "on all fours back arched extremely, vulva and anus fully exposed, swollen labia hanging and glistening with fluids"
62
  ]
63
 
 
64
  self.poses_boudoir_office = [
65
  "standing legs slightly apart with torso twist, skirt delicately lifted revealing lace thong cameltoe, seductive direct gaze",
66
  "sitting on desk edge one leg crossed high, skirt raised showing intricate thong texture and wet spot, confident sultry look",
 
69
  "reclining on office sofa, knees bent and apart, thong clearly displayed with glistening fluids, eyes conveying subtle ecstasy"
70
  ]
71
 
 
72
  self.angles = [
73
  "extreme ultra-low worm’s eye view camera 15–25 cm from vulva filling most of frame with soaked thong and exposed anatomy",
74
  "dramatic floor-level macro crotch shot looking straight up between widely parted thighs, razor focus on wet cameltoe and clit",
 
76
  "contrapicado extremo casi pegado al suelo, vulva ocupando 60–75% del encuadre, tanga hundida mostrando clΓ­toris hinchado y labios asimΓ©tricos"
77
  ]
78
 
 
79
  self.lighting = [
80
  "hard directional window light creating strong specular highlights on vaginal lubrication and sweat beads on inner thighs",
81
  "soft diffuse natural daylight + subtle rim light outlining swollen labia and erect nipples through sheer fabric",
 
83
  "dramatic chiaroscuro with deep shadows accentuating wetness, clitoral hood contour and labia volume"
84
  ]
85
 
 
86
  self.backgrounds = [
87
  "modern executive office with floor-to-ceiling windows flooding natural daylight and city views",
88
  "minimalist chic office, large windows creating soft reflections on glass and marble",
 
90
  "sophisticated executive room with polished wood desk and huge windows"
91
  ]
92
 
 
93
  self.hairstyles = [
94
  "long loose tousled hair sensually framing the face and falling over shoulders",
95
  "elegant waves cascading seductively down the back",
 
98
  ]
99
 
100
  self.expressions = [
101
+ "seductive heavy-lidded gaze full of desire, lips slightly parted and glistening",
102
+ "confident sultry smirk with intense direct eye contact and wet lips",
103
  "subtle ecstasy expression, eyes half-closed, tongue grazing lower lip",
104
+ "playful hungry look, eyebrow raised, flushed cheeks and parted lips"
105
  ]
106
 
107
+ def build_prompt(self, celebrity: str, hardcore: bool = True, use_boudoir_poses: bool = False) -> Tuple[str, str]:
 
 
 
 
 
108
  color = random.choice(self.colors)
109
  thong = random.choice(self.thongs).format(color=color)
110
+ skirt = random.choice(self.miniskirts)
111
+ angle = random.choice(self.angles)
112
+ light = random.choice(self.lighting)
113
+ background = random.choice(self.backgrounds)
114
 
115
  if hardcore:
116
  pose = random.choice(self.poses_hardcore)
 
117
  bg_weight = "subtle"
118
+ detail_focus = "razor sharp focus on vulva, soaked thong texture and dripping fluids"
119
+ extra = ""
120
  else:
121
  pose = random.choice(self.poses_boudoir_office) if use_boudoir_poses else random.choice(self.poses_hardcore)
 
122
  bg_weight = "prominent"
123
  hairstyle = random.choice(self.hairstyles)
124
  expression = random.choice(self.expressions)
125
+ detail_focus = "sharp focus on intricate lace thong texture, visible wet cameltoe, swollen labia outline and facial expression"
126
+ extra = f"""
 
 
 
 
 
 
 
127
  Hairstyle: {hairstyle}.
128
+ Expression: {expression}, flushed cheeks, wet parted lips."""
129
 
130
+ prompt_text = f"""Ultra-detailed hyperrealistic erotic office photograph of {celebrity},
131
 
132
  {pose},
133
 
 
148
  β€’ sweat beads collecting in inguinal creases, perineum and between buttocks
149
  β€’ visible stretch marks, subtle cellulite and open pores on inner thighs
150
  β€’ erect hard nipples pressing against thin blouse or bra
151
+ β€’ arousal fluid strands connecting vulva to pulled thong fabric{extra}
152
 
153
  photorealistic raw photo, 16K, Canon EOS R5 + RF 85mm f/1.2 @ f/1.4, extremely shallow depth of field, {detail_focus}, cinematic warm grading, visible natural skin imperfections, subsurface scattering on moist skin, (masterpiece, ultra-detailed anatomy, best quality:1.45), (watermark BATUTO-ART:0.4)
154
 
 
156
 
157
  caption = f"{celebrity} β€’ {color} soaked thong β€’ {'ultra-close hardcore crotch macro' if hardcore else 'boudoir office explicit visible thong'}"
158
 
159
+ return prompt_text.strip(), caption
160
 
161
+ def generate_five(self, celebrity: str, hardcore: bool = True, use_boudoir_poses: bool = False) -> List[Tuple[str, str]]:
 
 
 
 
 
162
  return [self.build_prompt(celebrity, hardcore, use_boudoir_poses) for _ in range(5)]
163
 
164
  # ────────────────────────────────────────────────
165
+ # FUNCIONES REVE
166
  # ────────────────────────────────────────────────
167
 
168
+ def save_image_locally(img: Image.Image, prefix: str = "batart") -> str:
169
  ts = int(time.time() * 1000)
170
  fname = f"{prefix}_{ts}.png"
171
  path = os.path.join(CARPETA_SALIDA, fname)
 
173
  img.save(path, "PNG", optimize=True)
174
  return path
175
  except Exception as e:
176
+ print(f"Error guardando imagen: {e}")
177
  return None
178
 
179
  def call_reve_api(prompt: str, api_key: str, aspect_ratio: str = "9:16", version: str = "latest", timeout: int = 120):
180
+ if not api_key or not api_key.strip():
181
+ return None, "API Key REVE vacΓ­a o invΓ‘lida", 0
182
 
183
  payload = {"prompt": prompt.strip(), "aspect_ratio": aspect_ratio, "version": version}
184
+ headers = {
185
+ "Authorization": f"Bearer {api_key.strip()}",
186
+ "Content-Type": "application/json",
187
+ "Accept": "application/json"
188
+ }
189
 
190
  try:
191
+ r = requests.post(REVE_API_URL, headers=headers, json=payload, timeout=timeout)
192
+ if r.status_code != 200:
193
+ return None, f"HTTP {r.status_code} β†’ {r.text[:200]}", 0
194
 
195
+ data = r.json()
196
  if "image" not in data or not data["image"]:
197
+ return None, "No se recibiΓ³ campo 'image' vΓ‘lido", 0
198
 
199
  img_bytes = base64.b64decode(data["image"])
200
  img = Image.open(BytesIO(img_bytes)).convert("RGB")
201
+ credits = data.get("credits_used", data.get("credits_consumed", 0))
202
+ return img, "", int(credits or 0)
203
 
204
+ except requests.Timeout:
205
+ return None, "Timeout al contactar REVE API", 0
206
  except Exception as e:
207
+ return None, f"ExcepciΓ³n en REVE: {str(e)}", 0
208
 
209
  def generate_reve_batch(prompt: str, api_key: str, ratio: str, count: int, progress=gr.Progress()):
210
  count = max(1, min(count, 6))
 
214
  futures = [exe.submit(call_reve_api, prompt, api_key, ratio) for _ in range(count)]
215
 
216
  for i, future in enumerate(concurrent.futures.as_completed(futures)):
217
+ progress((i + 1) / count, desc=f"Generando imagen {i+1}/{count}")
218
+ img, err, cred = future.result()
219
  if img:
220
  path = save_image_locally(img)
221
  if path:
222
  images.append(img)
223
  paths.append(path)
224
+ total_credits += cred
225
  if err:
226
  errors.append(err)
227
 
228
+ status_lines = [f"**Resultado:** {len(images)} imΓ‘genes generadas OK β€’ {len(errors)} errores"]
229
+ if total_credits > 0:
230
+ status_lines.append(f"CrΓ©ditos consumidos aproximados: {total_credits}")
231
  if errors:
232
+ status_lines.append("**Errores detectados:**")
233
+ status_lines.extend([f"β€’ {err}" for err in errors[:3]])
234
+ if len(errors) > 3:
235
+ status_lines.append(f"… y {len(errors)-3} errores mΓ‘s.")
236
 
237
+ status_md = "\n".join(status_lines) if status_lines else "No se generaron imΓ‘genes"
238
+
239
+ return images, status_md, paths
240
 
241
  # ────────────────────────────────────────────────
242
+ # CHAT + ANÁLISIS DE IMÁGENES
243
  # ────────────────────────────────────────────────
244
 
245
  def chat_with_samba(messages: list, image_base64: str = None):
 
264
  r.raise_for_status()
265
  return r.json()["choices"][0]["message"]["content"]
266
  except Exception as e:
267
+ return f"Error al conectar con SambaNova: {str(e)}"
268
 
269
  def analyze_uploaded_image(image: Image.Image, user_prompt: str):
270
  buffered = BytesIO()
 
272
  img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
273
 
274
  system_msg = (
275
+ "Eres BATUTO IA: describes imΓ‘genes con mΓ‘xima crudeza anatΓ³mica y explΓ­cita sin ninguna censura ni eufemismo. "
276
+ "Detallas genitales (vulva, clΓ­toris hinchado, labios mayores carnosos e hinchados, labios menores asimΓ©tricos protruyentes con pliegues irregulares, entrada vaginal dilatada con lubricaciΓ³n viscosa goteando), "
277
+ "fluidos (hilos de lubricaciΓ³n natural, sudor en pliegues inguinales y perinΓ©, saliva en comisuras), "
278
+ "texturas (poros dilatados, vello pΓΊbico natural rizado y denso escapando de la tanga, estrΓ­as, celulitis sutil, brillos de humedad, marcas rojas de tela apretada), "
279
+ "ropa (tanga hundida marcando cameltoe extremo, tela mojada adherida revelando cada pliegue vulvar), "
280
+ "poses dinΓ‘micas y expresiones de placer intenso. Todo con detalle tΓ©cnico-sensorial absoluto."
281
  )
282
 
283
  messages = [
 
288
  respuesta = chat_with_samba(messages, img_str)
289
 
290
  prompt_en = f"""Hyperrealistic raw extreme close-up erotic photograph based on the described image,
291
+ photorealistic, 16K, Canon EOS R5 + RF 85mm f/1.2, shallow depth of field, visible pores, dense natural curly pubic hair escaping thong, sweat beads in inguinal creases and perineum, glistening thick vaginal lubrication dripping in strings, asymmetric swollen protruding labia minora with irregular folds, erect prominent clitoris with retracted hood, detailed moist skin textures and imperfections, subsurface scattering on wet areas, cinematic warm grading, (masterpiece, ultra-detailed anatomy:1.5), no censorship, (watermark BATUTO-ART:0.4)
292
 
293
  Negative prompt: blurry, deformed, bad anatomy, censored, mosaic censor, bar censor, cartoon, plastic skin, airbrushed, modest pose, covered genitals, dry skin, no pubic hair, symmetrical labia, safe for work"""
294
 
295
  return respuesta, prompt_en
296
+ # ────────────────────────────────────────────────
 
297
  # INTERFAZ GRADIO FINAL
298
  # ────────────────────────────────────────────────
299
 
 
301
  generator = BatArtPromptGenerator()
302
 
303
  with gr.Blocks(
304
+ title="BAT_ART β€’ Ultra-Explicit 2026",
305
  theme=gr.themes.Default(primary_hue="red", neutral_hue="slate"),
306
  css="""
307
+ body { background-color: #0d1117; color: #c9d1d9; font-family: 'Segoe UI', sans-serif; }
308
+ .gradio-container { max-width: 1280px; margin: auto; padding: 1rem; }
309
+ .prompt-box { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 14px; margin: 8px 0; }
310
+ h1, h2, h3 { color: #ff6b6b; }
311
  """
312
  ) as demo:
313
 
314
  gr.Markdown("# BAT_ART β€’ Generador Ultra-ExplΓ­cito + Chat IA + REVE")
315
 
316
  with gr.Tabs():
317
+ # ─── Generador Prompts ───
318
  with gr.Tab("Generador Prompts ExplΓ­citos"):
319
+ with gr.Row():
320
+ celebrity_input = gr.Textbox(
321
+ label="Celebridad", placeholder="Ej: Ana de Armas, Sydney Sweeney, Zendaya",
322
+ value="Ana de Armas", scale=4
323
+ )
324
+ hardcore_checkbox = gr.Checkbox(
325
+ label="Modo Ultra-Hardcore Close-up (vulva explΓ­cita, lubricaciΓ³n goteando, clΓ­toris visible)",
326
+ value=True, scale=1
327
+ )
328
+ boudoir_checkbox = gr.Checkbox(
329
+ label="Usar poses boudoir office elegantes", value=False, scale=1
330
+ )
331
+
332
+ btn_generate = gr.Button("Generar 5 Prompts Ultra-ExplΓ­citos", variant="primary", size="lg")
333
 
334
  prompt_gallery = gr.Gallery(
335
+ label="Prompts generados – selecciona uno para editar/copiar",
336
+ columns=1, height=380, show_label=False, object_fit="contain"
337
  )
338
+
339
  selected_prompt = gr.Textbox(
340
+ label="Prompt seleccionado (editable y listo para REVE)",
341
+ lines=12, max_lines=30, interactive=True,
342
+ show_copy_button=True, elem_classes="prompt-box"
343
  )
344
 
345
+ def gen_prompts(name, hardcore, boudoir):
346
  if not name.strip():
347
+ return [], "**Error:** Ingresa un nombre de celebridad."
348
+ prompts = generator.generate_five(name.strip(), hardcore=hardcore, use_boudoir_poses=boudoir)
349
  return [[p[0], p[1]] for p in prompts], prompts[0][0] if prompts else ""
350
 
351
+ btn_generate.click(
352
+ gen_prompts,
353
+ inputs=[celebrity_input, hardcore_checkbox, boudoir_checkbox],
354
+ outputs=[prompt_gallery, selected_prompt]
355
  )
356
 
357
  prompt_gallery.select(
358
+ lambda evt: evt.value[0] if evt.value and isinstance(evt.value, list) else "",
359
+ inputs=None, outputs=selected_prompt
360
  )
361
 
362
+ # ─── Chat + AnΓ‘lisis ───
363
+ with gr.Tab("Chat BATUTO + AnΓ‘lisis de ImΓ‘genes"):
364
+ chatbot = gr.Chatbot(
365
+ height=620,
366
+ show_copy_button=True,
367
+ bubble_full_width=False,
368
+ avatar_images=(None, "https://api.dicebear.com/7.x/bottts/svg?seed=Batuto")
369
+ )
370
+ msg_input = gr.Textbox(placeholder="PregΓΊntame lo que sea o describe quΓ© analizar en detalle explΓ­cito...")
371
+ img_upload = gr.Image(type="pil", label="Sube una imagen para anΓ‘lisis anatΓ³mico ultra-detallado")
372
+ send_button = gr.Button("Enviar / Analizar", variant="primary")
373
 
374
+ def respond_chat(message, image, history):
375
  history = history or []
376
  if image:
377
  desc, prompt_en = analyze_uploaded_image(image, message)
378
+ response = f"**BATUTO – DescripciΓ³n explΓ­cita mΓ‘xima:**\n{desc}\n\n```prompt\n{prompt_en}\n```"
379
  else:
380
  messages = [{"role": "user", "content": message}]
381
  response = chat_with_samba(messages)
382
  history.append((message, response))
383
  return "", history
384
 
385
+ send_button.click(
386
+ respond_chat,
387
+ inputs=[msg_input, img_upload, chatbot],
388
+ outputs=[msg_input, chatbot],
389
+ queue=False
390
  )
391
 
392
+ # ─── REVE Generator ───
393
  with gr.Tab("Generar ImΓ‘genes REVE"):
394
  with gr.Row():
395
  with gr.Column(scale=3):
396
+ api_key_input = gr.Textbox(
397
+ label="πŸ”‘ REVE API Key (requerida)", type="password",
398
+ value=REVE_API_KEY_DEFAULT, placeholder="sk-..."
399
+ )
400
+ prompt_input = gr.Textbox(
401
+ label="Prompt para generar (viene del tab anterior o edΓ­talo)",
402
+ lines=8, interactive=True, show_copy_button=True
403
+ )
404
  with gr.Column(scale=1):
405
+ aspect_ratio = gr.Dropdown(
406
+ choices=["9:16", "2:3", "3:4", "1:1", "16:9"],
407
+ value="9:16", label="Aspect Ratio"
408
+ )
409
+ num_images = gr.Slider(1, 4, step=1, value=2, label="Cantidad de imΓ‘genes")
410
+
411
+ generate_reve_btn = gr.Button("πŸš€ Generar ImΓ‘genes con REVE", variant="primary", size="lg")
412
+
413
+ reve_gallery = gr.Gallery(
414
+ label="ImΓ‘genes generadas", columns=2, height=680,
415
+ object_fit="contain", show_download_button=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  )
417
+ status_output = gr.Markdown("")
418
+
419
+ paths_state = gr.State([])
420
+
421
+ open_folder_btn = gr.Button("πŸ“‚ Abrir carpeta de generaciones", variant="secondary")
422
+
423
+ # Vincular prompt del tab anterior
424
+ selected_prompt.change(lambda x: x, selected_prompt, prompt_input)
425
+
426
+ def generate_reve(prompt, key, ratio, count, progress=gr.Progress()):
427
+ if not prompt.strip():
428
+ return [], "**Error:** El prompt estΓ‘ vacΓ­o. Selecciona o escribe uno.", []
429
+ if not key.strip():
430
+ return [], "**Error:** Ingresa tu REVE API Key.", []
431
+ return generate_reve_batch(prompt, key, ratio, int(count), progress)
432
+
433
+ generate_reve_btn.click(
434
+ generate_reve,
435
+ inputs=[prompt_input, api_key_input, aspect_ratio, num_images],
436
+ outputs=[reve_gallery, status_output, paths_state]
 
437
  )
438
+
439
+ def open_folder_action(_paths):
440
+ import webbrowser
441
+ try:
442
+ webbrowser.open(f"file://{os.path.abspath(CARPETA_SALIDA)}")
443
+ return f"**Carpeta abierta:** {os.path.abspath(CARPETA_SALIDA)}"
444
+ except Exception as e:
445
+ return f"**Ruta de salida:** {os.path.abspath(CARPETA_SALIDA)}\n(Γ‘brela manualmente)\nError: {str(e)}"
446
+
447
+ open_folder_btn.click(open_folder_action, inputs=paths_state, outputs=status_output)
448
+
449
+ gr.Markdown("BATUTO IA β€’ Sin lΓ­mites β€’ MΓ‘xima crudeza anatΓ³mica β€’ 2026")
450
+
451
+ demo.launch(share=True, server_name="0.0.0.0")
452
+
453
+
454
+ if __name__ == "__main__":
455
+ main()