Spaces:
Running
on
Zero
Running
on
Zero
Update app.py (#2)
Browse files- Update app.py (cb6a3673a5f67465153a5b5fd72087d8fef4e32c)
app.py
CHANGED
@@ -5,6 +5,7 @@ import torch
|
|
5 |
import spaces
|
6 |
import os
|
7 |
import json
|
|
|
8 |
|
9 |
from PIL import Image, ImageDraw
|
10 |
import torch
|
@@ -277,6 +278,36 @@ optimize_pipeline_(pipe, image=Image.new("RGB", (1024, 1024)), prompt="prompt")
|
|
277 |
# --- UI Constants and Helpers ---
|
278 |
MAX_SEED = np.iinfo(np.int32).max
|
279 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
def preload_presets(target_ratio, ui_width, ui_height):
|
281 |
"""Updates the width and height sliders based on the selected aspect ratio."""
|
282 |
if target_ratio == "9:16":
|
@@ -380,12 +411,16 @@ def infer(
|
|
380 |
return result_image, seed
|
381 |
|
382 |
# --- Examples and UI Layout ---
|
383 |
-
examples
|
|
|
|
|
|
|
|
|
384 |
|
385 |
css = """
|
386 |
#col-container {
|
387 |
margin: 0 auto;
|
388 |
-
max-width:
|
389 |
}
|
390 |
#edit_text{margin-top: -62px !important}
|
391 |
.preview-container {
|
@@ -394,6 +429,9 @@ css = """
|
|
394 |
padding: 10px;
|
395 |
margin-top: 10px;
|
396 |
}
|
|
|
|
|
|
|
397 |
"""
|
398 |
|
399 |
with gr.Blocks(css=css) as demo:
|
@@ -408,6 +446,11 @@ with gr.Blocks(css=css) as demo:
|
|
408 |
|
409 |
Extend your images beyond their original boundaries with intelligent outpainting. The model will generate new content that seamlessly blends with your original image.
|
410 |
|
|
|
|
|
|
|
|
|
|
|
411 |
[Learn more](https://github.com/QwenLM/Qwen-Image) about the Qwen-Image series.
|
412 |
Try on [Qwen Chat](https://chat.qwen.ai/), or [download model](https://huggingface.co/Qwen/Qwen-Image-Edit) to run locally.
|
413 |
""")
|
@@ -435,9 +478,9 @@ with gr.Blocks(css=css) as demo:
|
|
435 |
label="Alignment"
|
436 |
)
|
437 |
|
438 |
-
run_button = gr.Button("Outpaint!", variant="primary")
|
439 |
|
440 |
-
with gr.Accordion("Outpainting Settings", open=False) as settings_panel:
|
441 |
with gr.Row():
|
442 |
width_slider = gr.Slider(
|
443 |
label="Target Width",
|
@@ -487,9 +530,9 @@ with gr.Blocks(css=css) as demo:
|
|
487 |
visible=False
|
488 |
)
|
489 |
|
490 |
-
preview_button = gr.Button("Preview alignment and mask", variant="secondary")
|
491 |
|
492 |
-
with gr.Accordion("Advanced Settings", open=False):
|
493 |
seed = gr.Slider(
|
494 |
label="Seed",
|
495 |
minimum=0,
|
@@ -525,10 +568,50 @@ with gr.Blocks(css=css) as demo:
|
|
525 |
with gr.Column():
|
526 |
result = gr.Image(label="Result", type="pil")
|
527 |
|
|
|
|
|
528 |
with gr.Column(visible=False) as preview_container:
|
529 |
preview_image = gr.Image(label="Preview (red area will be generated)", type="pil")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
530 |
|
531 |
# Event handlers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
532 |
target_ratio.change(
|
533 |
fn=preload_presets,
|
534 |
inputs=[target_ratio, width_slider, height_slider],
|
@@ -573,8 +656,13 @@ with gr.Blocks(css=css) as demo:
|
|
573 |
queue=False,
|
574 |
)
|
575 |
|
576 |
-
|
577 |
-
|
|
|
|
|
|
|
|
|
|
|
578 |
fn=infer,
|
579 |
inputs=[
|
580 |
input_image,
|
@@ -596,6 +684,56 @@ with gr.Blocks(css=css) as demo:
|
|
596 |
rewrite_prompt,
|
597 |
],
|
598 |
outputs=[result, seed],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
599 |
)
|
600 |
|
601 |
if __name__ == "__main__":
|
|
|
5 |
import spaces
|
6 |
import os
|
7 |
import json
|
8 |
+
import time
|
9 |
|
10 |
from PIL import Image, ImageDraw
|
11 |
import torch
|
|
|
278 |
# --- UI Constants and Helpers ---
|
279 |
MAX_SEED = np.iinfo(np.int32).max
|
280 |
|
281 |
+
def clear_result():
|
282 |
+
"""Clears the result image."""
|
283 |
+
return gr.update(value=None)
|
284 |
+
|
285 |
+
def update_history(new_image, history):
|
286 |
+
"""Updates the history gallery with the new image."""
|
287 |
+
time.sleep(0.5) # Small delay to ensure image is ready
|
288 |
+
if history is None:
|
289 |
+
history = []
|
290 |
+
if new_image is not None:
|
291 |
+
# Convert to list if needed (Gradio sometimes returns tuples)
|
292 |
+
if not isinstance(history, list):
|
293 |
+
history = list(history) if history else []
|
294 |
+
history.insert(0, new_image)
|
295 |
+
# Keep only the last 20 images in history
|
296 |
+
history = history[:20]
|
297 |
+
return history
|
298 |
+
|
299 |
+
def use_history_as_input(evt: gr.SelectData, history):
|
300 |
+
"""Sets the selected history image as the new input image."""
|
301 |
+
if history and evt.index < len(history):
|
302 |
+
return gr.update(value=history[evt.index])
|
303 |
+
return gr.update()
|
304 |
+
|
305 |
+
def use_output_as_input(output_image):
|
306 |
+
"""Sets the generated output as the new input image."""
|
307 |
+
if output_image is not None:
|
308 |
+
return gr.update(value=output_image)
|
309 |
+
return gr.update()
|
310 |
+
|
311 |
def preload_presets(target_ratio, ui_width, ui_height):
|
312 |
"""Updates the width and height sliders based on the selected aspect ratio."""
|
313 |
if target_ratio == "9:16":
|
|
|
411 |
return result_image, seed
|
412 |
|
413 |
# --- Examples and UI Layout ---
|
414 |
+
# You can add examples here if you have sample images
|
415 |
+
# examples = [
|
416 |
+
# ["path/to/example1.jpg", "extend the landscape", 1280, 720, "Middle"],
|
417 |
+
# ["path/to/example2.jpg", "add more sky", 1024, 1024, "Top"],
|
418 |
+
# ]
|
419 |
|
420 |
css = """
|
421 |
#col-container {
|
422 |
margin: 0 auto;
|
423 |
+
max-width: 1200px;
|
424 |
}
|
425 |
#edit_text{margin-top: -62px !important}
|
426 |
.preview-container {
|
|
|
429 |
padding: 10px;
|
430 |
margin-top: 10px;
|
431 |
}
|
432 |
+
.gallery-container {
|
433 |
+
margin-top: 20px;
|
434 |
+
}
|
435 |
"""
|
436 |
|
437 |
with gr.Blocks(css=css) as demo:
|
|
|
446 |
|
447 |
Extend your images beyond their original boundaries with intelligent outpainting. The model will generate new content that seamlessly blends with your original image.
|
448 |
|
449 |
+
**Tips:**
|
450 |
+
- Use the preview button to see which areas will be generated before running
|
451 |
+
- Click on any image in the history to use it as a new input
|
452 |
+
- Try different alignments to expand your image in specific directions
|
453 |
+
|
454 |
[Learn more](https://github.com/QwenLM/Qwen-Image) about the Qwen-Image series.
|
455 |
Try on [Qwen Chat](https://chat.qwen.ai/), or [download model](https://huggingface.co/Qwen/Qwen-Image-Edit) to run locally.
|
456 |
""")
|
|
|
478 |
label="Alignment"
|
479 |
)
|
480 |
|
481 |
+
run_button = gr.Button("๐จ Outpaint!", variant="primary")
|
482 |
|
483 |
+
with gr.Accordion("โ๏ธ Outpainting Settings", open=False) as settings_panel:
|
484 |
with gr.Row():
|
485 |
width_slider = gr.Slider(
|
486 |
label="Target Width",
|
|
|
530 |
visible=False
|
531 |
)
|
532 |
|
533 |
+
preview_button = gr.Button("๐๏ธ Preview alignment and mask", variant="secondary")
|
534 |
|
535 |
+
with gr.Accordion("๐ง Advanced Settings", open=False):
|
536 |
seed = gr.Slider(
|
537 |
label="Seed",
|
538 |
minimum=0,
|
|
|
568 |
with gr.Column():
|
569 |
result = gr.Image(label="Result", type="pil")
|
570 |
|
571 |
+
use_as_input_button = gr.Button("๐ Use as Input Image", visible=False, variant="secondary")
|
572 |
+
|
573 |
with gr.Column(visible=False) as preview_container:
|
574 |
preview_image = gr.Image(label="Preview (red area will be generated)", type="pil")
|
575 |
+
|
576 |
+
gr.Markdown("---")
|
577 |
+
|
578 |
+
with gr.Row():
|
579 |
+
gr.Markdown("### ๐ History")
|
580 |
+
clear_history_button = gr.Button("๐๏ธ Clear History", size="sm", variant="stop")
|
581 |
+
|
582 |
+
history_gallery = gr.Gallery(
|
583 |
+
label="Click any image to use as input",
|
584 |
+
columns=4,
|
585 |
+
rows=2,
|
586 |
+
object_fit="contain",
|
587 |
+
height="auto",
|
588 |
+
interactive=True,
|
589 |
+
show_label=True,
|
590 |
+
elem_classes=["gallery-container"]
|
591 |
+
)
|
592 |
|
593 |
# Event handlers
|
594 |
+
use_as_input_button.click(
|
595 |
+
fn=use_output_as_input,
|
596 |
+
inputs=[result],
|
597 |
+
outputs=[input_image],
|
598 |
+
show_api=False
|
599 |
+
)
|
600 |
+
|
601 |
+
history_gallery.select(
|
602 |
+
fn=use_history_as_input,
|
603 |
+
inputs=[history_gallery],
|
604 |
+
outputs=[input_image],
|
605 |
+
show_api=False
|
606 |
+
)
|
607 |
+
|
608 |
+
clear_history_button.click(
|
609 |
+
fn=lambda: [],
|
610 |
+
inputs=None,
|
611 |
+
outputs=history_gallery,
|
612 |
+
show_api=False
|
613 |
+
)
|
614 |
+
|
615 |
target_ratio.change(
|
616 |
fn=preload_presets,
|
617 |
inputs=[target_ratio, width_slider, height_slider],
|
|
|
656 |
queue=False,
|
657 |
)
|
658 |
|
659 |
+
# Main generation pipeline with result clearing, history update, and button visibility
|
660 |
+
run_button.click(
|
661 |
+
fn=clear_result,
|
662 |
+
inputs=None,
|
663 |
+
outputs=result,
|
664 |
+
show_api=False
|
665 |
+
).then(
|
666 |
fn=infer,
|
667 |
inputs=[
|
668 |
input_image,
|
|
|
684 |
rewrite_prompt,
|
685 |
],
|
686 |
outputs=[result, seed],
|
687 |
+
).then(
|
688 |
+
fn=lambda: gr.update(visible=True),
|
689 |
+
inputs=None,
|
690 |
+
outputs=use_as_input_button,
|
691 |
+
show_api=False
|
692 |
+
).then(
|
693 |
+
fn=update_history,
|
694 |
+
inputs=[result, history_gallery],
|
695 |
+
outputs=history_gallery,
|
696 |
+
show_api=False
|
697 |
+
)
|
698 |
+
|
699 |
+
# Also trigger on prompt submit
|
700 |
+
prompt.submit(
|
701 |
+
fn=clear_result,
|
702 |
+
inputs=None,
|
703 |
+
outputs=result,
|
704 |
+
show_api=False
|
705 |
+
).then(
|
706 |
+
fn=infer,
|
707 |
+
inputs=[
|
708 |
+
input_image,
|
709 |
+
prompt,
|
710 |
+
width_slider,
|
711 |
+
height_slider,
|
712 |
+
overlap_percentage,
|
713 |
+
resize_option,
|
714 |
+
custom_resize_percentage,
|
715 |
+
alignment_dropdown,
|
716 |
+
overlap_left,
|
717 |
+
overlap_right,
|
718 |
+
overlap_top,
|
719 |
+
overlap_bottom,
|
720 |
+
seed,
|
721 |
+
randomize_seed,
|
722 |
+
true_guidance_scale,
|
723 |
+
num_inference_steps,
|
724 |
+
rewrite_prompt,
|
725 |
+
],
|
726 |
+
outputs=[result, seed],
|
727 |
+
).then(
|
728 |
+
fn=lambda: gr.update(visible=True),
|
729 |
+
inputs=None,
|
730 |
+
outputs=use_as_input_button,
|
731 |
+
show_api=False
|
732 |
+
).then(
|
733 |
+
fn=update_history,
|
734 |
+
inputs=[result, history_gallery],
|
735 |
+
outputs=history_gallery,
|
736 |
+
show_api=False
|
737 |
)
|
738 |
|
739 |
if __name__ == "__main__":
|