Spaces:
Running on Zero
Running on Zero
Professional Noob commited on
Update app.py
Browse files
app.py
CHANGED
|
@@ -366,26 +366,76 @@ LOADED_ADAPTERS = set()
|
|
| 366 |
# Helpers: resolution
|
| 367 |
# ============================================================
|
| 368 |
|
|
|
|
|
|
|
| 369 |
|
| 370 |
-
def
|
| 371 |
-
return max(
|
| 372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
|
| 374 |
-
|
|
|
|
| 375 |
w, h = image.size
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 384 |
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 795 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
)
|