Tanut commited on
Commit
e20d060
·
1 Parent(s): 0eaf945

using ZeroGPU

Browse files
Files changed (3) hide show
  1. README.md +3 -0
  2. app.py +79 -122
  3. requirements.txt +9 -8
README.md CHANGED
@@ -9,6 +9,9 @@ app_file: app.py
9
  pinned: false
10
  license: openrail
11
  short_description: Testing generate Images from Controlnet
 
 
 
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
9
  pinned: false
10
  license: openrail
11
  short_description: Testing generate Images from Controlnet
12
+ preload_from_hub:
13
+ - runwayml/stable-diffusion-v1-5
14
+ - monster-labs/control_v1p_sd15_qrcode_monster
15
  ---
16
 
17
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,137 +1,94 @@
 
1
  import gradio as gr
2
- import torch
3
- from diffusers import StableDiffusionPipeline
4
  from PIL import Image
5
  import qrcode
6
  from qrcode.constants import ERROR_CORRECT_H
7
 
8
- # ========= device/dtype =========
9
- device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
10
- dtype = torch.float16 if device != "cpu" else torch.float32
11
-
12
- # ========= SD 1.5 (prompt-only) =========
13
- sd_pipe = StableDiffusionPipeline.from_pretrained(
14
- "runwayml/stable-diffusion-v1-5",
15
- torch_dtype=dtype
16
- ).to(device)
17
-
18
- def sd_generate(prompt, negative, steps, guidance, seed):
19
- gen = torch.Generator(device=device).manual_seed(int(seed)) if int(seed) != 0 else None
20
- def run():
21
- return sd_pipe(
22
- prompt,
23
- negative_prompt=negative or "",
24
- num_inference_steps=int(steps),
25
- guidance_scale=float(guidance),
26
- generator=gen
27
- ).images[0]
28
- if device in ("cuda", "mps"):
29
- with torch.autocast(device):
30
- return run()
31
- return run()
32
 
33
- # ========= QR Maker =========
34
- def make_qr(url: str = "http://www.mybirdfire.com", size: int = 512, border: int = 4) -> Image.Image:
35
  qr = qrcode.QRCode(
36
  version=None,
37
- error_correction=ERROR_CORRECT_H, # highest EC
38
- box_size=10,
39
- border=border
40
  )
41
- qr.add_data(url.strip())
42
  qr.make(fit=True)
43
- img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
44
- return img.resize((size, size), resample=Image.NEAREST)
45
-
46
- # ========= SD1.5 ControlNet stylizer (canny + tile) =========
47
- from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
48
- from diffusers.schedulers.scheduling_euler_discrete import EulerDiscreteScheduler
49
- from controlnet_aux import CannyDetector
50
-
51
- BASE_15 = "runwayml/stable-diffusion-v1-5"
52
- CN_CANNY_15 = "lllyasviel/sd-controlnet-canny"
53
- CN_TILE_15 = "lllyasviel/control_v11f1e_sd15_tile"
54
-
55
- _cn = {"pipe": None}
56
- def _load_sd15_dual():
57
- if _cn["pipe"] is None:
58
- canny = ControlNetModel.from_pretrained(CN_CANNY_15, torch_dtype=dtype)
59
- tile = ControlNetModel.from_pretrained(CN_TILE_15, torch_dtype=dtype)
60
- pipe = StableDiffusionControlNetPipeline.from_pretrained(
61
- BASE_15, controlnet=[canny, tile], torch_dtype=dtype, safety_checker=None
62
- ).to(device)
63
- pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config) # Sampler: Euler
64
- pipe.enable_attention_slicing()
65
- pipe.enable_vae_slicing()
66
- _cn["pipe"] = pipe
67
- _cn["canny_aux"] = CannyDetector()
68
- return _cn["pipe"], _cn["canny_aux"]
69
-
70
- NEG_DEFAULT = "lowres, low contrast, blurry, jpeg artifacts, worst quality, bad anatomy, extra digits"
71
-
72
- def stylize_qr_sd15(prompt: str, negative: str, steps: int, guidance: float, seed: int,
73
- canny_low: int, canny_high: int, border: int):
74
- # Make fresh QR each time
75
- qr_img = make_qr("http://www.mybirdfire.com", size=512, border=int(border))
76
- pipe, canny = _load_sd15_dual()
77
- edges = canny(qr_img, low_threshold=int(canny_low), high_threshold=int(canny_high))
78
-
79
- gen = torch.Generator(device=device).manual_seed(int(seed)) if int(seed) != 0 else None
80
-
81
- # Control weights (canny, tile). Tune if too “lego” or too artsy.
82
- cn_scales = [1.2, 0.6]
83
-
84
- def run():
85
- return pipe(
86
- prompt=str(prompt),
87
- negative_prompt=negative or NEG_DEFAULT,
88
- image=[edges, qr_img], # canny first, tile second
89
- controlnet_conditioning_scale=cn_scales,
90
- num_inference_steps=int(steps),
91
- guidance_scale=float(guidance),
92
- generator=gen
93
- ).images[0]
94
-
95
- if device in ("cuda", "mps"):
96
- with torch.autocast(device):
97
- return run()
98
- return run()
99
 
100
- # ========= UI =========
101
  with gr.Blocks() as demo:
102
- gr.Markdown("## Stable Diffusion + QR Code + ControlNet (SD1.5)")
103
-
104
- with gr.Tab("Stable Diffusion (prompt → image)"):
105
- prompt = gr.Textbox(label="Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
106
- negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, worst quality")
107
- steps = gr.Slider(10, 50, value=30, label="Steps", step=1)
108
- cfg = gr.Slider(1, 12, value=7.0, label="Guidance Scale", step=0.1)
109
- seed = gr.Number(value=0, label="Seed (0 = random)", precision=0)
110
- out_sd = gr.Image(label="Generated Image")
111
- gr.Button("Generate").click(sd_generate, [prompt, negative, steps, cfg, seed], out_sd)
112
-
113
- with gr.Tab("QR Maker (mybirdfire)"):
114
- url = gr.Textbox(label="URL/Text", value="http://www.mybirdfire.com")
115
- size = gr.Slider(256, 1024, value=512, step=64, label="Size (px)")
116
- quiet = gr.Slider(0, 8, value=4, step=1, label="Border (quiet zone)")
117
- out_qr = gr.Image(label="QR Code", type="pil")
118
- gr.Button("Generate QR").click(make_qr, [url, size, quiet], out_qr)
119
-
120
- with gr.Tab("QR Stylizer (SD1.5 canny + tile, Euler)"):
121
- s_prompt = gr.Textbox(label="Style Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
122
- s_negative = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT)
123
- s_steps = gr.Slider(10, 50, value=28, label="Steps", step=1)
124
- s_cfg = gr.Slider(1, 12, value=7.0, label="CFG", step=0.1)
125
- s_seed = gr.Number(value=1470713301, label="Seed", precision=0)
126
- canny_l = gr.Slider(0, 255, value=80, step=1, label="Canny low")
127
- canny_h = gr.Slider(0, 255, value=160, step=1, label="Canny high")
128
- s_border = gr.Slider(2, 10, value=6, step=1, label="QR border")
129
- out_styl = gr.Image(label="Stylized QR")
130
- gr.Button("Stylize").click(
131
- stylize_qr_sd15,
132
- [s_prompt, s_negative, s_steps, s_cfg, s_seed, canny_l, canny_h, s_border],
133
- out_styl
134
- )
135
 
136
  if __name__ == "__main__":
137
  demo.launch()
 
1
+ import io, random, spaces
2
  import gradio as gr
 
 
3
  from PIL import Image
4
  import qrcode
5
  from qrcode.constants import ERROR_CORRECT_H
6
 
7
+ import torch
8
+ from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, DPMSolverMultistepScheduler
9
+
10
+ SD15 = "runwayml/stable-diffusion-v1-5"
11
+ QR_MONSTER = "monster-labs/control_v1p_sd15_qrcode_monster" # v2 lives in a subfolder
12
+
13
+ # ----- Load models on first GPU call (saves ZeroGPU minutes) -----
14
+ pipe = None
15
+ def get_pipe(dtype=torch.float16):
16
+ global pipe
17
+ if pipe is not None:
18
+ return pipe
19
+ controlnet = ControlNetModel.from_pretrained(
20
+ QR_MONSTER, subfolder="v2", torch_dtype=dtype
21
+ )
22
+ pipe = StableDiffusionControlNetPipeline.from_pretrained(
23
+ SD15, controlnet=controlnet, torch_dtype=dtype, safety_checker=None
24
+ )
25
+ pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
26
+ pipe.enable_model_cpu_offload() # better mem usage on H200 slice
27
+ return pipe
 
 
 
28
 
29
+ def make_qr_img(data: str, module_size: int = 16, border: int = 4) -> Image.Image:
 
30
  qr = qrcode.QRCode(
31
  version=None,
32
+ error_correction=ERROR_CORRECT_H,
33
+ box_size=module_size,
34
+ border=border,
35
  )
36
+ qr.add_data(data)
37
  qr.make(fit=True)
38
+ # Gray background (#808080) improves blend/readability for v2
39
+ img = qr.make_image(fill_color="black", back_color="#808080").convert("RGB")
40
+ return img
41
+
42
+ @spaces.GPU(duration=120)
43
+ def generate(
44
+ qr_text, prompt, negative_prompt, steps, guidance_scale,
45
+ controlnet_scale, width, height, seed
46
+ ):
47
+ pipe = get_pipe()
48
+ if seed is None or seed < 0:
49
+ seed = random.randint(0, 2**31 - 1)
50
+ generator = torch.Generator(device="cuda").manual_seed(seed)
51
+
52
+ control_img = make_qr_img(qr_text, module_size=16, border=4).resize((width, height), Image.NEAREST)
53
+
54
+ out = pipe(
55
+ prompt=prompt,
56
+ negative_prompt=negative_prompt,
57
+ num_inference_steps=steps,
58
+ guidance_scale=guidance_scale,
59
+ controlnet_conditioning_scale=controlnet_scale, # higher => more readable
60
+ image=control_img,
61
+ width=width,
62
+ height=height,
63
+ generator=generator,
64
+ )
65
+ img = out.images[0]
66
+ return img, seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
 
68
  with gr.Blocks() as demo:
69
+ gr.Markdown("# 🧩 QR‑Blended Image (ZeroGPU + ControlNet QR Monster v2)")
70
+
71
+ with gr.Row():
72
+ with gr.Column():
73
+ qr_text = gr.Textbox(label="QR Content (URL or text)", value="https://example.com")
74
+ prompt = gr.Textbox(
75
+ label="Prompt",
76
+ value="a detailed isometric cyberpunk city with neon lights, intricate geometry, depth, high detail, trending artstation"
77
+ )
78
+ negative = gr.Textbox(label="Negative Prompt", value="lowres, blurry, deformed, distorted, extra limbs, watermark, signature")
79
+ steps = gr.Slider(10, 50, value=30, step=1, label="Steps")
80
+ guidance = gr.Slider(1.0, 12.0, value=7.0, step=0.5, label="CFG Scale")
81
+ cn_scale = gr.Slider(0.2, 2.0, value=1.0, step=0.05, label="ControlNet Guidance (↑=more scannable)")
82
+ width = gr.Slider(512, 1024, value=768, step=64, label="Width")
83
+ height = gr.Slider(512, 1024, value=768, step=64, label="Height")
84
+ seed = gr.Number(value=-1, precision=0, label="Seed (-1=random)")
85
+ go = gr.Button("Generate", variant="primary")
86
+ with gr.Column():
87
+ out_img = gr.Image(label="Result", interactive=False)
88
+ out_seed = gr.Number(label="Used Seed", interactive=False)
89
+
90
+ go.click(generate, inputs=[qr_text, prompt, negative, steps, guidance, cn_scale, width, height, seed],
91
+ outputs=[out_img, out_seed])
 
 
 
 
 
 
 
 
 
 
92
 
93
  if __name__ == "__main__":
94
  demo.launch()
requirements.txt CHANGED
@@ -1,10 +1,11 @@
1
- torch
2
- diffusers
3
- transformers
4
- accelerate
5
  safetensors
6
- gradio
 
7
  qrcode[pil]
8
- controlnet-aux
9
- mediapipe
10
- timm
 
1
+ torch==2.4.0
2
+ diffusers>=0.27.2
3
+ transformers>=4.42.0
4
+ accelerate>=0.31.0
5
  safetensors
6
+ xformers
7
+ gradio>=4.29.0
8
  qrcode[pil]
9
+ Pillow
10
+ huggingface-hub
11
+ spaces