Spaces:
Running
on
Zero
Running
on
Zero
import spaces | |
import gradio as gr | |
import torch | |
import math | |
from PIL import Image | |
from diffusers import QwenImageEditPlusPipeline, FlowMatchEulerDiscreteScheduler | |
# Load pipeline with optimized scheduler at startup | |
scheduler_config = { | |
"base_image_seq_len": 256, | |
"base_shift": math.log(3), | |
"invert_sigmas": False, | |
"max_image_seq_len": 8192, | |
"max_shift": math.log(3), | |
"num_train_timesteps": 1000, | |
"shift": 1.0, | |
"shift_terminal": None, | |
"stochastic_sampling": False, | |
"time_shift_type": "exponential", | |
"use_beta_sigmas": False, | |
"use_dynamic_shifting": True, | |
"use_exponential_sigmas": False, | |
"use_karras_sigmas": False, | |
} | |
scheduler = FlowMatchEulerDiscreteScheduler.from_config(scheduler_config) | |
pipeline = QwenImageEditPlusPipeline.from_pretrained( | |
"Qwen/Qwen-Image-Edit-2509", | |
scheduler=scheduler, | |
torch_dtype=torch.bfloat16 | |
) | |
pipeline.to('cuda') | |
pipeline.set_progress_bar_config(disable=None) | |
# Load LoRA for faster inference | |
pipeline.load_lora_weights( | |
"lightx2v/Qwen-Image-Lightning", | |
weight_name="Qwen-Image-Lightning-8steps-V2.0-bf16.safetensors" | |
) | |
pipeline.fuse_lora() | |
def edit_images(image1, image2, prompt, seed, true_cfg_scale, negative_prompt, num_steps, guidance_scale): | |
if image1 is None or image2 is None: | |
gr.Warning("Please upload both images") | |
return None | |
# Convert to PIL if needed | |
if not isinstance(image1, Image.Image): | |
image1 = Image.fromarray(image1) | |
if not isinstance(image2, Image.Image): | |
image2 = Image.fromarray(image2) | |
inputs = { | |
"image": [image1, image2], | |
"prompt": prompt, | |
"generator": torch.manual_seed(seed), | |
"true_cfg_scale": true_cfg_scale, | |
"negative_prompt": negative_prompt, | |
"num_inference_steps": num_steps, | |
"guidance_scale": guidance_scale, | |
"num_images_per_prompt": 1, | |
} | |
with torch.inference_mode(): | |
output = pipeline(**inputs) | |
return output.images[0] | |
# Example prompts and images | |
example_prompts = [ | |
"The magician bear is on the left, the alchemist bear is on the right, facing each other in the central park square.", | |
"Two characters standing side by side in a beautiful garden with flowers blooming", | |
"The hero on the left and the villain on the right, facing off in an epic battle scene", | |
"Two friends sitting together on a park bench, enjoying the sunset", | |
] | |
# Example image paths | |
example_images = [ | |
["bear1.jpg", "bear2.jpg", "The magician bear is on the left, the alchemist bear is on the right, facing each other in the central park square."], | |
] | |
with gr.Blocks(css="footer {visibility: hidden}") as demo: | |
gr.Markdown( | |
""" | |
# Qwen Image Edit Plus (Optimized) | |
Upload two images and describe how you want them combined or edited together. | |
[Built with anycoder](https://huggingface.co/spaces/akhaliq/anycoder) | |
""" | |
) | |
with gr.Row(): | |
with gr.Column(): | |
image1_input = gr.Image( | |
label="First Image", | |
type="pil", | |
height=300 | |
) | |
image2_input = gr.Image( | |
label="Second Image", | |
type="pil", | |
height=300 | |
) | |
with gr.Column(): | |
output_image = gr.Image( | |
label="Edited Result", | |
type="pil", | |
height=620 | |
) | |
with gr.Group(): | |
prompt_input = gr.Textbox( | |
label="Prompt", | |
placeholder="Describe how you want the images combined or edited...", | |
value=example_prompts[0], | |
lines=3 | |
) | |
gr.Examples( | |
examples=example_images, | |
inputs=[image1_input, image2_input, prompt_input], | |
label="Example Images and Prompts" | |
) | |
gr.Examples( | |
examples=[[p] for p in example_prompts], | |
inputs=[prompt_input], | |
label="Example Prompts Only" | |
) | |
with gr.Accordion("Advanced Settings", open=False): | |
with gr.Row(): | |
seed_input = gr.Number( | |
label="Seed", | |
value=0, | |
precision=0 | |
) | |
num_steps = gr.Slider( | |
label="Number of Inference Steps", | |
minimum=8, | |
maximum=30, | |
value=8, | |
step=1 | |
) | |
with gr.Row(): | |
true_cfg_scale = gr.Slider( | |
label="True CFG Scale", | |
minimum=1.0, | |
maximum=10.0, | |
value=1.0, | |
step=0.5 | |
) | |
guidance_scale = gr.Slider( | |
label="Guidance Scale", | |
minimum=1.0, | |
maximum=5.0, | |
value=1.0, | |
step=0.1 | |
) | |
negative_prompt = gr.Textbox( | |
label="Negative Prompt", | |
value=" ", | |
placeholder="What to avoid in the generation..." | |
) | |
generate_btn = gr.Button("Generate Edited Image", variant="primary", size="lg") | |
generate_btn.click( | |
fn=edit_images, | |
inputs=[ | |
image1_input, | |
image2_input, | |
prompt_input, | |
seed_input, | |
true_cfg_scale, | |
negative_prompt, | |
num_steps, | |
guidance_scale | |
], | |
outputs=output_image, | |
show_progress="full" | |
) | |
demo.launch() |