Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -480,79 +480,23 @@ def _replacement_command(
|
|
| 480 |
|
| 481 |
|
| 482 |
@spaces.GPU(duration=GPU_DURATION, size=GPU_SIZE)
|
| 483 |
-
def
|
|
|
|
| 484 |
ref_image,
|
| 485 |
driving_video,
|
| 486 |
prompt,
|
| 487 |
sam3_text,
|
| 488 |
max_persons,
|
| 489 |
crop_mode,
|
| 490 |
-
progress=gr.Progress(track_tqdm=True),
|
| 491 |
-
):
|
| 492 |
-
try:
|
| 493 |
-
progress(0.0, desc="Checking SCAIL-Pose repo")
|
| 494 |
-
_require_repo_layout()
|
| 495 |
-
progress(0.04, desc="Preparing SAM3 weights")
|
| 496 |
-
sam3_model = _ensure_sam3_weights()
|
| 497 |
-
|
| 498 |
-
job_dir = _new_job_dir("animation")
|
| 499 |
-
progress(0.08, desc="Preparing inputs")
|
| 500 |
-
_save_reference_image(ref_image, job_dir / "ref.png")
|
| 501 |
-
_copy_video(driving_video, job_dir / "driving.mp4", "driving video")
|
| 502 |
-
_write_metadata(
|
| 503 |
-
job_dir,
|
| 504 |
-
"animation",
|
| 505 |
-
prompt,
|
| 506 |
-
{
|
| 507 |
-
"driving": {
|
| 508 |
-
"video": "rendered_v2.mp4",
|
| 509 |
-
"mask_video": "rendered_mask_v2.mp4",
|
| 510 |
-
},
|
| 511 |
-
"primary": {
|
| 512 |
-
"image": "ref.png",
|
| 513 |
-
"mask": "ref_mask.jpg",
|
| 514 |
-
},
|
| 515 |
-
"sam3_text": _text_args(sam3_text),
|
| 516 |
-
"max_persons": int(max_persons),
|
| 517 |
-
"crop_mode": crop_mode,
|
| 518 |
-
},
|
| 519 |
-
)
|
| 520 |
-
|
| 521 |
-
progress(0.12, desc="Generating animation masks")
|
| 522 |
-
logs = _run_command(
|
| 523 |
-
_animation_command(job_dir, sam3_model, int(max_persons), sam3_text, crop_mode),
|
| 524 |
-
progress=progress,
|
| 525 |
-
)
|
| 526 |
-
_require_outputs(job_dir, ["ref_mask.jpg", "rendered_v2.mp4", "rendered_mask_v2.mp4"])
|
| 527 |
-
|
| 528 |
-
progress(0.92, desc="Packaging SCAIL-2 input pack")
|
| 529 |
-
zip_path = _zip_pack(job_dir, "animation")
|
| 530 |
-
progress(1.0, desc="Done")
|
| 531 |
-
status = f"Done. Pack created at {zip_path}\n\n{logs}"
|
| 532 |
-
return (
|
| 533 |
-
str(job_dir / "ref_mask.jpg"),
|
| 534 |
-
str(job_dir / "rendered_v2.mp4"),
|
| 535 |
-
str(job_dir / "rendered_mask_v2.mp4"),
|
| 536 |
-
str(zip_path),
|
| 537 |
-
status,
|
| 538 |
-
)
|
| 539 |
-
except Exception:
|
| 540 |
-
logging.exception("Animation pack generation failed")
|
| 541 |
-
return None, None, None, None, traceback.format_exc()
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
@spaces.GPU(duration=GPU_DURATION, size=GPU_SIZE)
|
| 545 |
-
def build_replacement_pack(
|
| 546 |
-
ref_image,
|
| 547 |
-
driving_video,
|
| 548 |
-
prompt,
|
| 549 |
-
sam3_text,
|
| 550 |
matchnearest,
|
| 551 |
egocentric,
|
| 552 |
progress=gr.Progress(track_tqdm=True),
|
| 553 |
):
|
| 554 |
try:
|
| 555 |
-
|
|
|
|
|
|
|
|
|
|
| 556 |
raise RuntimeError("matchnearest and egocentric are mutually exclusive.")
|
| 557 |
|
| 558 |
progress(0.0, desc="Checking SCAIL-Pose repo")
|
|
@@ -560,8 +504,50 @@ def build_replacement_pack(
|
|
| 560 |
progress(0.04, desc="Preparing SAM3 weights")
|
| 561 |
sam3_model = _ensure_sam3_weights()
|
| 562 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
job_dir = _new_job_dir("replacement")
|
| 564 |
-
progress(0.08, desc="Preparing inputs")
|
| 565 |
_save_reference_image(ref_image, job_dir / "ref.png")
|
| 566 |
_copy_video(driving_video, job_dir / "driving.mp4", "source video")
|
| 567 |
_write_metadata(
|
|
@@ -589,11 +575,10 @@ def build_replacement_pack(
|
|
| 589 |
progress=progress,
|
| 590 |
)
|
| 591 |
_require_outputs(job_dir, ["ref_mask.png", "rendered_v2.mp4", "replace_mask.mp4"])
|
| 592 |
-
|
| 593 |
progress(0.92, desc="Packaging SCAIL-2 input pack")
|
| 594 |
zip_path = _zip_pack(job_dir, "replacement")
|
| 595 |
progress(1.0, desc="Done")
|
| 596 |
-
status = f"Done.
|
| 597 |
return (
|
| 598 |
str(job_dir / "ref_mask.png"),
|
| 599 |
str(job_dir / "rendered_v2.mp4"),
|
|
@@ -602,7 +587,7 @@ def build_replacement_pack(
|
|
| 602 |
status,
|
| 603 |
)
|
| 604 |
except Exception:
|
| 605 |
-
logging.exception("
|
| 606 |
return None, None, None, None, traceback.format_exc()
|
| 607 |
|
| 608 |
|
|
@@ -742,42 +727,59 @@ def build_ui():
|
|
| 742 |
)
|
| 743 |
gr.Textbox(value=_repo_status(), label="Startup status", interactive=False, lines=7)
|
| 744 |
|
| 745 |
-
with gr.Tab("
|
| 746 |
gr.Markdown(
|
| 747 |
-
"Create
|
| 748 |
-
"
|
| 749 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 750 |
)
|
| 751 |
with gr.Row():
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
["none", "mask silhouette", "moving bbox", "steady bbox"],
|
| 760 |
value="none",
|
| 761 |
label="Driving crop mode",
|
| 762 |
)
|
| 763 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 764 |
with gr.Row():
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
inputs=[
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
|
|
|
|
|
|
|
|
|
| 779 |
],
|
| 780 |
-
outputs=[
|
| 781 |
)
|
| 782 |
|
| 783 |
with gr.Tab("Advanced Character Pack"):
|
|
@@ -848,42 +850,9 @@ def build_ui():
|
|
| 848 |
outputs=[adv_gallery, adv_rendered, adv_mask_video, adv_zip, adv_status],
|
| 849 |
)
|
| 850 |
|
| 851 |
-
with gr.Tab("Replacement Pack"):
|
| 852 |
-
gr.Markdown(
|
| 853 |
-
"Create a replacement pack from a replacement reference image and a source video. "
|
| 854 |
-
"The source video becomes `rendered_v2.mp4`, and SAM3 produces `replace_mask.mp4`."
|
| 855 |
-
)
|
| 856 |
-
with gr.Row():
|
| 857 |
-
repl_ref = gr.Image(type="filepath", label="Replacement reference image")
|
| 858 |
-
repl_driving = gr.Video(label="Source / driving video")
|
| 859 |
-
repl_prompt = gr.Textbox(label="Prompt for SCAIL-2", lines=3)
|
| 860 |
-
with gr.Row():
|
| 861 |
-
repl_sam3_text = gr.Textbox(value="human character", label="SAM3 text prompt")
|
| 862 |
-
repl_matchnearest = gr.Checkbox(value=False, label="Match nearest target when two people are detected")
|
| 863 |
-
repl_egocentric = gr.Checkbox(value=False, label="Egocentric: union two detected parts into one actor")
|
| 864 |
-
repl_run = gr.Button("Generate replacement pack", variant="primary")
|
| 865 |
-
with gr.Row():
|
| 866 |
-
repl_ref_mask = gr.Image(label="Reference mask", interactive=False)
|
| 867 |
-
repl_mask_video = gr.Video(label="Replacement mask video")
|
| 868 |
-
repl_rendered = gr.Video(label="Rendered / source video")
|
| 869 |
-
repl_zip = gr.File(label="Download SCAIL-2 replacement pack")
|
| 870 |
-
repl_status = gr.Textbox(label="Run logs", lines=14)
|
| 871 |
-
repl_run.click(
|
| 872 |
-
build_replacement_pack,
|
| 873 |
-
inputs=[
|
| 874 |
-
repl_ref,
|
| 875 |
-
repl_driving,
|
| 876 |
-
repl_prompt,
|
| 877 |
-
repl_sam3_text,
|
| 878 |
-
repl_matchnearest,
|
| 879 |
-
repl_egocentric,
|
| 880 |
-
],
|
| 881 |
-
outputs=[repl_ref_mask, repl_rendered, repl_mask_video, repl_zip, repl_status],
|
| 882 |
-
)
|
| 883 |
-
|
| 884 |
with gr.Tab("Pack Format"):
|
| 885 |
gr.Markdown(
|
| 886 |
-
"The
|
| 887 |
"character pack with explicit character folders.\n\n"
|
| 888 |
"Simple animation pack:\n"
|
| 889 |
"```text\n"
|
|
|
|
| 480 |
|
| 481 |
|
| 482 |
@spaces.GPU(duration=GPU_DURATION, size=GPU_SIZE)
|
| 483 |
+
def build_simple_pack(
|
| 484 |
+
mode,
|
| 485 |
ref_image,
|
| 486 |
driving_video,
|
| 487 |
prompt,
|
| 488 |
sam3_text,
|
| 489 |
max_persons,
|
| 490 |
crop_mode,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 491 |
matchnearest,
|
| 492 |
egocentric,
|
| 493 |
progress=gr.Progress(track_tqdm=True),
|
| 494 |
):
|
| 495 |
try:
|
| 496 |
+
mode = str(mode or "Animation").lower()
|
| 497 |
+
if mode not in {"animation", "replacement"}:
|
| 498 |
+
raise RuntimeError(f"Unsupported mode: {mode}")
|
| 499 |
+
if mode == "replacement" and matchnearest and egocentric:
|
| 500 |
raise RuntimeError("matchnearest and egocentric are mutually exclusive.")
|
| 501 |
|
| 502 |
progress(0.0, desc="Checking SCAIL-Pose repo")
|
|
|
|
| 504 |
progress(0.04, desc="Preparing SAM3 weights")
|
| 505 |
sam3_model = _ensure_sam3_weights()
|
| 506 |
|
| 507 |
+
if mode == "animation":
|
| 508 |
+
job_dir = _new_job_dir("animation")
|
| 509 |
+
progress(0.08, desc="Preparing animation inputs")
|
| 510 |
+
_save_reference_image(ref_image, job_dir / "ref.png")
|
| 511 |
+
_copy_video(driving_video, job_dir / "driving.mp4", "driving video")
|
| 512 |
+
_write_metadata(
|
| 513 |
+
job_dir,
|
| 514 |
+
"animation",
|
| 515 |
+
prompt,
|
| 516 |
+
{
|
| 517 |
+
"driving": {
|
| 518 |
+
"video": "rendered_v2.mp4",
|
| 519 |
+
"mask_video": "rendered_mask_v2.mp4",
|
| 520 |
+
},
|
| 521 |
+
"primary": {
|
| 522 |
+
"image": "ref.png",
|
| 523 |
+
"mask": "ref_mask.jpg",
|
| 524 |
+
},
|
| 525 |
+
"sam3_text": _text_args(sam3_text),
|
| 526 |
+
"max_persons": int(max_persons),
|
| 527 |
+
"crop_mode": crop_mode,
|
| 528 |
+
},
|
| 529 |
+
)
|
| 530 |
+
|
| 531 |
+
progress(0.12, desc="Generating animation masks")
|
| 532 |
+
logs = _run_command(
|
| 533 |
+
_animation_command(job_dir, sam3_model, int(max_persons), sam3_text, crop_mode),
|
| 534 |
+
progress=progress,
|
| 535 |
+
)
|
| 536 |
+
_require_outputs(job_dir, ["ref_mask.jpg", "rendered_v2.mp4", "rendered_mask_v2.mp4"])
|
| 537 |
+
progress(0.92, desc="Packaging SCAIL-2 input pack")
|
| 538 |
+
zip_path = _zip_pack(job_dir, "animation")
|
| 539 |
+
progress(1.0, desc="Done")
|
| 540 |
+
status = f"Done. Animation pack created at {zip_path}\n\n{logs}"
|
| 541 |
+
return (
|
| 542 |
+
str(job_dir / "ref_mask.jpg"),
|
| 543 |
+
str(job_dir / "rendered_v2.mp4"),
|
| 544 |
+
str(job_dir / "rendered_mask_v2.mp4"),
|
| 545 |
+
str(zip_path),
|
| 546 |
+
status,
|
| 547 |
+
)
|
| 548 |
+
|
| 549 |
job_dir = _new_job_dir("replacement")
|
| 550 |
+
progress(0.08, desc="Preparing replacement inputs")
|
| 551 |
_save_reference_image(ref_image, job_dir / "ref.png")
|
| 552 |
_copy_video(driving_video, job_dir / "driving.mp4", "source video")
|
| 553 |
_write_metadata(
|
|
|
|
| 575 |
progress=progress,
|
| 576 |
)
|
| 577 |
_require_outputs(job_dir, ["ref_mask.png", "rendered_v2.mp4", "replace_mask.mp4"])
|
|
|
|
| 578 |
progress(0.92, desc="Packaging SCAIL-2 input pack")
|
| 579 |
zip_path = _zip_pack(job_dir, "replacement")
|
| 580 |
progress(1.0, desc="Done")
|
| 581 |
+
status = f"Done. Replacement pack created at {zip_path}\n\n{logs}"
|
| 582 |
return (
|
| 583 |
str(job_dir / "ref_mask.png"),
|
| 584 |
str(job_dir / "rendered_v2.mp4"),
|
|
|
|
| 587 |
status,
|
| 588 |
)
|
| 589 |
except Exception:
|
| 590 |
+
logging.exception("Simple pack generation failed")
|
| 591 |
return None, None, None, None, traceback.format_exc()
|
| 592 |
|
| 593 |
|
|
|
|
| 727 |
)
|
| 728 |
gr.Textbox(value=_repo_status(), label="Startup status", interactive=False, lines=7)
|
| 729 |
|
| 730 |
+
with gr.Tab("Simple Pack"):
|
| 731 |
gr.Markdown(
|
| 732 |
+
"Create a standard SCAIL-2 pack from one reference image and one video. "
|
| 733 |
+
"Choose Animation to follow motion from the driving video, or Replacement to replace "
|
| 734 |
+
"a target region in the source video."
|
| 735 |
+
)
|
| 736 |
+
simple_mode = gr.Radio(
|
| 737 |
+
["Animation", "Replacement"],
|
| 738 |
+
value="Animation",
|
| 739 |
+
label="Mode",
|
| 740 |
)
|
| 741 |
with gr.Row():
|
| 742 |
+
simple_ref = gr.Image(type="filepath", label="Reference image")
|
| 743 |
+
simple_driving = gr.Video(label="Driving / source video")
|
| 744 |
+
simple_prompt = gr.Textbox(label="Prompt for SCAIL-2", lines=3)
|
| 745 |
+
simple_sam3_text = gr.Textbox(value="human character", label="SAM3 text prompt")
|
| 746 |
+
with gr.Accordion("Animation options", open=True):
|
| 747 |
+
simple_max_persons = gr.Number(value=2, precision=0, label="Max tracked subjects")
|
| 748 |
+
simple_crop = gr.Dropdown(
|
| 749 |
["none", "mask silhouette", "moving bbox", "steady bbox"],
|
| 750 |
value="none",
|
| 751 |
label="Driving crop mode",
|
| 752 |
)
|
| 753 |
+
with gr.Accordion("Replacement options", open=False):
|
| 754 |
+
simple_matchnearest = gr.Checkbox(
|
| 755 |
+
value=False,
|
| 756 |
+
label="Match nearest target when two people are detected",
|
| 757 |
+
)
|
| 758 |
+
simple_egocentric = gr.Checkbox(
|
| 759 |
+
value=False,
|
| 760 |
+
label="Egocentric: union two detected parts into one actor",
|
| 761 |
+
)
|
| 762 |
+
simple_run = gr.Button("Generate pack", variant="primary")
|
| 763 |
with gr.Row():
|
| 764 |
+
simple_ref_mask = gr.Image(label="Reference mask", interactive=False)
|
| 765 |
+
simple_mask_video = gr.Video(label="Mask video")
|
| 766 |
+
simple_rendered = gr.Video(label="Rendered / source video")
|
| 767 |
+
simple_zip = gr.File(label="Download SCAIL-2 pack")
|
| 768 |
+
simple_status = gr.Textbox(label="Run logs", lines=14)
|
| 769 |
+
simple_run.click(
|
| 770 |
+
build_simple_pack,
|
| 771 |
inputs=[
|
| 772 |
+
simple_mode,
|
| 773 |
+
simple_ref,
|
| 774 |
+
simple_driving,
|
| 775 |
+
simple_prompt,
|
| 776 |
+
simple_sam3_text,
|
| 777 |
+
simple_max_persons,
|
| 778 |
+
simple_crop,
|
| 779 |
+
simple_matchnearest,
|
| 780 |
+
simple_egocentric,
|
| 781 |
],
|
| 782 |
+
outputs=[simple_ref_mask, simple_rendered, simple_mask_video, simple_zip, simple_status],
|
| 783 |
)
|
| 784 |
|
| 785 |
with gr.Tab("Advanced Character Pack"):
|
|
|
|
| 850 |
outputs=[adv_gallery, adv_rendered, adv_mask_video, adv_zip, adv_status],
|
| 851 |
)
|
| 852 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
with gr.Tab("Pack Format"):
|
| 854 |
gr.Markdown(
|
| 855 |
+
"The Simple Pack tab exports flat packs. The Advanced Character Pack tab exports a canonical "
|
| 856 |
"character pack with explicit character folders.\n\n"
|
| 857 |
"Simple animation pack:\n"
|
| 858 |
"```text\n"
|