Spaces:
Runtime error
Runtime error
File size: 5,175 Bytes
ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa ec03850 1ed16aa |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
import os, random, re, torch
from typing import List, Tuple
from PIL import Image, ImageDraw, ImageFont
import gradio as gr
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
# =========================
# SPEED PRESET
# =========================
# Use SD Turbo (1.5) – optimized for very few steps on CPU
DEFAULT_MODEL_ID = "stabilityai/sd-turbo"
MODEL_ID = os.getenv("MODEL_ID", DEFAULT_MODEL_ID)
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DTYPE = torch.float16 if torch.cuda.is_available() else torch.float32
# Short NSFW guardrail (block, no blur)
NSFW_TERMS = [
r"\bnsfw\b", r"\bnude\b", r"\bnudity\b", r"\bsex\b", r"\bexplicit\b", r"\bporn\b",
r"\bboobs\b", r"\bbutt\b", r"\bass\b", r"\bnaked\b", r"\btits\b",
r"\b18\+\b", r"\berotic\b", r"\bfetish\b"
]
NSFW_REGEX = re.compile("|".join(NSFW_TERMS), flags=re.IGNORECASE)
def _blocked_tile(reason: str, w=384, h=384) -> Image.Image:
img = Image.new("RGB", (w, h), (18, 20, 26))
d = ImageDraw.Draw(img)
text = f"BLOCKED\n{reason}"
try:
font = ImageFont.truetype("DejaVuSans-Bold.ttf", 26)
except:
font = ImageFont.load_default()
box = d.multiline_textbbox((0,0), text, font=font, align="center")
tw, th = box[2]-box[0], box[3]-box[1]
d.multiline_text(((w-tw)//2, (h-th)//2), text, font=font, fill=(255,255,255), align="center")
return img
def _is_nsfw(s: str) -> bool:
return bool(NSFW_REGEX.search(s or ""))
# -------------------------
# Load pipeline (fast path)
# -------------------------
torch.set_grad_enabled(False)
pipe = StableDiffusionPipeline.from_pretrained(
MODEL_ID,
torch_dtype=DTYPE,
safety_checker=None # let model config handle; we block explicitly on prompts
)
# Turbo still benefits from DPMSolver for CPU
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
if DEVICE == "cuda":
pipe = pipe.to("cuda")
pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
else:
pipe = pipe.to("cpu")
# -------------------------
# Generate fn (kept lean)
# -------------------------
def generate(
prompt: str,
negative_prompt: str,
steps: int,
guidance: float,
width: int,
height: int,
seed: int,
batch_size: int
) -> Tuple[List[Image.Image], str]:
if not prompt.strip():
return [], "Add a prompt first."
# block obvious NSFW prompts
if _is_nsfw(prompt) or _is_nsfw(negative_prompt or ""):
return [_blocked_tile("NSFW prompt detected", width, height)], "Blocked: NSFW prompt."
# SD-Turbo is designed for tiny step counts + low/zero CFG
# guard rails on parameters
steps = max(1, min(int(steps), 12))
guidance = max(0.0, min(float(guidance), 2.0))
# Seed
if seed < 0:
seed = random.randint(0, 2**31 - 1)
generator = torch.Generator(device=DEVICE).manual_seed(seed)
out = pipe(
prompt=prompt,
negative_prompt=(negative_prompt or None),
num_inference_steps=steps,
guidance_scale=guidance,
width=width,
height=height,
num_images_per_prompt=batch_size,
generator=generator
)
imgs = out.images
# Some sd-turbo configs may not return nsfw flags; we already block on prompt
msg = f"Model: {MODEL_ID} • Seed: {seed} • Steps: {steps} • CFG: {guidance} • {width}x{height} • Batch: {batch_size}"
return imgs, msg
# -------------------------
# UI (defaults tuned for CPU)
# -------------------------
with gr.Blocks(title="VibeForge — Fast (CPU-friendly) Image Gen") as demo:
gr.Markdown(
"""
# VibeForge ⚒️
**Fast, clean image generation (CPU-friendly).**
Uses **SD-Turbo** tuned for low steps. NSFW inputs are blocked.
"""
)
with gr.Row():
with gr.Column(scale=3):
prompt = gr.Textbox(
label="Prompt",
placeholder="a neon-lit lighthouse on a stormy cliff at night, cinematic, volumetric fog, high contrast"
)
negative = gr.Textbox(label="Negative Prompt", placeholder="low quality, watermark, overexposed")
with gr.Row():
steps = gr.Slider(1, 12, value=4, step=1, label="Steps (SD-Turbo sweet spot: 2-6)")
guidance = gr.Slider(0.0, 2.0, value=0.5, step=0.1, label="CFG (SD-Turbo likes low)")
with gr.Row():
width = gr.Dropdown(choices=[384, 448, 512], value=384, label="Width")
height = gr.Dropdown(choices=[384, 448, 512], value=384, label="Height")
with gr.Row():
seed = gr.Number(value=-1, label="Seed (-1 = random)", precision=0)
batch = gr.Slider(1, 2, value=1, step=1, label="Batch (keep small on CPU)")
go = gr.Button("Generate", variant="primary")
with gr.Column(scale=5):
gallery = gr.Gallery(label="Output", columns=2, height=448)
info = gr.Markdown()
go.click(
fn=generate,
inputs=[prompt, negative, steps, guidance, width, height, seed, batch],
outputs=[gallery, info]
)
if __name__ == "__main__":
demo.launch()
|