ImageToImageSus / lustify.py
Dalmanski
Initial commit
8e6ccba
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()