Fix video load planning, lifecycle, and trust gaps from review

Review round on the video backend:
- the resident memory check now budgets transformer plus companions like the
  image backend, instead of letting auto pick a resident placement that OOMs
  while the LTX text encoder and VAEs load
- a new load waits for the signalled in flight generation to exit before
  tearing down the old pipeline, so two models never share VRAM during a swap
- the load worker rechecks its token right before placement, narrowing the
  window where a cancelled load could put weights on a GPU the arbiter
  already handed to another backend
- the step cache installs before the speed profile and compile now keys
  fullgraph off an active cache, matching the image order; compiling
  fullgraph first crashed the first cached generation
- teardown uninstalls the process wide compiled GGUF dequantizer so a later
  speed off load gets the bit identical path
- explicit base_repo goes through the same trust gate as non GGUF repo ids,
  and local checkpoint paths are verified during validation, before the
  route evicts a resident model
- status reports only the speed optimisations that actually engaged
- the gallery file route streams via FileResponse with range support instead
  of buffering whole clips
- the build step reuses the checkpoint path resolved during planning
This commit is contained in:
Daniel Han 2026-07-05 00:24:16 +00:00
commit baf6a3c832
3 changed files with 107 additions and 15 deletions

View file

@ -187,6 +187,7 @@ class VideoBackend:
repo_id: str,
*,
gguf_filename: Optional[str] = None,
base_repo: Optional[str] = None,
family_override: Optional[str] = None,
model_kind: Optional[str] = None,
) -> VideoFamily:
@ -208,8 +209,29 @@ class VideoBackend:
f"Non-GGUF video loads are limited to unsloth/* repos, the official "
f"family base repos, and local paths; '{repo_id}' is neither."
)
# The companions load with from_pretrained too, so an explicit base repo is
# held to the same bar as a non-GGUF repo id: a GGUF pick must not smuggle
# in an arbitrary remote base.
if base_repo and (base_repo or "").strip() and not _is_trusted_video_repo(base_repo):
raise ValueError(
f"base_repo is limited to unsloth/* repos, the official family base "
f"repos, and local paths; '{base_repo}' is neither."
)
if kind in ("gguf", "single_file") and not gguf_filename:
raise ValueError("A gguf/single_file load needs the checkpoint filename.")
# A local checkpoint that cannot exist must fail HERE, before the route evicts
# a resident chat/image model for a load that dies at resolve time.
if kind in ("gguf", "single_file"):
root = Path(repo_id).expanduser()
if root.is_dir():
from .diffusion_families import resolve_local_gguf_child
try:
resolve_local_gguf_child(root, gguf_filename or "")
except Exception as exc: # noqa: BLE001 -- surface as client input error
raise ValueError(str(exc)) from exc
elif repo_id.startswith(("/", "~", "./", "../")) and not root.is_file():
raise ValueError(f"Local model path '{repo_id}' does not exist.")
_ensure_mp4_encoder_available()
return fam
@ -235,6 +257,7 @@ class VideoBackend:
fam = self.validate_load_request(
repo_id,
gguf_filename = gguf_filename,
base_repo = base_repo,
family_override = family_override,
model_kind = model_kind,
)
@ -405,6 +428,7 @@ class VideoBackend:
fam = self.validate_load_request(
repo_id,
gguf_filename = gguf_filename,
base_repo = base_repo,
family_override = family_override,
model_kind = model_kind,
)
@ -418,6 +442,13 @@ class VideoBackend:
# above already bailed a superseded worker before this point.
if self._active_generate_cancel is not None:
self._active_generate_cancel.set()
# Wait for the signalled generation to actually exit before tearing the old
# pipeline down: the denoise loop holds its own pipe reference until the
# next step callback, and freeing/reallocating under it would put two
# models in VRAM at once. generate() holds _generate_lock for its full
# body, so a bare acquire is the exit barrier (never while holding _lock).
with self._generate_lock:
pass
self._teardown_state()
target = resolve_diffusion_device_target()
@ -449,7 +480,13 @@ class VideoBackend:
if components is not None
else None
)
model_dense_mib = transformer_mib
# The resident check budgets ALL weights (the image backend's contract):
# the companions stay resident even when only the transformer would fit,
# so budgeting the transformer alone lets auto pick OFFLOAD_NONE and OOM
# while from_pretrained loads the text encoder / VAEs.
model_dense_mib = (
transformer_mib + (companion_mib or 0) if transformer_mib is not None else None
)
runtime_mib = estimate_video_runtime_mib(
width = fam.resolution_presets[0][0],
height = fam.resolution_presets[0][1],
@ -473,7 +510,8 @@ class VideoBackend:
pipe = pipeline_cls.from_pretrained(repo_id, **pipe_kwargs)
else:
transformer_cls = getattr(diffusers, fam.transformer_class)
checkpoint_path = self._resolve_checkpoint_path(repo_id, gguf_filename, hf_token)
# checkpoint_path was already resolved (and downloaded) by the memory
# planning branch above for every non-pipeline kind.
sf_kwargs: dict[str, Any] = {
"torch_dtype": dtype,
"config": base,
@ -506,11 +544,19 @@ class VideoBackend:
clear_gpu_cache()
raise RuntimeError("Video load was cancelled or superseded.")
# ── optimisation layers, in the image backend's order: speed profile
# (compile must precede placement), attention (compile traces it),
# placement/offload, then the step cache.
# ── optimisation layers, in the image backend's order: step cache FIRST
# (compile keys its fullgraph decision off an active cache: FBCache hooks
# graph-break, so compiling fullgraph before installing the cache crashes
# the first cached generation), then attention, the speed profile, and
# placement/offload last.
effective_speed = resolve_speed_mode(speed_mode, is_gguf = kind == "gguf")
backend_flags = snapshot_backend_flags()
cache_engaged = apply_step_cache(
pipe,
mode = normalize_transformer_cache(transformer_cache),
threshold = transformer_cache_threshold,
logger = logger,
)
attention_engaged = apply_attention_backend(
pipe,
select_attention_backend(
@ -524,8 +570,16 @@ class VideoBackend:
is_gguf = kind == "gguf",
family = fam,
speed_mode = effective_speed,
cache_active = cache_engaged is not None,
offload_active = plan.offload_policy != "none",
)
# A cancelled/superseded load must not place weights on the GPU the arbiter
# may already have handed to another backend; recheck right before placement
# (the commit below still does the final locked check).
if _load_token is not None and _load_token != self._load_token:
del pipe
clear_gpu_cache()
raise RuntimeError("Video load was cancelled or superseded.")
offload_policy, vae_tiling = apply_memory_plan(pipe, plan, device = device, logger = logger)
if not vae_tiling:
# Decode of a whole clip is the video memory peak; tiling is near-free
@ -535,12 +589,6 @@ class VideoBackend:
vae_tiling = True
except Exception as exc: # noqa: BLE001 -- tiling is an optimisation only
logger.warning("video.vae_tiling_failed: %s", exc)
cache_engaged = apply_step_cache(
pipe,
mode = normalize_transformer_cache(transformer_cache),
threshold = transformer_cache_threshold,
logger = logger,
)
resolved = build_resolved_record(
{
@ -585,7 +633,10 @@ class VideoBackend:
vae_tiling = vae_tiling,
memory_mode = plan.requested_mode,
speed_mode = effective_speed,
speed_optims = tuple(speed_optims or ()),
# Only the optimisations that actually engaged: apply_speed_optims
# returns every flag with True/False, and iterating the dict raw
# would report disabled ones as active in /video/status.
speed_optims = tuple(k for k, v in (speed_optims or {}).items() if v),
backend_flags = backend_flags,
attention_backend = attention_engaged,
transformer_cache = cache_engaged,
@ -812,6 +863,12 @@ class VideoBackend:
state, self._state = self._state, None
if state is not None:
restore_backend_flags(state.backend_flags)
# A GGUF video load may have installed the process-wide compiled GGUF
# dequantizer; restore the stock kernels so a later load that asked for
# speed_mode=off gets the bit-identical path (mirrors the image unload).
from . import diffusion_gguf_compile
diffusion_gguf_compile.uninstall_all()
del state
clear_gpu_cache()

View file

@ -271,10 +271,13 @@ async def get_gallery_video_file(
path = await asyncio.to_thread(video_gallery.video_path, video_id)
if path is None:
raise HTTPException(status_code = 404, detail = "Video not found.")
data = await asyncio.to_thread(path.read_bytes)
from fastapi.responses import FileResponse
# FileResponse streams from disk (no whole-clip buffering per request) and
# serves HTTP range requests so a direct URL can seek without a full fetch.
# Immutable content (id is unique per video), so let the browser cache it.
return Response(
content = data,
return FileResponse(
path,
media_type = "video/mp4",
headers = {"Cache-Control": "private, max-age=31536000, immutable"},
)

View file

@ -179,6 +179,38 @@ def test_validate_rejects_unknown_and_untrusted():
backend.validate_load_request("unsloth/LTX-2.3-GGUF", model_kind = "gguf")
def test_validate_gates_base_repo_and_local_paths(tmp_path):
backend = VideoBackend()
# An arbitrary remote base_repo must not reach from_pretrained via a GGUF pick.
with pytest.raises(ValueError, match = "base_repo"):
backend.validate_load_request(
"unsloth/LTX-2.3-GGUF",
gguf_filename = "x.gguf",
model_kind = "gguf",
base_repo = "evil/companions",
)
# The family base and local dirs stay allowed.
fam = backend.validate_load_request(
"unsloth/LTX-2.3-GGUF",
gguf_filename = "x.gguf",
model_kind = "gguf",
base_repo = "Lightricks/LTX-2",
)
assert fam.name == "ltx-2"
# A local dir without the picked checkpoint fails BEFORE the GPU handoff.
with pytest.raises(ValueError):
backend.validate_load_request(
str(tmp_path), gguf_filename = "missing.gguf", family_override = "ltx-2"
)
# A path-shaped repo id that does not exist fails validation too.
with pytest.raises(ValueError, match = "does not exist"):
backend.validate_load_request(
str(tmp_path / "nope" / "model.gguf"),
gguf_filename = "model.gguf",
family_override = "ltx-2",
)
def test_load_generate_unload_gguf(fake_runtime, tmp_path):
backend = VideoBackend()
status = _load_gguf(backend, tmp_path)