prithivMLmods commited on
Commit
339703a
·
verified ·
1 Parent(s): 9a92f4a

update app [Qwen-Image-Edit-2511]

Browse files
Files changed (1) hide show
  1. app.py +286 -0
app.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gc
3
+ import gradio as gr
4
+ import numpy as np
5
+ import spaces
6
+ import torch
7
+ import random
8
+ from PIL import Image
9
+ from typing import Iterable
10
+ from gradio.themes import Soft
11
+ from gradio.themes.utils import colors, fonts, sizes
12
+
13
+ colors.orange_red = colors.Color(
14
+ name="orange_red",
15
+ c50="#FFF0E5",
16
+ c100="#FFE0CC",
17
+ c200="#FFC299",
18
+ c300="#FFA366",
19
+ c400="#FF8533",
20
+ c500="#FF4500",
21
+ c600="#E63E00",
22
+ c700="#CC3700",
23
+ c800="#B33000",
24
+ c900="#992900",
25
+ c950="#802200",
26
+ )
27
+
28
+ class OrangeRedTheme(Soft):
29
+ def __init__(
30
+ self,
31
+ *,
32
+ primary_hue: colors.Color | str = colors.gray,
33
+ secondary_hue: colors.Color | str = colors.orange_red,
34
+ neutral_hue: colors.Color | str = colors.slate,
35
+ text_size: sizes.Size | str = sizes.text_lg,
36
+ font: fonts.Font | str | Iterable[fonts.Font | str] = (
37
+ fonts.GoogleFont("Outfit"), "Arial", "sans-serif",
38
+ ),
39
+ font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
40
+ fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
41
+ ),
42
+ ):
43
+ super().__init__(
44
+ primary_hue=primary_hue,
45
+ secondary_hue=secondary_hue,
46
+ neutral_hue=neutral_hue,
47
+ text_size=text_size,
48
+ font=font,
49
+ font_mono=font_mono,
50
+ )
51
+ super().set(
52
+ background_fill_primary="*primary_50",
53
+ background_fill_primary_dark="*primary_900",
54
+ body_background_fill="linear-gradient(135deg, *primary_200, *primary_100)",
55
+ body_background_fill_dark="linear-gradient(135deg, *primary_900, *primary_800)",
56
+ button_primary_text_color="white",
57
+ button_primary_text_color_hover="white",
58
+ button_primary_background_fill="linear-gradient(90deg, *secondary_500, *secondary_600)",
59
+ button_primary_background_fill_hover="linear-gradient(90deg, *secondary_600, *secondary_700)",
60
+ button_primary_background_fill_dark="linear-gradient(90deg, *secondary_600, *secondary_700)",
61
+ button_primary_background_fill_hover_dark="linear-gradient(90deg, *secondary_500, *secondary_600)",
62
+ button_secondary_text_color="black",
63
+ button_secondary_text_color_hover="white",
64
+ button_secondary_background_fill="linear-gradient(90deg, *primary_300, *primary_300)",
65
+ button_secondary_background_fill_hover="linear-gradient(90deg, *primary_400, *primary_400)",
66
+ button_secondary_background_fill_dark="linear-gradient(90deg, *primary_500, *primary_600)",
67
+ button_secondary_background_fill_hover_dark="linear-gradient(90deg, *primary_500, *primary_500)",
68
+ slider_color="*secondary_500",
69
+ slider_color_dark="*secondary_600",
70
+ block_title_text_weight="600",
71
+ block_border_width="3px",
72
+ block_shadow="*shadow_drop_lg",
73
+ button_primary_shadow="*shadow_drop_lg",
74
+ button_large_padding="11px",
75
+ color_accent_soft="*primary_100",
76
+ block_label_background_fill="*primary_200",
77
+ )
78
+
79
+ orange_red_theme = OrangeRedTheme()
80
+
81
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
82
+
83
+ print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
84
+ print("torch.__version__ =", torch.__version__)
85
+ print("torch.version.cuda =", torch.version.cuda)
86
+ print("cuda available:", torch.cuda.is_available())
87
+ print("Using device:", device)
88
+
89
+ from diffusers import FlowMatchEulerDiscreteScheduler
90
+ from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
91
+ from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
92
+ from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
93
+
94
+ dtype = torch.bfloat16
95
+
96
+ pipe = QwenImageEditPlusPipeline.from_pretrained(
97
+ "Qwen/Qwen-Image-Edit-2511",
98
+ transformer=QwenImageTransformer2DModel.from_pretrained(
99
+ "linoyts/Qwen-Image-Edit-Rapid-AIO",
100
+ subfolder='transformer',
101
+ torch_dtype=dtype,
102
+ device_map='cuda'
103
+ ),
104
+ torch_dtype=dtype
105
+ ).to(device)
106
+
107
+ try:
108
+ pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
109
+ print("Flash Attention 3 Processor set successfully.")
110
+ except Exception as e:
111
+ print(f"Warning: Could not set FA3 processor: {e}")
112
+
113
+ MAX_SEED = np.iinfo(np.int32).max
114
+
115
+ ADAPTER_SPECS = {
116
+ "Photo-to-Anime": {
117
+ "repo": "autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
118
+ "weights": "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
119
+ "adapter_name": "anime"
120
+ }
121
+ }
122
+
123
+ LOADED_ADAPTERS = set()
124
+
125
+ def update_dimensions_on_upload(image):
126
+ if image is None:
127
+ return 1024, 1024
128
+
129
+ original_width, original_height = image.size
130
+
131
+ if original_width > original_height:
132
+ new_width = 1024
133
+ aspect_ratio = original_height / original_width
134
+ new_height = int(new_width * aspect_ratio)
135
+ else:
136
+ new_height = 1024
137
+ aspect_ratio = original_width / original_height
138
+ new_width = int(new_height * aspect_ratio)
139
+
140
+ new_width = (new_width // 8) * 8
141
+ new_height = (new_height // 8) * 8
142
+
143
+ return new_width, new_height
144
+
145
+ @spaces.GPU(duration=60)
146
+ def infer(
147
+ input_image,
148
+ prompt,
149
+ lora_adapter,
150
+ seed,
151
+ randomize_seed,
152
+ guidance_scale,
153
+ steps,
154
+ progress=gr.Progress(track_tqdm=True)
155
+ ):
156
+ gc.collect()
157
+ torch.cuda.empty_cache()
158
+
159
+ if input_image is None:
160
+ raise gr.Error("Please upload an image to edit.")
161
+
162
+ if lora_adapter == "Base Model":
163
+ pipe.set_adapters([], adapter_weights=[])
164
+ else:
165
+ spec = ADAPTER_SPECS.get(lora_adapter)
166
+ if not spec:
167
+ raise gr.Error(f"Configuration not found for: {lora_adapter}")
168
+
169
+ adapter_name = spec["adapter_name"]
170
+
171
+ if adapter_name not in LOADED_ADAPTERS:
172
+ print(f"--- Downloading and Loading Adapter: {lora_adapter} ---")
173
+ try:
174
+ pipe.load_lora_weights(
175
+ spec["repo"],
176
+ weight_name=spec["weights"],
177
+ adapter_name=adapter_name
178
+ )
179
+ LOADED_ADAPTERS.add(adapter_name)
180
+ except Exception as e:
181
+ raise gr.Error(f"Failed to load adapter {lora_adapter}: {e}")
182
+ else:
183
+ print(f"--- Adapter {lora_adapter} is already loaded. ---")
184
+
185
+ pipe.set_adapters([adapter_name], adapter_weights=[1.0])
186
+
187
+ if randomize_seed:
188
+ seed = random.randint(0, MAX_SEED)
189
+
190
+ generator = torch.Generator(device=device).manual_seed(seed)
191
+ negative_prompt = "worst quality, low quality, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry"
192
+
193
+ original_image = input_image.convert("RGB")
194
+ width, height = update_dimensions_on_upload(original_image)
195
+
196
+ try:
197
+ result = pipe(
198
+ image=original_image,
199
+ prompt=prompt,
200
+ negative_prompt=negative_prompt,
201
+ height=height,
202
+ width=width,
203
+ num_inference_steps=steps,
204
+ generator=generator,
205
+ true_cfg_scale=guidance_scale,
206
+ ).images[0]
207
+
208
+ return result, seed
209
+
210
+ except Exception as e:
211
+ raise e
212
+ finally:
213
+ gc.collect()
214
+ torch.cuda.empty_cache()
215
+
216
+ @spaces.GPU(duration=60)
217
+ def infer_example(input_image, prompt, lora_adapter):
218
+ if input_image is None:
219
+ return None, 0
220
+
221
+ input_pil = input_image.convert("RGB")
222
+ guidance_scale = 1.0
223
+ steps = 4
224
+ result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
225
+ return result, seed
226
+
227
+ css="""
228
+ #col-container {
229
+ margin: 0 auto;
230
+ max-width: 960px;
231
+ }
232
+ #main-title h1 {font-size: 2.1em !important;}
233
+ """
234
+
235
+ with gr.Blocks() as demo:
236
+ with gr.Column(elem_id="col-container"):
237
+ gr.Markdown("# **Qwen-Image-Edit-2511-LoRA-Fast**", elem_id="main-title")
238
+ gr.Markdown("Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2511) adapters for the [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2511) model.")
239
+
240
+ with gr.Row(equal_height=True):
241
+ with gr.Column():
242
+ input_image = gr.Image(label="Upload Image", type="pil", height=290)
243
+
244
+ prompt = gr.Text(
245
+ label="Edit Prompt",
246
+ show_label=True,
247
+ placeholder="e.g., transform into anime..",
248
+ )
249
+
250
+ run_button = gr.Button("Edit Image", variant="primary")
251
+
252
+ with gr.Column():
253
+ output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
254
+
255
+ with gr.Row():
256
+ choices_list = ["Base Model"] + list(ADAPTER_SPECS.keys())
257
+ lora_adapter = gr.Dropdown(
258
+ label="Choose Editing Style",
259
+ choices=choices_list,
260
+ value="Base Model"
261
+ )
262
+ with gr.Accordion("Advanced Settings", open=False, visible=False):
263
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
264
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
265
+ guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
266
+ steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
267
+
268
+ gr.Examples(
269
+ examples=[
270
+ ["examples/1.jpg", "Transform into anime.", "Photo-to-Anime"],
271
+ ],
272
+ inputs=[input_image, prompt, lora_adapter],
273
+ outputs=[output_image, seed],
274
+ fn=infer_example,
275
+ cache_examples=False,
276
+ label="Examples"
277
+ )
278
+
279
+ run_button.click(
280
+ fn=infer,
281
+ inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
282
+ outputs=[output_image, seed]
283
+ )
284
+
285
+ if __name__ == "__main__":
286
+ demo.queue(max_size=30).launch(css=css, theme=orange_red_theme, mcp_server=True, ssr_mode=False, show_error=True)