"""One-shot push: stage the Space layout in a tempdir and upload it to `EngEmmanuel/EchoLVFM` (private by default). The Space repo mirrors the local layout — `space/`, `utils/`, `vae/`, `src/` sit as siblings at the Space root, with `space/README.md` and `space/requirements.txt` promoted to root so HF picks them up. The README's frontmatter declares `app_file: space/app.py`, so the Space launcher finds the entrypoint inside the `space/` package — and `space/app.py`'s existing `sys.path` shim makes `from space import ...` and `from utils.hub import ...` resolve identically locally and on the Space. """ from __future__ import annotations import argparse import shutil import subprocess import sys import tempfile from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] DEFAULT_REPO_ID = "EngEmmanuel/EchoLVFM" # Folders copied verbatim into the Space upload, preserving their layout. DEPS = ["space", "utils", "vae", "src"] # Stale paths from the previous (flat) push that need wiping before the # mirrored structure lands. `hf repos delete-files` takes literal paths # and shallow `*` globs (no `**` recursion), so list each subdir's known # files explicitly to be sure the wipe lands. STALE_PATTERNS = [ "app.py", "assets.py", "inference.py", "metrics.py", "video_io.py", "samples/*", "samples/*/*", "assets/*", "scripts/build_samples.py", "scripts/sync_to_hub.py", ] def _parse_args() -> argparse.Namespace: p = argparse.ArgumentParser(description=__doc__) p.add_argument("--repo-id", default=DEFAULT_REPO_ID) p.add_argument("--public", action="store_true", help="Create the Space as public (default: private).") return p.parse_args() def _stage(tmp: Path) -> None: """Materialise the Space-shaped tree under `tmp/`.""" ignore = shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyo") for name in DEPS: shutil.copytree(REPO_ROOT / name, tmp / name, ignore=ignore) # Promote the Space README + requirements to the upload root so HF picks # them up; the originals live under `space/` for editing convenience. shutil.move(str(tmp / "space" / "README.md"), str(tmp / "README.md")) shutil.move(str(tmp / "space" / "requirements.txt"), str(tmp / "requirements.txt")) def main() -> int: args = _parse_args() create_cmd = [ "hf", "repos", "create", args.repo_id, "--type", "space", "--space-sdk", "gradio", "--exist-ok", ] if not args.public: create_cmd.append("--private") print("$", " ".join(create_cmd)) rc = subprocess.call(create_cmd) if rc != 0: return rc # Wipe the stale flat-file root from a prior push. Best-effort — # `delete-files` returns non-zero when patterns match nothing, which # is fine on a fresh repo. delete_cmd = [ "hf", "repos", "delete-files", args.repo_id, *STALE_PATTERNS, "--type", "space", "--commit-message", "Drop stale flat-file root before mirrored push", ] print("$", " ".join(delete_cmd)) subprocess.call(delete_cmd) with tempfile.TemporaryDirectory(prefix="echolvfm_space_") as td: tmp = Path(td) _stage(tmp) upload_cmd = [ "hf", "upload", args.repo_id, str(tmp), ".", "--type", "space", "--commit-message", "Sync EchoLVFM Space (mirrored layout: space/, utils/, vae/, src/)", ] print("$", " ".join(upload_cmd)) return subprocess.call(upload_cmd) if __name__ == "__main__": sys.exit(main())