Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import random | |
| from typing import Dict, Any, List | |
| import json | |
| import datetime | |
| class HyperRealisticConfig: | |
| ETHNICITIES = [ | |
| "Mediterranean", "Scandinavian", "Slavic", "Latin American", | |
| "Middle Eastern", "East Asian", "South Asian", "African", | |
| "Caribbean", "Polynesian", "Mixed Heritage" | |
| ] | |
| BODY_TYPES = [ | |
| "athletic slender", "voluptuous curves", "petite feminine", | |
| "toned hourglass", "soft natural", "elegant tall" | |
| ] | |
| SKIN_DETAILS = [ | |
| "with subtle freckles and skin texture", "with dewy natural complexion", | |
| "showing realistic skin pores and veins", "with natural skin imperfections", | |
| "with subsurface scattering effect", "with delicate skin translucency" | |
| ] | |
| PROFESSIONAL_ROLES = [ | |
| { | |
| "role": "Executive Secretary", | |
| "uniform": "form-fitting tailored black dress with silk blouse slightly unbuttoned", | |
| "environment": "luxurious corporate office with marble floors", | |
| "accessories": "slim tablet and leather portfolio", | |
| "pose": "bending over conference table arranging documents" | |
| }, | |
| { | |
| "role": "Luxury Hotel Manager", | |
| "uniform": "elegant navy blue blazer and pencil skirt riding up when seated", | |
| "environment": "five-star hotel lobby with golden lighting", | |
| "accessories": "gold name tag and master key cards", | |
| "pose": "leaning forward to assist guest at reception" | |
| }, | |
| { | |
| "role": "Fashion Boutique Manager", | |
| "uniform": "chic black designer dress with elegant draping that accents curves", | |
| "environment": "high-end boutique with minimalist decor and spotlights", | |
| "accessories": "designer handbag and inventory clipboard", | |
| "pose": "kneeling to adjust mannequin display" | |
| }, | |
| { | |
| "role": "Corporate Lawyer", | |
| "uniform": "sharp charcoal gray pantsuit with skirt hiking up when walking", | |
| "environment": "modern law firm with floor-to-ceiling windows", | |
| "accessories": "leather briefcase and legal documents", | |
| "pose": "stretching to reach high shelf in law library" | |
| }, | |
| { | |
| "role": "Private Jet Attendant", | |
| "uniform": "custom-fitted aviation uniform with skirt shortening when bending", | |
| "environment": "luxurious private jet cabin with leather seats", | |
| "accessories": "champagne flute and service tray", | |
| "pose": "bending to serve passengers in low cabin" | |
| }, | |
| { | |
| "role": "Art Gallery Curator", | |
| "uniform": "sleek black turtleneck and high-waisted trousers with visible panty lines", | |
| "environment": "contemporary art gallery with dramatic lighting", | |
| "accessories": "curator's catalog and white gloves", | |
| "pose": "squatting to examine lower artwork" | |
| }, | |
| { | |
| "role": "University Professor", | |
| "uniform": "elegant tweed blazer and knee-length skirt that rides up when seated", | |
| "environment": "university library with wooden ladders", | |
| "accessories": "academic books and reading glasses", | |
| "pose": "reaching for book on high shelf" | |
| }, | |
| { | |
| "role": "Ballet Instructor", | |
| "uniform": "black leotard with wrap skirt and visible dance belt lines", | |
| "environment": "dance studio with wall mirrors and barre", | |
| "accessories": "pointe shoe ribbon and demonstration stick", | |
| "pose": "demonstrating deep plié at barre" | |
| }, | |
| { | |
| "role": "Yacht Stewardess", | |
| "uniform": "crisp white polo and navy shorts that tighten when bending", | |
| "environment": "luxury yacht deck at sunset with teak flooring", | |
| "accessories": "silver tray with cocktails and nautical rope", | |
| "pose": "leaning over side to adjust fenders" | |
| }, | |
| { | |
| "role": "Elegant Maid", | |
| "uniform": "classic black maid dress with white lace apron that flips up", | |
| "environment": "opulent mansion hallway with grand staircase", | |
| "accessories": "feather duster and cleaning cart", | |
| "pose": "bending to polish banister" | |
| } | |
| ] | |
| EVERYDAY_MOMENTS = [ | |
| { | |
| "scene": "Morning Kitchen", | |
| "action": "bending down to take something from the low oven causing shirt to rise", | |
| "outfit": "oversized white t-shirt and cotton shorts with visible panty lines", | |
| "setting": "sunlit kitchen with open window and morning light", | |
| "accessories": "coffee mug on counter, apron hanging, fresh herbs", | |
| "pose": "natural bending with back arched" | |
| }, | |
| { | |
| "scene": "Laundry Room", | |
| "action": "bending over to take clothes from the dryer showing waistband", | |
| "outfit": "sports top and fitted leggings with subtle sheer panels", | |
| "setting": "laundry room with baskets and folding table", | |
| "accessories": "basket of clean clothes, fabric softener", | |
| "pose": "deep forward bend with legs straight" | |
| }, | |
| { | |
| "scene": "Gardening", | |
| "action": "kneeling while planting flowers with shorts riding up", | |
| "outfit": "light cotton sundress with thin straps and no bra lines", | |
| "setting": "backyard garden with flower pots and watering system", | |
| "accessories": "gardening gloves, watering can, trowel", | |
| "pose": "kneeling with one leg forward" | |
| }, | |
| { | |
| "scene": "Home Yoga", | |
| "action": "doing downward dog pose with leggings becoming translucent", | |
| "outfit": "yoga leggings and crop top with sweat patches", | |
| "setting": "living room with yoga mat and natural side lighting", | |
| "accessories": "yoga block, water bottle, meditation app", | |
| "pose": "inverted V-shape with head down" | |
| }, | |
| { | |
| "scene": "Shelf Cleaning", | |
| "action": "stretching on tiptoes to reach a book showing midriff", | |
| "outfit": "loose t-shirt and pajama shorts with lace trim visible", | |
| "setting": "personal library with small ladder and dust particles", | |
| "accessories": "feather duster, stack of books, reading glasses", | |
| "pose": "full body stretch on toes" | |
| }, | |
| { | |
| "scene": "Dog Walk", | |
| "action": "bending down to attach the leash with dress gaping", | |
| "outfit": "floral summer dress with thin fabric blowing in wind", | |
| "setting": "park at sunset with long shadows and golden hour", | |
| "accessories": "leash, treat pouch, dog water bottle", | |
| "pose": "squatting while holding excited dog" | |
| }, | |
| { | |
| "scene": "Terrace Coffee", | |
| "action": "sitting with legs crossed, dropping a napkin and reaching", | |
| "outfit": "silk blouse and pleated skirt that opens when seated", | |
| "setting": "terrace with iron table and morning mist", | |
| "accessories": "open book, tea cup, croissant", | |
| "pose": "leaning forward from seated position" | |
| }, | |
| { | |
| "scene": "Climbing Stairs", | |
| "action": "going up with shopping bags showing back view", | |
| "outfit": "pencil skirt and fitted blouse with tension lines", | |
| "setting": "spiral staircase in apartment with dramatic lighting", | |
| "accessories": "shopping bags, keys in hand, mail", | |
| "pose": "mid-step with weight on one leg" | |
| }, | |
| { | |
| "scene": "Changing Lightbulb", | |
| "action": "standing on a chair with arms raised fully", | |
| "outfit": "long t-shirt as dress with back lift when reaching", | |
| "setting": "kitchen with pendant light and afternoon shadows", | |
| "accessories": "new lightbulb, step stool, tool box", | |
| "pose": "tiptoes on chair reaching upward" | |
| }, | |
| { | |
| "scene": "Post-Shower", | |
| "action": "drying hair with towel that keeps slipping", | |
| "outfit": "short towel wrapped tightly with damp edges", | |
| "setting": "bathroom with foggy mirror and steam effect", | |
| "accessories": "hairdryer, bathrobe on hook, skincare products", | |
| "pose": "bent forward hair drying motion" | |
| } | |
| ] | |
| LACE_BIKINI_STYLES = [ | |
| "delicate black lace bikini with floral embroidery and sheer panels", | |
| "sheer nude illusion bikini with scalloped lace edges and ribbon ties", | |
| "burgundy silk bikini with Chantilly lace inserts and satin strings", | |
| "ivory French lace bikini with pearl accents and delicate stitching", | |
| "champagne colored lace bikini with geometric patterns and silk backing", | |
| "deep emerald lace bikini with velvet trim and adjustable sides", | |
| "rose gold metallic lace bikini with transparent mesh panels", | |
| "midnight blue lace bikini with crystal beading and underwire support" | |
| ] | |
| HOSIERY_STYLES = [ | |
| "black sheer thigh-high stockings with lace tops and stay-up silicone", | |
| "nude ultra-sheer stockings with reinforced toes and back seam", | |
| "fishnet thigh-highs with delicate diamond pattern and satin band", | |
| "back-seam stockings with Cuban heel and vintage reinforcement", | |
| "sheer to waist stockings with lace panel and no panty line", | |
| "opaque tights with subtle sheen and reinforced gusset", | |
| "stay-up stockings with French lace band and bow details", | |
| "glossy finish stockings with sandalwood foot and sheer legs" | |
| ] | |
| HEEL_STYLES = [ | |
| "black patent leather stilettos with pointed toe and slim heel", | |
| "nude pumps with platform and ankle strap for stability", | |
| "gold strappy sandals with multiple thin straps and high arch", | |
| "black suede pointed-toe heels with cut-out details", | |
| "red bottom Louboutin-style heels with glossy finish", | |
| "clear PVC heels with geometric shapes and metallic accents", | |
| "silver glitter block heels with ankle support and comfort pad", | |
| "white leather slingbacks with kitten heel and bow detail" | |
| ] | |
| HAIRSTYLES = [ | |
| "long wavy hair with natural volume and soft highlights", | |
| "sleek straight hair with middle part and glossy finish", | |
| "elegant updo with loose tendrils and pearl pins", | |
| "beach waves with sun-kissed highlights and textured ends", | |
| "high ponytail with smooth finish and subtle curls", | |
| "braided crown with floral accents and soft flyaways", | |
| "vintage Hollywood curls with deep side part", | |
| "messy bun with face-framing strands and natural texture" | |
| ] | |
| MAKEUP_STYLES = [ | |
| "natural glam with dewy skin, soft contour, and nude lips", | |
| "smoky eye with winged liner and voluminous lashes", | |
| "rosy cheeks with glossy lips and subtle highlighter", | |
| "bold red lip with flawless matte foundation", | |
| "bronzed goddess with shimmery eyeshadow and golden highlights", | |
| "minimalist makeup with tinted moisturizer and mascara", | |
| "vintage pin-up with defined brows and classic red lip", | |
| "ethereal glow with iridescent highlighter and soft blush" | |
| ] | |
| LIGHTING_DETAILS = [ | |
| "soft diffused lighting with a warm golden glow", | |
| "dramatic chiaroscuro lighting with deep shadows", | |
| "natural sunlight filtering through sheer curtains", | |
| "studio lighting with a three-point setup for dimensionality", | |
| "candlelit ambiance with flickering shadows", | |
| "backlit silhouette with a soft halo effect", | |
| "moody blue-toned lighting for a cinematic feel", | |
| "sunset glow with lens flare and warm hues" | |
| ] | |
| PHOTOGRAPHY_STYLES = [ | |
| "cinematic lighting with rim light and soft shadows", | |
| "natural window light with lens flare and soft focus", | |
| "studio softbox lighting with catchlights in eyes", | |
| "golden hour backlighting with hair light effect", | |
| "moody low-key lighting with dramatic contrasts", | |
| "bright high-key lighting with minimal shadows", | |
| "film noir inspired lighting with venetian blind patterns", | |
| "ethereal foggy lighting with diffusion filter" | |
| ] | |
| CAMERAS = ["Canon EOS R5", "Sony α7R V", "Nikon Z9", "Hasselblad X2D", "Phase One IQ4"] | |
| LENSES = ["85mm f/1.2", "50mm f/1.4", "24-70mm f/2.8", "100mm f/2.8 macro", "135mm f/1.8"] | |
| class HyperRealisticPromptGenerator: | |
| def __init__(self): | |
| self.config = HyperRealisticConfig() | |
| self.history: List[Dict] = [] | |
| def _get_role_by_name(self, name: str) -> Dict: | |
| return next((r for r in self.config.PROFESSIONAL_ROLES if r["role"] == name), self.config.PROFESSIONAL_ROLES[0]) | |
| def _get_moment_by_name(self, name: str) -> Dict: | |
| return next((m for m in self.config.EVERYDAY_MOMENTS if m["scene"] == name), self.config.EVERYDAY_MOMENTS[0]) | |
| def _random_style(self): | |
| return ( | |
| random.choice(self.config.BODY_TYPES), | |
| random.choice(self.config.SKIN_DETAILS), | |
| random.choice(self.config.LACE_BIKINI_STYLES), | |
| random.choice(self.config.HOSIERY_STYLES), | |
| random.choice(self.config.HEEL_STYLES), | |
| random.choice(self.config.HAIRSTYLES), | |
| random.choice(self.config.MAKEUP_STYLES), | |
| random.choice(self.config.LIGHTING_DETAILS), | |
| random.choice(self.config.PHOTOGRAPHY_STYLES), | |
| random.choice(self.config.CAMERAS), | |
| random.choice(self.config.LENSES) | |
| ) | |
| def generate_role_prompt(self, ethnicity: str, role_name: str, nsfw_mode: bool = False) -> str: | |
| role = self._get_role_by_name(role_name) | |
| body, skin, lace, hosiery, heels, hairstyle, makeup, lighting, photo_style, camera, lens = self._random_style() | |
| if nsfw_mode: | |
| reveal = f"subtle reveal of {lace} through clothing during {role['pose']}" | |
| underwear_desc = f"wearing {lace} under {role['uniform']}" | |
| nudity = "artistic sensuality with focus on natural beauty" | |
| else: | |
| reveal = f"subtle hint of lace underwear during {role['pose']}" | |
| underwear_desc = f"with delicate lace underwear under {role['uniform']}" | |
| nudity = "elegant and professional with subtle sensuality" | |
| prompt = ( | |
| f"Hyper-realistic 4K photograph, 9:16 vertical composition, full-body portrait from dynamic low angle, " | |
| f"of a stunning {ethnicity.lower()} {role['role']} with {body} figure {skin}, " | |
| f"{underwear_desc}, {hosiery}, {heels}, styled with {hairstyle}, and {makeup}. " | |
| f"In {role['environment']}, captured during {role['pose']} causing {reveal}. " | |
| f"{lighting}, {photo_style}, Camera: {camera} with {lens} lens, professional lighting setup, " | |
| f"ultra-high resolution 16K, extreme detail showing skin texture with visible pores, " | |
| f"realistic fabric wrinkles, subsurface scattering effect, cinematic depth of field. " | |
| f"Professional atmosphere, elegant composition, {nudity}. " | |
| f"Include {role['accessories']} in scene. --no explicit_nudity --style raw --stylize 150" | |
| ) | |
| self.history.append({ | |
| "type": "role", | |
| "ethnicity": ethnicity, | |
| "role": role_name, | |
| "nsfw": nsfw_mode, | |
| "prompt": prompt, | |
| "timestamp": datetime.datetime.now().isoformat() | |
| }) | |
| return prompt | |
| def generate_moment_prompt(self, ethnicity: str, moment_name: str, nsfw_mode: bool = False) -> str: | |
| moment = self._get_moment_by_name(moment_name) | |
| body, skin, lace, hosiery, heels, hairstyle, makeup, lighting, photo_style, camera, lens = self._random_style() | |
| if nsfw_mode: | |
| reveal = f"natural reveal of {lace} while {moment['action']}" | |
| underwear_desc = f"wearing {lace} under {moment['outfit']}" | |
| sensuality = "artistic intimate moment with sensual atmosphere" | |
| else: | |
| reveal = f"subtle suggestion of lace underwear while {moment['action']}" | |
| underwear_desc = f"with delicate lace underwear under {moment['outfit']}" | |
| sensuality = "natural private moment with elegant sensuality" | |
| prompt = ( | |
| f"Hyper-realistic candid photograph, 9:16 vertical format, intimate low angle perspective, " | |
| f"of a beautiful {ethnicity.lower()} woman with {body} physique {skin}, styled with {hairstyle}, and {makeup}. " | |
| f"{underwear_desc}, {hosiery}, {heels}, in {moment['setting']}, " | |
| f"captured during {moment['pose']}, {moment['action']}. " | |
| f"{lighting}, {photo_style}, Camera: {camera} with {lens}, ultra-high detail 16K resolution, " | |
| f"realistic skin texture with pores and fine hairs, fabric micro-details, " | |
| f"natural lighting with soft shadows, cinematic composition. " | |
| f"{sensuality}. Include {moment['accessories']} in scene. " | |
| f"--no explicit_content --style photographic --stylize 180" | |
| ) | |
| self.history.append({ | |
| "type": "moment", | |
| "ethnicity": ethnicity, | |
| "scene": moment_name, | |
| "nsfw": nsfw_mode, | |
| "prompt": prompt, | |
| "timestamp": datetime.datetime.now().isoformat() | |
| }) | |
| return prompt | |
| def generate_batch_prompts(self, count: int, prompt_type: str, nsfw_mode: bool = False) -> List[str]: | |
| prompts = [] | |
| for _ in range(count): | |
| ethnicity = random.choice(self.config.ETHNICITIES) | |
| if prompt_type == "roles": | |
| role = random.choice([r["role"] for r in self.config.PROFESSIONAL_ROLES]) | |
| prompts.append(self.generate_role_prompt(ethnicity, role, nsfw_mode)) | |
| else: | |
| moment = random.choice([m["scene"] for m in self.config.EVERYDAY_MOMENTS]) | |
| prompts.append(self.generate_moment_prompt(ethnicity, moment, nsfw_mode)) | |
| return prompts | |
| def get_history(self) -> List[Dict]: | |
| return self.history | |
| def clear_history(self) -> str: | |
| self.history = [] | |
| return "History cleared" | |
| # Crear instancia del generador | |
| generator = HyperRealisticPromptGenerator() | |
| # JavaScript para copiar al portapapeles | |
| copy_js = """ | |
| function copyToClipboard(text) { | |
| navigator.clipboard.writeText(text).then(function() { | |
| console.log('Text copied to clipboard'); | |
| }).catch(function(err) { | |
| console.error('Could not copy text: ', err); | |
| }); | |
| } | |
| """ | |
| def generate_batch_with_blocks(count, prompt_type, nsfw): | |
| prompts = generator.generate_batch_prompts(count, prompt_type, nsfw) | |
| blocks_html = "" | |
| for i, prompt in enumerate(prompts, 1): | |
| # Escapar comillas dobles para que el string de JavaScript funcione correctamente | |
| escaped_prompt = prompt.replace('"', '\\"') | |
| blocks_html += f""" | |
| <div class="prompt-block"> | |
| <h4>📋 Prompt #{i}:</h4> | |
| <textarea id="prompt-{i}" style="width: 100%; height: 150px; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-family: monospace; margin-bottom: 10px;" readonly>{prompt}</textarea> | |
| <button class="copy-btn" onclick="copyToClipboard(`{escaped_prompt}`)">📋 Copy Prompt #{i}</button> | |
| </div> | |
| """ | |
| return prompts, blocks_html | |
| def export_history(): | |
| history = generator.get_history() | |
| if not history: | |
| return "No history to export" | |
| filename = f"prompt_history_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.json" | |
| # Guardar en un archivo temporal para que Gradio lo pueda devolver | |
| temp_path = f"/tmp/{filename}" | |
| with open(temp_path, 'w', encoding='utf-8') as f: | |
| json.dump(history, f, indent=2, ensure_ascii=False) | |
| # Devolver el archivo para descarga. Gradio maneja esto automáticamente si se devuelve un archivo. | |
| # Sin embargo, la función de Gradio debe estar diseñada para devolver un gr.File. | |
| # Como la función original devuelve un string, la mantendré así y asumiré que el usuario | |
| # manejará la descarga del archivo generado en el entorno de Gradio. | |
| # Para el despliegue en Hugging Face, el archivo se crea en el directorio del Space. | |
| # Para la prueba local, se puede devolver el path. Para Gradio en HF Spaces, | |
| # es mejor que el usuario acceda al archivo directamente si es necesario. | |
| # Para simplificar y seguir el código original, devolveré un mensaje de estado. | |
| return f"History exported to {filename}. Check the Space's file system." | |
| # Interfaz Gradio | |
| with gr.Blocks(title="HyperRealistic Humanized Perfection Generator", theme=gr.themes.Soft(), css=""" | |
| .prompt-block { | |
| border: 1px solid #e0e0e0; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| background: white; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .copy-btn { | |
| background: #4CAF50; | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| } | |
| .copy-btn:hover { | |
| background: #45a049; | |
| } | |
| .tab-content { | |
| padding: 20px; | |
| } | |
| .generated-prompt { | |
| font-family: monospace; | |
| background: #f8f9fa; | |
| padding: 15px; | |
| border-radius: 8px; | |
| border: 1px solid #e9ecef; | |
| margin: 10px 0; | |
| white-space: pre-wrap; | |
| word-wrap: break-word; | |
| } | |
| """) as demo: | |
| gr.Markdown("# 🌟 HyperRealistic Humanized Perfection Generator") | |
| gr.Markdown("Generate ultra-realistic humanized prompts with perfect lace details in 9:16 vertical format") | |
| # Inyectar JavaScript | |
| gr.HTML(f"<script>{copy_js}</script>") | |
| with gr.Tab("👔 Professional Roles"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| role_ethnicity = gr.Dropdown( | |
| choices=generator.config.ETHNICITIES, | |
| label="🎭 Ethnicity", | |
| value="Mediterranean", | |
| interactive=True | |
| ) | |
| role_selection = gr.Dropdown( | |
| choices=[role["role"] for role in generator.config.PROFESSIONAL_ROLES], | |
| label="💼 Professional Role", | |
| value=generator.config.PROFESSIONAL_ROLES[0]["role"], | |
| interactive=True | |
| ) | |
| role_nsfw = gr.Checkbox( | |
| label="🎨 Artistic NSFW Mode", | |
| value=False, | |
| info="Enable for more artistic sensuality" | |
| ) | |
| generate_role_btn = gr.Button( | |
| "✨ Generate Role Prompt", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=2): | |
| role_output = gr.Textbox( | |
| label="📝 Generated Prompt", | |
| lines=6, | |
| max_lines=10, | |
| show_copy_button=True | |
| ) | |
| role_prompt_block = gr.HTML(label="Prompt Block") | |
| # Uso de .then() para actualizar el bloque HTML después de generar el prompt | |
| def update_role_prompt_block(prompt): | |
| # Escapar comillas dobles para el string de JavaScript | |
| escaped_prompt = prompt.replace('"', '\\"') | |
| return f""" | |
| <div class="prompt-block"> | |
| <h4>📋 Prompt Ready to Copy:</h4> | |
| <div class="generated-prompt">{prompt}</div> | |
| <button class="copy-btn" onclick="copyToClipboard(`{escaped_prompt}`)">📋 Copy Prompt</button> | |
| </div> | |
| """ | |
| generate_role_btn.click( | |
| fn=generator.generate_role_prompt, | |
| inputs=[role_ethnicity, role_selection, role_nsfw], | |
| outputs=[role_output] | |
| ).then( | |
| fn=update_role_prompt_block, | |
| inputs=[role_output], | |
| outputs=[role_prompt_block] | |
| ) | |
| with gr.Tab("🏠 Everyday Moments"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| moment_ethnicity = gr.Dropdown( | |
| choices=generator.config.ETHNICITIES, | |
| label="🎭 Ethnicity", | |
| value="Latin American", | |
| interactive=True | |
| ) | |
| moment_selection = gr.Dropdown( | |
| choices=[moment["scene"] for moment in generator.config.EVERYDAY_MOMENTS], | |
| label="🌅 Daily Moment", | |
| value=generator.config.EVERYDAY_MOMENTS[0]["scene"], | |
| interactive=True | |
| ) | |
| moment_nsfw = gr.Checkbox( | |
| label="🎨 Artistic NSFW Mode", | |
| value=False, | |
| info="Enable for more artistic sensuality" | |
| ) | |
| generate_moment_btn = gr.Button( | |
| "✨ Generate Moment Prompt", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=2): | |
| moment_output = gr.Textbox( | |
| label="📝 Generated Prompt", | |
| lines=6, | |
| max_lines=10, | |
| show_copy_button=True | |
| ) | |
| moment_prompt_block = gr.HTML(label="Prompt Block") | |
| # Uso de .then() para actualizar el bloque HTML después de generar el prompt | |
| def update_moment_prompt_block(prompt): | |
| # Escapar comillas dobles para el string de JavaScript | |
| escaped_prompt = prompt.replace('"', '\\"') | |
| return f""" | |
| <div class="prompt-block"> | |
| <h4>📋 Prompt Ready to Copy:</h4> | |
| <div class="generated-prompt">{prompt}</div> | |
| <button class="copy-btn" onclick="copyToClipboard(`{escaped_prompt}`)">📋 Copy Prompt</button> | |
| </div> | |
| """ | |
| generate_moment_btn.click( | |
| fn=generator.generate_moment_prompt, | |
| inputs=[moment_ethnicity, moment_selection, moment_nsfw], | |
| outputs=[moment_output] | |
| ).then( | |
| fn=update_moment_prompt_block, | |
| inputs=[moment_output], | |
| outputs=[moment_prompt_block] | |
| ) | |
| with gr.Tab("🔄 Batch Generator"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| batch_count = gr.Slider( | |
| minimum=1, | |
| maximum=10, | |
| value=3, | |
| step=1, | |
| label="Number of Prompts" | |
| ) | |
| batch_type = gr.Radio( | |
| choices=["roles", "moments"], | |
| label="Prompt Type", | |
| value="roles", | |
| interactive=True | |
| ) | |
| batch_nsfw = gr.Checkbox( | |
| label="🎨 Artistic NSFW Mode", | |
| value=False | |
| ) | |
| generate_batch_btn = gr.Button( | |
| "🔄 Generate Batch", | |
| variant="primary" | |
| ) | |
| with gr.Column(): | |
| batch_output = gr.JSON( | |
| label="📦 Batch Prompts" | |
| ) | |
| batch_prompt_blocks = gr.HTML(label="Batch Prompt Blocks") | |
| generate_batch_btn.click( | |
| fn=generate_batch_with_blocks, | |
| inputs=[batch_count, batch_type, batch_nsfw], | |
| outputs=[batch_output, batch_prompt_blocks] | |
| ) | |
| with gr.Tab("📊 History & Export"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| history_display = gr.JSON( | |
| label="📜 Prompt History", | |
| value=generator.get_history | |
| ) | |
| clear_history_btn = gr.Button( | |
| "🗑️ Clear History", | |
| variant="secondary" | |
| ) | |
| with gr.Column(): | |
| export_btn = gr.Button( | |
| "💾 Export History as JSON", | |
| variant="primary" | |
| ) | |
| export_status = gr.Textbox( | |
| label="Export Status", | |
| interactive=False | |
| ) | |
| clear_history_btn.click( | |
| fn=generator.clear_history, | |
| inputs=[], | |
| outputs=[export_status] | |
| ).then( | |
| fn=generator.get_history, | |
| inputs=[], | |
| outputs=[history_display] | |
| ) | |
| export_btn.click( | |
| fn=export_history, | |
| inputs=[], | |
| outputs=[export_status] | |
| ) | |
| demo.launch() | |