Files changed (2) hide show
  1. README.md +1 -1
  2. app.py +124 -121
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 👁
4
  colorFrom: red
5
  colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.14.0
8
  app_file: app.py
9
  pinned: false
10
  license: openrail
 
4
  colorFrom: red
5
  colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 4.36.1
8
  app_file: app.py
9
  pinned: false
10
  license: openrail
app.py CHANGED
@@ -1,19 +1,25 @@
1
  import spaces
2
  import torch
3
  import gradio as gr
 
4
  from PIL import Image
5
  import random
6
 
7
  from diffusers import (
 
8
  AutoencoderKL,
9
  StableDiffusionControlNetPipeline,
10
  ControlNetModel,
 
 
11
  StableDiffusionControlNetImg2ImgPipeline,
12
  DPMSolverMultistepScheduler,
13
- EulerDiscreteScheduler,
14
  )
 
15
  import time
16
  from share_btn import community_icon_html, loading_icon_html, share_js
 
17
  from illusion_style import css
18
  import os
19
  from transformers import CLIPImageProcessor
@@ -23,18 +29,14 @@ BASE_MODEL = "SG161222/Realistic_Vision_V5.1_noVAE"
23
 
24
  # Initialize both pipelines
25
  vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype=torch.float16)
26
- controlnet = ControlNetModel.from_pretrained(
27
- "monster-labs/control_v1p_sd15_qrcode_monster", torch_dtype=torch.float16
28
- )
29
 
30
  # Initialize the safety checker conditionally
31
  SAFETY_CHECKER_ENABLED = os.environ.get("SAFETY_CHECKER", "0") == "1"
32
  safety_checker = None
33
  feature_extractor = None
34
  if SAFETY_CHECKER_ENABLED:
35
- safety_checker = StableDiffusionSafetyChecker.from_pretrained(
36
- "CompVis/stable-diffusion-safety-checker"
37
- ).to("cuda")
38
  feature_extractor = CLIPImageProcessor.from_pretrained("openai/clip-vit-base-patch32")
39
 
40
  main_pipe = StableDiffusionControlNetPipeline.from_pretrained(
@@ -46,53 +48,76 @@ main_pipe = StableDiffusionControlNetPipeline.from_pretrained(
46
  torch_dtype=torch.float16,
47
  ).to("cuda")
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  image_pipe = StableDiffusionControlNetImg2ImgPipeline(**main_pipe.components)
50
 
 
 
 
 
 
 
51
  # Sampler map
52
  SAMPLER_MAP = {
53
- "DPM++ Karras SDE": lambda config: DPMSolverMultistepScheduler.from_config(
54
- config, use_karras=True, algorithm_type="sde-dpmsolver++"
55
- ),
56
  "Euler": lambda config: EulerDiscreteScheduler.from_config(config),
57
  }
58
 
59
-
60
  def center_crop_resize(img, output_size=(512, 512)):
61
  width, height = img.size
 
 
62
  new_dimension = min(width, height)
63
- left = (width - new_dimension) / 2
64
- top = (height - new_dimension) / 2
65
- right = (width + new_dimension) / 2
66
- bottom = (height + new_dimension) / 2
 
 
67
  img = img.crop((left, top, right, bottom))
68
  img = img.resize(output_size)
69
- return img
70
 
 
71
 
72
  def common_upscale(samples, width, height, upscale_method, crop=False):
73
- if crop == "center":
74
- old_width = samples.shape[3]
75
- old_height = samples.shape[2]
76
- old_aspect = old_width / old_height
77
- new_aspect = width / height
78
- x = 0
79
- y = 0
80
- if old_aspect > new_aspect:
81
- x = round((old_width - old_width * (new_aspect / old_aspect)) / 2)
82
- elif old_aspect < new_aspect:
83
- y = round((old_height - old_height * (old_aspect / new_aspect)) / 2)
84
- s = samples[:, :, y:old_height - y, x:old_width - x]
85
- else:
86
- s = samples
87
- return torch.nn.functional.interpolate(s, size=(height, width), mode=upscale_method)
88
 
 
89
 
90
  def upscale(samples, upscale_method, scale_by):
91
- width = round(samples["images"].shape[3] * scale_by)
92
- height = round(samples["images"].shape[2] * scale_by)
93
- s = common_upscale(samples["images"], width, height, upscale_method, "disabled")
94
- return s
95
-
96
 
97
  def check_inputs(prompt: str, control_image: Image.Image):
98
  if control_image is None:
@@ -100,6 +125,14 @@ def check_inputs(prompt: str, control_image: Image.Image):
100
  if prompt is None or prompt == "":
101
  raise gr.Error("Prompt is required")
102
 
 
 
 
 
 
 
 
 
103
 
104
  # Inference function
105
  @spaces.GPU
@@ -109,25 +142,30 @@ def inference(
109
  negative_prompt: str,
110
  guidance_scale: float = 8.0,
111
  controlnet_conditioning_scale: float = 1,
112
- control_guidance_start: float = 1,
113
  control_guidance_end: float = 1,
114
  upscaler_strength: float = 0.5,
115
  seed: int = -1,
116
- sampler="DPM++ Karras SDE",
117
- progress=gr.Progress(track_tqdm=True),
 
118
  ):
119
  start_time = time.time()
120
  start_time_struct = time.localtime(start_time)
121
  start_time_formatted = time.strftime("%H:%M:%S", start_time_struct)
122
  print(f"Inference started at {start_time_formatted}")
 
 
 
123
 
 
124
  control_image_small = center_crop_resize(control_image)
125
  control_image_large = center_crop_resize(control_image, (1024, 1024))
126
 
127
  main_pipe.scheduler = SAMPLER_MAP[sampler](main_pipe.scheduler.config)
128
  my_seed = random.randint(0, 2**32 - 1) if seed == -1 else seed
129
  generator = torch.Generator(device="cuda").manual_seed(my_seed)
130
-
131
  out = main_pipe(
132
  prompt=prompt,
133
  negative_prompt=negative_prompt,
@@ -138,13 +176,13 @@ def inference(
138
  control_guidance_start=float(control_guidance_start),
139
  control_guidance_end=float(control_guidance_end),
140
  num_inference_steps=15,
141
- output_type="latent",
142
  )
143
  upscaled_latents = upscale(out, "nearest-exact", 2)
144
  out_image = image_pipe(
145
  prompt=prompt,
146
  negative_prompt=negative_prompt,
147
- control_image=control_image_large,
148
  image=upscaled_latents,
149
  guidance_scale=float(guidance_scale),
150
  generator=generator,
@@ -152,17 +190,34 @@ def inference(
152
  strength=upscaler_strength,
153
  control_guidance_start=float(control_guidance_start),
154
  control_guidance_end=float(control_guidance_end),
155
- controlnet_conditioning_scale=float(controlnet_conditioning_scale),
156
  )
157
  end_time = time.time()
158
  end_time_struct = time.localtime(end_time)
159
  end_time_formatted = time.strftime("%H:%M:%S", end_time_struct)
160
  print(f"Inference ended at {end_time_formatted}, taking {end_time-start_time}s")
161
 
162
- return out_image["images"][0], gr.update(visible=True), gr.update(visible=True), my_seed
163
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- with gr.Blocks(css=css) as app:
 
 
166
  gr.Markdown(
167
  '''
168
  <div style="text-align: center;">
@@ -175,58 +230,24 @@ with gr.Blocks(css=css) as app:
175
  '''
176
  )
177
 
 
178
  state_img_input = gr.State()
179
  state_img_output = gr.State()
180
  with gr.Row():
181
  with gr.Column():
182
  control_image = gr.Image(label="Input Illusion", type="pil", elem_id="control_image")
183
- controlnet_conditioning_scale = gr.Slider(
184
- minimum=0.0,
185
- maximum=5.0,
186
- step=0.01,
187
- value=0.8,
188
- label="Illusion strength",
189
- elem_id="illusion_strength",
190
- info="ControlNet conditioning scale",
191
- )
192
- gr.Examples(
193
- examples=[
194
- "checkers.png",
195
- "checkers_mid.jpg",
196
- "pattern.png",
197
- "ultra_checkers.png",
198
- "spiral.jpeg",
199
- "funky.jpeg",
200
- ],
201
- inputs=control_image,
202
- )
203
- prompt = gr.Textbox(
204
- label="Prompt",
205
- elem_id="prompt",
206
- info="Type what you want to generate",
207
- placeholder="Medieval village scene with busy streets and castle in the distance",
208
- )
209
- negative_prompt = gr.Textbox(
210
- label="Negative Prompt",
211
- info="Type what you don't want to see",
212
- value="low quality",
213
- elem_id="negative_prompt",
214
- )
215
  with gr.Accordion(label="Advanced Options", open=False):
216
  guidance_scale = gr.Slider(minimum=0.0, maximum=50.0, step=0.25, value=7.5, label="Guidance Scale")
217
  sampler = gr.Dropdown(choices=list(SAMPLER_MAP.keys()), value="Euler")
218
  control_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0, label="Start of ControlNet")
219
  control_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=1, label="End of ControlNet")
220
  strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=1, label="Strength of the upscaler")
221
- seed = gr.Slider(
222
- minimum=-1,
223
- maximum=9999999999,
224
- step=1,
225
- value=-1,
226
- label="Seed",
227
- info="-1 means random seed",
228
- )
229
- used_seed = gr.Number(label="Last seed used", interactive=False)
230
  run_btn = gr.Button("Run")
231
  with gr.Column():
232
  result_image = gr.Image(label="Illusion Diffusion Output", interactive=False, elem_id="output")
@@ -238,48 +259,30 @@ with gr.Blocks(css=css) as app:
238
  prompt.submit(
239
  check_inputs,
240
  inputs=[prompt, control_image],
241
- queue=False,
242
  ).success(
243
  inference,
244
- inputs=[
245
- control_image,
246
- prompt,
247
- negative_prompt,
248
- guidance_scale,
249
- controlnet_conditioning_scale,
250
- control_start,
251
- control_end,
252
- strength,
253
- seed,
254
- sampler,
255
- ],
256
- outputs=[result_image, result_image, share_group, used_seed],
257
- )
258
-
259
  run_btn.click(
260
  check_inputs,
261
  inputs=[prompt, control_image],
262
- queue=False,
263
  ).success(
264
  inference,
265
- inputs=[
266
- control_image,
267
- prompt,
268
- negative_prompt,
269
- guidance_scale,
270
- controlnet_conditioning_scale,
271
- control_start,
272
- control_end,
273
- strength,
274
- seed,
275
- sampler,
276
- ],
277
- outputs=[result_image, result_image, share_group, used_seed],
278
- )
279
-
280
  share_button.click(None, [], [], js=share_js)
281
 
282
- app.queue(max_size=20, api_open=False)
 
 
 
 
 
 
283
 
284
  if __name__ == "__main__":
285
- app.launch(max_threads=400)
 
1
  import spaces
2
  import torch
3
  import gradio as gr
4
+ from gradio import processing_utils, utils
5
  from PIL import Image
6
  import random
7
 
8
  from diffusers import (
9
+ DiffusionPipeline,
10
  AutoencoderKL,
11
  StableDiffusionControlNetPipeline,
12
  ControlNetModel,
13
+ StableDiffusionLatentUpscalePipeline,
14
+ StableDiffusionImg2ImgPipeline,
15
  StableDiffusionControlNetImg2ImgPipeline,
16
  DPMSolverMultistepScheduler,
17
+ EulerDiscreteScheduler
18
  )
19
+ import tempfile
20
  import time
21
  from share_btn import community_icon_html, loading_icon_html, share_js
22
+ import user_history
23
  from illusion_style import css
24
  import os
25
  from transformers import CLIPImageProcessor
 
29
 
30
  # Initialize both pipelines
31
  vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype=torch.float16)
32
+ controlnet = ControlNetModel.from_pretrained("monster-labs/control_v1p_sd15_qrcode_monster", torch_dtype=torch.float16)
 
 
33
 
34
  # Initialize the safety checker conditionally
35
  SAFETY_CHECKER_ENABLED = os.environ.get("SAFETY_CHECKER", "0") == "1"
36
  safety_checker = None
37
  feature_extractor = None
38
  if SAFETY_CHECKER_ENABLED:
39
+ safety_checker = StableDiffusionSafetyChecker.from_pretrained("CompVis/stable-diffusion-safety-checker").to("cuda")
 
 
40
  feature_extractor = CLIPImageProcessor.from_pretrained("openai/clip-vit-base-patch32")
41
 
42
  main_pipe = StableDiffusionControlNetPipeline.from_pretrained(
 
48
  torch_dtype=torch.float16,
49
  ).to("cuda")
50
 
51
+ # Function to check NSFW images
52
+ #def check_nsfw_images(images: list[Image.Image]) -> tuple[list[Image.Image], list[bool]]:
53
+ # if SAFETY_CHECKER_ENABLED:
54
+ # safety_checker_input = feature_extractor(images, return_tensors="pt").to("cuda")
55
+ # has_nsfw_concepts = safety_checker(
56
+ # images=[images],
57
+ # clip_input=safety_checker_input.pixel_values.to("cuda")
58
+ # )
59
+ # return images, has_nsfw_concepts
60
+ # else:
61
+ # return images, [False] * len(images)
62
+
63
+ #main_pipe.unet = torch.compile(main_pipe.unet, mode="reduce-overhead", fullgraph=True)
64
+ #main_pipe.unet.to(memory_format=torch.channels_last)
65
+ #main_pipe.unet = torch.compile(main_pipe.unet, mode="reduce-overhead", fullgraph=True)
66
+ #model_id = "stabilityai/sd-x2-latent-upscaler"
67
  image_pipe = StableDiffusionControlNetImg2ImgPipeline(**main_pipe.components)
68
 
69
+
70
+ #image_pipe.unet = torch.compile(image_pipe.unet, mode="reduce-overhead", fullgraph=True)
71
+ #upscaler = StableDiffusionLatentUpscalePipeline.from_pretrained(model_id, torch_dtype=torch.float16)
72
+ #upscaler.to("cuda")
73
+
74
+
75
  # Sampler map
76
  SAMPLER_MAP = {
77
+ "DPM++ Karras SDE": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True, algorithm_type="sde-dpmsolver++"),
 
 
78
  "Euler": lambda config: EulerDiscreteScheduler.from_config(config),
79
  }
80
 
 
81
  def center_crop_resize(img, output_size=(512, 512)):
82
  width, height = img.size
83
+
84
+ # Calculate dimensions to crop to the center
85
  new_dimension = min(width, height)
86
+ left = (width - new_dimension)/2
87
+ top = (height - new_dimension)/2
88
+ right = (width + new_dimension)/2
89
+ bottom = (height + new_dimension)/2
90
+
91
+ # Crop and resize
92
  img = img.crop((left, top, right, bottom))
93
  img = img.resize(output_size)
 
94
 
95
+ return img
96
 
97
  def common_upscale(samples, width, height, upscale_method, crop=False):
98
+ if crop == "center":
99
+ old_width = samples.shape[3]
100
+ old_height = samples.shape[2]
101
+ old_aspect = old_width / old_height
102
+ new_aspect = width / height
103
+ x = 0
104
+ y = 0
105
+ if old_aspect > new_aspect:
106
+ x = round((old_width - old_width * (new_aspect / old_aspect)) / 2)
107
+ elif old_aspect < new_aspect:
108
+ y = round((old_height - old_height * (old_aspect / new_aspect)) / 2)
109
+ s = samples[:,:,y:old_height-y,x:old_width-x]
110
+ else:
111
+ s = samples
 
112
 
113
+ return torch.nn.functional.interpolate(s, size=(height, width), mode=upscale_method)
114
 
115
  def upscale(samples, upscale_method, scale_by):
116
+ #s = samples.copy()
117
+ width = round(samples["images"].shape[3] * scale_by)
118
+ height = round(samples["images"].shape[2] * scale_by)
119
+ s = common_upscale(samples["images"], width, height, upscale_method, "disabled")
120
+ return (s)
121
 
122
  def check_inputs(prompt: str, control_image: Image.Image):
123
  if control_image is None:
 
125
  if prompt is None or prompt == "":
126
  raise gr.Error("Prompt is required")
127
 
128
+ def convert_to_pil(base64_image):
129
+ pil_image = Image.open(base64_image)
130
+ return pil_image
131
+
132
+ def convert_to_base64(pil_image):
133
+ with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
134
+ image.save(temp_file.name)
135
+ return temp_file.name
136
 
137
  # Inference function
138
  @spaces.GPU
 
142
  negative_prompt: str,
143
  guidance_scale: float = 8.0,
144
  controlnet_conditioning_scale: float = 1,
145
+ control_guidance_start: float = 1,
146
  control_guidance_end: float = 1,
147
  upscaler_strength: float = 0.5,
148
  seed: int = -1,
149
+ sampler = "DPM++ Karras SDE",
150
+ progress = gr.Progress(track_tqdm=True),
151
+ profile: gr.OAuthProfile | None = None,
152
  ):
153
  start_time = time.time()
154
  start_time_struct = time.localtime(start_time)
155
  start_time_formatted = time.strftime("%H:%M:%S", start_time_struct)
156
  print(f"Inference started at {start_time_formatted}")
157
+
158
+ # Generate the initial image
159
+ #init_image = init_pipe(prompt).images[0]
160
 
161
+ # Rest of your existing code
162
  control_image_small = center_crop_resize(control_image)
163
  control_image_large = center_crop_resize(control_image, (1024, 1024))
164
 
165
  main_pipe.scheduler = SAMPLER_MAP[sampler](main_pipe.scheduler.config)
166
  my_seed = random.randint(0, 2**32 - 1) if seed == -1 else seed
167
  generator = torch.Generator(device="cuda").manual_seed(my_seed)
168
+
169
  out = main_pipe(
170
  prompt=prompt,
171
  negative_prompt=negative_prompt,
 
176
  control_guidance_start=float(control_guidance_start),
177
  control_guidance_end=float(control_guidance_end),
178
  num_inference_steps=15,
179
+ output_type="latent"
180
  )
181
  upscaled_latents = upscale(out, "nearest-exact", 2)
182
  out_image = image_pipe(
183
  prompt=prompt,
184
  negative_prompt=negative_prompt,
185
+ control_image=control_image_large,
186
  image=upscaled_latents,
187
  guidance_scale=float(guidance_scale),
188
  generator=generator,
 
190
  strength=upscaler_strength,
191
  control_guidance_start=float(control_guidance_start),
192
  control_guidance_end=float(control_guidance_end),
193
+ controlnet_conditioning_scale=float(controlnet_conditioning_scale)
194
  )
195
  end_time = time.time()
196
  end_time_struct = time.localtime(end_time)
197
  end_time_formatted = time.strftime("%H:%M:%S", end_time_struct)
198
  print(f"Inference ended at {end_time_formatted}, taking {end_time-start_time}s")
199
 
200
+ # Save image + metadata
201
+ user_history.save_image(
202
+ label=prompt,
203
+ image=out_image["images"][0],
204
+ profile=profile,
205
+ metadata={
206
+ "prompt": prompt,
207
+ "negative_prompt": negative_prompt,
208
+ "guidance_scale": guidance_scale,
209
+ "controlnet_conditioning_scale": controlnet_conditioning_scale,
210
+ "control_guidance_start": control_guidance_start,
211
+ "control_guidance_end": control_guidance_end,
212
+ "upscaler_strength": upscaler_strength,
213
+ "seed": seed,
214
+ "sampler": sampler,
215
+ },
216
+ )
217
 
218
+ return out_image["images"][0], gr.update(visible=True), gr.update(visible=True), my_seed
219
+
220
+ with gr.Blocks() as app:
221
  gr.Markdown(
222
  '''
223
  <div style="text-align: center;">
 
230
  '''
231
  )
232
 
233
+
234
  state_img_input = gr.State()
235
  state_img_output = gr.State()
236
  with gr.Row():
237
  with gr.Column():
238
  control_image = gr.Image(label="Input Illusion", type="pil", elem_id="control_image")
239
+ controlnet_conditioning_scale = gr.Slider(minimum=0.0, maximum=5.0, step=0.01, value=0.8, label="Illusion strength", elem_id="illusion_strength", info="ControlNet conditioning scale")
240
+ gr.Examples(examples=["checkers.png", "checkers_mid.jpg", "pattern.png", "ultra_checkers.png", "spiral.jpeg", "funky.jpeg" ], inputs=control_image)
241
+ prompt = gr.Textbox(label="Prompt", elem_id="prompt", info="Type what you want to generate", placeholder="Medieval village scene with busy streets and castle in the distance")
242
+ negative_prompt = gr.Textbox(label="Negative Prompt", info="Type what you don't want to see", value="low quality", elem_id="negative_prompt")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  with gr.Accordion(label="Advanced Options", open=False):
244
  guidance_scale = gr.Slider(minimum=0.0, maximum=50.0, step=0.25, value=7.5, label="Guidance Scale")
245
  sampler = gr.Dropdown(choices=list(SAMPLER_MAP.keys()), value="Euler")
246
  control_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0, label="Start of ControlNet")
247
  control_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=1, label="End of ControlNet")
248
  strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=1, label="Strength of the upscaler")
249
+ seed = gr.Slider(minimum=-1, maximum=9999999999, step=1, value=-1, label="Seed", info="-1 means random seed")
250
+ used_seed = gr.Number(label="Last seed used",interactive=False)
 
 
 
 
 
 
 
251
  run_btn = gr.Button("Run")
252
  with gr.Column():
253
  result_image = gr.Image(label="Illusion Diffusion Output", interactive=False, elem_id="output")
 
259
  prompt.submit(
260
  check_inputs,
261
  inputs=[prompt, control_image],
262
+ queue=False
263
  ).success(
264
  inference,
265
+ inputs=[control_image, prompt, negative_prompt, guidance_scale, controlnet_conditioning_scale, control_start, control_end, strength, seed, sampler],
266
+ outputs=[result_image, result_image, share_group, used_seed])
267
+
 
 
 
 
 
 
 
 
 
 
 
 
268
  run_btn.click(
269
  check_inputs,
270
  inputs=[prompt, control_image],
271
+ queue=False
272
  ).success(
273
  inference,
274
+ inputs=[control_image, prompt, negative_prompt, guidance_scale, controlnet_conditioning_scale, control_start, control_end, strength, seed, sampler],
275
+ outputs=[result_image, result_image, share_group, used_seed])
276
+
 
 
 
 
 
 
 
 
 
 
 
 
277
  share_button.click(None, [], [], js=share_js)
278
 
279
+ with gr.Blocks(css=css) as app_with_history:
280
+ with gr.Tab("Demo"):
281
+ app.render()
282
+ with gr.Tab("Past generations"):
283
+ user_history.render()
284
+
285
+ app_with_history.queue(max_size=20,api_open=False )
286
 
287
  if __name__ == "__main__":
288
+ app_with_history.launch(max_threads=400)