Professional Noob commited on
Commit
597f648
·
verified ·
1 Parent(s): 1cfb46c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -23
app.py CHANGED
@@ -366,26 +366,76 @@ LOADED_ADAPTERS = set()
366
  # Helpers: resolution
367
  # ============================================================
368
 
 
 
369
 
370
- def _round8(x: int) -> int:
371
- return max(8, (int(x) // 8) * 8)
372
 
 
 
 
 
 
 
373
 
374
- def compute_dimensions(image: Image.Image, long_edge: int) -> tuple[int, int]:
 
375
  w, h = image.size
376
- if w >= h:
377
- new_w = long_edge
378
- new_h = int(round(long_edge * (h / w)))
379
- else:
380
- new_h = long_edge
381
- new_w = int(round(long_edge * (w / h)))
382
- return _round8(new_w), _round8(new_h)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
 
 
 
 
 
384
 
385
- def get_target_long_edge_for_lora(lora_adapter: str) -> int:
386
- spec = ADAPTER_SPECS.get(lora_adapter, {})
387
- return int(spec.get("target_long_edge", 1024))
 
 
 
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
  # ============================================================
391
  # Helpers: multi-input routing + gallery normalization
@@ -702,7 +752,7 @@ def _ensure_loaded_and_get_active_adapters(selected_lora: str):
702
  # ============================================================
703
 
704
 
705
- def on_lora_change_ui(selected_lora, current_prompt):
706
  # Preset prompt (fill only if empty)
707
  if selected_lora != NONE_LORA:
708
  preset = LORA_PRESET_PROMPTS.get(selected_lora, "")
@@ -719,7 +769,14 @@ def on_lora_change_ui(selected_lora, current_prompt):
719
  else:
720
  img2_update = gr.update(visible=False, value=None, label="Upload Reference (Image 2)")
721
 
722
- return prompt_update, img2_update
 
 
 
 
 
 
 
723
 
724
 
725
  # ============================================================
@@ -738,6 +795,9 @@ def infer(
738
  randomize_seed,
739
  guidance_scale,
740
  steps,
 
 
 
741
  progress=gr.Progress(track_tqdm=True),
742
  ):
743
  gc.collect()
@@ -791,15 +851,30 @@ def infer(
791
  pipe_images = pipe_images[0]
792
 
793
  # Resolution derived from Image 1 (base/body/target)
794
- target_long_edge = get_target_long_edge_for_lora(lora_adapter)
795
- width, height = compute_dimensions(img1, target_long_edge)
 
 
 
 
 
 
 
 
 
 
 
 
796
 
797
  try:
798
  print(
799
  "[DEBUG][infer] submitting request | "
800
- f"lora_adapter={lora_adapter!r} seed={seed} prompt={prompt!r}"
 
 
 
801
  )
802
-
803
  result = pipe(
804
  image=pipe_images,
805
  prompt=prompt,
@@ -809,6 +884,8 @@ def infer(
809
  num_inference_steps=steps,
810
  generator=generator,
811
  true_cfg_scale=guidance_scale,
 
 
812
  ).images[0]
813
  return result, seed
814
  finally:
@@ -825,7 +902,7 @@ def infer_example(input_image, prompt, lora_adapter):
825
  guidance_scale = 1.0
826
  steps = 4
827
  # Examples don't supply Image 2 or extra images; and example list doesn't include AnyPose/BFS.
828
- result, seed = infer(input_pil, None, None, prompt, lora_adapter, 0, True, guidance_scale, steps)
829
  return result, seed
830
 
831
 
@@ -894,12 +971,27 @@ with gr.Blocks() as demo:
894
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
895
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
896
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
897
 
898
- # On LoRA selection: preset prompt + toggle Image 2
899
  lora_adapter.change(
900
  fn=on_lora_change_ui,
901
- inputs=[lora_adapter, prompt],
902
- outputs=[prompt, input_image_2],
903
  )
904
 
905
  gr.Examples(
@@ -948,6 +1040,9 @@ with gr.Blocks() as demo:
948
  randomize_seed,
949
  guidance_scale,
950
  steps,
 
 
 
951
  ],
952
  outputs=[output_image, seed],
953
  )
 
366
  # Helpers: resolution
367
  # ============================================================
368
 
369
+ # We prefer *area-based* sizing (≈ megapixels) over long-edge sizing.
370
+ # This aligns better with Qwen-Image-Edit's internal assumptions and reduces FOV drift.
371
 
372
+ def _round_to_multiple(x: int, m: int) -> int:
373
+ return max(m, (int(x) // m) * m)
374
 
375
+ def compute_canvas_dimensions_from_area(
376
+ image: Image.Image,
377
+ target_area: int,
378
+ multiple_of: int,
379
+ ) -> tuple[int, int]:
380
+ """Compute (width, height) that matches image aspect ratio and approximates target_area.
381
 
382
+ The result is floored to be divisible by multiple_of (typically vae_scale_factor*2).
383
+ """
384
  w, h = image.size
385
+ aspect = w / h if h else 1.0
386
+
387
+ # Use the pipeline's own area->(w,h) helper for consistency.
388
+ from qwenimage.pipeline_qwenimage_edit_plus import calculate_dimensions
389
+
390
+ width, height = calculate_dimensions(int(target_area), float(aspect))
391
+ width = _round_to_multiple(int(width), int(multiple_of))
392
+ height = _round_to_multiple(int(height), int(multiple_of))
393
+ return width, height
394
+
395
+ def get_target_area_for_lora(
396
+ image: Image.Image,
397
+ lora_adapter: str,
398
+ user_target_megapixels: float,
399
+ ) -> int:
400
+ """Return target pixel area for the canvas.
401
+
402
+ Priority:
403
+ 1) Adapter spec: target_area (pixels) or target_megapixels
404
+ 2) Adapter spec: target_long_edge (legacy) -> converted to area using image aspect
405
+ 3) User slider target megapixels
406
+ """
407
+ spec = ADAPTER_SPECS.get(lora_adapter, {})
408
 
409
+ if "target_area" in spec:
410
+ try:
411
+ return int(spec["target_area"])
412
+ except Exception:
413
+ pass
414
 
415
+ if "target_megapixels" in spec:
416
+ try:
417
+ mp = float(spec["target_megapixels"])
418
+ return int(mp * 1024 * 1024)
419
+ except Exception:
420
+ pass
421
 
422
+ # Legacy support (e.g. Upscale2K)
423
+ if "target_long_edge" in spec:
424
+ try:
425
+ long_edge = int(spec["target_long_edge"])
426
+ w, h = image.size
427
+ if w >= h:
428
+ new_w = long_edge
429
+ new_h = int(round(long_edge * (h / w)))
430
+ else:
431
+ new_h = long_edge
432
+ new_w = int(round(long_edge * (w / h)))
433
+ return int(new_w * new_h)
434
+ except Exception:
435
+ pass
436
+
437
+ # User default
438
+ return int(float(user_target_megapixels) * 1024 * 1024)
439
 
440
  # ============================================================
441
  # Helpers: multi-input routing + gallery normalization
 
752
  # ============================================================
753
 
754
 
755
+ def on_lora_change_ui(selected_lora, current_prompt, current_extras_condition_only):
756
  # Preset prompt (fill only if empty)
757
  if selected_lora != NONE_LORA:
758
  preset = LORA_PRESET_PROMPTS.get(selected_lora, "")
 
769
  else:
770
  img2_update = gr.update(visible=False, value=None, label="Upload Reference (Image 2)")
771
 
772
+ # Extra references routing default:
773
+ # For BFS/AnyPose-like adapters, it's usually safer to keep extra refs as conditioning-only.
774
+ if selected_lora in ("BFS-Best-FaceSwap", "BFS-Best-FaceSwap-merge", "AnyPose"):
775
+ extras_update = gr.update(value=True)
776
+ else:
777
+ extras_update = gr.update(value=current_extras_condition_only)
778
+
779
+ return prompt_update, img2_update, extras_update
780
 
781
 
782
  # ============================================================
 
795
  randomize_seed,
796
  guidance_scale,
797
  steps,
798
+ target_megapixels,
799
+ extras_condition_only,
800
+ pad_to_canvas,
801
  progress=gr.Progress(track_tqdm=True),
802
  ):
803
  gc.collect()
 
851
  pipe_images = pipe_images[0]
852
 
853
  # Resolution derived from Image 1 (base/body/target)
854
+ # Use target *area* (≈ megapixels) rather than long-edge sizing to reduce FOV drift.
855
+ target_area = get_target_area_for_lora(img1, lora_adapter, float(target_megapixels))
856
+ width, height = compute_canvas_dimensions_from_area(
857
+ img1,
858
+ target_area=target_area,
859
+ multiple_of=int(pipe.vae_scale_factor * 2),
860
+ )
861
+
862
+ # Decide which images participate in the VAE latent stream.
863
+ # If enabled, extra references beyond (Img_1, Img_2) become conditioning-only.
864
+ vae_image_indices = None
865
+ if extras_condition_only:
866
+ if isinstance(pipe_images, list) and len(pipe_images) > 2:
867
+ vae_image_indices = [0, 1] if len(pipe_images) >= 2 else [0]
868
 
869
  try:
870
  print(
871
  "[DEBUG][infer] submitting request | "
872
+ f"lora_adapter={lora_adapter!r} seed={seed} prompt={prompt!r} "
873
+ f"canvas={width}x{height} target_area={target_area} "
874
+ f"extras_condition_only={extras_condition_only} vae_image_indices={vae_image_indices} "
875
+ f"pad_to_canvas={bool(pad_to_canvas)}"
876
  )
877
+
878
  result = pipe(
879
  image=pipe_images,
880
  prompt=prompt,
 
884
  num_inference_steps=steps,
885
  generator=generator,
886
  true_cfg_scale=guidance_scale,
887
+ vae_image_indices=vae_image_indices,
888
+ pad_to_canvas=bool(pad_to_canvas),
889
  ).images[0]
890
  return result, seed
891
  finally:
 
902
  guidance_scale = 1.0
903
  steps = 4
904
  # Examples don't supply Image 2 or extra images; and example list doesn't include AnyPose/BFS.
905
+ result, seed = infer(input_pil, None, None, prompt, lora_adapter, 0, True, guidance_scale, steps, 1.0, True, True)
906
  return result, seed
907
 
908
 
 
971
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
972
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
973
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
974
+ target_megapixels = gr.Slider(
975
+ label="Target Megapixels (canvas)",
976
+ minimum=0.5,
977
+ maximum=6.0,
978
+ step=0.1,
979
+ value=1.0,
980
+ )
981
+ extras_condition_only = gr.Checkbox(
982
+ label="Extra references are conditioning-only (exclude from VAE)",
983
+ value=True,
984
+ )
985
+ pad_to_canvas = gr.Checkbox(
986
+ label="Pad images to canvas aspect (avoid warping)",
987
+ value=True,
988
+ )
989
 
990
+ # On LoRA selection: preset prompt + toggle Image 2 + default extras routing
991
  lora_adapter.change(
992
  fn=on_lora_change_ui,
993
+ inputs=[lora_adapter, prompt, extras_condition_only],
994
+ outputs=[prompt, input_image_2, extras_condition_only],
995
  )
996
 
997
  gr.Examples(
 
1040
  randomize_seed,
1041
  guidance_scale,
1042
  steps,
1043
+ target_megapixels,
1044
+ extras_condition_only,
1045
+ pad_to_canvas,
1046
  ],
1047
  outputs=[output_image, seed],
1048
  )