Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| import hashlib | |
| import json | |
| import os | |
| from pathlib import Path | |
| import time | |
| from huggingface_hub import hf_hub_download | |
| class ModelSpec: | |
| key: str | |
| repo: str | |
| filename: str | |
| category: str | |
| size: int | |
| sha256: str | |
| mount_root: str | |
| SPECS = { | |
| "high": ModelSpec("high", "marck1391/DaSiWa-WAN2.2-I2V-14B", "DasiwaWAN22I2V14BLightspeed_snatchkissHighV11.safetensors", "diffusion_models", 14528782272, "fa4202ea621725c57b0cbb84543bd6a5548de1d85c0c5a9f18db0bcf91202a54", "/models/high"), | |
| "low": ModelSpec("low", "FX-FeiHou/wan2.2-Remix", "NSFW/Wan2.2_Remix_NSFW_i2v_14b_low_lighting_fp8_e4m3fn_v3.0.safetensors", "diffusion_models", 14291272136, "a239063c377e530229c4e5b1fecdcbe9de1201a30126dd42297435287e713229", "/models/low"), | |
| "text": ModelSpec("text", "NSFW-API/NSFW-Wan-UMT5-XXL", "nsfw_wan_umt5-xxl_bf16.safetensors", "text_encoders", 11361851256, "daa3cdf38e2dc7cd776548e59d7956db3a3bc95fecf95f95e6ca2722419eeb66", "/models/text"), | |
| "text_int8": ModelSpec("text_int8", "n-Arno/NSFW-Wan-UMT5-XXL-QINT8", "models_t5_umt5-xxl-enc-quanto_int8.safetensors", "text_encoders", 6733326448, "751f895bb238e6fc63030d107cbb7ee2e814e3793b880ab4d972139ac8b2bebb", "/models/text-int8"), | |
| "vae": ModelSpec("vae", "Comfy-Org/Wan_2.1_ComfyUI_repackaged", "split_files/vae/wan_2.1_vae.safetensors", "vae", 253815318, "2fc39d31359a4b0a64f55876d8ff7fa8d780956ae2cb13463b0223e15148976b", "/models/vae"), | |
| } | |
| def _sha256(path: Path) -> str: | |
| digest = hashlib.sha256() | |
| with path.open("rb") as handle: | |
| for chunk in iter(lambda: handle.read(16 * 1024 * 1024), b""): | |
| digest.update(chunk) | |
| return digest.hexdigest() | |
| def _resolve_source(spec: ModelSpec) -> Path: | |
| explicit = os.environ.get(f"WAN_{spec.key.upper()}_MODEL_PATH", "").strip() | |
| if explicit: | |
| return Path(explicit).expanduser().resolve() | |
| localize_active = os.environ.get( | |
| "WAN_LOCALIZE_ACTIVE_MODELS", | |
| os.environ.get("WAN_LOCALIZE_DIFFUSION_MODELS", "1"), | |
| ).strip().lower() not in { | |
| "0", "false", "no", "off", | |
| } | |
| if spec.key in {"high", "low", "text_int8", "vae"} and localize_active: | |
| # Model volumes remain read-only fallbacks. Their lazy/FUSE views are | |
| # much slower when ZeroGPU rereads every active tensor for O_DIRECT | |
| # packing. A normal ephemeral Hub cache mirrors from_pretrained and | |
| # gives materialization and packing regular local backing files. | |
| started = time.perf_counter() | |
| print(f"[WAN_MODEL] {json.dumps({'event': 'localize.start', 'role': spec.key}, sort_keys=True)}", flush=True) | |
| path = Path(hf_hub_download( | |
| repo_id=spec.repo, | |
| filename=spec.filename, | |
| cache_dir=os.environ.get("WAN_HUB_CACHE", "/tmp/wan-hub-cache"), | |
| )) | |
| print(f"[WAN_MODEL] {json.dumps({'elapsed_s': round(time.perf_counter() - started, 3), 'event': 'localize.done', 'role': spec.key}, sort_keys=True)}", flush=True) | |
| return path | |
| mounted = Path(spec.mount_root) / spec.filename | |
| if mounted.is_file(): | |
| return mounted.resolve() | |
| return Path(hf_hub_download(repo_id=spec.repo, filename=spec.filename)) | |
| def prepare_models_root(*, verify_hashes: bool | None = None) -> tuple[Path, dict[str, str]]: | |
| # Hub-mounted weights are immutable for the selected repository revision. | |
| # Re-hashing ~40 GB on every cold ZeroGPU request stalls the UI at model | |
| # loading and can consume most of the GPU lease before inference starts. | |
| verify = verify_hashes if verify_hashes is not None else os.environ.get("VERIFY_MODEL_HASHES", "0") != "0" | |
| root = Path(os.environ.get("WAN_MODELS_ROOT", "/tmp/wan_models")).resolve() | |
| names: dict[str, str] = {} | |
| for spec in SPECS.values(): | |
| source = _resolve_source(spec) | |
| if not source.is_file(): | |
| raise FileNotFoundError(f"Modello {spec.key} non trovato: {source}") | |
| if source.stat().st_size != spec.size: | |
| raise RuntimeError(f"Dimensione errata per {spec.key}: {source.stat().st_size}, attesa {spec.size}") | |
| if verify and _sha256(source) != spec.sha256: | |
| raise RuntimeError(f"SHA-256 errato per {spec.key}: {source}") | |
| category = root / spec.category | |
| category.mkdir(parents=True, exist_ok=True) | |
| target = category / Path(spec.filename).name | |
| if target.is_symlink() or target.exists(): | |
| if target.resolve() != source: | |
| target.unlink() | |
| if not target.exists(): | |
| target.symlink_to(source) | |
| names[spec.key] = target.name | |
| return root, names | |