macayaven commited on
Commit
3044bfe
·
verified ·
1 Parent(s): 9dbb3de

Deploy relay publisher script

Browse files
Files changed (1) hide show
  1. scripts/publish_hf_relay.py +113 -0
scripts/publish_hf_relay.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Publish finished Small Cuts engine scenes into a Hugging Face bucket relay."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import os
8
+ import shutil
9
+ import tempfile
10
+ import time
11
+ from pathlib import Path
12
+
13
+ from huggingface_hub import HfApi
14
+
15
+ from small_cuts.hf_relay import (
16
+ DEFAULT_RELAY_PREFIX,
17
+ DEFAULT_SCENE_LIMIT,
18
+ RELAY_BUCKET_ENV,
19
+ RELAY_PREFIX_ENV,
20
+ prepare_relay_snapshot,
21
+ )
22
+ from small_cuts.observability import capture_exception, init_sentry
23
+
24
+
25
+ def parse_args() -> argparse.Namespace:
26
+ parser = argparse.ArgumentParser(description=__doc__)
27
+ parser.add_argument(
28
+ "--engine-url",
29
+ default=os.environ.get("SMALL_CUTS_ENGINE_URL", "http://127.0.0.1:8077"),
30
+ help="Private engine base URL. Defaults to SMALL_CUTS_ENGINE_URL or local engine.",
31
+ )
32
+ parser.add_argument(
33
+ "--bucket",
34
+ default=os.environ.get(RELAY_BUCKET_ENV, ""),
35
+ help=(
36
+ "HF bucket id, e.g. build-small-hackathon/small-cuts-scenes. "
37
+ f"Can use {RELAY_BUCKET_ENV}."
38
+ ),
39
+ )
40
+ parser.add_argument(
41
+ "--prefix",
42
+ default=os.environ.get(RELAY_PREFIX_ENV, DEFAULT_RELAY_PREFIX),
43
+ help=f"Bucket prefix. Defaults to {DEFAULT_RELAY_PREFIX!r}.",
44
+ )
45
+ parser.add_argument("--limit", type=int, default=DEFAULT_SCENE_LIMIT)
46
+ parser.add_argument("--interval", type=float, default=2.0, help="Watch interval in seconds.")
47
+ parser.add_argument("--watch", action="store_true", help="Keep publishing on an interval.")
48
+ parser.add_argument(
49
+ "--include-private",
50
+ action="store_true",
51
+ help="Publish private scenes too. Use only for an intentional controlled demo.",
52
+ )
53
+ parser.add_argument(
54
+ "--delete-extra",
55
+ action="store_true",
56
+ help="Delete bucket files not present in the staged snapshot.",
57
+ )
58
+ parser.add_argument("--dry-run", action="store_true", help="Stage locally without syncing.")
59
+ parser.add_argument(
60
+ "--stage-dir",
61
+ default=str(Path(tempfile.gettempdir()) / "small-cuts-relay-publish"),
62
+ help="Local staging directory.",
63
+ )
64
+ return parser.parse_args()
65
+
66
+
67
+ def _clean_stage(path: Path) -> None:
68
+ if path.exists():
69
+ shutil.rmtree(path)
70
+ path.mkdir(parents=True, exist_ok=True)
71
+
72
+
73
+ def publish_once(args: argparse.Namespace) -> None:
74
+ if not args.bucket:
75
+ raise SystemExit(f"--bucket or {RELAY_BUCKET_ENV} is required")
76
+ stage_dir = Path(args.stage_dir)
77
+ _clean_stage(stage_dir)
78
+ snapshot = prepare_relay_snapshot(
79
+ args.engine_url,
80
+ stage_dir,
81
+ limit=args.limit,
82
+ include_private=args.include_private,
83
+ )
84
+ dest = f"hf://buckets/{args.bucket}/{args.prefix.strip('/')}"
85
+ if args.dry_run:
86
+ print(f"dry-run staged {snapshot.scene_count} scene(s) at {snapshot.path}")
87
+ print(f"would sync to {dest}")
88
+ return
89
+ HfApi().sync_bucket(
90
+ source=str(snapshot.path),
91
+ dest=dest,
92
+ delete=args.delete_extra,
93
+ quiet=False,
94
+ )
95
+ print(f"published {snapshot.scene_count} scene(s) to {dest}")
96
+
97
+
98
+ def main() -> None:
99
+ init_sentry()
100
+ args = parse_args()
101
+ while True:
102
+ try:
103
+ publish_once(args)
104
+ except Exception as exc:
105
+ capture_exception(exc)
106
+ raise
107
+ if not args.watch:
108
+ return
109
+ time.sleep(args.interval)
110
+
111
+
112
+ if __name__ == "__main__":
113
+ main()