Spaces:
Running
on
Zero
Running
on
Zero
File size: 7,692 Bytes
19c2aa1 1fc8d06 19c2aa1 d25b42d 184daa2 e20d060 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b e20d060 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 6ae079b 19c2aa1 56a99b7 19c2aa1 6ae079b 3315876 56a99b7 a2495ec 19c2aa1 a2495ec |
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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
import os, gc, random
import gradio as gr
import numpy as np
from PIL import Image
import qrcode
from qrcode.constants import ERROR_CORRECT_H
import torch
import spaces # <- ZeroGPU decorator
from diffusers import (
StableDiffusionPipeline,
StableDiffusionControlNetPipeline,
ControlNetModel,
)
from diffusers.schedulers.scheduling_euler_discrete import EulerDiscreteScheduler
from controlnet_aux import CannyDetector
# -----------------------------
# Versions / env
# -----------------------------
TORCH_DTYPE = torch.float16 # Spaces GPU slice supports fp16 well
# Optional (private models): set HF_TOKEN in Space secrets
HF_TOKEN = os.getenv("HF_TOKEN")
AUTH = {"token": HF_TOKEN} if HF_TOKEN else {}
# -----------------------------
# Global caches (lazy)
# -----------------------------
_sd_txt = {"pipe": None}
_sd_cn = {"pipe": None, "canny": None}
BASE_15 = "runwayml/stable-diffusion-v1-5"
CN_CANNY_15 = "lllyasviel/sd-controlnet-canny"
CN_TILE_15 = "lllyasviel/control_v11f1e_sd15_tile"
NEG_DEFAULT = "lowres, low contrast, blurry, jpeg artifacts, worst quality, bad anatomy, extra digits"
# -----------------------------
# QR maker (unchanged behavior)
# -----------------------------
def make_qr(url: str = "http://www.mybirdfire.com", size: int = 512, border: int = 4) -> Image.Image:
qr = qrcode.QRCode(version=None, error_correction=ERROR_CORRECT_H, box_size=10, border=int(border))
qr.add_data(url.strip())
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
return img.resize((int(size), int(size)), resample=Image.NEAREST)
# -----------------------------
# Lazy loaders (Spaces-safe)
# -----------------------------
def _get_sd15_txt2img():
if _sd_txt["pipe"] is None:
pipe = StableDiffusionPipeline.from_pretrained(
BASE_15,
torch_dtype=TORCH_DTYPE,
safety_checker=None,
use_safetensors=True,
low_cpu_mem_usage=True,
**AUTH
)
# Memory savers β ok to call before GPU is attached
pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
pipe.enable_model_cpu_offload()
_sd_txt["pipe"] = pipe
return _sd_txt["pipe"]
def _get_sd15_canny_tile():
if _sd_cn["pipe"] is None:
canny = ControlNetModel.from_pretrained(CN_CANNY_15, torch_dtype=TORCH_DTYPE, use_safetensors=True, **AUTH)
tile = ControlNetModel.from_pretrained(CN_TILE_15, torch_dtype=TORCH_DTYPE, use_safetensors=True, **AUTH)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
BASE_15,
controlnet=[canny, tile],
torch_dtype=TORCH_DTYPE,
safety_checker=None,
use_safetensors=True,
low_cpu_mem_usage=True,
**AUTH
)
pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config)
pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
pipe.enable_model_cpu_offload()
_sd_cn["pipe"] = pipe
_sd_cn["canny"] = CannyDetector()
return _sd_cn["pipe"], _sd_cn["canny"]
# -----------------------------
# SD 1.5 (prompt-only)
# -----------------------------
@spaces.GPU(duration=120)
def sd_generate(prompt, negative, steps, guidance, seed):
pipe = _get_sd15_txt2img()
# Reproducible generator on CUDA (available during @GPU call)
g = torch.Generator(device="cuda")
g = g.manual_seed(int(seed)) if int(seed) != 0 else g.manual_seed(random.randint(0, 2**31 - 1))
if torch.cuda.is_available():
torch.cuda.empty_cache()
gc.collect()
with torch.autocast(device_type="cuda", dtype=TORCH_DTYPE):
out = pipe(
prompt=str(prompt),
negative_prompt=(negative or ""),
num_inference_steps=int(steps),
guidance_scale=float(guidance),
generator=g
)
return out.images[0]
# -----------------------------
# Stylizer (SD1.5 + ControlNet canny + tile)
# -----------------------------
@spaces.GPU(duration=180)
def stylize_qr_sd15(prompt: str, negative: str, steps: int, guidance: float, seed: int,
canny_low: int, canny_high: int, border: int):
pipe, canny = _get_sd15_canny_tile()
# Fresh QR β edges
qr_img = make_qr("http://www.mybirdfire.com", size=512, border=int(border))
edges = canny(qr_img, low_threshold=int(canny_low), high_threshold=int(canny_high))
# Control weights (canny, tile). Tune to taste.
cn_scales = [1.2, 0.6]
g = torch.Generator(device="cuda")
g = g.manual_seed(int(seed)) if int(seed) != 0 else g.manual_seed(random.randint(0, 2**31 - 1))
if torch.cuda.is_available():
torch.cuda.empty_cache()
gc.collect()
with torch.autocast(device_type="cuda", dtype=TORCH_DTYPE):
out = pipe(
prompt=str(prompt),
negative_prompt=(negative or NEG_DEFAULT),
image=[edges, qr_img], # txt2img ControlNet: control images
controlnet_conditioning_scale=cn_scales,
num_inference_steps=int(steps),
guidance_scale=float(guidance),
generator=g
)
return out.images[0]
# -----------------------------
# UI (same layout as yours)
# -----------------------------
with gr.Blocks() as demo:
gr.Markdown("## Stable Diffusion + QR Code + ControlNet (SD1.5) β ZeroGPU")
with gr.Tab("Stable Diffusion (prompt β image)"):
prompt = gr.Textbox(label="Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, worst quality")
steps = gr.Slider(10, 50, value=30, label="Steps", step=1)
cfg = gr.Slider(1, 12, value=7.0, label="Guidance Scale", step=0.1)
seed = gr.Number(value=0, label="Seed (0 = random)", precision=0)
out_sd = gr.Image(label="Generated Image")
gr.Button("Generate").click(sd_generate, [prompt, negative, steps, cfg, seed], out_sd)
with gr.Tab("QR Maker (mybirdfire)"):
url = gr.Textbox(label="URL/Text", value="http://www.mybirdfire.com")
size = gr.Slider(256, 1024, value=512, step=64, label="Size (px)")
quiet = gr.Slider(0, 8, value=4, step=1, label="Border (quiet zone)")
out_qr = gr.Image(label="QR Code", type="pil")
gr.Button("Generate QR").click(make_qr, [url, size, quiet], out_qr)
with gr.Tab("QR Stylizer (SD1.5 canny + tile, Euler)"):
s_prompt = gr.Textbox(label="Style Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
s_negative = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT)
s_steps = gr.Slider(10, 50, value=28, label="Steps", step=1)
s_cfg = gr.Slider(1, 12, value=7.0, label="CFG", step=0.1)
s_seed = gr.Number(value=1470713301, label="Seed", precision=0)
canny_l = gr.Slider(0, 255, value=80, step=1, label="Canny low")
canny_h = gr.Slider(0, 255, value=160, step=1, label="Canny high")
s_border = gr.Slider(2, 10, value=6, step=1, label="QR border")
out_styl = gr.Image(label="Stylized QR")
gr.Button("Stylize").click(
stylize_qr_sd15,
[s_prompt, s_negative, s_steps, s_cfg, s_seed, canny_l, canny_h, s_border],
out_styl
)
if __name__ == "__main__":
demo.queue(max_size=12).launch(
server_name="0.0.0.0",
server_port=7860,
share=True,
show_api=True,
analytics_enabled=False
)
|