Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Deploy helper for: | |
| 1) Uploading fine-tuned weights to a model repo. | |
| 2) Uploading Space code to a Streamlit Space repo. | |
| Usage: | |
| HF_TOKEN=hf_xxx python3 deploy_hf.py | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import os | |
| import sys | |
| from typing import Iterable | |
| from huggingface_hub import HfApi | |
| from huggingface_hub.errors import BadRequestError | |
| DEFAULT_WEIGHTS_REPO = "griddev/vlm-caption-weights" | |
| DEFAULT_SPACE_REPO = "griddev/project_02_DS" | |
| DEFAULT_WEIGHTS_SOURCE = "../project_02" | |
| DEFAULT_SPACE_DIR = "." | |
| DEFAULT_SPACE_SDK = "streamlit" | |
| def _abort(message: str) -> None: | |
| print(f"ERROR: {message}", file=sys.stderr) | |
| raise SystemExit(1) | |
| def _ensure_exists(path: str) -> None: | |
| if not os.path.exists(path): | |
| _abort(f"Required path not found: {path}") | |
| def _print_list(header: str, items: Iterable[str]) -> None: | |
| print(header) | |
| for item in items: | |
| print(f" - {item}") | |
| def upload_weights(api: HfApi, repo_id: str, weights_source: str) -> None: | |
| source_root = os.path.abspath(weights_source) | |
| outputs_dir = os.path.join(source_root, "outputs") | |
| shakespeare_txt = os.path.join(source_root, "input.txt") | |
| shakespeare_weights = os.path.join(source_root, "shakespeare_transformer.pt") | |
| _ensure_exists(outputs_dir) | |
| _ensure_exists(shakespeare_txt) | |
| _ensure_exists(shakespeare_weights) | |
| api.create_repo(repo_id=repo_id, repo_type="model", exist_ok=True) | |
| print(f"Uploading weights to model repo: {repo_id}") | |
| api.upload_folder( | |
| repo_id=repo_id, | |
| repo_type="model", | |
| folder_path=outputs_dir, | |
| path_in_repo="outputs", | |
| commit_message="Upload fine-tuned checkpoints", | |
| ) | |
| api.upload_file( | |
| repo_id=repo_id, | |
| repo_type="model", | |
| path_or_fileobj=shakespeare_txt, | |
| path_in_repo="input.txt", | |
| commit_message="Upload input corpus for custom VLM", | |
| ) | |
| api.upload_file( | |
| repo_id=repo_id, | |
| repo_type="model", | |
| path_or_fileobj=shakespeare_weights, | |
| path_in_repo="shakespeare_transformer.pt", | |
| commit_message="Upload Shakespeare decoder weights", | |
| ) | |
| def _create_space_repo(api: HfApi, repo_id: str, space_sdk: str) -> None: | |
| try: | |
| api.create_repo( | |
| repo_id=repo_id, | |
| repo_type="space", | |
| space_sdk=space_sdk, | |
| exist_ok=True, | |
| ) | |
| return | |
| except BadRequestError as e: | |
| msg = str(e) | |
| if "Invalid option" not in msg or "sdk" not in msg: | |
| raise | |
| print( | |
| "Space creation rejected sdk value " | |
| f"'{space_sdk}'. Retrying with 'gradio' " | |
| "and relying on README.md front matter for streamlit." | |
| ) | |
| api.create_repo( | |
| repo_id=repo_id, | |
| repo_type="space", | |
| space_sdk="gradio", | |
| exist_ok=True, | |
| ) | |
| def upload_space_code(api: HfApi, repo_id: str, space_dir: str, space_sdk: str) -> None: | |
| space_dir = os.path.abspath(space_dir) | |
| _ensure_exists(space_dir) | |
| _create_space_repo(api, repo_id=repo_id, space_sdk=space_sdk) | |
| print(f"Uploading Space code to: {repo_id}") | |
| ignore_patterns = [ | |
| ".git/**", | |
| "__pycache__/**", | |
| "*.pyc", | |
| ".DS_Store", | |
| "venv/**", | |
| "weights_bundle/**", | |
| "outputs/**", | |
| "*.pt", | |
| ] | |
| _print_list("Ignoring during Space upload:", ignore_patterns) | |
| api.upload_folder( | |
| repo_id=repo_id, | |
| repo_type="space", | |
| folder_path=space_dir, | |
| ignore_patterns=ignore_patterns, | |
| commit_message="Deploy Streamlit Space app", | |
| ) | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description="Deploy weights + Space to Hugging Face") | |
| parser.add_argument( | |
| "--weights-repo", | |
| default=DEFAULT_WEIGHTS_REPO, | |
| help=f"Model repo for fine-tuned checkpoints (default: {DEFAULT_WEIGHTS_REPO})", | |
| ) | |
| parser.add_argument( | |
| "--space-repo", | |
| default=DEFAULT_SPACE_REPO, | |
| help=f"Space repo id (default: {DEFAULT_SPACE_REPO})", | |
| ) | |
| parser.add_argument( | |
| "--weights-source", | |
| default=DEFAULT_WEIGHTS_SOURCE, | |
| help=f"Local folder containing outputs/, input.txt, shakespeare_transformer.pt (default: {DEFAULT_WEIGHTS_SOURCE})", | |
| ) | |
| parser.add_argument( | |
| "--space-dir", | |
| default=DEFAULT_SPACE_DIR, | |
| help=f"Local Space code folder to upload (default: {DEFAULT_SPACE_DIR})", | |
| ) | |
| parser.add_argument( | |
| "--space-sdk", | |
| default=DEFAULT_SPACE_SDK, | |
| help=f"Space SDK to request on create (default: {DEFAULT_SPACE_SDK})", | |
| ) | |
| parser.add_argument( | |
| "--skip-weights", | |
| action="store_true", | |
| help="Skip uploading weights repo.", | |
| ) | |
| parser.add_argument( | |
| "--skip-space", | |
| action="store_true", | |
| help="Skip uploading Space repo.", | |
| ) | |
| parser.add_argument( | |
| "--token", | |
| default=os.getenv("HF_TOKEN"), | |
| help="Hugging Face token. Defaults to HF_TOKEN env var.", | |
| ) | |
| return parser.parse_args() | |
| def main() -> None: | |
| args = parse_args() | |
| if not args.token: | |
| _abort("No token found. Set HF_TOKEN or pass --token.") | |
| api = HfApi(token=args.token) | |
| if not args.skip_weights: | |
| upload_weights(api, repo_id=args.weights_repo, weights_source=args.weights_source) | |
| if not args.skip_space: | |
| upload_space_code( | |
| api, | |
| repo_id=args.space_repo, | |
| space_dir=args.space_dir, | |
| space_sdk=args.space_sdk, | |
| ) | |
| print("Deployment finished.") | |
| print(f"Weights repo: https://huggingface.co/{args.weights_repo}") | |
| print(f"Space repo: https://huggingface.co/spaces/{args.space_repo}") | |
| if __name__ == "__main__": | |
| main() | |