Files changed (3) hide show
  1. README.md +1 -1
  2. app.py +18 -82
  3. requirements.txt +3 -5
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 🔅
4
  colorFrom: gray
5
  colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.34.2
8
  app_file: app.py
9
  pinned: true
10
  license: apache-2.0
 
4
  colorFrom: gray
5
  colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 4.42.0
8
  app_file: app.py
9
  pinned: true
10
  license: apache-2.0
app.py CHANGED
@@ -1,6 +1,5 @@
1
  import gradio as gr
2
  import spaces
3
- import time
4
  import torch
5
  from diffusers import AutoencoderKL, TCDScheduler
6
  from diffusers.models.model_loading_utils import load_state_dict
@@ -169,57 +168,10 @@ def preview_image_and_mask(image, width, height, overlap_percentage, resize_opti
169
 
170
  return preview
171
 
172
- @spaces.GPU()
173
- def infer(
174
- image,
175
- width,
176
- height,
177
- overlap_percentage,
178
- num_inference_steps,
179
- resize_option,
180
- custom_resize_percentage,
181
- prompt_input,
182
- alignment,
183
- overlap_left,
184
- overlap_right,
185
- overlap_top,
186
- overlap_bottom
187
- ):
188
- """
189
- Generate an outpainted image using Stable Diffusion XL with ControlNet guidance.
190
 
191
- This function performs intelligent image outpainting by expanding the input image
192
- according to the specified target dimensions and alignment, generating new content
193
- guided by a textual prompt. It uses a ControlNet-enabled diffusion pipeline to ensure
194
- coherent image extension.
195
-
196
- Args:
197
- image (PIL.Image): The input image to be outpainted.
198
- width (int): The target width of the output image.
199
- height (int): The target height of the output image.
200
- overlap_percentage (int): Percentage of overlap between original and outpainted regions for seamless blending.
201
- num_inference_steps (int): Number of inference steps for image generation. Higher values yield better results.
202
- resize_option (str): Predefined or custom percentage to resize the input image ("Full", "50%", "33%", "25%", or "Custom").
203
- custom_resize_percentage (int): Custom resize percentage if resize_option is "Custom".
204
- prompt_input (str): A text prompt describing desired content for the generated region.
205
- alignment (str): Alignment of the original image within the canvas ("Middle", "Left", "Right", "Top", "Bottom").
206
- overlap_left (bool): Whether to allow blending on the left edge.
207
- overlap_right (bool): Whether to allow blending on the right edge.
208
- overlap_top (bool): Whether to allow blending on the top edge.
209
- overlap_bottom (bool): Whether to allow blending on the bottom edge.
210
-
211
- Yields:
212
- Tuple[PIL.Image, PIL.Image]:
213
- - The intermediate ControlNet input image (showing the masked area).
214
- - The final generated image with the inpainted region.
215
- """
216
- #gr.Info("10 seconds will be used from your daily ZeroGPU time credits.")
217
- background, mask = prepare_image_and_mask(
218
- image, width, height, overlap_percentage,
219
- resize_option, custom_resize_percentage, alignment,
220
- overlap_left, overlap_right, overlap_top, overlap_bottom
221
- )
222
-
223
  if not can_expand(background.width, background.height, width, height, alignment):
224
  alignment = "Middle"
225
 
@@ -245,12 +197,10 @@ def infer(
245
  ):
246
  yield cnet_image, image
247
 
248
- #time.sleep(1)
249
- #image = image.convert("RGBA")
250
- #cnet_image.paste(image, (0, 0), mask)
251
-
252
- #return background, cnet_image
253
 
 
254
 
255
  def clear_result():
256
  """Clears the result ImageSlider."""
@@ -288,7 +238,6 @@ def toggle_custom_resize_slider(resize_option):
288
 
289
  def update_history(new_image, history):
290
  """Updates the history gallery with the new image."""
291
- time.sleep(1)
292
  if history is None:
293
  history = []
294
  history.insert(0, new_image)
@@ -296,7 +245,7 @@ def update_history(new_image, history):
296
 
297
  css = """
298
  .gradio-container {
299
- max-width: 1200px !important;
300
  }
301
  """
302
 
@@ -425,87 +374,75 @@ with gr.Blocks(css=css) as demo:
425
  use_as_input_button.click(
426
  fn=use_output_as_input,
427
  inputs=[result],
428
- outputs=[input_image],
429
- show_api=False
430
  )
431
 
432
  target_ratio.change(
433
  fn=preload_presets,
434
  inputs=[target_ratio, width_slider, height_slider],
435
  outputs=[width_slider, height_slider, settings_panel],
436
- queue=False,
437
- show_api=False
438
  )
439
 
440
  width_slider.change(
441
  fn=select_the_right_preset,
442
  inputs=[width_slider, height_slider],
443
  outputs=[target_ratio],
444
- queue=False,
445
- show_api=False
446
  )
447
 
448
  height_slider.change(
449
  fn=select_the_right_preset,
450
  inputs=[width_slider, height_slider],
451
  outputs=[target_ratio],
452
- queue=False,
453
- show_api=False
454
  )
455
 
456
  resize_option.change(
457
  fn=toggle_custom_resize_slider,
458
  inputs=[resize_option],
459
  outputs=[custom_resize_percentage],
460
- queue=False,
461
- show_api=False
462
  )
463
 
464
  run_button.click( # Clear the result
465
  fn=clear_result,
466
  inputs=None,
467
  outputs=result,
468
- show_api=False
469
  ).then( # Generate the new image
470
  fn=infer,
471
  inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
472
  resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
473
  overlap_left, overlap_right, overlap_top, overlap_bottom],
474
  outputs=result,
475
- ).then( # Show the "Use as Input Image" button
476
- fn=lambda: gr.update(visible=True),
477
- inputs=None,
478
- outputs=use_as_input_button,
479
- show_api=False
480
  ).then( # Update the history gallery
481
  fn=lambda x, history: update_history(x[1], history),
482
  inputs=[result, history_gallery],
483
  outputs=history_gallery,
484
- show_api=False
 
 
 
485
  )
486
 
487
  prompt_input.submit( # Clear the result
488
  fn=clear_result,
489
  inputs=None,
490
  outputs=result,
491
- show_api=False
492
  ).then( # Generate the new image
493
  fn=infer,
494
  inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
495
  resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
496
  overlap_left, overlap_right, overlap_top, overlap_bottom],
497
  outputs=result,
498
- show_api=False
499
  ).then( # Update the history gallery
500
  fn=lambda x, history: update_history(x[1], history),
501
  inputs=[result, history_gallery],
502
  outputs=history_gallery,
503
- show_api=False
504
  ).then( # Show the "Use as Input Image" button
505
  fn=lambda: gr.update(visible=True),
506
  inputs=None,
507
  outputs=use_as_input_button,
508
- show_api=False
509
  )
510
 
511
  preview_button.click(
@@ -513,8 +450,7 @@ with gr.Blocks(css=css) as demo:
513
  inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
514
  overlap_left, overlap_right, overlap_top, overlap_bottom],
515
  outputs=preview_image,
516
- queue=False,
517
- show_api=False
518
  )
519
 
520
- demo.queue(max_size=12).launch(share=False, show_error=True, mcp_server=True)
 
1
  import gradio as gr
2
  import spaces
 
3
  import torch
4
  from diffusers import AutoencoderKL, TCDScheduler
5
  from diffusers.models.model_loading_utils import load_state_dict
 
168
 
169
  return preview
170
 
171
+ @spaces.GPU(duration=24)
172
+ def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
173
+ background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  if not can_expand(background.width, background.height, width, height, alignment):
176
  alignment = "Middle"
177
 
 
197
  ):
198
  yield cnet_image, image
199
 
200
+ image = image.convert("RGBA")
201
+ cnet_image.paste(image, (0, 0), mask)
 
 
 
202
 
203
+ yield background, cnet_image
204
 
205
  def clear_result():
206
  """Clears the result ImageSlider."""
 
238
 
239
  def update_history(new_image, history):
240
  """Updates the history gallery with the new image."""
 
241
  if history is None:
242
  history = []
243
  history.insert(0, new_image)
 
245
 
246
  css = """
247
  .gradio-container {
248
+ width: 1200px !important;
249
  }
250
  """
251
 
 
374
  use_as_input_button.click(
375
  fn=use_output_as_input,
376
  inputs=[result],
377
+ outputs=[input_image]
 
378
  )
379
 
380
  target_ratio.change(
381
  fn=preload_presets,
382
  inputs=[target_ratio, width_slider, height_slider],
383
  outputs=[width_slider, height_slider, settings_panel],
384
+ queue=False
 
385
  )
386
 
387
  width_slider.change(
388
  fn=select_the_right_preset,
389
  inputs=[width_slider, height_slider],
390
  outputs=[target_ratio],
391
+ queue=False
 
392
  )
393
 
394
  height_slider.change(
395
  fn=select_the_right_preset,
396
  inputs=[width_slider, height_slider],
397
  outputs=[target_ratio],
398
+ queue=False
 
399
  )
400
 
401
  resize_option.change(
402
  fn=toggle_custom_resize_slider,
403
  inputs=[resize_option],
404
  outputs=[custom_resize_percentage],
405
+ queue=False
 
406
  )
407
 
408
  run_button.click( # Clear the result
409
  fn=clear_result,
410
  inputs=None,
411
  outputs=result,
 
412
  ).then( # Generate the new image
413
  fn=infer,
414
  inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
415
  resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
416
  overlap_left, overlap_right, overlap_top, overlap_bottom],
417
  outputs=result,
 
 
 
 
 
418
  ).then( # Update the history gallery
419
  fn=lambda x, history: update_history(x[1], history),
420
  inputs=[result, history_gallery],
421
  outputs=history_gallery,
422
+ ).then( # Show the "Use as Input Image" button
423
+ fn=lambda: gr.update(visible=True),
424
+ inputs=None,
425
+ outputs=use_as_input_button,
426
  )
427
 
428
  prompt_input.submit( # Clear the result
429
  fn=clear_result,
430
  inputs=None,
431
  outputs=result,
 
432
  ).then( # Generate the new image
433
  fn=infer,
434
  inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
435
  resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
436
  overlap_left, overlap_right, overlap_top, overlap_bottom],
437
  outputs=result,
 
438
  ).then( # Update the history gallery
439
  fn=lambda x, history: update_history(x[1], history),
440
  inputs=[result, history_gallery],
441
  outputs=history_gallery,
 
442
  ).then( # Show the "Use as Input Image" button
443
  fn=lambda: gr.update(visible=True),
444
  inputs=None,
445
  outputs=use_as_input_button,
 
446
  )
447
 
448
  preview_button.click(
 
450
  inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
451
  overlap_left, overlap_right, overlap_top, overlap_bottom],
452
  outputs=preview_image,
453
+ queue=False
 
454
  )
455
 
456
+ demo.queue(max_size=12).launch(share=False, show_error=True)
requirements.txt CHANGED
@@ -1,12 +1,10 @@
1
  torch==2.5.1
2
- spaces==0.37.0
3
- gradio[mcp]
4
  gradio-imageslider
5
  numpy==1.26.4
6
  transformers==4.45.0
7
  accelerate==0.33.0
8
- #diffusers==0.30.3
9
- diffusers==0.32.2
10
- huggingface-hub
11
  fastapi<0.113.0
12
  opencv-python
 
1
  torch==2.5.1
2
+ spaces==0.30.4
3
+ gradio==4.42.0
4
  gradio-imageslider
5
  numpy==1.26.4
6
  transformers==4.45.0
7
  accelerate==0.33.0
8
+ diffusers==0.30.3
 
 
9
  fastapi<0.113.0
10
  opencv-python