fffiloni commited on
Commit
d7750da
·
verified ·
1 Parent(s): 557df65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -126
app.py CHANGED
@@ -480,79 +480,23 @@ def _replacement_command(
480
 
481
 
482
  @spaces.GPU(duration=GPU_DURATION, size=GPU_SIZE)
483
- def build_animation_pack(
 
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
- if matchnearest and egocentric:
 
 
 
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. Pack created at {zip_path}\n\n{logs}"
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("Replacement pack generation failed")
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("Animation Pack"):
746
  gr.Markdown(
747
- "Create an animation pack from one reference image and one driving video. "
748
- "This uses SCAIL-Pose end-to-end mode: the driving video becomes `rendered_v2.mp4`, "
749
- "and SAM3 produces the colored driving mask video."
 
 
 
 
 
750
  )
751
  with gr.Row():
752
- anim_ref = gr.Image(type="filepath", label="Reference image")
753
- anim_driving = gr.Video(label="Driving video")
754
- anim_prompt = gr.Textbox(label="Prompt for SCAIL-2", lines=3)
755
- with gr.Row():
756
- anim_sam3_text = gr.Textbox(value="human character", label="SAM3 text prompt")
757
- anim_max_persons = gr.Number(value=2, precision=0, label="Max tracked subjects")
758
- anim_crop = gr.Dropdown(
759
  ["none", "mask silhouette", "moving bbox", "steady bbox"],
760
  value="none",
761
  label="Driving crop mode",
762
  )
763
- anim_run = gr.Button("Generate animation pack", variant="primary")
 
 
 
 
 
 
 
 
 
764
  with gr.Row():
765
- anim_ref_mask = gr.Image(label="Reference mask", interactive=False)
766
- anim_mask_video = gr.Video(label="Driving mask video")
767
- anim_rendered = gr.Video(label="Rendered / driving video")
768
- anim_zip = gr.File(label="Download SCAIL-2 animation pack")
769
- anim_status = gr.Textbox(label="Run logs", lines=14)
770
- anim_run.click(
771
- build_animation_pack,
772
  inputs=[
773
- anim_ref,
774
- anim_driving,
775
- anim_prompt,
776
- anim_sam3_text,
777
- anim_max_persons,
778
- anim_crop,
 
 
 
779
  ],
780
- outputs=[anim_ref_mask, anim_rendered, anim_mask_video, anim_zip, anim_status],
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 simple tabs export flat packs. The advanced tab exports a canonical "
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"