prithivMLmods commited on
Commit
c2860de
·
verified ·
1 Parent(s): 8f395b3

update app

Browse files
Files changed (1) hide show
  1. app.py +347 -12
app.py CHANGED
@@ -5,11 +5,17 @@ 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.deep_sky_blue = colors.Color(
14
  name="deep_sky_blue",
15
  c50="#E0F7FF",
@@ -83,12 +89,318 @@ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
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("cuda device count:", torch.cuda.device_count())
88
- if torch.cuda.is_available():
89
- print("current device:", torch.cuda.current_device())
90
- print("device name:", torch.cuda.get_device_name(torch.cuda.current_device()))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  print("Using device:", device)
93
 
94
  from diffusers import FlowMatchEulerDiscreteScheduler
@@ -116,6 +428,8 @@ except Exception as e:
116
  print(f"Warning: Could not set FA3 processor: {e}")
117
 
118
  MAX_SEED = np.iinfo(np.int32).max
 
 
119
 
120
  ADAPTER_SPECS = {
121
  "Multiple-Angles": {
@@ -196,7 +510,8 @@ def infer(
196
  width, height = update_dimensions_on_upload(original_image)
197
 
198
  try:
199
- result = pipe(
 
200
  image=original_image,
201
  prompt=prompt,
202
  negative_prompt=negative_prompt,
@@ -207,7 +522,22 @@ def infer(
207
  true_cfg_scale=guidance_scale,
208
  ).images[0]
209
 
210
- return result, seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
  except Exception as e:
213
  raise e
@@ -223,8 +553,9 @@ def infer_example(input_image, prompt, lora_adapter):
223
  input_pil = input_image.convert("RGB")
224
  guidance_scale = 1.0
225
  steps = 4
226
- result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
227
- return result, seed
 
228
 
229
  css="""
230
  #col-container {
@@ -252,7 +583,11 @@ with gr.Blocks() as demo:
252
  run_button = gr.Button("Edit Image", variant="primary")
253
 
254
  with gr.Column():
255
- output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
 
 
 
 
256
 
257
  with gr.Row():
258
  lora_adapter = gr.Dropdown(
@@ -271,7 +606,7 @@ with gr.Blocks() as demo:
271
  ["examples/A.jpeg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
272
  ],
273
  inputs=[input_image, prompt, lora_adapter],
274
- outputs=[output_image, seed],
275
  fn=infer_example,
276
  cache_examples=False,
277
  label="Examples"
@@ -282,7 +617,7 @@ with gr.Blocks() as demo:
282
  run_button.click(
283
  fn=infer,
284
  inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
285
- outputs=[output_image, seed]
286
  )
287
 
288
  if __name__ == "__main__":
 
5
  import spaces
6
  import torch
7
  import random
8
+ import uuid
9
+ import tempfile
10
  from PIL import Image
11
  from typing import Iterable
12
  from gradio.themes import Soft
13
  from gradio.themes.utils import colors, fonts, sizes
14
 
15
+ # Rerun imports
16
+ import rerun as rr
17
+ from gradio_rerun import Rerun
18
+
19
  colors.deep_sky_blue = colors.Color(
20
  name="deep_sky_blue",
21
  c50="#E0F7FF",
 
89
  print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
90
  print("torch.__version__ =", torch.__version__)
91
  print("torch.version.cuda =", torch.version.cuda)
92
+ print("Using device:", device)
93
+
94
+ from diffusers import FlowMatchEulerDiscreteScheduler
95
+ from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
96
+ from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
97
+ from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
98
+
99
+ dtype = torch.bfloat16
100
+
101
+ pipe = QwenImageEditPlusPipeline.from_pretrained(
102
+ "Qwen/Qwen-Image-Edit-2511",
103
+ transformer=QwenImageTransformer2DModel.from_pretrained(
104
+ "linoyts/Qwen-Image-Edit-Rapid-AIO",
105
+ subfolder='transformer',
106
+ torch_dtype=dtype,
107
+ device_map='cuda'
108
+ ),
109
+ torch_dtype=dtype
110
+ ).to(device)
111
+
112
+ try:
113
+ pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
114
+ print("Flash Attention 3 Processor set successfully.")
115
+ except Exception as e:
116
+ print(f"Warning: Could not set FA3 processor: {e}")
117
+
118
+ MAX_SEED = np.iinfo(np.int32).max
119
+ TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp_rerun')
120
+ os.makedirs(TMP_DIR, exist_ok=True)
121
+
122
+ ADAPTER_SPECS = {
123
+ "Multiple-Angles": {
124
+ "repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
125
+ "weights": "镜头转换.safetensors",
126
+ "adapter_name": "multiple-angles"
127
+ }
128
+ }
129
+
130
+ LOADED_ADAPTERS = set()
131
+
132
+ def update_dimensions_on_upload(image):
133
+ if image is None:
134
+ return 1024, 1024
135
+
136
+ original_width, original_height = image.size
137
+
138
+ if original_width > original_height:
139
+ new_width = 1024
140
+ aspect_ratio = original_height / original_width
141
+ new_height = int(new_width * aspect_ratio)
142
+ else:
143
+ new_height = 1024
144
+ aspect_ratio = original_width / original_height
145
+ new_width = int(new_height * aspect_ratio)
146
+
147
+ new_width = (new_width // 8) * 8
148
+ new_height = (new_height // 8) * 8
149
+
150
+ return new_width, new_height
151
+
152
+ @spaces.GPU
153
+ def infer(
154
+ input_image,
155
+ prompt,
156
+ lora_adapter,
157
+ seed,
158
+ randomize_seed,
159
+ guidance_scale,
160
+ steps,
161
+ progress=gr.Progress(track_tqdm=True)
162
+ ):
163
+ gc.collect()
164
+ torch.cuda.empty_cache()
165
 
166
+ if input_image is None:
167
+ raise gr.Error("Please upload an image to edit.")
168
+
169
+ spec = ADAPTER_SPECS.get(lora_adapter)
170
+ if not spec:
171
+ raise gr.Error(f"Configuration not found for: {lora_adapter}")
172
+
173
+ adapter_name = spec["adapter_name"]
174
+
175
+ if adapter_name not in LOADED_ADAPTERS:
176
+ print(f"--- Downloading and Loading Adapter: {lora_adapter} ---")
177
+ try:
178
+ pipe.load_lora_weights(
179
+ spec["repo"],
180
+ weight_name=spec["weights"],
181
+ adapter_name=adapter_name
182
+ )
183
+ LOADED_ADAPTERS.add(adapter_name)
184
+ except Exception as e:
185
+ raise gr.Error(f"Failed to load adapter {lora_adapter}: {e}")
186
+ else:
187
+ print(f"--- Adapter {lora_adapter} is already loaded. ---")
188
+
189
+ pipe.set_adapters([adapter_name], adapter_weights=[1.0])
190
+
191
+ if randomize_seed:
192
+ seed = random.randint(0, MAX_SEED)
193
+
194
+ generator = torch.Generator(device=device).manual_seed(seed)
195
+ 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"
196
+
197
+ original_image = input_image.convert("RGB")
198
+ width, height = update_dimensions_on_upload(original_image)
199
+
200
+ try:
201
+ progress(0.4, desc="Generating Image...")
202
+ result_image = pipe(
203
+ image=original_image,
204
+ prompt=prompt,
205
+ negative_prompt=negative_prompt,
206
+ height=height,
207
+ width=width,
208
+ num_inference_steps=steps,
209
+ generator=generator,
210
+ true_cfg_scale=guidance_scale,
211
+ ).images[0]
212
+
213
+ # --- Rerun Visualization Logic ---
214
+ progress(0.9, desc="Preparing Rerun Visualization...")
215
+
216
+ run_id = str(uuid.uuid4())
217
+ rec = rr.new_recording(application_id="Qwen-Image-Edit", recording_id=run_id)
218
+
219
+ # Log images to Rerun
220
+ # We convert PIL images to numpy arrays for Rerun
221
+ rec.log("images/original", rr.Image(np.array(original_image)))
222
+ rec.log("images/edited", rr.Image(np.array(result_image)))
223
+
224
+ # Save RRD
225
+ rrd_path = os.path.join(TMP_DIR, f"{run_id}.rrd")
226
+ rec.save(rrd_path)
227
+
228
+ return rrd_path, seed
229
+
230
+ except Exception as e:
231
+ raise e
232
+ finally:
233
+ gc.collect()
234
+ torch.cuda.empty_cache()
235
+
236
+ @spaces.GPU
237
+ def infer_example(input_image, prompt, lora_adapter):
238
+ if input_image is None:
239
+ return None, 0
240
+
241
+ input_pil = input_image.convert("RGB")
242
+ guidance_scale = 1.0
243
+ steps = 4
244
+ # Call main infer but ignore progress for examples if needed
245
+ result_rrd, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
246
+ return result_rrd, seed
247
+
248
+ css="""
249
+ #col-container {
250
+ margin: 0 auto;
251
+ max-width: 960px;
252
+ }
253
+ #main-title h1 {font-size: 2.1em !important;}
254
+ """
255
+
256
+ with gr.Blocks() as demo:
257
+ with gr.Column(elem_id="col-container"):
258
+ gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast**", elem_id="main-title")
259
+ 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.")
260
+
261
+ with gr.Row(equal_height=True):
262
+ with gr.Column():
263
+ input_image = gr.Image(label="Upload Image", type="pil", height=290)
264
+
265
+ prompt = gr.Text(
266
+ label="Edit Prompt",
267
+ show_label=True,
268
+ placeholder="e.g., transform into anime..",
269
+ )
270
+
271
+ run_button = gr.Button("Edit Image", variant="primary")
272
+
273
+ with gr.Column():
274
+ # Replaced standard Image with Rerun Viewer
275
+ rerun_output = Rerun(
276
+ label="Rerun Visualization",
277
+ height=353
278
+ )
279
+
280
+ with gr.Row():
281
+ lora_adapter = gr.Dropdown(
282
+ label="Choose Editing Style",
283
+ choices=list(ADAPTER_SPECS.keys()),
284
+ value="Multiple-Angles"
285
+ )
286
+ with gr.Accordion("Advanced Settings", open=False, visible=False):
287
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
288
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
289
+ guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
290
+ steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
291
+
292
+ # Note: Cache examples might need to be False if using Rerun paths that are temporary
293
+ gr.Examples(
294
+ examples=[
295
+ ["examples/A.jpeg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
296
+ ],
297
+ inputs=[input_image, prompt, lora_adapter],
298
+ outputs=[rerun_output, seed],
299
+ fn=infer_example,
300
+ cache_examples=False,
301
+ label="Examples"
302
+ )
303
+
304
+ gr.Markdown("[*](https://huggingface.co/spaces/prithivMLmods/Qwen-Image-Edit-2511-LoRAs-Fast)This is still an experimental Space for Qwen-Image-Edit-2511; you can use [Qwen-Image-Edit-2509-LoRAs-Fast](https://huggingface.co/spaces/prithivMLmods/Qwen-Image-Edit-2509-LoRAs-Fast) instead. This Space will be updated soon.")
305
+
306
+ run_button.click(
307
+ fn=infer,
308
+ inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
309
+ outputs=[rerun_output, seed]
310
+ )
311
+
312
+ if __name__ == "__main__":
313
+ demo.queue(max_size=30).launch(css=css, theme=deep_sky_blue_theme, mcp_server=True, ssr_mode=False, show_error=True)import os
314
+ import gc
315
+ import gradio as gr
316
+ import numpy as np
317
+ import spaces
318
+ import torch
319
+ import random
320
+ import uuid
321
+ import tempfile
322
+ from PIL import Image
323
+ from typing import Iterable
324
+ from gradio.themes import Soft
325
+ from gradio.themes.utils import colors, fonts, sizes
326
+
327
+ # Rerun imports
328
+ import rerun as rr
329
+ from gradio_rerun import Rerun
330
+
331
+ colors.deep_sky_blue = colors.Color(
332
+ name="deep_sky_blue",
333
+ c50="#E0F7FF",
334
+ c100="#B3EAFF",
335
+ c200="#80DFFF",
336
+ c300="#4DD2FF",
337
+ c400="#1AC6FF",
338
+ c500="#00BFFF",
339
+ c600="#0099CC",
340
+ c700="#007399",
341
+ c800="#004C66",
342
+ c900="#002633",
343
+ c950="#00131A",
344
+ )
345
+
346
+ class DeepSkyBlueTheme(Soft):
347
+ def __init__(
348
+ self,
349
+ *,
350
+ primary_hue: colors.Color | str = colors.gray,
351
+ secondary_hue: colors.Color | str = colors.deep_sky_blue,
352
+ neutral_hue: colors.Color | str = colors.slate,
353
+ text_size: sizes.Size | str = sizes.text_lg,
354
+ font: fonts.Font | str | Iterable[fonts.Font | str] = (
355
+ fonts.GoogleFont("Outfit"), "Arial", "sans-serif",
356
+ ),
357
+ font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
358
+ fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
359
+ ),
360
+ ):
361
+ super().__init__(
362
+ primary_hue=primary_hue,
363
+ secondary_hue=secondary_hue,
364
+ neutral_hue=neutral_hue,
365
+ text_size=text_size,
366
+ font=font,
367
+ font_mono=font_mono,
368
+ )
369
+ super().set(
370
+ background_fill_primary="*primary_50",
371
+ background_fill_primary_dark="*primary_900",
372
+ body_background_fill="linear-gradient(135deg, *primary_100, #E0F7FF)",
373
+ body_background_fill_dark="linear-gradient(135deg, *primary_900, *primary_800)",
374
+ button_primary_text_color="white",
375
+ button_primary_text_color_hover="white",
376
+ button_primary_background_fill="linear-gradient(90deg, *secondary_500, *secondary_600)",
377
+ button_primary_background_fill_hover="linear-gradient(90deg, *secondary_600, *secondary_700)",
378
+ button_primary_background_fill_dark="linear-gradient(90deg, *secondary_600, *secondary_700)",
379
+ button_primary_background_fill_hover_dark="linear-gradient(90deg, *secondary_500, *secondary_600)",
380
+ button_secondary_text_color="black",
381
+ button_secondary_text_color_hover="white",
382
+ button_secondary_background_fill="linear-gradient(90deg, *primary_300, *primary_300)",
383
+ button_secondary_background_fill_hover="linear-gradient(90deg, *primary_400, *primary_400)",
384
+ button_secondary_background_fill_dark="linear-gradient(90deg, *primary_500, *primary_600)",
385
+ button_secondary_background_fill_hover_dark="linear-gradient(90deg, *primary_500, *primary_500)",
386
+ slider_color="*secondary_500",
387
+ slider_color_dark="*secondary_600",
388
+ block_title_text_weight="600",
389
+ block_border_width="3px",
390
+ block_shadow="*shadow_drop_lg",
391
+ button_primary_shadow="*shadow_drop_lg",
392
+ button_large_padding="11px",
393
+ color_accent_soft="*primary_100",
394
+ block_label_background_fill="*primary_200",
395
+ )
396
+
397
+ deep_sky_blue_theme = DeepSkyBlueTheme()
398
+
399
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
400
+
401
+ print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
402
+ print("torch.__version__ =", torch.__version__)
403
+ print("torch.version.cuda =", torch.version.cuda)
404
  print("Using device:", device)
405
 
406
  from diffusers import FlowMatchEulerDiscreteScheduler
 
428
  print(f"Warning: Could not set FA3 processor: {e}")
429
 
430
  MAX_SEED = np.iinfo(np.int32).max
431
+ TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp_rerun')
432
+ os.makedirs(TMP_DIR, exist_ok=True)
433
 
434
  ADAPTER_SPECS = {
435
  "Multiple-Angles": {
 
510
  width, height = update_dimensions_on_upload(original_image)
511
 
512
  try:
513
+ progress(0.4, desc="Generating Image...")
514
+ result_image = pipe(
515
  image=original_image,
516
  prompt=prompt,
517
  negative_prompt=negative_prompt,
 
522
  true_cfg_scale=guidance_scale,
523
  ).images[0]
524
 
525
+ # --- Rerun Visualization Logic ---
526
+ progress(0.9, desc="Preparing Rerun Visualization...")
527
+
528
+ run_id = str(uuid.uuid4())
529
+ rec = rr.new_recording(application_id="Qwen-Image-Edit", recording_id=run_id)
530
+
531
+ # Log images to Rerun
532
+ # We convert PIL images to numpy arrays for Rerun
533
+ rec.log("images/original", rr.Image(np.array(original_image)))
534
+ rec.log("images/edited", rr.Image(np.array(result_image)))
535
+
536
+ # Save RRD
537
+ rrd_path = os.path.join(TMP_DIR, f"{run_id}.rrd")
538
+ rec.save(rrd_path)
539
+
540
+ return rrd_path, seed
541
 
542
  except Exception as e:
543
  raise e
 
553
  input_pil = input_image.convert("RGB")
554
  guidance_scale = 1.0
555
  steps = 4
556
+ # Call main infer but ignore progress for examples if needed
557
+ result_rrd, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
558
+ return result_rrd, seed
559
 
560
  css="""
561
  #col-container {
 
583
  run_button = gr.Button("Edit Image", variant="primary")
584
 
585
  with gr.Column():
586
+ # Replaced standard Image with Rerun Viewer
587
+ rerun_output = Rerun(
588
+ label="Rerun Visualization",
589
+ height=353
590
+ )
591
 
592
  with gr.Row():
593
  lora_adapter = gr.Dropdown(
 
606
  ["examples/A.jpeg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
607
  ],
608
  inputs=[input_image, prompt, lora_adapter],
609
+ outputs=[rerun_output, seed],
610
  fn=infer_example,
611
  cache_examples=False,
612
  label="Examples"
 
617
  run_button.click(
618
  fn=infer,
619
  inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
620
+ outputs=[rerun_output, seed]
621
  )
622
 
623
  if __name__ == "__main__":