| """Deploy BankMind to a Hugging Face Spaces Docker SDK Space. |
| |
| Reads `HUGGINGFACE_TOKEN`, `ANTHROPIC_API_KEY`, `QDRANT_URL`, `QDRANT_API_KEY` |
| from .env. Creates the Space (idempotent: ok if it already exists), sets the |
| 3 runtime secrets, then uploads the repo contents (excluding raw/processed |
| data, .venv, .git, etc.). Prints the resulting URL. |
| |
| Usage: python scripts/deploy_to_hf_spaces.py [--space-name USER/REPO] |
| Default: Arjun10g/bankmind |
| """ |
| from __future__ import annotations |
|
|
| import argparse |
| import os |
| import sys |
| from pathlib import Path |
|
|
| from dotenv import load_dotenv |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| load_dotenv(ROOT / ".env") |
|
|
| DEFAULT_SPACE = "Arjun10g/bankmind" |
|
|
| |
| |
| SECRETS_TO_SET = ("ANTHROPIC_API_KEY", "QDRANT_URL", "QDRANT_API_KEY") |
|
|
| IGNORE_PATTERNS = [ |
| ".git/*", ".git/**", |
| ".venv/*", ".venv/**", |
| ".claude/*", ".claude/**", |
| "venv/*", "venv/**", |
| "__pycache__/*", "__pycache__/**", "*/__pycache__/*", "*/__pycache__/**", |
| "*.pyc", "*.pyo", |
| ".env", ".env.local", |
| "data/raw/*", "data/raw/**", |
| "data/processed/*", "data/processed/**", |
| "logs/*", "logs/**", |
| ".pytest_cache/*", ".pytest_cache/**", |
| ".ruff_cache/*", ".ruff_cache/**", |
| ".mypy_cache/*", ".mypy_cache/**", |
| ".DS_Store", |
| "*.egg-info/*", "*.egg-info/**", |
| "build/*", "build/**", |
| "dist/*", "dist/**", |
| ".uv-cache/*", ".uv-cache/**", |
| ".cache/*", ".cache/**", |
| ] |
|
|
|
|
| def main() -> int: |
| ap = argparse.ArgumentParser() |
| ap.add_argument("--space-name", default=DEFAULT_SPACE, |
| help=f"HF Space repo (USER/REPO). Default: {DEFAULT_SPACE}") |
| ap.add_argument("--private", action="store_true", |
| help="Create the Space as private (default: public)") |
| args = ap.parse_args() |
|
|
| token = os.environ.get("HUGGINGFACE_TOKEN", "").strip() |
| if not token: |
| print("ERROR: HUGGINGFACE_TOKEN not set in .env", file=sys.stderr) |
| print(" Get one at https://huggingface.co/settings/tokens (Write scope)", |
| file=sys.stderr) |
| return 1 |
|
|
| from huggingface_hub import HfApi |
| from huggingface_hub.utils import RepositoryNotFoundError |
|
|
| api = HfApi(token=token) |
|
|
| print(f"\n=== Deploying to {args.space_name} ===") |
|
|
| |
| print(f"\n[1/3] Creating Space (Docker SDK, " |
| f"{'private' if args.private else 'public'})...") |
| try: |
| api.repo_info(args.space_name, repo_type="space") |
| print(f" Space {args.space_name} already exists — will overwrite contents.") |
| except RepositoryNotFoundError: |
| api.create_repo( |
| repo_id=args.space_name, |
| repo_type="space", |
| space_sdk="docker", |
| private=args.private, |
| ) |
| print(f" Created new Space.") |
|
|
| |
| print(f"\n[2/3] Setting Space secrets...") |
| n_set = 0 |
| for key in SECRETS_TO_SET: |
| value = os.environ.get(key, "").strip() |
| if not value: |
| print(f" SKIP {key} (not in .env)") |
| continue |
| api.add_space_secret(repo_id=args.space_name, key=key, value=value) |
| n_set += 1 |
| print(f" SET {key}") |
| print(f" → {n_set}/{len(SECRETS_TO_SET)} secrets set.") |
|
|
| |
| print(f"\n[3/3] Uploading repo contents...") |
| api.upload_folder( |
| repo_id=args.space_name, |
| repo_type="space", |
| folder_path=str(ROOT), |
| ignore_patterns=IGNORE_PATTERNS, |
| commit_message="Deploy BankMind", |
| ) |
|
|
| url = f"https://huggingface.co/spaces/{args.space_name}" |
| print(f"\n✅ Deployed → {url}") |
| print(f"\nThe Space will rebuild from the Dockerfile. First build takes ~10-15 minutes.") |
| print(f"Monitor build progress at: {url}/?logs=container") |
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| sys.exit(main()) |
|
|