prithivMLmods commited on
Commit
e93e938
·
verified ·
1 Parent(s): e8d7cbd

update app

Browse files
Files changed (1) hide show
  1. app.py +115 -72
app.py CHANGED
@@ -15,6 +15,7 @@ from gradio.themes.utils import colors, fonts, sizes
15
  import rerun as rr
16
  from gradio_rerun import Rerun
17
 
 
18
  colors.orange_red = colors.Color(
19
  name="orange_red",
20
  c50="#FFF0E5",
@@ -83,11 +84,8 @@ class OrangeRedTheme(Soft):
83
 
84
  orange_red_theme = OrangeRedTheme()
85
 
 
86
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
87
-
88
- print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
89
- print("torch.__version__ =", torch.__version__)
90
- print("torch.version.cuda =", torch.version.cuda)
91
  print("Using device:", device)
92
 
93
  from diffusers import FlowMatchEulerDiscreteScheduler
@@ -97,6 +95,7 @@ from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
97
 
98
  dtype = torch.bfloat16
99
 
 
100
  pipe = QwenImageEditPlusPipeline.from_pretrained(
101
  "Qwen/Qwen-Image-Edit-2511",
102
  transformer=QwenImageTransformer2DModel.from_pretrained(
@@ -155,7 +154,7 @@ def update_dimensions_on_upload(image):
155
 
156
  @spaces.GPU
157
  def infer(
158
- input_image,
159
  prompt,
160
  lora_adapter,
161
  seed,
@@ -164,12 +163,17 @@ def infer(
164
  steps,
165
  progress=gr.Progress(track_tqdm=True)
166
  ):
 
 
 
 
167
  gc.collect()
168
  torch.cuda.empty_cache()
169
 
170
- if input_image is None:
171
- raise gr.Error("Please upload an image to edit.")
172
 
 
173
  spec = ADAPTER_SPECS.get(lora_adapter)
174
  if not spec:
175
  raise gr.Error(f"Configuration not found for: {lora_adapter}")
@@ -198,67 +202,91 @@ def infer(
198
  generator = torch.Generator(device=device).manual_seed(seed)
199
  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"
200
 
201
- original_image = input_image.convert("RGB")
202
- width, height = update_dimensions_on_upload(original_image)
203
-
204
- try:
205
- progress(0.4, desc="Generating Image...")
206
- result_image = pipe(
207
- image=original_image,
208
- prompt=prompt,
209
- negative_prompt=negative_prompt,
210
- height=height,
211
- width=width,
212
- num_inference_steps=steps,
213
- generator=generator,
214
- true_cfg_scale=guidance_scale,
215
- ).images[0]
216
-
217
- # --- Rerun Visualization Logic ---
218
- progress(0.9, desc="Preparing Rerun Visualization...")
219
-
220
- run_id = str(uuid.uuid4())
221
-
222
- # Handle different Rerun SDK versions robustly
223
- rec = None
224
- if hasattr(rr, "new_recording"):
225
- # Newer Rerun versions
226
- rec = rr.new_recording(application_id="Qwen-Image-Edit", recording_id=run_id)
227
- elif hasattr(rr, "RecordingStream"):
228
- # Alternative direct class instantiation
229
- rec = rr.RecordingStream(application_id="Qwen-Image-Edit", recording_id=run_id)
230
  else:
231
- # Fallback for older versions or simple scripts (Global State)
232
- rr.init("Qwen-Image-Edit", recording_id=run_id, spawn=False)
233
- rec = rr
234
 
235
- # Log images to Rerun
236
- # rec.log handles logging for both RecordingStream objects and the global rr module
237
- rec.log("images/original", rr.Image(np.array(original_image)))
238
- rec.log("images/edited", rr.Image(np.array(result_image)))
239
-
240
- # Save RRD
241
- rrd_path = os.path.join(TMP_DIR, f"{run_id}.rrd")
242
- rec.save(rrd_path)
243
-
244
- return rrd_path, seed
245
 
246
- except Exception as e:
247
- raise e
248
- finally:
249
- gc.collect()
250
- torch.cuda.empty_cache()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
 
252
  @spaces.GPU
253
- def infer_example(input_image, prompt, lora_adapter):
254
- if input_image is None:
 
 
255
  return None, 0
256
 
257
- input_pil = input_image.convert("RGB")
258
- guidance_scale = 1.0
259
- steps = 4
260
- # Call main infer but ignore progress for examples if needed
261
- result_rrd, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
 
 
 
 
 
262
  return result_rrd, seed
263
 
264
  css="""
@@ -271,12 +299,19 @@ css="""
271
 
272
  with gr.Blocks() as demo:
273
  with gr.Column(elem_id="col-container"):
274
- gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast**", elem_id="main-title")
275
- 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.")
276
 
277
  with gr.Row(equal_height=True):
278
  with gr.Column():
279
- input_image = gr.Image(label="Upload Image", type="pil", height=290)
 
 
 
 
 
 
 
280
 
281
  prompt = gr.Text(
282
  label="Edit Prompt",
@@ -284,12 +319,11 @@ with gr.Blocks() as demo:
284
  placeholder="e.g., transform into anime..",
285
  )
286
 
287
- run_button = gr.Button("Edit Image", variant="primary")
288
 
289
  with gr.Column():
290
- # Replaced standard Image with Rerun Viewer
291
  rerun_output = Rerun(
292
- label="Rerun Visualization",
293
  height=353
294
  )
295
 
@@ -305,23 +339,32 @@ with gr.Blocks() as demo:
305
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
306
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
307
 
 
308
  gr.Examples(
309
  examples=[
310
- ["examples/B.jpg", "Transform into anime.", "Photo-to-Anime"],
311
- ["examples/A.jpeg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
 
 
 
 
 
 
 
 
312
  ],
313
- inputs=[input_image, prompt, lora_adapter],
314
  outputs=[rerun_output, seed],
315
  fn=infer_example,
316
  cache_examples=False,
317
  label="Examples"
318
  )
319
 
320
- 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.")
321
 
322
  run_button.click(
323
  fn=infer,
324
- inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
325
  outputs=[rerun_output, seed]
326
  )
327
 
 
15
  import rerun as rr
16
  from gradio_rerun import Rerun
17
 
18
+ # --- Theme Configuration ---
19
  colors.orange_red = colors.Color(
20
  name="orange_red",
21
  c50="#FFF0E5",
 
84
 
85
  orange_red_theme = OrangeRedTheme()
86
 
87
+ # --- Device Setup ---
88
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
 
 
 
89
  print("Using device:", device)
90
 
91
  from diffusers import FlowMatchEulerDiscreteScheduler
 
95
 
96
  dtype = torch.bfloat16
97
 
98
+ # --- Model Loading ---
99
  pipe = QwenImageEditPlusPipeline.from_pretrained(
100
  "Qwen/Qwen-Image-Edit-2511",
101
  transformer=QwenImageTransformer2DModel.from_pretrained(
 
154
 
155
  @spaces.GPU
156
  def infer(
157
+ input_gallery,
158
  prompt,
159
  lora_adapter,
160
  seed,
 
163
  steps,
164
  progress=gr.Progress(track_tqdm=True)
165
  ):
166
+ """
167
+ Processes a list of images from the gallery.
168
+ Logs each image pair (original, edited) to a Rerun timeline.
169
+ """
170
  gc.collect()
171
  torch.cuda.empty_cache()
172
 
173
+ if not input_gallery:
174
+ raise gr.Error("Please upload at least one image.")
175
 
176
+ # 1. Load Adapter
177
  spec = ADAPTER_SPECS.get(lora_adapter)
178
  if not spec:
179
  raise gr.Error(f"Configuration not found for: {lora_adapter}")
 
202
  generator = torch.Generator(device=device).manual_seed(seed)
203
  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"
204
 
205
+ # 2. Setup Rerun
206
+ run_id = str(uuid.uuid4())
207
+ if hasattr(rr, "new_recording"):
208
+ rec = rr.new_recording(application_id="Qwen-Image-Edit-Multi", recording_id=run_id)
209
+ elif hasattr(rr, "RecordingStream"):
210
+ rec = rr.RecordingStream(application_id="Qwen-Image-Edit-Multi", recording_id=run_id)
211
+ else:
212
+ rr.init("Qwen-Image-Edit-Multi", recording_id=run_id, spawn=False)
213
+ rec = rr
214
+
215
+ # 3. Iterate through Gallery
216
+ # input_gallery is a list of PIL Images (when type="pil") or objects depending on version.
217
+
218
+ total_images = len(input_gallery)
219
+
220
+ for idx, img_obj in enumerate(input_gallery):
221
+ # Gradio Gallery type="pil" returns a list of tuples (image, caption) or images.
222
+ # We ensure we get the PIL image.
223
+ if isinstance(img_obj, (tuple, list)):
224
+ input_pil = img_obj[0]
 
 
 
 
 
 
 
 
 
225
  else:
226
+ input_pil = img_obj
 
 
227
 
228
+ if not isinstance(input_pil, Image.Image):
229
+ # Try converting if it's a path string (fallback)
230
+ try:
231
+ input_pil = Image.open(input_pil)
232
+ except:
233
+ continue
234
+
235
+ input_pil = input_pil.convert("RGB")
236
+ width, height = update_dimensions_on_upload(input_pil)
 
237
 
238
+ progress((idx + 1) / total_images, desc=f"Processing Image {idx+1}/{total_images}...")
239
+
240
+ try:
241
+ result_image = pipe(
242
+ image=input_pil,
243
+ prompt=prompt,
244
+ negative_prompt=negative_prompt,
245
+ height=height,
246
+ width=width,
247
+ num_inference_steps=steps,
248
+ generator=generator,
249
+ true_cfg_scale=guidance_scale,
250
+ ).images[0]
251
+
252
+ # Log to Rerun Timeline
253
+ # We use 'sample_index' as the timeline axis.
254
+ # In the viewer, dragging the slider changes the visible image.
255
+ rec.set_time_sequence("image_index", idx)
256
+ rec.log("images/original", rr.Image(np.array(input_pil)))
257
+ rec.log("images/edited", rr.Image(np.array(result_image)))
258
+ rec.log("metadata/prompt", rr.TextDocument(f"Image {idx+1}: {prompt}"))
259
+
260
+ except Exception as e:
261
+ print(f"Error processing image {idx}: {e}")
262
+ continue
263
+
264
+ # 4. Save RRD
265
+ rrd_path = os.path.join(TMP_DIR, f"{run_id}.rrd")
266
+ rec.save(rrd_path)
267
+
268
+ gc.collect()
269
+ torch.cuda.empty_cache()
270
+
271
+ return rrd_path, seed
272
 
273
  @spaces.GPU
274
+ def infer_example(input_gallery, prompt, lora_adapter):
275
+ # Wrapper for examples
276
+ # input_gallery comes as a list of file paths from gr.Examples
277
+ if not input_gallery:
278
  return None, 0
279
 
280
+ pil_list = []
281
+ for path in input_gallery:
282
+ pil_list.append(Image.open(path))
283
+
284
+ result_rrd, seed = infer(
285
+ pil_list,
286
+ prompt,
287
+ lora_adapter,
288
+ 0, True, 1.0, 4
289
+ )
290
  return result_rrd, seed
291
 
292
  css="""
 
299
 
300
  with gr.Blocks() as demo:
301
  with gr.Column(elem_id="col-container"):
302
+ gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast (Multi-Image)**", elem_id="main-title")
303
+ gr.Markdown("Perform diverse image edits on **multiple images** at once using specialized LoRA adapters. View results in the Rerun timeline.")
304
 
305
  with gr.Row(equal_height=True):
306
  with gr.Column():
307
+ # CHANGED: Using Gallery instead of Image
308
+ input_gallery = gr.Gallery(
309
+ label="Upload Images",
310
+ type="pil",
311
+ columns=2,
312
+ height=300,
313
+ allow_preview=True
314
+ )
315
 
316
  prompt = gr.Text(
317
  label="Edit Prompt",
 
319
  placeholder="e.g., transform into anime..",
320
  )
321
 
322
+ run_button = gr.Button("Edit Images", variant="primary")
323
 
324
  with gr.Column():
 
325
  rerun_output = Rerun(
326
+ label="Rerun Visualization (Use Slider)",
327
  height=353
328
  )
329
 
 
339
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
340
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
341
 
342
+ # UPDATED: Examples must handle list of paths for gallery
343
  gr.Examples(
344
  examples=[
345
+ [
346
+ ["examples/B.jpg"],
347
+ "Transform into anime.",
348
+ "Photo-to-Anime"
349
+ ],
350
+ [
351
+ ["examples/A.jpeg", "examples/B.jpg"],
352
+ "Rotate the camera 45 degrees to the right.",
353
+ "Multiple-Angles"
354
+ ],
355
  ],
356
+ inputs=[input_gallery, prompt, lora_adapter],
357
  outputs=[rerun_output, seed],
358
  fn=infer_example,
359
  cache_examples=False,
360
  label="Examples"
361
  )
362
 
363
+ # gr.Markdown("Note: When multiple images are processed, use the **timeline slider** in the Rerun viewer to switch between them.")
364
 
365
  run_button.click(
366
  fn=infer,
367
+ inputs=[input_gallery, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
368
  outputs=[rerun_output, seed]
369
  )
370