test / deploy.sh
CyberWaifu's picture
Sking image-to-Minecraft-skin pipeline (AGPL-3.0)
fbe2cc1 verified
Raw History Blame Contribute Delete
5.41 kB
#!/usr/bin/env bash
# ---------------------------------------------------------------------------
# One-command deploy for the Sking Space.
#
# export HF_TOKEN=hf_xxx... # fine-grained, "Write" on this Space
# ./deploy.sh <your-username>/<space-name>
#
# 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 <username>/<space-name>" >&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 <<EOF
==> 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