BoxOfColors Claude Opus 4.7 (1M context) commited on
Commit
5d79cd0
Β·
1 Parent(s): 777c82c

fix: harden upstream-protection so the Space survives upstream deletion

Browse files

The audit revealed two paths where a runtime fetch could still hit
upstream sources (Wan-AI, lightx2v, github.com/enesmsahin) even though
all the weights are mirrored at
JackIsNotInTheBox/Video_Watermark_Remover_Checkpoints. Both closed:

pipeline/lama.py
- LAMA_MODEL_URL now defaults to the mirror URL directly (was None
unless the Space variable was set). If the Space variable is dropped
for any reason, the prefetch still works β€” no silent fallback to the
hardcoded GitHub release that simple_lama_inpainting would otherwise
reach for.

pipeline/vace.py
- New VACE_LOCAL_ONLY knob (defaults to True when VACE_PREWARM=1, which
is the default). Forces every from_pretrained / load_lora_weights call
inside _get_pipe() to pass local_files_only=True. Combined with the
prewarm step populating the cache from the mirror, this guarantees no
upstream HF Hub fetch is ever attempted at inference time β€” even if
the mirror itself goes offline mid-session, the cached files keep
working. If anything's missing from the cache, from_pretrained raises
loudly instead of silently downloading from upstream.

After this change the Space's runtime is fully self-contained:
βœ“ LaMa weights β€” mirror (lama/big-lama.pt)
βœ“ VACE-14B base β€” mirror (vace-14b/) loaded with local_files_only=True
βœ“ Distill LoRA β€” mirror (loras/...) loaded with local_files_only=True
βœ“ Prewarm fetches everything at startup from the mirror
βœ— Upstream Wan-AI / lightx2v / GitHub releases β€” never touched
at runtime regardless of their state

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files changed (2) hide show
  1. pipeline/lama.py +12 -5
  2. pipeline/vace.py +18 -1
pipeline/lama.py CHANGED
@@ -36,11 +36,18 @@ from pipeline.crop import CropRegion
36
  # ---------------------------------------------------------------------------
37
  # simple-lama-inpainting hardcodes its big-lama.pt download URL to a GitHub
38
  # release. If that release ever vanishes, every Space cold start fails.
39
- # When LAMA_MODEL_URL is set, we pre-populate the file in the cache path
40
- # SimpleLama() will look at, so its own download logic finds it pre-existing
41
- # and never reaches GitHub. This closes the upstream-protection loop opened
42
- # by the JackIsNotInTheBox/Video_Watermark_Remover_Checkpoints mirror.
43
- LAMA_MODEL_URL = os.environ.get("LAMA_MODEL_URL")
 
 
 
 
 
 
 
44
 
45
 
46
  def _ensure_lama_weights_cached() -> None:
 
36
  # ---------------------------------------------------------------------------
37
  # simple-lama-inpainting hardcodes its big-lama.pt download URL to a GitHub
38
  # release. If that release ever vanishes, every Space cold start fails.
39
+ # We pre-populate the file in the cache path SimpleLama() will look at, so
40
+ # its own download logic finds it pre-existing and never reaches GitHub.
41
+ #
42
+ # Default URL points at the project's HF mirror so the Space remains
43
+ # self-contained even if the Space variable LAMA_MODEL_URL is dropped or
44
+ # the upstream GitHub release disappears. Override via env var if you want
45
+ # to test a different mirror.
46
+ LAMA_MODEL_URL = os.environ.get(
47
+ "LAMA_MODEL_URL",
48
+ "https://huggingface.co/JackIsNotInTheBox/"
49
+ "Video_Watermark_Remover_Checkpoints/resolve/main/lama/big-lama.pt",
50
+ )
51
 
52
 
53
  def _ensure_lama_weights_cached() -> None:
pipeline/vace.py CHANGED
@@ -48,7 +48,10 @@ Configuration knobs (all read at module import via env vars)
48
  - VACE_SUBFOLDER : subfolder within the repo (default: ``vace-14b``)
49
  - VACE_LORA_REPO_ID : HF repo holding the distill LoRA (default: mirror)
50
  - VACE_LORA_FILE : LoRA filename (default: lightx2v rank-64 4-step)
51
- - VACE_PREWARM : "1" (default) prewarms checkpoint cache; "0" skips
 
 
 
52
 
53
  License: Apache-2.0 (Wan2.1 base) + Apache-2.0 (lightx2v distill LoRA).
54
  """
@@ -85,6 +88,15 @@ VACE_LORA_FILE = os.environ.get(
85
  "loras/wan2.1_t2v_14b_lora_rank64_lightx2v_4step.safetensors",
86
  )
87
 
 
 
 
 
 
 
 
 
 
88
  # VACE requires num_frames = 4n+1. 81 = 16*5+1 is the documented sweet spot.
89
  CHUNK_FRAMES = 81
90
  # Frames shared between consecutive chunks for temporal continuity at seams.
@@ -184,16 +196,20 @@ def _get_pipe():
184
  )
185
 
186
  # VAE in fp32 (per the official diffusers example) for numerical stability.
 
 
187
  vae = AutoencoderKLWan.from_pretrained(
188
  VACE_REPO_ID,
189
  subfolder=f"{VACE_SUBFOLDER}/vae",
190
  torch_dtype=torch.float32,
 
191
  )
192
  pipe = WanVACEPipeline.from_pretrained(
193
  VACE_REPO_ID,
194
  subfolder=VACE_SUBFOLDER,
195
  vae=vae,
196
  torch_dtype=torch.bfloat16,
 
197
  )
198
 
199
  # flow_shift = 3.0 β†’ 480P-friendly. 5.0 would be 720P-friendly.
@@ -211,6 +227,7 @@ def _get_pipe():
211
  VACE_LORA_REPO_ID,
212
  weight_name=VACE_LORA_FILE,
213
  adapter_name="distill",
 
214
  )
215
  pipe.set_adapters(["distill"], adapter_weights=[1.0])
216
  pipe.fuse_lora(adapter_names=["distill"], lora_scale=1.0)
 
48
  - VACE_SUBFOLDER : subfolder within the repo (default: ``vace-14b``)
49
  - VACE_LORA_REPO_ID : HF repo holding the distill LoRA (default: mirror)
50
  - VACE_LORA_FILE : LoRA filename (default: lightx2v rank-64 4-step)
51
+ - VACE_PREWARM : "1" (default) prewarms checkpoint cache; "0" skips.
52
+ Also controls whether _get_pipe() forces
53
+ ``local_files_only=True`` on its from_pretrained calls
54
+ (yes when prewarmed, no when prewarm is disabled).
55
 
56
  License: Apache-2.0 (Wan2.1 base) + Apache-2.0 (lightx2v distill LoRA).
57
  """
 
88
  "loras/wan2.1_t2v_14b_lora_rank64_lightx2v_4step.safetensors",
89
  )
90
 
91
+ # Force ``local_files_only=True`` on every from_pretrained / load_lora_weights
92
+ # call inside _get_pipe(). Combined with prewarm_vace_cache() populating the
93
+ # cache from the mirror at startup, this guarantees no upstream HF Hub fetch
94
+ # is ever attempted at runtime β€” even if the mirror itself goes offline
95
+ # mid-session, what's already cached keeps working. If you opt out of
96
+ # prewarm (VACE_PREWARM=0) you almost certainly want to opt out of this too,
97
+ # so the toggle defaults follow each other.
98
+ VACE_LOCAL_ONLY = os.environ.get("VACE_PREWARM", "1") != "0"
99
+
100
  # VACE requires num_frames = 4n+1. 81 = 16*5+1 is the documented sweet spot.
101
  CHUNK_FRAMES = 81
102
  # Frames shared between consecutive chunks for temporal continuity at seams.
 
196
  )
197
 
198
  # VAE in fp32 (per the official diffusers example) for numerical stability.
199
+ # local_files_only=True (default) prevents silent fallback to upstream HF
200
+ # if anything's missing from the prewarmed cache.
201
  vae = AutoencoderKLWan.from_pretrained(
202
  VACE_REPO_ID,
203
  subfolder=f"{VACE_SUBFOLDER}/vae",
204
  torch_dtype=torch.float32,
205
+ local_files_only=VACE_LOCAL_ONLY,
206
  )
207
  pipe = WanVACEPipeline.from_pretrained(
208
  VACE_REPO_ID,
209
  subfolder=VACE_SUBFOLDER,
210
  vae=vae,
211
  torch_dtype=torch.bfloat16,
212
+ local_files_only=VACE_LOCAL_ONLY,
213
  )
214
 
215
  # flow_shift = 3.0 β†’ 480P-friendly. 5.0 would be 720P-friendly.
 
227
  VACE_LORA_REPO_ID,
228
  weight_name=VACE_LORA_FILE,
229
  adapter_name="distill",
230
+ local_files_only=VACE_LOCAL_ONLY,
231
  )
232
  pipe.set_adapters(["distill"], adapter_weights=[1.0])
233
  pipe.fuse_lora(adapter_names=["distill"], lora_scale=1.0)