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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -78
app.py CHANGED
@@ -84,7 +84,7 @@ class OrangeRedTheme(Soft):
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
 
@@ -117,6 +117,7 @@ MAX_SEED = np.iinfo(np.int32).max
117
  TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp_rerun')
118
  os.makedirs(TMP_DIR, exist_ok=True)
119
 
 
120
  ADAPTER_SPECS = {
121
  "Multiple-Angles": {
122
  "repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
@@ -163,17 +164,13 @@ def infer(
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}")
@@ -196,99 +193,107 @@ def infer(
196
 
197
  pipe.set_adapters([adapter_name], adapter_weights=[1.0])
198
 
199
- if randomize_seed:
200
- seed = random.randint(0, MAX_SEED)
201
-
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="""
293
  #col-container {
294
  margin: 0 auto;
@@ -300,11 +305,11 @@ css="""
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",
@@ -319,11 +324,11 @@ with gr.Blocks() as demo:
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,19 +344,12 @@ with gr.Blocks() as demo:
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],
@@ -360,7 +358,7 @@ with gr.Blocks() as demo:
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,
 
84
 
85
  orange_red_theme = OrangeRedTheme()
86
 
87
+ # --- Hardware Setup ---
88
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
89
  print("Using device:", device)
90
 
 
117
  TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp_rerun')
118
  os.makedirs(TMP_DIR, exist_ok=True)
119
 
120
+ # --- Adapters ---
121
  ADAPTER_SPECS = {
122
  "Multiple-Angles": {
123
  "repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
 
164
  steps,
165
  progress=gr.Progress(track_tqdm=True)
166
  ):
 
 
 
 
167
  gc.collect()
168
  torch.cuda.empty_cache()
169
 
170
  if not input_gallery:
171
+ raise gr.Error("Please upload at least one image to edit.")
172
 
173
+ # --- Adapter Loading ---
174
  spec = ADAPTER_SPECS.get(lora_adapter)
175
  if not spec:
176
  raise gr.Error(f"Configuration not found for: {lora_adapter}")
 
193
 
194
  pipe.set_adapters([adapter_name], adapter_weights=[1.0])
195
 
196
+ # --- Setup Rerun ---
 
 
 
 
 
 
197
  run_id = str(uuid.uuid4())
198
  if hasattr(rr, "new_recording"):
199
+ rec = rr.new_recording(application_id="Qwen-Image-Edit", recording_id=run_id)
200
  elif hasattr(rr, "RecordingStream"):
201
+ rec = rr.RecordingStream(application_id="Qwen-Image-Edit", recording_id=run_id)
202
  else:
203
+ rr.init("Qwen-Image-Edit", recording_id=run_id, spawn=False)
204
  rec = rr
205
 
206
+ # --- Processing Loop ---
207
+ # gr.Gallery(type="pil") returns a list of tuples: [(PIL.Image, str_caption), ...]
208
+ # We iterate over them.
209
 
210
  total_images = len(input_gallery)
211
 
212
+ for i, item in enumerate(input_gallery):
213
+ # Handle format: item might be (image, caption) tuple or just image depending on version/updates
214
+ if isinstance(item, (tuple, list)):
215
+ input_pil = item[0]
 
216
  else:
217
+ input_pil = item
218
+
219
+ if randomize_seed:
220
+ current_seed = random.randint(0, MAX_SEED)
221
+ else:
222
+ current_seed = seed
223
+
224
+ generator = torch.Generator(device=device).manual_seed(current_seed)
225
+ 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"
226
 
227
  input_pil = input_pil.convert("RGB")
228
  width, height = update_dimensions_on_upload(input_pil)
229
 
 
 
230
  try:
231
+ progress((i + 0.5) / total_images, desc=f"Processing Image {i+1}/{total_images}...")
232
+
233
+ with torch.inference_mode():
234
+ result_image = pipe(
235
+ image=input_pil,
236
+ prompt=prompt,
237
+ negative_prompt=negative_prompt,
238
+ height=height,
239
+ width=width,
240
+ num_inference_steps=steps,
241
+ generator=generator,
242
+ true_cfg_scale=guidance_scale,
243
+ ).images[0]
244
+
245
+ # --- Log to Rerun ---
246
+ # We use set_time_sequence to create a timeline slider in the Rerun viewer
247
+ # allowing the user to slide through their batch of images.
248
+ rec.set_time_sequence("batch_index", i)
249
  rec.log("images/original", rr.Image(np.array(input_pil)))
250
  rec.log("images/edited", rr.Image(np.array(result_image)))
251
+
 
252
  except Exception as e:
253
+ print(f"Error processing image {i}: {e}")
254
  continue
255
+ finally:
256
+ # Clear VRAM after every image to avoid stacking up memory usage
257
+ gc.collect()
258
+ torch.cuda.empty_cache()
259
 
260
+ # Save RRD
261
  rrd_path = os.path.join(TMP_DIR, f"{run_id}.rrd")
262
  rec.save(rrd_path)
263
 
 
 
 
264
  return rrd_path, seed
265
 
266
  @spaces.GPU
267
  def infer_example(input_gallery, prompt, lora_adapter):
268
  # Wrapper for examples
 
269
  if not input_gallery:
270
  return None, 0
271
 
272
+ # input_gallery comes as a list of paths from Examples,
273
+ # we need to load them as PIL images to mimic the Gallery output structure for the main function if needed,
274
+ # BUT gr.Gallery in examples usually passes list of paths.
275
+ # The main logic above expects tuples of (PIL, caption) OR PIL.
276
+ # Let's ensure we convert paths to PIL here.
277
+
278
+ processed_gallery = []
279
  for path in input_gallery:
280
+ if isinstance(path, str):
281
+ processed_gallery.append((Image.open(path), ""))
282
+ else:
283
+ processed_gallery.append((path, "")) # Already PIL or weird format
284
+
285
  result_rrd, seed = infer(
286
+ processed_gallery,
287
  prompt,
288
  lora_adapter,
289
+ 0, # seed
290
+ True, # randomize
291
+ 1.0, # guidance
292
+ 4 # steps
293
  )
294
  return result_rrd, seed
295
 
296
+ # --- Gradio UI Layout ---
297
  css="""
298
  #col-container {
299
  margin: 0 auto;
 
305
  with gr.Blocks() as demo:
306
  with gr.Column(elem_id="col-container"):
307
  gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast (Multi-Image)**", elem_id="main-title")
308
+ gr.Markdown("Perform diverse image edits using specialized adapters. Upload multiple images to process them in a batch. Use the timeline slider in the output to view results.")
309
 
310
  with gr.Row(equal_height=True):
311
  with gr.Column():
312
+ # Changed to Gallery for multi-upload
313
  input_gallery = gr.Gallery(
314
  label="Upload Images",
315
  type="pil",
 
324
  placeholder="e.g., transform into anime..",
325
  )
326
 
327
+ run_button = gr.Button("Edit Batch", variant="primary")
328
 
329
  with gr.Column():
330
  rerun_output = Rerun(
331
+ label="Rerun Visualization",
332
  height=353
333
  )
334
 
 
344
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
345
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
346
 
347
+ # Updated Examples to be lists of paths
348
  gr.Examples(
349
  examples=[
350
+ [["examples/B.jpg"], "Transform into anime.", "Photo-to-Anime"],
351
+ [["examples/A.jpeg"], "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
352
+ [["examples/B.jpg", "examples/A.jpeg"], "Transform into sketches.", "Photo-to-Anime"],
 
 
 
 
 
 
 
353
  ],
354
  inputs=[input_gallery, prompt, lora_adapter],
355
  outputs=[rerun_output, seed],
 
358
  label="Examples"
359
  )
360
 
361
+ gr.Markdown("[*](https://huggingface.co/spaces/prithivMLmods/Qwen-Image-Edit-2511-LoRAs-Fast) Experimental Space.")
362
 
363
  run_button.click(
364
  fn=infer,