""" Upload WorldDisasterLM-8B as a public HuggingFace Space using urllib (no httpx/requests). Works on Python 3.14 on Windows where httpx TLS may fail. Usage ----- python scripts/upload_space_urllib.py --token hf_xxx --username drdeveloper88 """ from __future__ import annotations import argparse import base64 import json import os import shutil import ssl import sys import tempfile import urllib.request from pathlib import Path ROOT = Path(__file__).parent.parent SPACE_DIR = ROOT / "hf_space" HF_API = "https://huggingface.co/api" CTX = ssl.create_default_context() def api(method: str, path: str, token: str, payload: dict | None = None) -> dict: url = f"{HF_API}{path}" data = json.dumps(payload).encode() if payload else None req = urllib.request.Request( url, data=data, method=method, headers={ "Authorization": f"Bearer {token}", "Content-Type": "application/json", }, ) try: with urllib.request.urlopen(req, context=CTX, timeout=30) as r: return json.loads(r.read()) except urllib.error.HTTPError as e: body = e.read().decode() raise RuntimeError(f"HTTP {e.code}: {body}") from e def upload_file(repo_id: str, token: str, local_path: Path, repo_path: str, commit_msg: str) -> None: """Upload a single file via the HF /api/repos endpoint (LFS-aware preupload + commit).""" content = local_path.read_bytes() # Step 1: preupload (get upload URL or confirm non-LFS) preupload_url = f"https://huggingface.co/api/spaces/{repo_id}/preupload/main" payload = json.dumps([{"path": repo_path, "size": len(content)}]).encode() req = urllib.request.Request( preupload_url, data=payload, method="POST", headers={ "Authorization": f"Bearer {token}", "Content-Type": "application/json", }, ) with urllib.request.urlopen(req, context=CTX, timeout=30) as r: preupload = json.loads(r.read()) files_info = preupload.get("files", [{}]) upload_mode = files_info[0].get("uploadMode", "regular") if files_info else "regular" if upload_mode == "lfs": # Upload to LFS URL upload_url = files_info[0]["uploadUrl"] put_req = urllib.request.Request( upload_url, data=content, method="PUT", headers={"Content-Type": "application/octet-stream"}, ) with urllib.request.urlopen(put_req, context=CTX, timeout=60) as r: r.read() oid = files_info[0]["oid"] size = files_info[0]["size"] lfs_content = ( f"version https://git-lfs.github.com/spec/v1\n" f"oid sha256:{oid}\n" f"size {size}\n" ).encode() final_content = lfs_content else: final_content = content # Step 2: commit commit_url = f"https://huggingface.co/api/spaces/{repo_id}/commit/main" header = json.dumps({ "summary": commit_msg, "files": [{"path": repo_path, "encoding": "base64"}], }) boundary = "----HFUploadBoundary" body_parts = [ f"--{boundary}\r\nContent-Disposition: form-data; name=\"header\"\r\n\r\n{header}\r\n".encode(), f"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{repo_path}\"\r\n\r\n".encode(), base64.b64encode(final_content), f"\r\n--{boundary}--\r\n".encode(), ] body = b"".join(body_parts) commit_req = urllib.request.Request( commit_url, data=body, method="POST", headers={ "Authorization": f"Bearer {token}", "Content-Type": f"multipart/form-data; boundary={boundary}", }, ) with urllib.request.urlopen(commit_req, context=CTX, timeout=60) as r: r.read() def upload_folder_simple(repo_id: str, token: str, folder: Path, readme_text: str) -> None: """Upload all Space files using the simpler single-commit API.""" files_payload = [] file_contents = {} for f in folder.iterdir(): if f.is_file(): if f.name == "README.md": content = readme_text.encode("utf-8") else: content = f.read_bytes() encoded = base64.b64encode(content).decode() files_payload.append({"path": f.name, "encoding": "base64"}) file_contents[f.name] = encoded # Build multipart commit boundary = "HFSpaceUpload42" parts = [] header = json.dumps({ "summary": "Upload WorldDisasterLM-8B Space", "files": files_payload, }) parts.append( f"--{boundary}\r\nContent-Disposition: form-data; name=\"header\"\r\n\r\n{header}\r\n".encode() ) for item in files_payload: fname = item["path"] parts.append( f"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{fname}\"\r\n\r\n".encode() ) parts.append(file_contents[fname].encode()) parts.append(b"\r\n") parts.append(f"--{boundary}--\r\n".encode()) body = b"".join(parts) commit_url = f"https://huggingface.co/api/spaces/{repo_id}/commit/main" req = urllib.request.Request( commit_url, data=body, method="POST", headers={ "Authorization": f"Bearer {token}", "Content-Type": f"multipart/form-data; boundary={boundary}", }, ) try: with urllib.request.urlopen(req, context=CTX, timeout=120) as r: result = json.loads(r.read()) return result except urllib.error.HTTPError as e: raise RuntimeError(f"Commit failed HTTP {e.code}: {e.read().decode()}") from e def parse_args() -> argparse.Namespace: p = argparse.ArgumentParser() p.add_argument("--token", default=os.environ.get("HF_TOKEN"), help="HF token (or set HF_TOKEN env var)") p.add_argument("--username", required=True) p.add_argument("--space-name", default="WorldDisasterLM-8B") p.add_argument("--private", action="store_true") return p.parse_args() def main() -> None: args = parse_args() token = args.token if not token: print("ERROR: provide --token or set HF_TOKEN"); sys.exit(1) repo_id = f"{args.username}/{args.space_name}" print(f"\n{'='*60}") print(f" WorldDisasterLM-8B → HuggingFace Space") print(f" Repo: {repo_id}") print(f"{'='*60}\n") # Verify token user = api("GET", "/whoami-v2", token) print(f" Authenticated as: {user.get('name')}") # Step 1: Create Space print("\nStep 1/3 — Creating Space repository...") try: api("POST", "/repos/create", token, { "type": "space", "name": args.space_name, "sdk": "gradio", "private": args.private, "exist_ok": True, }) print(f" ✓ Space created") except RuntimeError as e: if "already exists" in str(e) or "409" in str(e): print(f" ✓ Space already exists, updating") else: raise # Step 2: Patch README readme_text = (SPACE_DIR / "README.md").read_text(encoding="utf-8") readme_text = readme_text.replace("YOUR_HF_USERNAME", args.username) # Step 3: Upload files print("Step 2/3 — Uploading files...") result = upload_folder_simple(repo_id, token, SPACE_DIR, readme_text) print(f" ✓ Files uploaded (commit: {result.get('commitOid', 'ok')[:12] if result.get('commitOid') else 'done'})") print(f"\nStep 3/3 — Done!\n") print(f"{'='*60}") print(f" Live at: https://huggingface.co/spaces/{repo_id}") print(f" (Space may take 1-2 min to build)") print(f"{'='*60}\n") if __name__ == "__main__": main()