Spaces:
Running
Running
File size: 5,113 Bytes
024efc3 | 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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | """Create and configure the Hugging Face Space in one step.
Reads the keys from `.env` and sets them as Space secrets over the API, so live credentials
never pass through a shell command line (and therefore never land in PSReadLine history).
Idempotent: safe to re-run to update settings on an existing Space.
python scripts/setup_space.py --space DevSchretl/ubc-calendar-rag
Free Gradio Spaces must run on ZeroGPU hardware, which is the default here. This app requests
no GPU (there is no @spaces.GPU anywhere) so it consumes a ZeroGPU *hosting* slot but never any
GPU quota. Afterwards, push the code:
git remote add hf https://huggingface.co/spaces/<space>
git push hf main
"""
from __future__ import annotations
import argparse
import secrets
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from dotenv import dotenv_values # noqa: E402
# Copied onto the Space as secrets. HF_TOKEN should be a READ-scoped token: the Space only
# ever pulls the private index dataset, so a write token there adds risk and no capability.
SECRET_KEYS = ("OPENAI_API_KEY", "COHERE_API_KEY", "ANTHROPIC_API_KEY", "HF_TOKEN")
def main() -> None:
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--space", required=True, help="e.g. DevSchretl/ubc-calendar-rag")
p.add_argument("--env", type=Path, default=Path(".env"))
p.add_argument("--hardware", default="zero-a10g",
help="ZeroGPU is what makes a free Gradio Space free (default: zero-a10g)")
p.add_argument("--private", action="store_true", help="create it private; flip later in Settings")
p.add_argument("--per-hour", type=int, default=30, help="DEMO_IP_PER_HOUR (default 30, good for testing)")
p.add_argument("--per-day", type=int, default=60)
p.add_argument("--daily-calls", type=int, default=400, help="global DEMO_DAILY_LLM_CALLS ceiling")
p.add_argument("--salt", default="", help="reuse a specific DEMO_IP_SALT instead of generating one")
args = p.parse_args()
env = dotenv_values(args.env)
missing = [k for k in SECRET_KEYS if not env.get(k)]
if missing:
sys.exit(f"{args.env} is missing: {', '.join(missing)}")
index_repo = env.get("DEMO_INDEX_REPO")
index_rev = env.get("DEMO_INDEX_REVISION")
if not index_repo or not index_rev:
sys.exit("Set DEMO_INDEX_REPO and DEMO_INDEX_REVISION in .env first "
"(run scripts/publish_index.py — it prints the sha to pin).")
from huggingface_hub import HfApi
api = HfApi() # the CLI's logged-in WRITE token, for creating and configuring
# Sanity-check the read token before baking it in, so a bad one fails here rather than as
# a 401 buried in the Space's startup log.
try:
who = HfApi(token=env["HF_TOKEN"]).whoami()
role = ((who.get("auth") or {}).get("accessToken") or {}).get("role")
print(f"HF_TOKEN belongs to {who.get('name')} (role: {role})")
if role not in ("read", "fineGrained"):
print(f" note: a '{role}' token is broader than this Space needs; a read token is enough.")
except Exception as exc:
sys.exit(f"The HF_TOKEN in {args.env} is not valid: {type(exc).__name__}: {exc}")
# And that it can actually see the private index — the single most common startup failure.
try:
info = HfApi(token=env["HF_TOKEN"]).dataset_info(index_repo)
if info.sha != index_rev:
print(f" warning: DEMO_INDEX_REVISION ({index_rev[:12]}…) is not the dataset HEAD "
f"({info.sha[:12]}…). That is fine if you pinned it deliberately.")
except Exception as exc:
sys.exit(f"HF_TOKEN cannot read {index_repo}: {type(exc).__name__}: {exc}")
url = api.create_repo(
args.space, repo_type="space", space_sdk="gradio",
space_hardware=args.hardware, private=args.private, exist_ok=True,
)
print(f"Space ready: {url}")
variables = {
"DEMO_INDEX_REPO": index_repo,
"DEMO_INDEX_REVISION": index_rev,
"DEMO_DAILY_LLM_CALLS": str(args.daily_calls),
"DEMO_IP_PER_HOUR": str(args.per_hour),
"DEMO_IP_PER_DAY": str(args.per_day),
}
for key, value in variables.items():
api.add_space_variable(args.space, key, value)
print(f" variable {key} = {value}")
salt = args.salt or env.get("DEMO_IP_SALT") or secrets.token_urlsafe(32)
for key in SECRET_KEYS:
api.add_space_secret(args.space, key, env[key])
print(f" secret {key} = {env[key][:6]}… ({len(env[key])} chars)")
api.add_space_secret(args.space, "DEMO_IP_SALT", salt)
print(f" secret DEMO_IP_SALT = {salt[:6]}… (generated)" if not (args.salt or env.get("DEMO_IP_SALT"))
else " secret DEMO_IP_SALT = (reused)")
print(f"\nNow push the code:\n"
f" git remote add hf https://huggingface.co/spaces/{args.space}\n"
f" git push hf main\n"
f"\nThen watch it start:\n"
f" hf spaces logs {args.space}")
if __name__ == "__main__":
main()
|