arabic-audio-reader-worker / scripts /deploy_hf_space.py
Syncre's picture
Deploy Arabic Audio Reader worker
5f069dc verified
from __future__ import annotations
import argparse
import os
import subprocess
import sys
from pathlib import Path
ROOT_DIR = Path(__file__).resolve().parent.parent
DEFAULT_BUNDLE_DIR = ROOT_DIR / "outputs" / "huggingface-space"
def load_env_file(path: Path) -> None:
if not path.exists():
return
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))
def require_huggingface_hub():
try:
from huggingface_hub import HfApi, create_repo, upload_folder
except ImportError as exc:
raise SystemExit(
"huggingface_hub is not installed. Run: .\\.venv\\Scripts\\python.exe -m pip install huggingface_hub"
) from exc
return HfApi, create_repo, upload_folder
def run_export(bundle_dir: Path, force_export: bool) -> None:
if bundle_dir.exists() and not force_export:
return
command = [
sys.executable,
str(ROOT_DIR / "scripts" / "export_hf_space.py"),
"--out",
str(bundle_dir),
]
if force_export:
command.append("--force")
subprocess.run(command, cwd=ROOT_DIR, check=True)
def get_token(explicit_token: str | None) -> str:
load_env_file(ROOT_DIR / ".env")
token = explicit_token or os.getenv("HF_TOKEN") or os.getenv("HF_API_TOKEN") or os.getenv("HUGGINGFACE_API_TOKEN")
if not token:
raise SystemExit(
"Missing Hugging Face token. Set HF_TOKEN, HF_API_TOKEN, or HUGGINGFACE_API_TOKEN, "
"or pass --token. Create a write token at https://huggingface.co/settings/tokens."
)
return token
def token_available(explicit_token: str | None = None) -> bool:
load_env_file(ROOT_DIR / ".env")
return bool(explicit_token or os.getenv("HF_TOKEN") or os.getenv("HF_API_TOKEN") or os.getenv("HUGGINGFACE_API_TOKEN"))
def split_repo_id(repo_id: str) -> tuple[str, str]:
if "/" not in repo_id:
raise ValueError("Hugging Face Space repo id must look like username/space-name")
owner, space_name = repo_id.split("/", 1)
if not owner or not space_name:
raise ValueError("Hugging Face Space repo id must include both owner and space name")
return owner, space_name
def worker_url_for_repo(repo_id: str) -> str:
owner, space_name = split_repo_id(repo_id)
return f"https://{owner}-{space_name}.hf.space".lower()
def deploy_hf_space(
repo_id: str,
bundle_dir: Path = DEFAULT_BUNDLE_DIR,
token: str | None = None,
private: bool = False,
force_export: bool = False,
commit_message: str = "Deploy Arabic Audio Reader worker",
) -> dict[str, object]:
bundle_dir = bundle_dir.resolve()
run_export(bundle_dir, force_export)
hf_token = get_token(token)
_hf_api, create_repo, upload_folder = require_huggingface_hub()
create_repo(
repo_id=repo_id,
repo_type="space",
space_sdk="docker",
private=private,
exist_ok=True,
token=hf_token,
)
commit_info = upload_folder(
repo_id=repo_id,
repo_type="space",
folder_path=str(bundle_dir),
path_in_repo=".",
commit_message=commit_message,
token=hf_token,
)
worker_url = worker_url_for_repo(repo_id)
return {
"repoId": repo_id,
"workerUrl": worker_url,
"bundleDir": str(bundle_dir),
"commitUrl": getattr(commit_info, "commit_url", None),
"nextCommand": (
f"python scripts\\deployment_handoff.py {worker_url} "
"--origin https://arabic-translator-mu.vercel.app --code 1234"
),
}
def main_with_args(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Create or update the Hugging Face Docker Space worker.")
parser.add_argument(
"repo_id",
help="Hugging Face Space repo id, for example username/arabic-audio-reader-worker.",
)
parser.add_argument("--bundle-dir", type=Path, default=DEFAULT_BUNDLE_DIR)
parser.add_argument("--token", help="Hugging Face write token. Prefer setting HF_TOKEN instead.")
parser.add_argument("--private", action="store_true", help="Create the Space as private.")
parser.add_argument("--force-export", action="store_true", help="Rebuild the worker bundle before upload.")
parser.add_argument("--commit-message", default="Deploy Arabic Audio Reader worker")
parser.add_argument("--json", action="store_true")
args = parser.parse_args(argv)
result = deploy_hf_space(
repo_id=args.repo_id,
bundle_dir=args.bundle_dir,
token=args.token,
private=args.private,
force_export=args.force_export,
commit_message=args.commit_message,
)
if args.json:
import json
print(json.dumps(result, indent=2))
else:
print(f"Uploaded worker bundle to https://huggingface.co/spaces/{args.repo_id}")
print(f"Worker URL: {result['workerUrl']}")
print("Next:")
print(result["nextCommand"])
return 0
def main() -> int:
return main_with_args()
if __name__ == "__main__":
raise SystemExit(main())