fffiloni commited on
Commit
cdca2a6
·
verified ·
1 Parent(s): ab500d2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -22
app.py CHANGED
@@ -19,7 +19,19 @@ from huggingface_hub import hf_hub_download, snapshot_download
19
  logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s")
20
 
21
  ROOT = Path(__file__).resolve().parent
22
- OUTPUT_DIR = Path(os.getenv("SCAIL_OUTPUT_DIR", "/tmp/scail2_outputs"))
 
 
 
 
 
 
 
 
 
 
 
 
23
  OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
24
 
25
  MODEL_REPO_ID = os.getenv("SCAIL_MODEL_REPO_ID", "zai-org/SCAIL-2")
@@ -133,7 +145,7 @@ def _download_safetensors_if_configured() -> Path | None:
133
  if not SAFETENSORS_REPO_ID:
134
  return None
135
 
136
- local_dir = Path(os.getenv("SCAIL_SAFETENSORS_CACHE", "/tmp/scail2_safetensors"))
137
  local_dir.mkdir(parents=True, exist_ok=True)
138
  local_path = local_dir / SAFETENSORS_FILENAME
139
  if local_path.exists():
@@ -163,7 +175,7 @@ def _find_converted_safetensors(ckpt_dir: Path | None) -> Path | None:
163
  ROOT / "SCAIL-2.safetensors",
164
  ROOT / "models" / "SCAIL-2.safetensors",
165
  ROOT / "model.safetensors",
166
- Path(os.getenv("SCAIL_CONVERTED_DIR", "/tmp/scail2_converted")) / "SCAIL-2.safetensors",
167
  ]
168
  if ckpt_dir is not None:
169
  candidates += [
@@ -184,7 +196,7 @@ def _download_checkpoint_if_needed(include_original_dit: bool = False) -> Path:
184
  raise RuntimeError(f"SCAIL_CKPT_DIR does not exist: {ckpt_dir}")
185
  return ckpt_dir
186
 
187
- local_dir = Path(os.getenv("SCAIL_CKPT_CACHE", "/tmp/scail2_ckpt"))
188
  clip_name = "models_clip_open-clip-xlm-roberta-large-vit-huge-14-onlyvisual.pth"
189
  original_dit = local_dir / "model" / "1" / "fsdp2_rank_0000_checkpoint.pt"
190
  has_base_assets = (
@@ -267,7 +279,7 @@ def _maybe_convert_checkpoint(ckpt_dir: Path, scail_path: Path | None) -> Path:
267
  "because SCAIL_AUTO_CONVERT=0."
268
  )
269
 
270
- save_dir = Path(os.getenv("SCAIL_CONVERTED_DIR", "/tmp/scail2_converted"))
271
  save_dir.mkdir(parents=True, exist_ok=True)
272
  save_path = save_dir / "SCAIL-2.safetensors"
273
  if save_path.exists():
@@ -509,16 +521,6 @@ def _duration_for_job(*args, **kwargs):
509
  return int(os.getenv("SCAIL_GPU_DURATION", str(GPU_DURATION_WARM)))
510
 
511
 
512
- @spaces.GPU(duration=_duration_for_job, size=GPU_SIZE)
513
- def warmup_model():
514
- try:
515
- _get_pipeline()
516
- return "Model is loaded. The next generation should skip the cold-start model load."
517
- except Exception:
518
- logging.exception("Warmup failed")
519
- return traceback.format_exc()
520
-
521
-
522
  def _run_scail_job(
523
  image_path,
524
  mask_image_path,
@@ -534,10 +536,15 @@ def _run_scail_job(
534
  seed,
535
  segment_len,
536
  segment_overlap,
 
537
  ):
 
 
538
  pipeline = _get_pipeline()
539
  cfg = _SCAIL_CONFIGS[MODEL_NAME]
540
  save_file = OUTPUT_DIR / f"scail2_{uuid.uuid4().hex}.mp4"
 
 
541
  args = SimpleNamespace(
542
  target_h=int(target_h),
543
  target_w=int(target_w),
@@ -554,6 +561,8 @@ def _run_scail_job(
554
  prompt=prompt or "",
555
  )
556
 
 
 
557
  _GENERATE_VIDEO(
558
  pipeline,
559
  prompt or "",
@@ -569,9 +578,13 @@ def _run_scail_job(
569
  replace_flag=bool(replace_flag),
570
  additional_task_input=None,
571
  )
 
 
572
  gc.collect()
573
  if torch.cuda.is_available():
574
  torch.cuda.empty_cache()
 
 
575
  return str(save_file)
576
 
577
 
@@ -586,8 +599,10 @@ def generate_from_example(
586
  target_size,
587
  segment_len,
588
  segment_overlap,
 
589
  ):
590
  try:
 
591
  examples = _existing_examples()
592
  if example_name not in examples:
593
  raise RuntimeError(f"Example is missing from this checkout: {example_name}")
@@ -608,6 +623,7 @@ def generate_from_example(
608
  seed,
609
  segment_len,
610
  segment_overlap,
 
611
  )
612
  return output, "Done."
613
  except Exception:
@@ -630,8 +646,10 @@ def generate_from_uploads(
630
  target_size,
631
  segment_len,
632
  segment_overlap,
 
633
  ):
634
  try:
 
635
  required = {
636
  "reference image": image,
637
  "reference mask": mask_image,
@@ -658,6 +676,7 @@ def generate_from_uploads(
658
  seed,
659
  segment_len,
660
  segment_overlap,
 
661
  )
662
  return output, "Done."
663
  except Exception:
@@ -689,6 +708,7 @@ def _startup_message():
689
  return "Repo layout detected, but no prepared examples were found."
690
  return (
691
  f"Ready. Found {len(examples)} prepared example(s). "
 
692
  f"{_ASSET_STATUS}\n\n{_RUNTIME_STATUS}\n\n"
693
  "Attention backend: HF Kernels flash-attn2 when available, otherwise SDPA."
694
  )
@@ -708,15 +728,11 @@ def build_ui():
708
  "V1 inference-only Space. It runs SCAIL-2 from prepared inputs: reference image, "
709
  "reference mask, driving/rendered video, and driving mask video. SCAIL-Pose/SAM3 "
710
  "preprocessing is intentionally not imported in this version.\n\n"
711
- "First GPU call is a cold start: it loads T5, VAE, CLIP, and the 14B DiT before "
712
- "sampling. Use the warmup button once after startup if you want to separate model "
713
- "loading from generation."
714
  )
715
  startup = gr.Textbox(value=_startup_message(), label="Startup status", interactive=False)
716
- with gr.Row():
717
- warmup_button = gr.Button("Load model / warm up GPU", variant="secondary")
718
- warmup_status = gr.Textbox(label="Warmup status", lines=4, interactive=False)
719
- warmup_button.click(warmup_model, outputs=[warmup_status])
720
 
721
  with gr.Tab("Prepared Examples"):
722
  with gr.Row():
 
19
  logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s")
20
 
21
  ROOT = Path(__file__).resolve().parent
22
+
23
+
24
+ def _default_storage_root() -> Path:
25
+ if os.getenv("SCAIL_STORAGE_ROOT"):
26
+ return Path(os.environ["SCAIL_STORAGE_ROOT"])
27
+ data_mount = Path("/data")
28
+ if data_mount.exists() and os.access(data_mount, os.W_OK):
29
+ return data_mount
30
+ return Path("/tmp")
31
+
32
+
33
+ STORAGE_ROOT = _default_storage_root()
34
+ OUTPUT_DIR = Path(os.getenv("SCAIL_OUTPUT_DIR", str(STORAGE_ROOT / "scail2_outputs")))
35
  OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
36
 
37
  MODEL_REPO_ID = os.getenv("SCAIL_MODEL_REPO_ID", "zai-org/SCAIL-2")
 
145
  if not SAFETENSORS_REPO_ID:
146
  return None
147
 
148
+ local_dir = Path(os.getenv("SCAIL_SAFETENSORS_CACHE", str(STORAGE_ROOT / "scail2_safetensors")))
149
  local_dir.mkdir(parents=True, exist_ok=True)
150
  local_path = local_dir / SAFETENSORS_FILENAME
151
  if local_path.exists():
 
175
  ROOT / "SCAIL-2.safetensors",
176
  ROOT / "models" / "SCAIL-2.safetensors",
177
  ROOT / "model.safetensors",
178
+ Path(os.getenv("SCAIL_CONVERTED_DIR", str(STORAGE_ROOT / "scail2_converted"))) / "SCAIL-2.safetensors",
179
  ]
180
  if ckpt_dir is not None:
181
  candidates += [
 
196
  raise RuntimeError(f"SCAIL_CKPT_DIR does not exist: {ckpt_dir}")
197
  return ckpt_dir
198
 
199
+ local_dir = Path(os.getenv("SCAIL_CKPT_CACHE", str(STORAGE_ROOT / "scail2_ckpt")))
200
  clip_name = "models_clip_open-clip-xlm-roberta-large-vit-huge-14-onlyvisual.pth"
201
  original_dit = local_dir / "model" / "1" / "fsdp2_rank_0000_checkpoint.pt"
202
  has_base_assets = (
 
279
  "because SCAIL_AUTO_CONVERT=0."
280
  )
281
 
282
+ save_dir = Path(os.getenv("SCAIL_CONVERTED_DIR", str(STORAGE_ROOT / "scail2_converted")))
283
  save_dir.mkdir(parents=True, exist_ok=True)
284
  save_path = save_dir / "SCAIL-2.safetensors"
285
  if save_path.exists():
 
521
  return int(os.getenv("SCAIL_GPU_DURATION", str(GPU_DURATION_WARM)))
522
 
523
 
 
 
 
 
 
 
 
 
 
 
524
  def _run_scail_job(
525
  image_path,
526
  mask_image_path,
 
536
  seed,
537
  segment_len,
538
  segment_overlap,
539
+ progress=None,
540
  ):
541
+ if progress is not None:
542
+ progress(0.02, desc="Loading SCAIL-2 pipeline")
543
  pipeline = _get_pipeline()
544
  cfg = _SCAIL_CONFIGS[MODEL_NAME]
545
  save_file = OUTPUT_DIR / f"scail2_{uuid.uuid4().hex}.mp4"
546
+ if progress is not None:
547
+ progress(0.12, desc="Preparing inputs")
548
  args = SimpleNamespace(
549
  target_h=int(target_h),
550
  target_w=int(target_w),
 
561
  prompt=prompt or "",
562
  )
563
 
564
+ if progress is not None:
565
+ progress(0.15, desc="Generating video")
566
  _GENERATE_VIDEO(
567
  pipeline,
568
  prompt or "",
 
578
  replace_flag=bool(replace_flag),
579
  additional_task_input=None,
580
  )
581
+ if progress is not None:
582
+ progress(0.95, desc="Finalizing output")
583
  gc.collect()
584
  if torch.cuda.is_available():
585
  torch.cuda.empty_cache()
586
+ if progress is not None:
587
+ progress(1.0, desc="Done")
588
  return str(save_file)
589
 
590
 
 
599
  target_size,
600
  segment_len,
601
  segment_overlap,
602
+ progress=gr.Progress(track_tqdm=True),
603
  ):
604
  try:
605
+ progress(0.0, desc="Checking example inputs")
606
  examples = _existing_examples()
607
  if example_name not in examples:
608
  raise RuntimeError(f"Example is missing from this checkout: {example_name}")
 
623
  seed,
624
  segment_len,
625
  segment_overlap,
626
+ progress=progress,
627
  )
628
  return output, "Done."
629
  except Exception:
 
646
  target_size,
647
  segment_len,
648
  segment_overlap,
649
+ progress=gr.Progress(track_tqdm=True),
650
  ):
651
  try:
652
+ progress(0.0, desc="Checking uploaded inputs")
653
  required = {
654
  "reference image": image,
655
  "reference mask": mask_image,
 
676
  seed,
677
  segment_len,
678
  segment_overlap,
679
+ progress=progress,
680
  )
681
  return output, "Done."
682
  except Exception:
 
708
  return "Repo layout detected, but no prepared examples were found."
709
  return (
710
  f"Ready. Found {len(examples)} prepared example(s). "
711
+ f"Storage root: {STORAGE_ROOT}. Output dir: {OUTPUT_DIR}.\n\n"
712
  f"{_ASSET_STATUS}\n\n{_RUNTIME_STATUS}\n\n"
713
  "Attention backend: HF Kernels flash-attn2 when available, otherwise SDPA."
714
  )
 
728
  "V1 inference-only Space. It runs SCAIL-2 from prepared inputs: reference image, "
729
  "reference mask, driving/rendered video, and driving mask video. SCAIL-Pose/SAM3 "
730
  "preprocessing is intentionally not imported in this version.\n\n"
731
+ "On ZeroGPU, each generation should be treated as a cold start: the GPU can be "
732
+ "released between calls, so the 14B stack may need to be loaded again before "
733
+ "sampling."
734
  )
735
  startup = gr.Textbox(value=_startup_message(), label="Startup status", interactive=False)
 
 
 
 
736
 
737
  with gr.Tab("Prepared Examples"):
738
  with gr.Row():