Deadmon commited on
Commit
ecbea96
·
verified ·
1 Parent(s): 98ab739

Create appc.py

Browse files
Files changed (1) hide show
  1. appc.py +306 -0
appc.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import spaces
4
+ import gradio as gr
5
+ import numpy as np
6
+ import PIL.Image
7
+ import torch
8
+ import torchvision.transforms.functional as TF
9
+ from compel import Compel
10
+
11
+ from diffusers import ControlNetModel, StableDiffusionXLControlNetPipeline, AutoencoderKL
12
+ from diffusers import DDIMScheduler, EulerAncestralDiscreteScheduler
13
+ from controlnet_aux import PidiNetDetector, HEDdetector
14
+ from diffusers.utils import load_image
15
+ from huggingface_hub import HfApi, snapshot_download
16
+ from pathlib import Path
17
+ from PIL import Image, ImageOps
18
+ import cv2
19
+ from gradio_imageslider import ImageSlider
20
+
21
+ js_func = """
22
+ function refresh() {
23
+ const url = new URL(window.location);
24
+ }
25
+ """
26
+
27
+ def nms(x, t, s):
28
+ x = cv2.GaussianBlur(x.astype(np.float32), (0, 0), s)
29
+
30
+ f1 = np.array([[0, 0, 0], [1, 1, 1], [0, 0, 0]], dtype=np.uint8)
31
+ f2 = np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]], dtype=np.uint8)
32
+ f3 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.uint8)
33
+ f4 = np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]], dtype=np.uint8)
34
+
35
+ y = np.zeros_like(x)
36
+
37
+ for f in [f1, f2, f3, f4]:
38
+ np.putmask(y, cv2.dilate(x, kernel=f) == x, x)
39
+
40
+ z = np.zeros_like(y, dtype=np.uint8)
41
+ z[y > t] = 255
42
+ return z
43
+
44
+ def HWC3(x):
45
+ assert x.dtype == np.uint8
46
+ if x.ndim == 2:
47
+ x = x[:, :, None]
48
+ assert x.ndim == 3
49
+ H, W, C = x.shape
50
+ assert C == 1 or C == 3 or C == 4
51
+ if C == 3:
52
+ return x
53
+ if C == 1:
54
+ return np.concatenate([x, x, x], axis=2)
55
+ if C == 4:
56
+ color = x[:, :, 0:3].astype(np.float32)
57
+ alpha = x[:, :, 3:4].astype(np.float32) / 255.0
58
+ y = color * alpha + 255.0 * (1.0 - alpha)
59
+ y = y.clip(0, 255).astype(np.uint8)
60
+ return y
61
+
62
+ DESCRIPTION = ''
63
+
64
+ if not torch.cuda.is_available():
65
+ DESCRIPTION += ""
66
+
67
+ style_list = [
68
+ {
69
+ "name": "(No style)",
70
+ "prompt": "{prompt}",
71
+ "negative_prompt": "longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality",
72
+ },
73
+ {
74
+ "name": "Cinematic",
75
+ "prompt": "cinematic still {prompt} . emotional, harmonious, vignette, highly detailed, high budget, bokeh, cinemascope, moody, epic, gorgeous, film grain, grainy",
76
+ "negative_prompt": "anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured",
77
+ },
78
+ # ... other styles ...
79
+ ]
80
+
81
+ styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list}
82
+ STYLE_NAMES = list(styles.keys())
83
+ DEFAULT_STYLE_NAME = "(No style)"
84
+
85
+ def apply_style(style_name: str, positive: str, negative: str = "") -> tuple[str, str]:
86
+ p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME])
87
+ return p.replace("{prompt}", positive), n + negative
88
+
89
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
90
+
91
+ eulera_scheduler = EulerAncestralDiscreteScheduler.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", subfolder="scheduler")
92
+
93
+ # Download the model files
94
+ ckpt_dir_pony = snapshot_download(repo_id="John6666/pony-realism-v21main-sdxl")
95
+ ckpt_dir_cyber = snapshot_download(repo_id="John6666/cyberrealistic-pony-v61-sdxl")
96
+ ckpt_dir_stallion = snapshot_download(repo_id="John6666/stallion-dreams-pony-realistic-v1-sdxl")
97
+
98
+ # Load the models
99
+ vae_pony = AutoencoderKL.from_pretrained(os.path.join(ckpt_dir_pony, "vae"), torch_dtype=torch.float16)
100
+ vae_cyber = AutoencoderKL.from_pretrained(os.path.join(ckpt_dir_cyber, "vae"), torch_dtype=torch.float16)
101
+ vae_stallion = AutoencoderKL.from_pretrained(os.path.join(ckpt_dir_stallion, "vae"), torch_dtype=torch.float16)
102
+
103
+ controlnet_pony = ControlNetModel.from_pretrained("xinsir/controlnet-union-sdxl-1.0", torch_dtype=torch.float16)
104
+ controlnet_cyber = ControlNetModel.from_pretrained("xinsir/controlnet-union-sdxl-1.0", torch_dtype=torch.float16)
105
+ controlnet_stallion = ControlNetModel.from_pretrained("xinsir/controlnet-union-sdxl-1.0", torch_dtype=torch.float16)
106
+
107
+ pipe_pony = StableDiffusionXLControlNetPipeline.from_pretrained(
108
+ ckpt_dir_pony, controlnet=controlnet_pony, vae=vae_pony, torch_dtype=torch.float16, scheduler=eulera_scheduler
109
+ )
110
+ pipe_cyber = StableDiffusionXLControlNetPipeline.from_pretrained(
111
+ ckpt_dir_cyber, controlnet=controlnet_cyber, vae=vae_cyber, torch_dtype=torch.float16, scheduler=eulera_scheduler
112
+ )
113
+ pipe_stallion = StableDiffusionXLControlNetPipeline.from_pretrained(
114
+ ckpt_dir_stallion, controlnet=controlnet_stallion, vae=vae_stallion, torch_dtype=torch.float16, scheduler=eulera_scheduler
115
+ )
116
+
117
+ MAX_SEED = np.iinfo(np.int32).max
118
+ processor = HEDdetector.from_pretrained('lllyasviel/Annotators')
119
+ compel_processor = Compel(tokenizer=pipe_pony.tokenizer, truncate_long_prompts=True)
120
+
121
+ def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
122
+ if randomize_seed:
123
+ seed = random.randint(0, MAX_SEED)
124
+ return seed
125
+
126
+ @spaces.GPU(duration=120)
127
+ def run(
128
+ image: dict,
129
+ prompt: str,
130
+ negative_prompt: str,
131
+ model_choice: str, # Add this new input
132
+ style_name: str = DEFAULT_STYLE_NAME,
133
+ num_steps: int = 25,
134
+ guidance_scale: float = 5,
135
+ controlnet_conditioning_scale: float = 1.0,
136
+ seed: int = 0,
137
+ use_hed: bool = False,
138
+ use_canny: bool = False,
139
+ progress=gr.Progress(track_tqdm=True),
140
+ ) -> PIL.Image.Image:
141
+ # Get the composite image from the EditorValue dict
142
+ composite_image = image['composite']
143
+ width, height = composite_image.size
144
+
145
+ # Calculate new dimensions to fit within 1024x1024 while maintaining aspect ratio
146
+ max_size = 1024
147
+ ratio = min(max_size / width, max_size / height)
148
+ new_width = int(width * ratio)
149
+ new_height = int(height * ratio)
150
+
151
+ # Resize the image
152
+ resized_image = composite_image.resize((new_width, new_height), Image.LANCZOS)
153
+
154
+ if use_canny:
155
+ controlnet_img = np.array(resized_image)
156
+ controlnet_img = cv2.Canny(controlnet_img, 100, 200)
157
+ controlnet_img = HWC3(controlnet_img)
158
+ image = Image.fromarray(controlnet_img)
159
+ elif not use_hed:
160
+ controlnet_img = resized_image
161
+ image = resized_image
162
+ else:
163
+ controlnet_img = processor(resized_image, scribble=False)
164
+ controlnet_img = np.array(controlnet_img)
165
+ controlnet_img = nms(controlnet_img, 127, 3)
166
+ controlnet_img = cv2.GaussianBlur(controlnet_img, (0, 0), 3)
167
+ random_val = int(round(random.uniform(0.01, 0.10), 2) * 255)
168
+ controlnet_img[controlnet_img > random_val] = 255
169
+ controlnet_img[controlnet_img < 255] = 0
170
+ image = Image.fromarray(controlnet_img)
171
+
172
+ prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
173
+
174
+ # Preprocess the prompt using compel
175
+ prompt_embeds = compel_processor(prompt)
176
+ negative_prompt_embeds = compel_processor(negative_prompt)
177
+
178
+ generator = torch.Generator(device=device).manual_seed(seed)
179
+
180
+ # Select the appropriate pipe based on the model choice
181
+ if model_choice == "Pony Realism v21":
182
+ pipe = pipe_pony
183
+ elif model_choice == "Cyber Realistic Pony v61":
184
+ pipe = pipe_cyber
185
+ else: # "Stallion Dreams Pony Realistic v1"
186
+ pipe = pipe_stallion
187
+
188
+ pipe.to(device)
189
+
190
+ if use_canny:
191
+ out = pipe(
192
+ prompt_embeds=prompt_embeds,
193
+ negative_prompt_embeds=negative_prompt_embeds,
194
+ image=image,
195
+ num_inference_steps=num_steps,
196
+ generator=generator,
197
+ controlnet_conditioning_scale=controlnet_conditioning_scale,
198
+ guidance_scale=guidance_scale,
199
+ width=new_width,
200
+ height=new_height,
201
+ ).images[0]
202
+ else:
203
+ out = pipe(
204
+ prompt_embeds=prompt_embeds,
205
+ negative_prompt_embeds=negative_prompt_embeds,
206
+ image=image,
207
+ num_inference_steps=num_steps,
208
+ generator=generator,
209
+ controlnet_conditioning_scale=controlnet_conditioning_scale,
210
+ guidance_scale=guidance_scale,
211
+ width=new_width,
212
+ height=new_height,
213
+ ).images[0]
214
+
215
+ pipe.to("cpu")
216
+ torch.cuda.empty_cache()
217
+
218
+ return (controlnet_img, out)
219
+
220
+ with gr.Blocks(css="style.css", js=js_func) as demo:
221
+ gr.Markdown(DESCRIPTION, elem_id="description")
222
+ gr.DuplicateButton(
223
+ value="Duplicate Space for private use",
224
+ elem_id="duplicate-button",
225
+ visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
226
+ )
227
+
228
+ with gr.Row():
229
+ with gr.Column():
230
+ with gr.Group():
231
+ image = gr.ImageEditor(type="pil", label="Sketch your image or upload one", width=512, height=512)
232
+ prompt = gr.Textbox(label="Prompt")
233
+ style = gr.Dropdown(label="Style", choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME)
234
+ model_choice = gr.Dropdown(
235
+ ["Pony Realism v21", "Cyber Realistic Pony v61", "Stallion Dreams Pony Realistic v1"],
236
+ label="Model Choice",
237
+ value="Pony Realism v21"
238
+ )
239
+ use_hed = gr.Checkbox(label="use HED detector", value=False, info="check this box if you upload an image and want to turn it to a sketch")
240
+ use_canny = gr.Checkbox(label="use Canny", value=False, info="check this to use ControlNet canny instead of scribble")
241
+ run_button = gr.Button("Run")
242
+ with gr.Accordion("Advanced options", open=False):
243
+ negative_prompt = gr.Textbox(
244
+ label="Negative prompt",
245
+ value="longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality",
246
+ )
247
+ num_steps = gr.Slider(
248
+ label="Number of steps",
249
+ minimum=1,
250
+ maximum=50,
251
+ step=1,
252
+ value=25,
253
+ )
254
+ guidance_scale = gr.Slider(
255
+ label="Guidance scale",
256
+ minimum=0.1,
257
+ maximum=10.0,
258
+ step=0.1,
259
+ value=5,
260
+ )
261
+ controlnet_conditioning_scale = gr.Slider(
262
+ label="controlnet conditioning scale",
263
+ minimum=0.5,
264
+ maximum=5.0,
265
+ step=0.1,
266
+ value=0.9,
267
+ )
268
+ seed = gr.Slider(
269
+ label="Seed",
270
+ minimum=0,
271
+ maximum=MAX_SEED,
272
+ step=1,
273
+ value=0,
274
+ )
275
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
276
+
277
+ with gr.Column():
278
+ with gr.Group():
279
+ image_slider = ImageSlider(position=0.5)
280
+
281
+
282
+ inputs = [
283
+ image,
284
+ prompt,
285
+ negative_prompt,
286
+ model_choice, # Add this new input
287
+ style,
288
+ num_steps,
289
+ guidance_scale,
290
+ controlnet_conditioning_scale,
291
+ seed,
292
+ use_hed,
293
+ use_canny
294
+ ]
295
+ outputs = [image_slider]
296
+ run_button.click(
297
+ fn=randomize_seed_fn,
298
+ inputs=[seed, randomize_seed],
299
+ outputs=seed,
300
+ queue=False,
301
+ api_name=False,
302
+ ).then(lambda x: None, inputs=None, outputs=image_slider).then(
303
+ fn=run, inputs=inputs, outputs=outputs
304
+ )
305
+
306
+ demo.queue().launch(show_error=True, ssl_verify=False)