Update app.py
Browse files
app.py
CHANGED
|
@@ -272,9 +272,19 @@ def load_and_apply_stack(extra_adapters: list[str], extra_weights: list[float]):
|
|
| 272 |
|
| 273 |
return loaded, weights_out
|
| 274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
# ── Inference ──────────────────────────────────────────────────────────────────
|
| 276 |
MAX_SEED = np.iinfo(np.int32).max
|
| 277 |
-
|
| 278 |
"worst quality, low quality, bad anatomy, bad hands, text, error, "
|
| 279 |
"missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, "
|
| 280 |
"signature, watermark, username, blurry"
|
|
@@ -288,6 +298,7 @@ def infer(
|
|
| 288 |
randomize_seed,
|
| 289 |
guidance_scale,
|
| 290 |
steps,
|
|
|
|
| 291 |
*lora_params,
|
| 292 |
progress=gr.Progress(track_tqdm=True),
|
| 293 |
):
|
|
@@ -339,7 +350,7 @@ def infer(
|
|
| 339 |
result = pipe(
|
| 340 |
image=image,
|
| 341 |
prompt=prompt,
|
| 342 |
-
negative_prompt=
|
| 343 |
num_inference_steps=steps,
|
| 344 |
generator=generator,
|
| 345 |
true_cfg_scale=guidance_scale,
|
|
@@ -366,35 +377,40 @@ def infer(
|
|
| 366 |
|
| 367 |
# ── UI ─────────────────────────────────────────────────────────────────────────
|
| 368 |
css = """
|
| 369 |
-
#col-container { margin: 0 auto; max-width:
|
| 370 |
-
#main-title h1 { font-size: 2.
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
.contain-preview .image-frame,
|
| 375 |
-
.contain-preview .image-frame > div {
|
| 376 |
-
overflow: visible !important;
|
| 377 |
-
}
|
| 378 |
-
#col-container .image-frame img,
|
| 379 |
.contain-preview .image-frame img {
|
| 380 |
object-fit: contain !important;
|
| 381 |
-
height:
|
| 382 |
-
max-height: min(75vh, 900px) !important;
|
| 383 |
width: auto !important;
|
| 384 |
max-width: 100% !important;
|
| 385 |
-
margin
|
|
|
|
|
|
|
| 386 |
}
|
|
|
|
|
|
|
| 387 |
"""
|
| 388 |
|
| 389 |
LORA_NAMES = ["None"] + sorted(LORA_CONFIGS.keys())
|
| 390 |
|
| 391 |
with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
| 392 |
with gr.Column(elem_id="col-container"):
|
| 393 |
-
gr.Markdown("# **Qwen-Image-Edit
|
| 394 |
gr.Markdown(
|
| 395 |
-
"
|
| 396 |
-
"
|
| 397 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
|
| 399 |
with gr.Row(equal_height=False):
|
| 400 |
with gr.Column():
|
|
@@ -419,9 +435,9 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 419 |
)
|
| 420 |
|
| 421 |
with gr.Accordion("➕ Extra LoRAs (optional)", open=False):
|
| 422 |
-
gr.
|
| 423 |
-
"Stack up to 6 LoRAs."
|
| 424 |
-
|
| 425 |
lora_stack = []
|
| 426 |
for i in range(6):
|
| 427 |
with gr.Row():
|
|
@@ -430,6 +446,7 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 430 |
value="None",
|
| 431 |
label=f"LoRA {i + 1}",
|
| 432 |
scale=3,
|
|
|
|
| 433 |
)
|
| 434 |
sl = gr.Slider(
|
| 435 |
0.0, 1.5, value=0.75,
|
|
@@ -437,7 +454,19 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 437 |
)
|
| 438 |
lora_stack.extend([dd, sl])
|
| 439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
with gr.Accordion("⚙️ Advanced", open=False):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
seed = gr.Slider(
|
| 442 |
label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0
|
| 443 |
)
|
|
@@ -451,7 +480,7 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 451 |
|
| 452 |
run_button.click(
|
| 453 |
fn=infer,
|
| 454 |
-
inputs=[input_image, prompt, seed, randomize_seed, guidance_scale, steps]
|
| 455 |
+ lora_stack,
|
| 456 |
outputs=[output_image, seed],
|
| 457 |
)
|
|
|
|
| 272 |
|
| 273 |
return loaded, weights_out
|
| 274 |
|
| 275 |
+
|
| 276 |
+
def clear_lora_stack():
|
| 277 |
+
"""Reset all 6 LoRA dropdowns to 'None' and sliders to 0.75."""
|
| 278 |
+
updates = []
|
| 279 |
+
for _ in range(6):
|
| 280 |
+
updates.append(gr.update(value="None"))
|
| 281 |
+
updates.append(gr.update(value=0.75))
|
| 282 |
+
return updates
|
| 283 |
+
|
| 284 |
+
|
| 285 |
# ── Inference ──────────────────────────────────────────────────────────────────
|
| 286 |
MAX_SEED = np.iinfo(np.int32).max
|
| 287 |
+
DEFAULT_NEGATIVE_PROMPT = (
|
| 288 |
"worst quality, low quality, bad anatomy, bad hands, text, error, "
|
| 289 |
"missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, "
|
| 290 |
"signature, watermark, username, blurry"
|
|
|
|
| 298 |
randomize_seed,
|
| 299 |
guidance_scale,
|
| 300 |
steps,
|
| 301 |
+
negative_prompt,
|
| 302 |
*lora_params,
|
| 303 |
progress=gr.Progress(track_tqdm=True),
|
| 304 |
):
|
|
|
|
| 350 |
result = pipe(
|
| 351 |
image=image,
|
| 352 |
prompt=prompt,
|
| 353 |
+
negative_prompt=negative_prompt if guidance_scale > 1.0 else None,
|
| 354 |
num_inference_steps=steps,
|
| 355 |
generator=generator,
|
| 356 |
true_cfg_scale=guidance_scale,
|
|
|
|
| 377 |
|
| 378 |
# ── UI ─────────────────────────────────────────────────────────────────────────
|
| 379 |
css = """
|
| 380 |
+
#col-container { margin: 0 auto; max-width: 980px; }
|
| 381 |
+
#main-title h1 { font-size: 2.25em !important; letter-spacing: -0.02em; }
|
| 382 |
+
.gr-button { transition: all 0.1s ease; }
|
| 383 |
+
.gr-button:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
|
| 384 |
+
/* Better image preview */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
.contain-preview .image-frame img {
|
| 386 |
object-fit: contain !important;
|
| 387 |
+
max-height: min(78vh, 920px) !important;
|
|
|
|
| 388 |
width: auto !important;
|
| 389 |
max-width: 100% !important;
|
| 390 |
+
margin: 0 auto;
|
| 391 |
+
border-radius: 12px;
|
| 392 |
+
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
| 393 |
}
|
| 394 |
+
/* LoRA rows alignment */
|
| 395 |
+
.gr-row { align-items: center; }
|
| 396 |
"""
|
| 397 |
|
| 398 |
LORA_NAMES = ["None"] + sorted(LORA_CONFIGS.keys())
|
| 399 |
|
| 400 |
with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
| 401 |
with gr.Column(elem_id="col-container"):
|
| 402 |
+
gr.Markdown("# **Qwen-Image-Edit • 2509**", elem_id="main-title")
|
| 403 |
gr.Markdown(
|
| 404 |
+
"**Fast local LoRA-powered image editing** powered by `Qwen-Image-Edit-2509` + `Qwen-Image-Edit-Rapid-AIO-V4` + 50+ community LoRAs.<br>"
|
| 405 |
+
"Upload an image, describe the edit, optionally stack LoRAs, and hit **Edit Image**."
|
| 406 |
)
|
| 407 |
+
with gr.Accordion("💡 Quick Tips", open=False):
|
| 408 |
+
gr.Markdown(
|
| 409 |
+
"- **LoRAs auto-add trigger words** to your prompt when selected.<br>"
|
| 410 |
+
"- Keep total LoRA strength under ~2.5 to avoid artifacts.<br>"
|
| 411 |
+
"- Use **Randomize Seed** for variations of the same edit.<br>"
|
| 412 |
+
"- For best results, start with 4-8 steps and CFG 1.0–2.0."
|
| 413 |
+
)
|
| 414 |
|
| 415 |
with gr.Row(equal_height=False):
|
| 416 |
with gr.Column():
|
|
|
|
| 435 |
)
|
| 436 |
|
| 437 |
with gr.Accordion("➕ Extra LoRAs (optional)", open=False):
|
| 438 |
+
with gr.Row():
|
| 439 |
+
gr.Markdown("**Stack up to 6 LoRAs.** Select a LoRA to auto-fill trigger words in the prompt.")
|
| 440 |
+
clear_btn = gr.Button("🧹 Clear All", size="sm", variant="secondary", scale=0)
|
| 441 |
lora_stack = []
|
| 442 |
for i in range(6):
|
| 443 |
with gr.Row():
|
|
|
|
| 446 |
value="None",
|
| 447 |
label=f"LoRA {i + 1}",
|
| 448 |
scale=3,
|
| 449 |
+
interactive=True,
|
| 450 |
)
|
| 451 |
sl = gr.Slider(
|
| 452 |
0.0, 1.5, value=0.75,
|
|
|
|
| 454 |
)
|
| 455 |
lora_stack.extend([dd, sl])
|
| 456 |
|
| 457 |
+
clear_btn.click(
|
| 458 |
+
fn=clear_lora_stack,
|
| 459 |
+
inputs=None,
|
| 460 |
+
outputs=lora_stack,
|
| 461 |
+
)
|
| 462 |
+
|
| 463 |
with gr.Accordion("⚙️ Advanced", open=False):
|
| 464 |
+
negative_prompt = gr.Textbox(
|
| 465 |
+
label="Negative Prompt",
|
| 466 |
+
value=DEFAULT_NEGATIVE_PROMPT,
|
| 467 |
+
lines=2,
|
| 468 |
+
placeholder="Customize what to avoid...",
|
| 469 |
+
)
|
| 470 |
seed = gr.Slider(
|
| 471 |
label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0
|
| 472 |
)
|
|
|
|
| 480 |
|
| 481 |
run_button.click(
|
| 482 |
fn=infer,
|
| 483 |
+
inputs=[input_image, prompt, seed, randomize_seed, guidance_scale, steps, negative_prompt]
|
| 484 |
+ lora_stack,
|
| 485 |
outputs=[output_image, seed],
|
| 486 |
)
|