#!/usr/bin/env bash # --------------------------------------------------------------------------- # One-command deploy for the Sking Space. # # export HF_TOKEN=hf_xxx... # fine-grained, "Write" on this Space # ./deploy.sh / # # The token is read from the environment only, is never written to disk, and is # never echoed. Prefer a *fine-grained* token scoped to the single Space repo. # # Uploads go through HfApi.upload_folder rather than `git push`: the Hub rejects # plain git pushes containing binary files ("Please use Xet to store binary # files"), and upload_folder routes them through Xet automatically. git-lfs is # not required anywhere. # # Set PRIVATE=1 to create a private Space instead of a public one. # NOTE: a private Space weakens AGPL-3.0 section 13 compliance -- if anyone can # use it over a network, the corresponding source must be available to them. # --------------------------------------------------------------------------- set -euo pipefail REPO_ID="${1:-}" if [[ -z "$REPO_ID" ]]; then echo "usage: HF_TOKEN=hf_... ./deploy.sh /" >&2 exit 2 fi if [[ -z "${HF_TOKEN:-}" ]]; then echo "error: HF_TOKEN is not set. Create one at https://huggingface.co/settings/tokens" >&2 exit 2 fi HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$HERE" PRIVATE="${PRIVATE:-0}" # Local hygiene: never upload caches or a local git dir. find . -name '__pycache__' -type d -prune -exec rm -rf {} + 2>/dev/null || true find . -name '*.pyc' -delete 2>/dev/null || true echo "==> installing huggingface_hub" python3 -m pip install --quiet --upgrade "huggingface_hub>=1.23" >/dev/null 2>&1 \ || python3 -m pip install --quiet --upgrade "huggingface_hub>=1.23" echo "==> ensuring Space $REPO_ID exists (sdk=gradio)" python3 - "$REPO_ID" "$PRIVATE" <<'PY' import sys from huggingface_hub import HfApi repo_id, private = sys.argv[1], sys.argv[2] == "1" api = HfApi() try: # NOTE: create_repo() has no `license` parameter in huggingface_hub 1.x. # A Space's license comes from the `license:` key in README.md's # frontmatter, which is set to agpl-3.0 and uploaded below. api.create_repo( repo_id=repo_id, repo_type="space", space_sdk="gradio", private=private, exist_ok=True, ) print(f" repo ready: https://huggingface.co/spaces/{repo_id}") except Exception as exc: print(f" create_repo failed: {exc}", file=sys.stderr) print(" Create it manually at https://huggingface.co/new-space " "(SDK: Gradio), then re-run -- the AGPL-3.0 license comes from " "README.md, not the creation call.", file=sys.stderr) sys.exit(1) PY echo "==> checking required files" for f in README.md app.py requirements.txt LICENSE NOTICE.md \ sking_pipeline/weights.py sking_pipeline/stage1_flux.py \ sking_pipeline/stage2_uv.py; do [[ -f "$f" ]] || { echo "error: missing $f" >&2; exit 1; } done echo " all present" echo "==> uploading (Xet handles the binary testdata PNGs)" python3 - "$REPO_ID" <<'PY' import sys from huggingface_hub import HfApi api = HfApi() url = api.upload_folder( folder_path=".", repo_id=sys.argv[1], repo_type="space", ignore_patterns=[".git/**", "__pycache__/**", "*.pyc", ".venv/**", "flagged/**", ".gradio/**"], commit_message="Sking image-to-Minecraft-skin pipeline (AGPL-3.0)", commit_description=( "Two-stage reproduction of EntropyDrop's open image-to-skin path.\n\n" "stage 1 FLUX.2 [klein] 4B Base + sking_v73_flux_4b_000027000 LoRA\n" "stage 2 EntropyDrop SKING_DDJ_v104 (BiRefNet foreground + Dense UV " "Parser)\n\n" "Stage 2 runs in-process via runpy rather than subprocess so it works " "on\nZeroGPU, where child processes get no CUDA context. Dependency " "pins are\ndeviated from the bundle's tested_environments.json in " "three places to keep\nthe resolver satisfiable alongside " "diffusers==0.40.0; see DEPLOY.md." ), ) print(f" committed: {url}") PY echo "==> requesting ZeroGPU hardware" python3 - "$REPO_ID" <<'PY' || echo " could not set hardware via API -- do it in Settings -> Space hardware -> ZeroGPU" import sys from huggingface_hub import HfApi, SpaceHardware # ZeroGPU's API identifier is "zero-a10g" (legacy name from when the pool was # A10G/A100-backed; the docs now describe RTX Pro 6000 Blackwell). There is no # "zerogpu" value -- passing one raises. api = HfApi() try: rt = api.request_space_hardware( repo_id=sys.argv[1], hardware=SpaceHardware.ZERO_A10G ) print(f" hardware = {getattr(rt, 'hardware', 'zero-a10g')}") except Exception as exc: print(f" request_space_hardware: {exc}", file=sys.stderr) raise SystemExit(1) PY cat < done https://huggingface.co/spaces/${REPO_ID} Watch the Logs tab. Expect ~20 GB of downloads on first build (5-15 min): [1/4] SKING_DDJ_v104 bundle (~2.58 GB) + SHA-256 verification [2/4] FLUX.2 [klein] 4B Base (~17 GB) [3/4] sking_v73 LoRA (~92 MB) [4/4] pinned SigLIP2 linked into the HF cache loading FLUX.2 [klein] 4B Base (bf16) ... stage 1 ready ZeroGPU eligibility (free tier): verified email, account older than 30 days, max 2 hosted ZeroGPU Spaces. If the hardware request failed, set it in Settings -> Space hardware -> ZeroGPU (GPU size: large). EOF