Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -195,24 +195,64 @@ def _list_loras():
|
|
| 195 |
return [LORA_NONE]
|
| 196 |
|
| 197 |
|
| 198 |
-
def
|
| 199 |
-
"""
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
|
| 217 |
|
| 218 |
def _build_workflow(
|
|
@@ -227,6 +267,8 @@ def _build_workflow(
|
|
| 227 |
scheduler,
|
| 228 |
lora_name=LORA_NONE,
|
| 229 |
lora_strength=1.0,
|
|
|
|
|
|
|
| 230 |
):
|
| 231 |
workflow = {
|
| 232 |
"1": {
|
|
@@ -285,7 +327,7 @@ def _build_workflow(
|
|
| 285 |
"inputs": {"conditioning": ["2", 0]},
|
| 286 |
}
|
| 287 |
|
| 288 |
-
model_ref =
|
| 289 |
workflow["5"]["inputs"]["model"] = model_ref
|
| 290 |
return workflow
|
| 291 |
|
|
@@ -329,6 +371,8 @@ def _build_edit_workflow(
|
|
| 329 |
denoise,
|
| 330 |
lora_name=LORA_NONE,
|
| 331 |
lora_strength=1.0,
|
|
|
|
|
|
|
| 332 |
):
|
| 333 |
workflow = {
|
| 334 |
"1": {
|
|
@@ -391,7 +435,7 @@ def _build_edit_workflow(
|
|
| 391 |
"inputs": {"conditioning": ["2", 0]},
|
| 392 |
}
|
| 393 |
|
| 394 |
-
model_ref =
|
| 395 |
workflow["5"]["inputs"]["model"] = model_ref
|
| 396 |
return workflow
|
| 397 |
|
|
@@ -424,10 +468,6 @@ def _wait_for_history(prompt_id, timeout=900):
|
|
| 424 |
|
| 425 |
|
| 426 |
def _load_output_image(history_item):
|
| 427 |
-
"""Downloads the generated PNG, extracts prompt/workflow from its metadata,
|
| 428 |
-
packs them into WebP's EXIF 'Make' and 'ImageDescription' tags, saves the
|
| 429 |
-
WebP file, and returns the path to it. This preserves workflow compatibility
|
| 430 |
-
with custom DnD extractors and saves tons of network bandwidth."""
|
| 431 |
outputs = history_item.get("outputs", {})
|
| 432 |
for output in outputs.values():
|
| 433 |
for image in output.get("images", []):
|
|
@@ -439,16 +479,13 @@ def _load_output_image(history_item):
|
|
| 439 |
response = requests.get(f"{COMFY_URL}/view", params=params, timeout=120)
|
| 440 |
response.raise_for_status()
|
| 441 |
|
| 442 |
-
# 1. Save temporary PNG fetched from Comfy (with metadata inside)
|
| 443 |
temp_png = Path("/tmp") / f"{uuid.uuid4().hex}.png"
|
| 444 |
temp_png.write_bytes(response.content)
|
| 445 |
|
| 446 |
-
# 2. Extract standard ComfyUI metadata
|
| 447 |
img = Image.open(temp_png)
|
| 448 |
prompt_data = img.info.get("prompt", "")
|
| 449 |
workflow_data = img.info.get("workflow", "")
|
| 450 |
|
| 451 |
-
# 3. Prepare EXIF payload for WebP matching your metadata ripper
|
| 452 |
prompt_bytes = prompt_data.encode('utf-8') if isinstance(prompt_data, str) else prompt_data
|
| 453 |
workflow_bytes = workflow_data.encode('utf-8') if isinstance(workflow_data, str) else workflow_data
|
| 454 |
|
|
@@ -460,14 +497,10 @@ def _load_output_image(history_item):
|
|
| 460 |
}
|
| 461 |
exif_bytes = piexif.dump(exif_dict)
|
| 462 |
|
| 463 |
-
# 4. Save to compressed WebP with the EXIF payload
|
| 464 |
temp_webp = Path("/tmp") / f"{uuid.uuid4().hex}.webp"
|
| 465 |
img.convert("RGB").save(temp_webp, "WEBP", exif=exif_bytes, quality=90)
|
| 466 |
|
| 467 |
-
# Cleanup temp PNG
|
| 468 |
temp_png.unlink(missing_ok=True)
|
| 469 |
-
|
| 470 |
-
# 5. Return filepath string so Gradio streams it byte-for-byte
|
| 471 |
return str(temp_webp)
|
| 472 |
|
| 473 |
raise RuntimeError("ComfyUI completed without returning an image.")
|
|
@@ -481,9 +514,6 @@ def _clamp_duration(value):
|
|
| 481 |
return max(DURATION_MIN, min(DURATION_MAX, value))
|
| 482 |
|
| 483 |
|
| 484 |
-
# spaces.GPU accepts a callable that receives the SAME positional args as the
|
| 485 |
-
# decorated function and returns the requested duration. gpu_duration is just
|
| 486 |
-
# the slider value passed straight through - no more 900s+megapixels guessing.
|
| 487 |
def _duration(
|
| 488 |
prompt,
|
| 489 |
negative_prompt,
|
|
@@ -497,6 +527,9 @@ def _duration(
|
|
| 497 |
scheduler,
|
| 498 |
lora_name,
|
| 499 |
lora_strength,
|
|
|
|
|
|
|
|
|
|
| 500 |
gpu_duration,
|
| 501 |
):
|
| 502 |
return _clamp_duration(gpu_duration)
|
|
@@ -517,6 +550,9 @@ def _edit_duration(
|
|
| 517 |
scheduler,
|
| 518 |
lora_name,
|
| 519 |
lora_strength,
|
|
|
|
|
|
|
|
|
|
| 520 |
gpu_duration,
|
| 521 |
):
|
| 522 |
return _clamp_duration(gpu_duration)
|
|
@@ -536,6 +572,9 @@ def generate(
|
|
| 536 |
scheduler="simple",
|
| 537 |
lora_name=LORA_NONE,
|
| 538 |
lora_strength=1.0,
|
|
|
|
|
|
|
|
|
|
| 539 |
gpu_duration=DURATION_DEFAULT,
|
| 540 |
):
|
| 541 |
if not prompt or not prompt.strip():
|
|
@@ -545,6 +584,10 @@ def generate(
|
|
| 545 |
|
| 546 |
try:
|
| 547 |
_start_comfyui()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
workflow = _build_workflow(
|
| 549 |
prompt,
|
| 550 |
negative_prompt,
|
|
@@ -557,6 +600,8 @@ def generate(
|
|
| 557 |
scheduler,
|
| 558 |
lora_name,
|
| 559 |
lora_strength,
|
|
|
|
|
|
|
| 560 |
)
|
| 561 |
prompt_id = _queue_prompt(workflow)
|
| 562 |
history_item = _wait_for_history(prompt_id)
|
|
@@ -581,6 +626,9 @@ def edit_image(
|
|
| 581 |
scheduler="simple",
|
| 582 |
lora_name=LORA_NONE,
|
| 583 |
lora_strength=1.0,
|
|
|
|
|
|
|
|
|
|
| 584 |
gpu_duration=DURATION_DEFAULT,
|
| 585 |
):
|
| 586 |
if input_image is None:
|
|
@@ -592,6 +640,10 @@ def edit_image(
|
|
| 592 |
|
| 593 |
try:
|
| 594 |
_start_comfyui()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
resized = _resize_for_edit(input_image, width, height)
|
| 596 |
input_filename = _upload_image_to_comfy(resized)
|
| 597 |
workflow = _build_edit_workflow(
|
|
@@ -606,6 +658,8 @@ def edit_image(
|
|
| 606 |
denoise,
|
| 607 |
lora_name,
|
| 608 |
lora_strength,
|
|
|
|
|
|
|
| 609 |
)
|
| 610 |
prompt_id = _queue_prompt(workflow)
|
| 611 |
history_item = _wait_for_history(prompt_id)
|
|
@@ -615,8 +669,6 @@ def edit_image(
|
|
| 615 |
|
| 616 |
|
| 617 |
def refresh_loras():
|
| 618 |
-
"""Button handler: re-scans models/loras (via ComfyUI if it's up, plain
|
| 619 |
-
glob otherwise) and returns a Dropdown update with the fresh choices."""
|
| 620 |
choices = _list_loras()
|
| 621 |
return gr.update(choices=choices, value=LORA_NONE)
|
| 622 |
|
|
@@ -665,13 +717,20 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 665 |
lora_name = gr.Dropdown(
|
| 666 |
choices=[LORA_NONE, LORA_FILE],
|
| 667 |
value=LORA_FILE,
|
| 668 |
-
label="LoRA",
|
| 669 |
info=LORA_INFO,
|
| 670 |
allow_custom_value=True,
|
| 671 |
scale=4,
|
| 672 |
)
|
| 673 |
lora_refresh = gr.Button("Refresh", scale=1)
|
| 674 |
-
lora_strength = gr.Slider(0.0, 10.0, value=0.0, step=0.05, label="LoRA strength")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
gpu_duration = gr.Slider(
|
| 676 |
DURATION_MIN,
|
| 677 |
DURATION_MAX,
|
|
@@ -689,7 +748,6 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 689 |
scheduler = gr.Dropdown(["simple", "normal", "karras", "exponential"], value="simple", label="Scheduler")
|
| 690 |
run = gr.Button("Generate", variant="primary")
|
| 691 |
with gr.Column(scale=6):
|
| 692 |
-
# We removed format="png" so Gradio accepts the raw WebP file path directly.
|
| 693 |
output = gr.Image(label="Result", elem_id="result-image")
|
| 694 |
|
| 695 |
inputs = [
|
|
@@ -705,6 +763,9 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 705 |
scheduler,
|
| 706 |
lora_name,
|
| 707 |
lora_strength,
|
|
|
|
|
|
|
|
|
|
| 708 |
gpu_duration,
|
| 709 |
]
|
| 710 |
run.click(generate, inputs, [output, seed])
|
|
@@ -738,13 +799,20 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 738 |
edit_lora_name = gr.Dropdown(
|
| 739 |
choices=[LORA_NONE, LORA_FILE],
|
| 740 |
value=LORA_FILE,
|
| 741 |
-
label="LoRA",
|
| 742 |
info=LORA_INFO,
|
| 743 |
allow_custom_value=True,
|
| 744 |
scale=4,
|
| 745 |
)
|
| 746 |
edit_lora_refresh = gr.Button("Refresh", scale=1)
|
| 747 |
-
edit_lora_strength = gr.Slider(-2.0, 2.0, value=1.0, step=0.05, label="LoRA strength")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
edit_gpu_duration = gr.Slider(
|
| 749 |
DURATION_MIN,
|
| 750 |
DURATION_MAX,
|
|
@@ -762,7 +830,6 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 762 |
edit_scheduler = gr.Dropdown(["simple", "normal", "karras", "exponential"], value="simple", label="Scheduler")
|
| 763 |
edit_run = gr.Button("Edit Image", variant="primary")
|
| 764 |
with gr.Column(scale=6):
|
| 765 |
-
# We removed format="png" here as well.
|
| 766 |
edit_output = gr.Image(label="Edited image", elem_id="result-image")
|
| 767 |
|
| 768 |
edit_inputs = [
|
|
@@ -780,6 +847,9 @@ with gr.Blocks(title="Redcraft Krea2", css=CSS) as demo:
|
|
| 780 |
edit_scheduler,
|
| 781 |
edit_lora_name,
|
| 782 |
edit_lora_strength,
|
|
|
|
|
|
|
|
|
|
| 783 |
edit_gpu_duration,
|
| 784 |
]
|
| 785 |
edit_run.click(edit_image, edit_inputs, [edit_output, edit_seed])
|
|
|
|
| 195 |
return [LORA_NONE]
|
| 196 |
|
| 197 |
|
| 198 |
+
def _download_dynamic_lora(repo, filename):
|
| 199 |
+
"""Downloads a dynamic LoRA from HuggingFace on-the-fly inside the execution flow.
|
| 200 |
+
Returns the relative path from models/loras for ComfyUI loader."""
|
| 201 |
+
if not repo or not filename:
|
| 202 |
+
return None
|
| 203 |
+
repo = repo.strip()
|
| 204 |
+
filename = filename.strip()
|
| 205 |
+
if not repo or not filename:
|
| 206 |
+
return None
|
| 207 |
+
|
| 208 |
+
lora_dir = COMFY_DIR / "models" / "loras"
|
| 209 |
+
lora_dir.mkdir(parents=True, exist_ok=True)
|
| 210 |
+
|
| 211 |
+
try:
|
| 212 |
+
print(f"[setup] Downloading dynamic LoRA: {repo}/{filename}", flush=True)
|
| 213 |
+
local_path = hf_hub_download(
|
| 214 |
+
repo_id=repo,
|
| 215 |
+
filename=filename,
|
| 216 |
+
local_dir=str(lora_dir),
|
| 217 |
+
token=os.environ.get("HF_TOKEN"),
|
| 218 |
+
)
|
| 219 |
+
# Returns path relative to lora_dir (handles nested folders perfectly)
|
| 220 |
+
return str(Path(local_path).relative_to(lora_dir))
|
| 221 |
+
except Exception as e:
|
| 222 |
+
print(f"[error] Failed to download dynamic LoRA from {repo}/{filename}: {e}", flush=True)
|
| 223 |
+
raise RuntimeError(f"Failed to download dynamic LoRA: {e}")
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def _add_loras_to_workflow(workflow, model_node_ref, lora_name, lora_strength, lora2_name=None, lora2_strength=0.0):
|
| 227 |
+
"""Inserts one or two LoraLoaderModelOnly nodes sequentially between the
|
| 228 |
+
diffusion model and the sampler."""
|
| 229 |
+
current_model = model_node_ref
|
| 230 |
+
|
| 231 |
+
# First LoRA
|
| 232 |
+
if lora_name and lora_name != LORA_NONE and float(lora_strength) != 0.0:
|
| 233 |
+
workflow["20"] = {
|
| 234 |
+
"class_type": "LoraLoaderModelOnly",
|
| 235 |
+
"inputs": {
|
| 236 |
+
"model": current_model,
|
| 237 |
+
"lora_name": lora_name,
|
| 238 |
+
"strength_model": float(lora_strength),
|
| 239 |
+
},
|
| 240 |
+
}
|
| 241 |
+
current_model = ["20", 0]
|
| 242 |
+
|
| 243 |
+
# Second dynamic LoRA
|
| 244 |
+
if lora2_name and lora2_name != LORA_NONE and float(lora2_strength) != 0.0:
|
| 245 |
+
workflow["21"] = {
|
| 246 |
+
"class_type": "LoraLoaderModelOnly",
|
| 247 |
+
"inputs": {
|
| 248 |
+
"model": current_model,
|
| 249 |
+
"lora_name": lora2_name,
|
| 250 |
+
"strength_model": float(lora2_strength),
|
| 251 |
+
},
|
| 252 |
+
}
|
| 253 |
+
current_model = ["21", 0]
|
| 254 |
+
|
| 255 |
+
return current_model
|
| 256 |
|
| 257 |
|
| 258 |
def _build_workflow(
|
|
|
|
| 267 |
scheduler,
|
| 268 |
lora_name=LORA_NONE,
|
| 269 |
lora_strength=1.0,
|
| 270 |
+
lora2_name=None,
|
| 271 |
+
lora2_strength=0.0,
|
| 272 |
):
|
| 273 |
workflow = {
|
| 274 |
"1": {
|
|
|
|
| 327 |
"inputs": {"conditioning": ["2", 0]},
|
| 328 |
}
|
| 329 |
|
| 330 |
+
model_ref = _add_loras_to_workflow(workflow, ["1", 0], lora_name, lora_strength, lora2_name, lora2_strength)
|
| 331 |
workflow["5"]["inputs"]["model"] = model_ref
|
| 332 |
return workflow
|
| 333 |
|
|
|
|
| 371 |
denoise,
|
| 372 |
lora_name=LORA_NONE,
|
| 373 |
lora_strength=1.0,
|
| 374 |
+
lora2_name=None,
|
| 375 |
+
lora2_strength=0.0,
|
| 376 |
):
|
| 377 |
workflow = {
|
| 378 |
"1": {
|
|
|
|
| 435 |
"inputs": {"conditioning": ["2", 0]},
|
| 436 |
}
|
| 437 |
|
| 438 |
+
model_ref = _add_loras_to_workflow(workflow, ["1", 0], lora_name, lora_strength, lora2_name, lora2_strength)
|
| 439 |
workflow["5"]["inputs"]["model"] = model_ref
|
| 440 |
return workflow
|
| 441 |
|
|
|
|
| 468 |
|
| 469 |
|
| 470 |
def _load_output_image(history_item):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 471 |
outputs = history_item.get("outputs", {})
|
| 472 |
for output in outputs.values():
|
| 473 |
for image in output.get("images", []):
|
|
|
|
| 479 |
response = requests.get(f"{COMFY_URL}/view", params=params, timeout=120)
|
| 480 |
response.raise_for_status()
|
| 481 |
|
|
|
|
| 482 |
temp_png = Path("/tmp") / f"{uuid.uuid4().hex}.png"
|
| 483 |
temp_png.write_bytes(response.content)
|
| 484 |
|
|
|
|
| 485 |
img = Image.open(temp_png)
|
| 486 |
prompt_data = img.info.get("prompt", "")
|
| 487 |
workflow_data = img.info.get("workflow", "")
|
| 488 |
|
|
|
|
| 489 |
prompt_bytes = prompt_data.encode('utf-8') if isinstance(prompt_data, str) else prompt_data
|
| 490 |
workflow_bytes = workflow_data.encode('utf-8') if isinstance(workflow_data, str) else workflow_data
|
| 491 |
|
|
|
|
| 497 |
}
|
| 498 |
exif_bytes = piexif.dump(exif_dict)
|
| 499 |
|
|
|
|
| 500 |
temp_webp = Path("/tmp") / f"{uuid.uuid4().hex}.webp"
|
| 501 |
img.convert("RGB").save(temp_webp, "WEBP", exif=exif_bytes, quality=90)
|
| 502 |
|
|
|
|
| 503 |
temp_png.unlink(missing_ok=True)
|
|
|
|
|
|
|
| 504 |
return str(temp_webp)
|
| 505 |
|
| 506 |
raise RuntimeError("ComfyUI completed without returning an image.")
|
|
|
|
| 514 |
return max(DURATION_MIN, min(DURATION_MAX, value))
|
| 515 |
|
| 516 |
|
|
|
|
|
|
|
|
|
|
| 517 |
def _duration(
|
| 518 |
prompt,
|
| 519 |
negative_prompt,
|
|
|
|
| 527 |
scheduler,
|
| 528 |
lora_name,
|
| 529 |
lora_strength,
|
| 530 |
+
lora2_repo,
|
| 531 |
+
lora2_file,
|
| 532 |
+
lora2_strength,
|
| 533 |
gpu_duration,
|
| 534 |
):
|
| 535 |
return _clamp_duration(gpu_duration)
|
|
|
|
| 550 |
scheduler,
|
| 551 |
lora_name,
|
| 552 |
lora_strength,
|
| 553 |
+
edit_lora2_repo,
|
| 554 |
+
edit_lora2_file,
|
| 555 |
+
edit_lora2_strength,
|
| 556 |
gpu_duration,
|
| 557 |
):
|
| 558 |
return _clamp_duration(gpu_duration)
|
|
|
|
| 572 |
scheduler="simple",
|
| 573 |
lora_name=LORA_NONE,
|
| 574 |
lora_strength=1.0,
|
| 575 |
+
lora2_repo="",
|
| 576 |
+
lora2_file="",
|
| 577 |
+
lora2_strength=0.0,
|
| 578 |
gpu_duration=DURATION_DEFAULT,
|
| 579 |
):
|
| 580 |
if not prompt or not prompt.strip():
|
|
|
|
| 584 |
|
| 585 |
try:
|
| 586 |
_start_comfyui()
|
| 587 |
+
|
| 588 |
+
# Download dynamic LoRA 2 if user filled details
|
| 589 |
+
lora2_name = _download_dynamic_lora(lora2_repo, lora2_file)
|
| 590 |
+
|
| 591 |
workflow = _build_workflow(
|
| 592 |
prompt,
|
| 593 |
negative_prompt,
|
|
|
|
| 600 |
scheduler,
|
| 601 |
lora_name,
|
| 602 |
lora_strength,
|
| 603 |
+
lora2_name,
|
| 604 |
+
lora2_strength,
|
| 605 |
)
|
| 606 |
prompt_id = _queue_prompt(workflow)
|
| 607 |
history_item = _wait_for_history(prompt_id)
|
|
|
|
| 626 |
scheduler="simple",
|
| 627 |
lora_name=LORA_NONE,
|
| 628 |
lora_strength=1.0,
|
| 629 |
+
edit_lora2_repo="",
|
| 630 |
+
edit_lora2_file="",
|
| 631 |
+
edit_lora2_strength=0.0,
|
| 632 |
gpu_duration=DURATION_DEFAULT,
|
| 633 |
):
|
| 634 |
if input_image is None:
|
|
|
|
| 640 |
|
| 641 |
try:
|
| 642 |
_start_comfyui()
|
| 643 |
+
|
| 644 |
+
# Download dynamic LoRA 2 if user filled details
|
| 645 |
+
lora2_name = _download_dynamic_lora(edit_lora2_repo, edit_lora2_file)
|
| 646 |
+
|
| 647 |
resized = _resize_for_edit(input_image, width, height)
|
| 648 |
input_filename = _upload_image_to_comfy(resized)
|
| 649 |
workflow = _build_edit_workflow(
|
|
|
|
| 658 |
denoise,
|
| 659 |
lora_name,
|
| 660 |
lora_strength,
|
| 661 |
+
lora2_name,
|
| 662 |
+
lora2_strength,
|
| 663 |
)
|
| 664 |
prompt_id = _queue_prompt(workflow)
|
| 665 |
history_item = _wait_for_history(prompt_id)
|
|
|
|
| 669 |
|
| 670 |
|
| 671 |
def refresh_loras():
|
|
|
|
|
|
|
| 672 |
choices = _list_loras()
|
| 673 |
return gr.update(choices=choices, value=LORA_NONE)
|
| 674 |
|
|
|
|
| 717 |
lora_name = gr.Dropdown(
|
| 718 |
choices=[LORA_NONE, LORA_FILE],
|
| 719 |
value=LORA_FILE,
|
| 720 |
+
label="LoRA 1",
|
| 721 |
info=LORA_INFO,
|
| 722 |
allow_custom_value=True,
|
| 723 |
scale=4,
|
| 724 |
)
|
| 725 |
lora_refresh = gr.Button("Refresh", scale=1)
|
| 726 |
+
lora_strength = gr.Slider(0.0, 10.0, value=0.0, step=0.05, label="LoRA 1 strength")
|
| 727 |
+
|
| 728 |
+
# Spoilered dynamic LoRA 2
|
| 729 |
+
with gr.Accordion("LoRA 2 (HuggingFace Dynamic)", open=False):
|
| 730 |
+
lora2_repo = gr.Textbox(label="HF Repo ID", placeholder="e.g., beznogim666/test2", value="")
|
| 731 |
+
lora2_file = gr.Textbox(label="Filename", placeholder="e.g., lora2.safetensors", value="")
|
| 732 |
+
lora2_strength = gr.Slider(0.0, 10.0, value=0.0, step=0.05, label="LoRA 2 strength")
|
| 733 |
+
|
| 734 |
gpu_duration = gr.Slider(
|
| 735 |
DURATION_MIN,
|
| 736 |
DURATION_MAX,
|
|
|
|
| 748 |
scheduler = gr.Dropdown(["simple", "normal", "karras", "exponential"], value="simple", label="Scheduler")
|
| 749 |
run = gr.Button("Generate", variant="primary")
|
| 750 |
with gr.Column(scale=6):
|
|
|
|
| 751 |
output = gr.Image(label="Result", elem_id="result-image")
|
| 752 |
|
| 753 |
inputs = [
|
|
|
|
| 763 |
scheduler,
|
| 764 |
lora_name,
|
| 765 |
lora_strength,
|
| 766 |
+
lora2_repo,
|
| 767 |
+
lora2_file,
|
| 768 |
+
lora2_strength,
|
| 769 |
gpu_duration,
|
| 770 |
]
|
| 771 |
run.click(generate, inputs, [output, seed])
|
|
|
|
| 799 |
edit_lora_name = gr.Dropdown(
|
| 800 |
choices=[LORA_NONE, LORA_FILE],
|
| 801 |
value=LORA_FILE,
|
| 802 |
+
label="LoRA 1",
|
| 803 |
info=LORA_INFO,
|
| 804 |
allow_custom_value=True,
|
| 805 |
scale=4,
|
| 806 |
)
|
| 807 |
edit_lora_refresh = gr.Button("Refresh", scale=1)
|
| 808 |
+
edit_lora_strength = gr.Slider(-2.0, 2.0, value=1.0, step=0.05, label="LoRA 1 strength")
|
| 809 |
+
|
| 810 |
+
# Spoilered dynamic LoRA 2 for Edit Tab
|
| 811 |
+
with gr.Accordion("LoRA 2 (HuggingFace Dynamic)", open=False):
|
| 812 |
+
edit_lora2_repo = gr.Textbox(label="HF Repo ID", placeholder="e.g., beznogim666/test2", value="")
|
| 813 |
+
edit_lora2_file = gr.Textbox(label="Filename", placeholder="e.g., lora2.safetensors", value="")
|
| 814 |
+
edit_lora2_strength = gr.Slider(-2.0, 2.0, value=0.0, step=0.05, label="LoRA 2 strength")
|
| 815 |
+
|
| 816 |
edit_gpu_duration = gr.Slider(
|
| 817 |
DURATION_MIN,
|
| 818 |
DURATION_MAX,
|
|
|
|
| 830 |
edit_scheduler = gr.Dropdown(["simple", "normal", "karras", "exponential"], value="simple", label="Scheduler")
|
| 831 |
edit_run = gr.Button("Edit Image", variant="primary")
|
| 832 |
with gr.Column(scale=6):
|
|
|
|
| 833 |
edit_output = gr.Image(label="Edited image", elem_id="result-image")
|
| 834 |
|
| 835 |
edit_inputs = [
|
|
|
|
| 847 |
edit_scheduler,
|
| 848 |
edit_lora_name,
|
| 849 |
edit_lora_strength,
|
| 850 |
+
edit_lora2_repo,
|
| 851 |
+
edit_lora2_file,
|
| 852 |
+
edit_lora2_strength,
|
| 853 |
edit_gpu_duration,
|
| 854 |
]
|
| 855 |
edit_run.click(edit_image, edit_inputs, [edit_output, edit_seed])
|