VIPRA-reproduce / scripts /push_to_hf.py
yqi19's picture
VIPER reproduction: code, mini VIPER-19K pipeline, qualitative comparisons and eval
9869532 verified
Raw
History Blame Contribute Delete
5.82 kB
"""Publish the reproduction (code + docs + results + videos + checkpoint) to the Hub.
Deliberately EXCLUDES:
* base model weights (models/, ~115GB, all redownloadable from their own repos)
* our trained checkpoints (checkpoints*/) -- weights are not published
* source/intermediate video data (data/videos, data/raw, data/cache)
* third_party/ (the upstream Wan2.2 checkout)
* the venv and every cache
* .hf_token and any other secret
Run: python scripts/push_to_hf.py --repo yqi19/VIPRA-reproduce
"""
from __future__ import annotations
import argparse
import os
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
ALLOW = [
"viper/**",
"scripts/**",
"*.md",
"env.sh",
# NOTE: .gitignore is deliberately NOT published. The Hub applies the repo's
# own .gitignore server-side during commits, and ours carries "*.mp4"/"*.pt"
# (there to keep 100+GB of local data out of git) -- publishing it makes the
# Hub silently drop every result video from the commit.
"data/*.jsonl",
"results/**",
"logs/*.log",
]
IGNORE = [
"models/**", "checkpoints/**", "checkpoints_interactive/**",
"third_party/**", ".venv/**", ".cache/**", ".tmp/**",
".uv_python/**", "data/videos/**", "data/raw/**", "data/cache/**",
"**/__pycache__/**", "*.pyc", ".hf_token", "**/.hf_token",
"results/smoke_videos/**", # superseded by results/comparison
]
TOKEN_RE = re.compile(r"hf_[A-Za-z0-9]{30,}")
# Directories never worth walking (huge / irrelevant); keeps the scan fast.
PRUNE = {"models", "third_party", ".venv", ".cache", ".tmp", ".uv_python",
"__pycache__", ".git", "checkpoints", "checkpoints_interactive"}
def _select(root: Path) -> list[Path]:
"""Files that upload_folder would send, using its fnmatch semantics."""
from fnmatch import fnmatch
out = []
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [d for d in dirnames if d not in PRUNE]
for fn in filenames:
p = Path(dirpath) / fn
rel = str(p.relative_to(root))
if any(fnmatch(rel, pat) for pat in IGNORE):
continue
if any(fnmatch(rel, pat) for pat in ALLOW):
out.append(p)
return sorted(out)
def secret_scan(root: Path) -> list[str]:
"""Refuse to publish if any tracked text file still contains a token."""
hits = []
exts = {".sh", ".py", ".md", ".json", ".jsonl", ".txt", ".yaml", ".yml"}
skip = {"models", "third_party", ".venv", ".cache", ".tmp", ".uv_python",
"__pycache__", ".uv-cache-tmp"}
for p in root.rglob("*"):
if not p.is_file() or p.suffix not in exts:
continue
if any(part in skip for part in p.parts):
continue
try:
txt = p.read_text(errors="ignore")
except Exception:
continue
for m in TOKEN_RE.findall(txt):
hits.append(f"{p.relative_to(root)}: {m[:8]}...")
return hits
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--repo", required=True)
ap.add_argument("--repo_type", default="model")
ap.add_argument("--token", default=os.environ.get("HF_PUSH_TOKEN"))
ap.add_argument("--dry_run", action="store_true")
args = ap.parse_args()
if not args.token:
sys.exit("no token: pass --token or set HF_PUSH_TOKEN")
leaks = secret_scan(ROOT)
if leaks:
print("REFUSING TO PUSH -- secrets found in files that would be published:")
for l in leaks:
print(" ", l)
sys.exit(1)
print("secret scan: clean")
# Preview using the SAME matching huggingface_hub applies, so the dry run is
# truthful (its filter is fnmatch over repo-relative paths, where '*' also
# crosses '/', not pathlib.glob semantics).
picked = _select(ROOT)
total = sum(p.stat().st_size for p in picked)
print(f"{len(picked)} files, {total/1e6:.1f} MB")
by_top: dict[str, list] = {}
for p in picked:
by_top.setdefault(p.relative_to(ROOT).parts[0], []).append(p)
for top, files in sorted(by_top.items()):
sz = sum(f.stat().st_size for f in files)
print(f" {top:28s} {len(files):4d} files {sz/1e6:8.1f} MB")
if args.dry_run:
print("\n(dry run -- nothing uploaded)")
return
from huggingface_hub import HfApi
api = HfApi(token=args.token)
api.create_repo(args.repo, repo_type=args.repo_type, exist_ok=True)
print(f"\nuploading -> https://huggingface.co/{args.repo}")
api.upload_folder(
folder_path=str(ROOT),
repo_id=args.repo,
repo_type=args.repo_type,
allow_patterns=ALLOW,
ignore_patterns=IGNORE,
commit_message="VIPER reproduction: code, mini VIPER-19K pipeline, "
"qualitative comparisons and eval",
)
# upload_folder honours the repo's .gitignore, and ours carries "*.mp4"/"*.pt"
# to keep the 100+GB of local data out of git. That silently drops every
# generated video from the pass above, so push the comparison media from its
# own folder (which contains no .gitignore) as a second commit.
media = ROOT / "results" / "comparison"
if media.is_dir():
n = len(list(media.rglob("*.mp4")))
print(f"\nuploading {n} videos from results/comparison ...")
api.upload_folder(
folder_path=str(media),
path_in_repo="results/comparison",
repo_id=args.repo,
repo_type=args.repo_type,
commit_message="qualitative comparison videos "
"(reference / target GT / Wan2.2 baseline / VIPER)",
)
print(f"done: https://huggingface.co/{args.repo}")
if __name__ == "__main__":
main()