Yankkee commited on
Commit
18c998c
·
verified ·
1 Parent(s): 554e0b3

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +14 -8
  2. app.py +141 -0
  3. controlnet_zerogpu_space.zip +3 -0
  4. requirements.txt +8 -0
README.md CHANGED
@@ -1,14 +1,20 @@
1
  ---
2
- title: Controllnet SDLX
3
- emoji: 📈
4
- colorFrom: blue
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
- short_description: Controllnet_SDLX
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: ControlNet SDXL Canny
3
+ emoji: 🔥
4
+ colorFrom: yellow
5
+ colorTo: red
6
  sdk: gradio
7
+ sdk_version: 5.28.0
 
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
+ # ControlNet · SDXL Canny (ZeroGPU)
13
+
14
+ Hochwertige Bildgenerierung mit SDXL + xinsir Canny ControlNet, läuft auf ZeroGPU.
15
+
16
+ ## Wichtig: Hardware in Settings auf "ZeroGPU" stellen
17
+ Dieser Space ist für ZeroGPU gebaut (benötigt einen Pro-Account oder eine
18
+ ZeroGPU-fähige Org). In den Space-Settings unter "Hardware" -> ZeroGPU wählen.
19
+
20
+ Der @spaces.GPU Decorator im Code weist die GPU nur während der Generierung zu.
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import gradio as gr
3
+ import torch
4
+ import numpy as np
5
+ from PIL import Image
6
+ import cv2
7
+ from diffusers import (
8
+ StableDiffusionXLControlNetPipeline,
9
+ ControlNetModel,
10
+ AutoencoderKL,
11
+ EulerAncestralDiscreteScheduler,
12
+ )
13
+
14
+ DTYPE = torch.float16
15
+
16
+ # ---------------------------------------------------------------------------
17
+ # Model loading (runs once on startup, stays on GPU via ZeroGPU)
18
+ # ---------------------------------------------------------------------------
19
+ controlnet = ControlNetModel.from_pretrained(
20
+ "xinsir/controlnet-canny-sdxl-1.0",
21
+ torch_dtype=DTYPE,
22
+ )
23
+ vae = AutoencoderKL.from_pretrained(
24
+ "madebyollin/sdxl-vae-fp16-fix",
25
+ torch_dtype=DTYPE,
26
+ )
27
+ pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
28
+ "stabilityai/stable-diffusion-xl-base-1.0",
29
+ controlnet=controlnet,
30
+ vae=vae,
31
+ torch_dtype=DTYPE,
32
+ safety_checker=None,
33
+ )
34
+ pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
35
+ pipe = pipe.to("cuda")
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # Helper: extract Canny edges (resized to ~1024 for best SDXL performance)
39
+ # ---------------------------------------------------------------------------
40
+ def extract_canny(image: Image.Image, low: int, high: int):
41
+ img = np.array(image.convert("RGB"))
42
+ h, w, _ = img.shape
43
+ ratio = np.sqrt(1024.0 * 1024.0 / (w * h))
44
+ new_w, new_h = int(w * ratio), int(h * ratio)
45
+ img = cv2.resize(img, (new_w, new_h))
46
+ edges = cv2.Canny(img, low, high)
47
+ edges = np.concatenate([edges[:, :, None]] * 3, axis=2)
48
+ return Image.fromarray(edges), new_w, new_h
49
+
50
+ # ---------------------------------------------------------------------------
51
+ # Main generation function — @spaces.GPU activates ZeroGPU during the call
52
+ # ---------------------------------------------------------------------------
53
+ @spaces.GPU(duration=90)
54
+ def generate(input_image, prompt, negative_prompt, canny_low, canny_high,
55
+ guidance_scale, steps, cn_scale, seed):
56
+ if input_image is None:
57
+ raise gr.Error("Bitte lade ein Bild hoch.")
58
+ if not prompt.strip():
59
+ raise gr.Error("Bitte gib einen Prompt ein.")
60
+
61
+ pil_image = Image.fromarray(input_image)
62
+ control_image, new_w, new_h = extract_canny(pil_image, int(canny_low), int(canny_high))
63
+
64
+ generator = torch.manual_seed(int(seed)) if seed >= 0 else None
65
+
66
+ result = pipe(
67
+ prompt=prompt,
68
+ negative_prompt=negative_prompt or None,
69
+ image=control_image,
70
+ controlnet_conditioning_scale=float(cn_scale),
71
+ num_inference_steps=int(steps),
72
+ guidance_scale=float(guidance_scale),
73
+ width=new_w,
74
+ height=new_h,
75
+ generator=generator,
76
+ ).images[0]
77
+
78
+ return control_image, result
79
+
80
+ # ---------------------------------------------------------------------------
81
+ # Gradio UI
82
+ # ---------------------------------------------------------------------------
83
+ css = """
84
+ body { font-family: 'Inter', sans-serif; background: #0f0f11; color: #e8e8f0; }
85
+ .gradio-container { max-width: 1100px; margin: 0 auto; }
86
+ #title { text-align: center; padding: 2rem 0 0.5rem; }
87
+ #title h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.5px;
88
+ background: linear-gradient(90deg, #f59e0b, #ef4444);
89
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
90
+ #title p { color: #9090a8; font-size: 0.95rem; margin-top: 0.25rem; }
91
+ .panel { background: #1a1a22; border: 1px solid #2a2a38; border-radius: 12px; padding: 1.25rem; }
92
+ .generate-btn { background: linear-gradient(135deg, #f59e0b, #ef4444) !important;
93
+ color: white !important; border: none !important;
94
+ font-weight: 600 !important; font-size: 1rem !important;
95
+ border-radius: 8px !important; height: 48px !important; }
96
+ .generate-btn:hover { opacity: 0.9 !important; }
97
+ """
98
+
99
+ with gr.Blocks(css=css, title="ControlNet SDXL Canny") as demo:
100
+ gr.HTML("""
101
+ <div id="title">
102
+ <h1>🔥 ControlNet · SDXL Canny</h1>
103
+ <p>Hochwertige Bildgenerierung mit SDXL auf ZeroGPU. Lade ein Bild hoch, schreib einen Prompt – die Struktur deines Originals bleibt erhalten.</p>
104
+ </div>
105
+ """)
106
+
107
+ with gr.Row():
108
+ with gr.Column(scale=1, elem_classes="panel"):
109
+ gr.Markdown("### 📥 Eingabe")
110
+ input_image = gr.Image(label="Referenzbild", type="numpy", height=300)
111
+ prompt = gr.Textbox(label="Prompt", lines=3,
112
+ placeholder="a rugged pirate on a wooden ship, photorealistic, cinematic, 8k")
113
+ negative_prompt = gr.Textbox(label="Negative Prompt (optional)", lines=2,
114
+ placeholder="blurry, low quality, deformed, extra limbs")
115
+
116
+ with gr.Accordion("⚙️ Erweiterte Einstellungen", open=False):
117
+ with gr.Row():
118
+ canny_low = gr.Slider(0, 255, value=100, step=1, label="Canny Low")
119
+ canny_high = gr.Slider(0, 255, value=200, step=1, label="Canny High")
120
+ with gr.Row():
121
+ guidance_scale = gr.Slider(1, 15, value=6.0, step=0.5, label="Guidance Scale")
122
+ steps = gr.Slider(15, 50, value=30, step=1, label="Inference Steps")
123
+ cn_scale = gr.Slider(0.1, 2.0, value=0.8, step=0.05,
124
+ label="ControlNet Stärke (niedriger = mehr Freiheit)")
125
+ seed = gr.Number(value=42, label="Seed (-1 = zufällig)", precision=0)
126
+
127
+ run_btn = gr.Button("🎨 Generieren", elem_classes="generate-btn")
128
+
129
+ with gr.Column(scale=1, elem_classes="panel"):
130
+ gr.Markdown("### 📤 Ergebnis")
131
+ canny_out = gr.Image(label="Canny-Kantenbild", height=250)
132
+ result_out = gr.Image(label="Generiertes Bild", height=400)
133
+
134
+ run_btn.click(
135
+ fn=generate,
136
+ inputs=[input_image, prompt, negative_prompt, canny_low, canny_high,
137
+ guidance_scale, steps, cn_scale, seed],
138
+ outputs=[canny_out, result_out],
139
+ )
140
+
141
+ demo.queue().launch()
controlnet_zerogpu_space.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:28e58f133d78916497255fb34300bd2b09b667b4ae40b524c8c5fbe6a3f3f700
3
+ size 3526
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ diffusers
4
+ transformers
5
+ accelerate
6
+ opencv-python-headless
7
+ Pillow
8
+ numpy