Spaces:
Paused
Paused
Download deploy/huggingface/deploy.py from whassan/SensorflowStudio: direct link, hf CLI and curl.
- Browser
- Download file 4.58 kB
-
https://huggingface.co/spaces/whassan/SensorflowStudio/resolve/main/deploy/huggingface/deploy.py
- Command line
-
hf download hf://spaces/whassan/SensorflowStudio/deploy/huggingface/deploy.py
-
curl -L -o deploy.py https://huggingface.co/spaces/whassan/SensorflowStudio/resolve/main/deploy/huggingface/deploy.py
4.58 kB
| #!/usr/bin/env python | |
| """Deploy Sensorflow Studio to a Hugging Face Space (Docker SDK). | |
| Idempotent / re-runnable: creates the Space if missing, uploads the current | |
| repo state (frontend is built inside the Docker image on HF's side), waits for | |
| the build, and smoke-tests the deployed endpoints. | |
| Usage: | |
| .venv/bin/python deploy/huggingface/deploy.py [--space-name NAME] [--no-wait] | |
| Requires a Hugging Face token with write access (`hf auth login` or HF_TOKEN). | |
| """ | |
| import argparse | |
| import json | |
| import sys | |
| import time | |
| import urllib.request | |
| from pathlib import Path | |
| from huggingface_hub import HfApi | |
| from huggingface_hub.errors import LocalTokenNotFoundError | |
| REPO_ROOT = Path(__file__).resolve().parents[2] | |
| # Mirrors .dockerignore, plus files that must not reach the Space repo as-is. | |
| IGNORE_PATTERNS = [ | |
| "node_modules/**", | |
| ".venv/**", | |
| ".git/**", | |
| "runs/**", | |
| "dist/**", | |
| "models/**", | |
| "*.pt", | |
| "**/*.pt", | |
| "**/__pycache__/**", | |
| ".pytest_cache/**", | |
| ".claude/**", | |
| ".DS_Store", | |
| "**/.DS_Store", | |
| "README.md", # root project README; the Space README is uploaded separately | |
| ] | |
| TERMINAL_ERROR_STAGES = {"BUILD_ERROR", "RUNTIME_ERROR", "CONFIG_ERROR", "DELETING"} | |
| def http_check(url: str, method: str = "GET", body: dict | None = None) -> str: | |
| data = json.dumps(body).encode() if body is not None else None | |
| req = urllib.request.Request( | |
| url, data=data, method=method, | |
| headers={"Content-Type": "application/json"} if body is not None else {}, | |
| ) | |
| try: | |
| with urllib.request.urlopen(req, timeout=30) as resp: | |
| snippet = resp.read(200).decode(errors="replace").replace("\n", " ") | |
| return f"{resp.status} {snippet[:120]}" | |
| except Exception as exc: # noqa: BLE001 - smoke test, report anything | |
| return f"FAILED: {exc}" | |
| def main() -> int: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--space-name", default="sensorflow-studio") | |
| parser.add_argument("--no-wait", action="store_true", | |
| help="upload only; don't wait for the build") | |
| parser.add_argument("--timeout-minutes", type=float, default=15) | |
| args = parser.parse_args() | |
| api = HfApi() | |
| try: | |
| user = api.whoami()["name"] | |
| except LocalTokenNotFoundError: | |
| print("ERROR: no Hugging Face token found. Run `hf auth login` " | |
| "(or set HF_TOKEN) with a WRITE token, then re-run this script.") | |
| return 1 | |
| repo_id = f"{user}/{args.space_name}" | |
| print(f"Deploying to Space: {repo_id}") | |
| api.create_repo(repo_id, repo_type="space", space_sdk="docker", exist_ok=True) | |
| print("Uploading repository files...") | |
| api.upload_folder( | |
| folder_path=str(REPO_ROOT), | |
| repo_id=repo_id, | |
| repo_type="space", | |
| ignore_patterns=IGNORE_PATTERNS, | |
| commit_message="Deploy Sensorflow Studio", | |
| ) | |
| # The Space README (with docker frontmatter) replaces the project README. | |
| api.upload_file( | |
| path_or_fileobj=str(REPO_ROOT / "deploy" / "huggingface" / "README.md"), | |
| path_in_repo="README.md", | |
| repo_id=repo_id, | |
| repo_type="space", | |
| commit_message="Update Space README", | |
| ) | |
| space_url = f"https://{user}-{args.space_name.replace('_', '-')}.hf.space" | |
| print(f"Space page: https://huggingface.co/spaces/{repo_id}") | |
| print(f"App URL: {space_url}/") | |
| if args.no_wait: | |
| return 0 | |
| print("Waiting for the Space build (this can take several minutes)...") | |
| deadline = time.time() + args.timeout_minutes * 60 | |
| stage = None | |
| while time.time() < deadline: | |
| runtime = api.get_space_runtime(repo_id) | |
| if runtime.stage != stage: | |
| stage = runtime.stage | |
| print(f" stage: {stage}") | |
| if stage == "RUNNING": | |
| break | |
| if stage in TERMINAL_ERROR_STAGES: | |
| print(f"Build/runtime failed (stage={stage}). Check logs at " | |
| f"https://huggingface.co/spaces/{repo_id}?logs=build") | |
| return 2 | |
| time.sleep(15) | |
| else: | |
| print(f"Timed out after {args.timeout_minutes} min (last stage: {stage}).") | |
| return 3 | |
| print("Space is RUNNING. Verifying endpoints...") | |
| print(f" GET / -> {http_check(space_url + '/')}") | |
| print(f" GET /dashboard/ -> {http_check(space_url + '/dashboard/')}") | |
| print(f" POST /api/ssam/statewide -> " | |
| f"{http_check(space_url + '/api/ssam/statewide', 'POST', {'page': 1, 'page_size': 1})}") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |