#!/usr/bin/env python3 """Robust one-click uploader for the CHISA-RSI Hugging Face release. Works with: * HF_TOKEN environment variable, or * an existing `hf auth login`, or * interactive Hugging Face login when run from a terminal. HF_REPO_ID is optional. If omitted, the script derives the authenticated username and proposes the release's default repository name. """ from __future__ import annotations import argparse import os import sys from pathlib import Path DEFAULT_SLUG = "CHISA-RSI-Proof-Carrying-Continuous-Capability-Closure-v1.0.0" REQUIRED_FILES = ( "README.md", "CHISA_RSI_v1.0.0.pdf", "CLAIMS_AND_SCOPE.md", "THEOREMS.json", "AI_AGENT_INDEX.json", "CITATION.cff", ) def die(message: str, code: int = 1) -> "NoReturn": print(f"\nERROR: {message}", file=sys.stderr) raise SystemExit(code) def package_check(folder: Path) -> None: missing = [name for name in REQUIRED_FILES if not (folder / name).is_file()] if missing: die("Release package is incomplete. Missing: " + ", ".join(missing), 2) print(f"Package check: OK ({len(REQUIRED_FILES)} required files found)") def load_hf(): try: import huggingface_hub from huggingface_hub import HfApi, get_token, login except Exception as exc: die( "huggingface_hub is not installed or failed to import. " "Run: python -m pip install -U huggingface_hub\n" f"Details: {exc}" ) return huggingface_hub, HfApi, get_token, login def obtain_token(api, get_token, login) -> str: # HF_TOKEN has priority. Otherwise use the cached token from `hf auth login`. token = os.environ.get("HF_TOKEN") or get_token() if token: try: who = api.whoami(token=token) except Exception as exc: die( "A Hugging Face token was found, but authentication failed. " "Use a current personal User Access Token with WRITE permission.\n" f"Details: {exc}", 3, ) name = who.get("name") or who.get("fullname") or "authenticated user" print(f"Authentication: OK ({name})") return token if not sys.stdin.isatty(): die( "No Hugging Face authentication was found. Set HF_TOKEN to a WRITE token " "or run `hf auth login` first.", 3, ) print("\nNo HF_TOKEN or cached login was found.") print("Starting Hugging Face login. Your token is not written into this release folder.") try: try: login(skip_if_logged_in=False) except TypeError: # Compatibility with older huggingface_hub releases. login() except Exception as exc: die( "Interactive Hugging Face login failed. You can instead run `hf auth login` " "in a terminal and then launch this uploader again.\n" f"Details: {exc}", 3, ) token = get_token() if not token: die("Login finished without producing an accessible Hugging Face token.", 3) try: who = api.whoami(token=token) except Exception as exc: die(f"Authentication verification failed after login: {exc}", 3) name = who.get("name") or who.get("fullname") or "authenticated user" print(f"Authentication: OK ({name})") return token def choose_repo_id(api, token: str, cli_repo_id: str | None) -> str: repo_id = cli_repo_id or os.environ.get("HF_REPO_ID") if repo_id: return repo_id.strip() who = api.whoami(token=token) username = who.get("name") if not username: die("Could not determine your Hugging Face username from the authenticated account.", 3) default = f"{username}/{DEFAULT_SLUG}" if sys.stdin.isatty(): print(f"\nDefault repository: {default}") entered = input("Repository ID [press Enter to accept]: ").strip() repo_id = entered or default else: repo_id = default if "/" not in repo_id or repo_id.startswith("/") or repo_id.endswith("/"): die("HF_REPO_ID must look like `username-or-org/repository-name`.", 2) return repo_id def repo_url(repo_id: str, repo_type: str) -> str: if repo_type == "dataset": return f"https://huggingface.co/datasets/{repo_id}" if repo_type == "space": return f"https://huggingface.co/spaces/{repo_id}" return f"https://huggingface.co/{repo_id}" def main() -> int: parser = argparse.ArgumentParser(description="Upload CHISA-RSI v1.0.0 to Hugging Face.") parser.add_argument("--repo-id", help="Override HF_REPO_ID (username-or-org/repo-name).") parser.add_argument( "--repo-type", choices=("model", "dataset", "space"), default=os.environ.get("HF_REPO_TYPE", "model"), help="Hugging Face repository type (default: model).", ) parser.add_argument( "--check-only", action="store_true", help="Validate the local package and Python dependency without contacting Hugging Face.", ) args = parser.parse_args() folder = Path(__file__).resolve().parent os.chdir(folder) package_check(folder) hub, HfApi, get_token, login = load_hf() print(f"huggingface_hub: {hub.__version__}") if args.check_only: print("Uploader self-test: OK") return 0 api = HfApi() token = obtain_token(api, get_token, login) repo_id = choose_repo_id(api, token, args.repo_id) repo_type = args.repo_type print("\nUpload target") print(f" repo: {repo_id}") print(f" type: {repo_type}") print(" visibility: public") try: # Current Hub clients support `visibility`; older ones use `private`. try: api.create_repo( repo_id=repo_id, repo_type=repo_type, visibility="public", exist_ok=True, token=token, ) except TypeError: api.create_repo( repo_id=repo_id, repo_type=repo_type, private=False, exist_ok=True, token=token, ) except Exception as exc: die( "Could not create/open the target repository. Check that the token has WRITE " "permission and that you own the namespace (or have write access to the organization).\n" f"Details: {exc}", 4, ) try: result = api.upload_folder( repo_id=repo_id, repo_type=repo_type, folder_path=str(folder), path_in_repo="", commit_message="Release CHISA-RSI v1.0.0", token=token, ignore_patterns=[ "*.zip", "__pycache__/**", "*.pyc", ".git/**", "hf_upload.log", ], ) if result is not None: print(f"Upload commit: {getattr(result, 'commit_url', result)}") except Exception as exc: die( "Upload failed. Re-running is safe: Hugging Face upload_folder is resumable and " "skips content already committed.\n" f"Details: {exc}", 5, ) # Verify that the core public-release files actually reached the repository. try: remote = set(api.list_repo_files(repo_id=repo_id, repo_type=repo_type, token=token)) missing_remote = [name for name in REQUIRED_FILES if name not in remote] if missing_remote: die( "Hugging Face accepted the upload, but verification found missing files: " + ", ".join(missing_remote), 6, ) except SystemExit: raise except Exception as exc: die(f"Upload finished but remote verification failed: {exc}", 6) url = repo_url(repo_id, repo_type) print("\nSUCCESS: upload and remote verification both passed.") print(url) return 0 if __name__ == "__main__": try: raise SystemExit(main()) except KeyboardInterrupt: print("\nCancelled by user.") raise SystemExit(130)