File size: 5,613 Bytes
29a36a9
86cad56
 
d458282
86cad56
d458282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86cad56
 
 
d458282
86cad56
 
 
 
 
d458282
 
 
 
 
 
2f0e386
 
d458282
 
86cad56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f0e386
86cad56
 
 
 
 
 
 
2f0e386
 
 
 
 
86cad56
 
 
d458282
86cad56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f0e386
 
 
 
 
 
86cad56
 
 
2f0e386
86cad56
 
 
 
 
 
 
 
 
 
 
d458282
b7e06cd
d458282
86cad56
 
 
 
 
 
 
 
d458282
86cad56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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()



@spaces.GPU(duration=60)
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()