File size: 3,093 Bytes
ca2a6e7
 
 
 
 
 
530ee58
 
ca2a6e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
530ee58
 
 
 
 
 
 
 
 
 
6e74009
530ee58
 
 
 
 
ca2a6e7
530ee58
ca2a6e7
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""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()