bankmind / scripts /deploy_to_hf_spaces.py
arjun10g's picture
Deploy BankMind
657d287 verified
"""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"
# Runtime secrets to set on the Space. These are required for queries that hit
# Qdrant or invoke the LLM. They never leave the user's HF account once set.
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} ===")
# 1. Create Space (idempotent)
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.")
# 2. Set secrets
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.")
# 3. Upload repo contents
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())