Spaces:
Running
Running
| import gradio as gr | |
| import torch | |
| from PIL import Image, ImageOps | |
| from diffusers import StableDiffusionXLImg2ImgPipeline | |
| import re | |
| model_id = "Lustify/Lustify-XL-v2" | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| dtype = torch.float16 if device == "cuda" else torch.float32 | |
| pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained( | |
| model_id, | |
| torch_dtype=dtype, | |
| use_safetensors=True, | |
| variant="fp16" | |
| ) | |
| pipe = pipe.to(device) | |
| pipe.enable_attention_slicing() | |
| if device == "cuda": | |
| pipe.enable_vae_slicing() | |
| def safe_filename(text: str, max_len: int = 80) -> str: | |
| text = text.strip() | |
| text = re.sub(r"[^\w\s.-]", "", text, flags=re.UNICODE) | |
| text = re.sub(r"\s+", "_", text) | |
| text = text.strip("._-") | |
| return (text or "edited")[:max_len] | |
| def generate(image, prompt, negative_prompt, strength, guidance_scale, steps): | |
| if image is None: | |
| return None, "Please upload an input image." | |
| if not prompt or not prompt.strip(): | |
| return None, "Please enter a positive prompt." | |
| init_image = ImageOps.exif_transpose(image).convert("RGB") | |
| init_image.thumbnail((1024, 1024), Image.Resampling.LANCZOS) | |
| progress = gr.Progress() | |
| def callback(step, timestep, latents): | |
| progress((steps - step) / steps, desc=f"Generating... Step {step}/{steps}") | |
| if not negative_prompt or not negative_prompt.strip(): | |
| negative_prompt = "blurry, low quality, worst quality, text, watermark, signature, logo, censored, bar, mosaic, deformed, ugly, bad anatomy, extra limbs, fused fingers, mutated hands, clothed, underwear, bra, panties, bikini" | |
| with torch.inference_mode(): | |
| result = pipe( | |
| prompt=prompt, | |
| negative_prompt=negative_prompt, | |
| image=init_image, | |
| strength=strength, | |
| guidance_scale=guidance_scale, | |
| num_inference_steps=int(steps), | |
| callback=callback, | |
| callback_steps=1 | |
| ) | |
| output_image = result.images[0] | |
| safe_prompt = safe_filename(prompt) | |
| output_path = f"/tmp/{safe_prompt[:60]}.png" | |
| output_image.save(output_path) | |
| status = f"✅ Generation complete! | Strength: {strength} | Steps: {steps}" | |
| return output_image, status | |
| demo = gr.Interface( | |
| fn=generate, | |
| inputs=[ | |
| gr.Image(type="pil", label="Input Image", sources=["upload"]), | |
| gr.Textbox(lines=3, placeholder="masterpiece, best quality, ultra realistic, 8k, raw photo, perfect face, beautiful detailed eyes, sharp focus, (completely nude:1.4), detailed skin texture, realistic body proportions, sensual pose, explicit nsfw, cinematic lighting", | |
| label="Positive Prompt", value=""), | |
| gr.Textbox(lines=2, placeholder="Leave empty for default negative prompt", | |
| label="Negative Prompt"), | |
| gr.Slider(0.1, 0.95, value=0.52, step=0.05, label="Strength (lower = better face & background fidelity)"), | |
| gr.Slider(1.0, 15.0, value=7.8, step=0.5, label="Guidance Scale"), | |
| gr.Slider(10, 50, value=36, step=1, label="Inference Steps") | |
| ], | |
| outputs=[ | |
| gr.Image(type="pil", label="Generated Image"), | |
| gr.Textbox(label="Status") | |
| ], | |
| title="Lustify XL v2 - Realistic NSFW Img2Img", | |
| description="Strong realistic NSFW model (Wan-style realism focus). Best for nude edits while preserving face and background. Use lower strength for better identity match.", | |
| flagging_mode="never", | |
| cache_examples=False | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |