"""Create/update the static demo Space using the user's local Hugging Face login.""" import argparse import hashlib import json from pathlib import Path import subprocess import shutil import tempfile from huggingface_hub import HfApi ROOT = Path(__file__).resolve().parents[1] def main(): parser = argparse.ArgumentParser() parser.add_argument("--repo", default="danmoreng/macrostories-browser") args = parser.parse_args() api = HfApi() try: identity = api.whoami() except Exception: raise SystemExit("No working Hugging Face login. Run `uvx --from huggingface_hub hf auth login` locally, then retry.") owner, name = args.repo.split("/", 1) namespaces = {namespace.lower(): namespace for namespace in [identity["name"], *(org["name"] for org in identity.get("orgs", []))]} if owner.lower() not in namespaces: raise SystemExit(f"Logged in as {identity['name']}, but the requested destination belongs to {owner}.") # Hub account URLs accept display casing, but repo creation requires the # canonical account namespace returned by whoami (here: danmoreng). args.repo = f"{namespaces[owner.lower()]}/{name}" provenance = json.loads((ROOT / "models/macrostories/provenance.json").read_text()) model = ROOT / "models/macrostories/onnx/model.onnx" if hashlib.sha256(model.read_bytes()).hexdigest() != provenance["onnx_sha256"]: raise SystemExit("ONNX model checksum mismatch. Re-export and verify the model before deployment.") subprocess.run(["npm", "run", "test"], cwd=ROOT, check=True) subprocess.run(["npm", "run", "build"], cwd=ROOT, check=True) api.create_repo(args.repo, repo_type="space", space_sdk="static", private=False, exist_ok=True) # Static Space build commands require credits. Publish the already-built # frontend directly, retaining readable sources alongside the runtime assets. with tempfile.TemporaryDirectory(prefix="macrostories-space-") as directory: staging = Path(directory) for name in ["README.md", "LICENSE", "THIRD_PARTY_NOTICES.md", ".gitignore", "styles.css", "package.json", "package-lock.json", "requirements-export.txt"]: shutil.copyfile(ROOT / name, staging / name) for name in ["src", "scripts", "tests", "models", "third-party"]: shutil.copytree(ROOT / name, staging / name, ignore=shutil.ignore_patterns("__pycache__", "*.pyc")) shutil.copytree(ROOT / "dist/src", staging / "assets") shutil.copytree(ROOT / "dist/vendor", staging / "vendor") html = (ROOT / "dist/index.html").read_text().replace('./src/app.js', './assets/app.js') (staging / "index.html").write_text(html) api.upload_folder( repo_id=args.repo, repo_type="space", folder_path=staging, commit_message="Publish prebuilt MacroStories browser lab with WebGPU and WASM", ) print(f"Uploaded: https://huggingface.co/spaces/{args.repo}") print("Published prebuilt static assets; no paid remote build is required.") if __name__ == "__main__": main()