cozyga commited on
Commit
4622fa9
·
verified ·
1 Parent(s): 5d7d869

Update provision.sh

Browse files
Files changed (1) hide show
  1. provision.sh +384 -138
provision.sh CHANGED
@@ -1,146 +1,392 @@
1
  #!/bin/bash
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- echo "Starting provisioning script..."
4
-
5
- ############################################
6
- # 0. HUGGING FACE AUTH
7
- ############################################
8
- if [ -z "$HF_TOKEN" ]; then
9
- echo "⚠️ HF_TOKEN not set — private Hugging Face repos will fail."
10
- else
11
- echo "Logging into Hugging Face..."
12
- pip install -q huggingface_hub
13
- huggingface-cli login --token $HF_TOKEN
 
 
 
 
 
 
 
 
 
 
14
  fi
15
 
16
- HF_HEADER="Authorization: Bearer $HF_TOKEN"
17
- AUTH_HEADER="Authorization: Bearer 50d5f37a60d5bb4b1148bbc7addfe2a0"
18
-
19
- ############################################
20
- # 1. DIRECTORIES
21
- ############################################
22
- mkdir -p /workspace/ComfyUI/models/{text_encoders,checkpoints,vae,clip,loras,diffusion_models,upscale_models}
23
- mkdir -p /workspace/ComfyUI/models/ultralytics/bbox
24
-
25
- ############################################
26
- # 2. HELPER FOR PRIVATE HF DOWNLOADS
27
- ############################################
28
- hf_wget () {
29
- DEST=$1
30
- URL=$2
31
- if [ ! -f "$DEST" ]; then
32
- echo "Downloading $(basename $DEST)"
33
- wget --header="$HF_HEADER" -O "$DEST" "$URL"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  else
35
- echo "Exists: $(basename $DEST)"
 
36
  fi
37
  }
38
 
39
- ############################################
40
- # 3. MODEL DOWNLOADS (Hugging Face)
41
- ############################################
42
- echo "Checking Hugging Face models..."
43
-
44
- [ ! -f /workspace/ComfyUI/models/text_encoders/t5xxl_fp8_e4m3fn_scaled.safetensors ] && \
45
- hf_wget /workspace/ComfyUI/models/text_encoders/t5xxl_fp8_e4m3fn_scaled.safetensors \
46
- https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp8_e4m3fn_scaled.safetensors
47
-
48
- [ ! -f /workspace/ComfyUI/models/checkpoints/Qwen-Rapid-AIO-SFW-v23.safetensors ] && \
49
- hf_wget /workspace/ComfyUI/models/checkpoints/Qwen-Rapid-AIO-SFW-v23.safetensors \
50
- https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO/resolve/main/v23/Qwen-Rapid-AIO-SFW-v23.safetensors
51
-
52
- [ ! -f /workspace/ComfyUI/models/checkpoints/Qwen-Rapid-AIO-NSFW-v23.safetensors ] && \
53
- hf_wget /workspace/ComfyUI/models/checkpoints/Qwen-Rapid-AIO-NSFW-v23.safetensors \
54
- https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO/resolve/main/v23/Qwen-Rapid-AIO-NSFW-v23.safetensors
55
-
56
- [ ! -f /workspace/ComfyUI/models/vae/qwen_image_vae.safetensors ] && \
57
- hf_wget /workspace/ComfyUI/models/vae/qwen_image_vae.safetensors \
58
- https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors
59
-
60
- [ ! -f /workspace/ComfyUI/models/clip/qwen_3_4b.safetensors ] && \
61
- hf_wget /workspace/ComfyUI/models/clip/qwen_3_4b.safetensors \
62
- https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/text_encoders/qwen_3_4b.safetensors
63
-
64
- [ ! -f /workspace/ComfyUI/models/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors ] && \
65
- hf_wget /workspace/ComfyUI/models/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors \
66
- https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors
67
-
68
- [ ! -f /workspace/ComfyUI/models/diffusion_models/z_image_turbo_bf16.safetensors ] && \
69
- hf_wget /workspace/ComfyUI/models/diffusion_models/z_image_turbo_bf16.safetensors \
70
- https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/diffusion_models/z_image_turbo_bf16.safetensors
71
-
72
- [ ! -f /workspace/ComfyUI/models/vae/flux_vae.safetensors ] && \
73
- hf_wget /workspace/ComfyUI/models/vae/flux_vae.safetensors \
74
- https://huggingface.co/StableDiffusionVN/Flux/resolve/main/Vae/flux_vae.safetensors
75
-
76
- [ ! -f /workspace/ComfyUI/models/ultralytics/bbox/FacesV1.pt ] && \
77
- hf_wget /workspace/ComfyUI/models/ultralytics/bbox/FacesV1.pt \
78
- https://huggingface.co/ashllay/YOLO_Models/resolve/e07b01219ff1807e1885015f439d788b038f49bd/bbox/FacesV1.pt
79
-
80
- [ ! -f /workspace/ComfyUI/models/upscale_models/1x-ITF-SkinDiffDetail-Lite-v1.pth ] && \
81
- hf_wget /workspace/ComfyUI/models/upscale_models/1x-ITF-SkinDiffDetail-Lite-v1.pth \
82
- https://huggingface.co/cozyga/test/resolve/main/1x-ITF-SkinDiffDetail-Lite-v1.pth
83
-
84
- ############################################
85
- # CIVITAI MODELS
86
- ############################################
87
- [ ! -f /workspace/ComfyUI/models/checkpoints/LustifyENDGAME.safetensors ] && \
88
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/checkpoints/LustifyENDGAME.safetensors \
89
- "https://civitai.com/api/download/models/1094291?type=Model&format=SafeTensor&size=pruned&fp=fp16"
90
-
91
- [ ! -f /workspace/ComfyUI/models/checkpoints/analogMadnessXL.safetensors ] && \
92
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/checkpoints/analogMadnessXL.safetensors \
93
- "https://civitai.com/api/download/models/2207703?type=Model&format=SafeTensor&size=full&fp=fp16"
94
-
95
- ############################################
96
- # REMAINING FILES (UNCHANGED)
97
- ############################################
98
- wget --content-disposition -P /workspace/ComfyUI/models/ultralytics/bbox/ \
99
- https://huggingface.co/cozyga/test/resolve/main/nipple.pt \
100
- https://huggingface.co/cozyga/test/resolve/main/pussyV2.pt
101
-
102
- wget --content-disposition -P /workspace/ComfyUI/models/checkpoints/ \
103
- https://huggingface.co/cozyga/test/resolve/main/lustifySDXLNSFW_endgame.safetensors
104
-
105
- wget --content-disposition -P /workspace/ComfyUI/models/loras/ \
106
- https://huggingface.co/cozyga/test/resolve/main/dmd2_sdxl_4step_lora_fp16.safetensors
107
-
108
- ############################################
109
- # (Your LoRAs + Civitai section stays identical)
110
- ############################################
111
- LORA_DIR="/workspace/ComfyUI/models/loras"
112
- [ ! -f "$LORA_DIR/Z-Isla_3K_0002_000003500.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/Z-Isla_3K_0002_000003500.safetensors
113
- [ ! -f "$LORA_DIR/z-kyla-v1.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/z-kyla-v1.safetensors
114
- [ ! -f "$LORA_DIR/m1a_zit_3.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/m1a_zit_3.safetensors
115
- [ ! -f "$LORA_DIR/c3lia_v1_000003600.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/c3lia_v1_000003600.safetensors
116
- [ ! -f "$LORA_DIR/c3lia_v1_000003900.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/c3lia_v1_000003900.safetensors
117
- [ ! -f "$LORA_DIR/qwen_c3lia_000003600.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/qwen_c3lia_000003600.safetensors
118
- [ ! -f "$LORA_DIR/l0ki_zit_v1_000003000.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/XLB666/qwenzitloras/resolve/main/l0ki_zit_v1_000003000.safetensors
119
- [ ! -f "$LORA_DIR/l0ki_qwen_v1_000002800.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/XLB666/qwenzitloras/resolve/main/l0ki_qwen_v1_000002800.safetensors
120
- [ ! -f "$LORA_DIR/s0fia_v2_000004800.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000004800.safetensors
121
- [ ! -f "$LORA_DIR/s0fia_v2_000003700.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000003700.safetensors
122
- [ ! -f "$LORA_DIR/s0fia_v2_000004300.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000004300.safetensors
123
- [ ! -f "$LORA_DIR/dmd2_sdxl_4step_lora_fp16.safetensors" ] && wget -P "$LORA_DIR" https://huggingface.co/tianweiy/DMD2/resolve/main/dmd2_sdxl_4step_lora_fp16.safetensors
124
- [ ! -f /workspace/ComfyUI/models/loras/zittitslider.safetensors ] && \
125
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/loras/zittitslider.safetensors "https://civitai.com/api/download/models/2478366"
126
- [ ! -f /workspace/ComfyUI/models/loras/QwenEditVersatilePoses.safetensors ] && \
127
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/loras/QwenEditVersatilePoses.safetensors "https://civitai.com/api/download/models/2457989?type=Model&format=SafeTensor"
128
- [ ! -f /workspace/ComfyUI/models/loras/sdxlcloseuppussy.safetensors ] && \
129
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/loras/sdxlcloseuppussy.safetensors "https://civitai.com/api/download/models/2376235?type=Model&format=SafeTensor"
130
- [ ! -f /workspace/ComfyUI/models/vae/zImage_vae.safetensors ] && \
131
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/vae/zImage_vae.safetensors "https://civitai.com/api/download/models/2442479"
132
- [ ! -f /workspace/ComfyUI/models/loras/amateurphotography.safetensors ] && \
133
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/loras/amateurphotography.safetensors "https://civitai.com/api/download/models/2363467"
134
- [ ! -f /workspace/ComfyUI/models/loras/nextscene.safetensors ] && \
135
- curl -L -H "$AUTH_HEADER" -o /workspace/ComfyUI/models/loras/nextscene.safetensors "https://civitai.com/api/download/models/2337214?type=Model&format=SafeTensor"
136
-
137
- ############################################
138
- # UPDATE & START
139
- ############################################
140
- echo "Provisioning complete. Updating ComfyUI..."
141
-
142
- cd /workspace/ComfyUI || exit
143
- git pull
144
-
145
- echo "ComfyUI is updated. Starting now..."
146
- python main.py --listen
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #!/bin/bash
2
+ # =============================================================================
3
+ # ComfyUI Provisioning Script for Vast.ai
4
+ #
5
+ # Unified setup: installs custom nodes, downloads all models (LoRAs, VAE,
6
+ # checkpoints) from HuggingFace (private + public) and CivitAI.
7
+ #
8
+ # Uses aria2c for fast parallel downloads (16 connections per file).
9
+ #
10
+ # Environment variables (set in Vast.ai template Docker Options):
11
+ # HF_TOKEN - Required. HuggingFace token for private repos.
12
+ # CIVITAI_TOKEN - Required. CivitAI API token for gated models.
13
+ #
14
+ # Usage:
15
+ # # Set in Vast.ai template environment:
16
+ # HF_TOKEN=hf_xxx CIVITAI_TOKEN=xxx ./setup-comfyui-vastai.sh
17
+ #
18
+ # # Or source the ai-dock venv first (if using ai-dock template):
19
+ # source /venv/main/bin/activate && ./setup-comfyui-vastai.sh
20
+ # =============================================================================
21
 
22
+ set -euo pipefail
23
+
24
+ # =============================================================================
25
+ # Configuration
26
+ # =============================================================================
27
+
28
+ WORKSPACE="${WORKSPACE:-/workspace}"
29
+ COMFYUI_DIR="${COMFYUI_DIR:-${WORKSPACE}/ComfyUI}"
30
+ LORA_DIR="${COMFYUI_DIR}/models/loras"
31
+ VAE_DIR="${COMFYUI_DIR}/models/vae"
32
+ CKPT_DIR="${COMFYUI_DIR}/models/checkpoints"
33
+ NODES_DIR="${COMFYUI_DIR}/custom_nodes"
34
+ TEXT_ENCODER_DIR="${COMFYUI_DIR}/models/text_encoders"
35
+ CLIP_DIR="${COMFYUI_DIR}/models/clip"
36
+ DIFFUSION_DIR="${COMFYUI_DIR}/models/diffusion_models"
37
+ ULTRALYTICS_DIR="${COMFYUI_DIR}/models/ultralytics/bbox"
38
+ UPSCALE_DIR="${COMFYUI_DIR}/models/upscale_models"
39
+
40
+ # Activate venv if available (ai-dock template)
41
+ if [ -f /venv/main/bin/activate ]; then
42
+ source /venv/main/bin/activate
43
  fi
44
 
45
+ # =============================================================================
46
+ # Model Definitions
47
+ # =============================================================================
48
+
49
+ # HuggingFace LoRAs — private repo (requires HF_TOKEN)
50
+ # Format: "filename|url"
51
+ HF_PRIVATE_LORAS=(
52
+ "Z-Isla_3K_0002_000003500.safetensors|https://huggingface.co/cozyga/test/resolve/main/Z-Isla_3K_0002_000003500.safetensors"
53
+ "z-kyla-v1.safetensors|https://huggingface.co/cozyga/test/resolve/main/z-kyla-v1.safetensors"
54
+ "m1a_zit_3.safetensors|https://huggingface.co/cozyga/test/resolve/main/m1a_zit_3.safetensors"
55
+ "c3lia_v1_000003600.safetensors|https://huggingface.co/cozyga/test/resolve/main/c3lia_v1_000003600.safetensors"
56
+ "c3lia_v1_000003900.safetensors|https://huggingface.co/cozyga/test/resolve/main/c3lia_v1_000003900.safetensors"
57
+ "qwen_c3lia_000003600.safetensors|https://huggingface.co/cozyga/test/resolve/main/qwen_c3lia_000003600.safetensors"
58
+ "s0fia_v2_000004800.safetensors|https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000004800.safetensors"
59
+ "s0fia_v2_000003700.safetensors|https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000003700.safetensors"
60
+ "s0fia_v2_000004300.safetensors|https://huggingface.co/cozyga/test/resolve/main/s0fia_v2_000004300.safetensors"
61
+ )
62
+
63
+ # HuggingFace LoRAs — public repos
64
+ HF_PUBLIC_LORAS=(
65
+ "l0ki_zit_v1_000003000.safetensors|https://huggingface.co/XLB666/qwenzitloras/resolve/main/l0ki_zit_v1_000003000.safetensors"
66
+ "l0ki_qwen_v1_000002800.safetensors|https://huggingface.co/XLB666/qwenzitloras/resolve/main/l0ki_qwen_v1_000002800.safetensors"
67
+ "dmd2_sdxl_4step_lora_fp16.safetensors|https://huggingface.co/tianweiy/DMD2/resolve/main/dmd2_sdxl_4step_lora_fp16.safetensors"
68
+ )
69
+
70
+ # Additional HuggingFace model groups (added from user's list)
71
+ HF_TEXT_ENCODERS=(
72
+ "t5xxl_fp8_e4m3fn_scaled.safetensors|https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp8_e4m3fn_scaled.safetensors"
73
+ "qwen_2.5_vl_7b_fp8_scaled.safetensors|https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors"
74
+ )
75
+
76
+ HF_CLIPS=(
77
+ "qwen_3_4b.safetensors|https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/text_encoders/qwen_3_4b.safetensors"
78
+ )
79
+
80
+ HF_CHECKPOINTS_EXTRA=(
81
+ "Qwen-Rapid-AIO-SFW-v23.safetensors|https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO/resolve/main/v23/Qwen-Rapid-AIO-SFW-v23.safetensors"
82
+ "Qwen-Rapid-AIO-NSFW-v23.safetensors|https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO/resolve/main/v23/Qwen-Rapid-AIO-NSFW-v23.safetensors"
83
+ "lustifySDXLNSFW_endgame.safetensors|https://huggingface.co/cozyga/test/resolve/main/lustifySDXLNSFW_endgame.safetensors"
84
+ )
85
+
86
+ HF_VAES_EXTRA=(
87
+ "qwen_image_vae.safetensors|https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors"
88
+ "flux_vae.safetensors|https://huggingface.co/StableDiffusionVN/Flux/resolve/main/Vae/flux_vae.safetensors"
89
+ )
90
+
91
+ HF_DIFFUSION=(
92
+ "z_image_turbo_bf16.safetensors|https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/diffusion_models/z_image_turbo_bf16.safetensors"
93
+ )
94
+
95
+ HF_ULTRALYTICS=(
96
+ "FacesV1.pt|https://huggingface.co/ashllay/YOLO_Models/resolve/e07b01219ff1807e1885015f439d788b038f49bd/bbox/FacesV1.pt"
97
+ "nipple.pt|https://huggingface.co/cozyga/test/resolve/main/nipple.pt"
98
+ "pussyV2.pt|https://huggingface.co/cozyga/test/resolve/main/pussyV2.pt"
99
+ )
100
+
101
+ HF_UPSCALE=(
102
+ "1x-ITF-SkinDiffDetail-Lite-v1.pth|https://huggingface.co/cozyga/test/resolve/main/1x-ITF-SkinDiffDetail-Lite-v1.pth"
103
+ )
104
+
105
+ # CivitAI LoRAs (requires CIVITAI_TOKEN)
106
+ # Format: "filename|url"
107
+ # Explicit filenames avoid the CivitAI redirect long-filename bug
108
+ CIVITAI_LORAS=(
109
+ "zittitslider.safetensors|https://civitai.com/api/download/models/2478366"
110
+ "QwenEditVersatilePoses.safetensors|https://civitai.com/api/download/models/2457989?type=Model&format=SafeTensor"
111
+ "sdxlcloseuppussy.safetensors|https://civitai.com/api/download/models/2376235?type=Model&format=SafeTensor"
112
+ "amateurphotography.safetensors|https://civitai.com/api/download/models/2363467"
113
+ "nextscene.safetensors|https://civitai.com/api/download/models/2337214?type=Model&format=SafeTensor"
114
+ )
115
+
116
+ # CivitAI VAE models
117
+ CIVITAI_VAE=(
118
+ "zImage_vae.safetensors|https://civitai.com/api/download/models/2442479"
119
+ )
120
+
121
+ # CivitAI Checkpoints
122
+ CIVITAI_CHECKPOINTS=(
123
+ # Pony Diffusion V6 XL (or whichever model ID 798204 maps to — verify this)
124
+ "checkpoint.safetensors|https://civitai.com/api/download/models/798204?type=Model&format=SafeTensor&size=full&fp=fp16"
125
+ "LustifyENDGAME.safetensors|https://civitai.com/api/download/models/1094291?type=Model&format=SafeTensor&size=pruned&fp=fp16"
126
+ "analogMadnessXL.safetensors|https://civitai.com/api/download/models/2207703?type=Model&format=SafeTensor&size=full&fp=fp16"
127
+ )
128
+
129
+ # Custom nodes to install/update
130
+ NODES=(
131
+ "https://github.com/ltdrdata/ComfyUI-Impact-Pack"
132
+ "https://github.com/chflame163/ComfyUI_LayerStyle"
133
+ "https://github.com/rgthree/rgthree-comfy"
134
+ "https://github.com/yolain/ComfyUI-Easy-Use"
135
+ "https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler"
136
+ "https://github.com/cubiq/ComfyUI_essentials"
137
+ "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
138
+ "https://github.com/EllangoK/ComfyUI-post-processing-nodes"
139
+ "https://github.com/wallish77/wlsh_nodes"
140
+ "https://github.com/chrisgoringe/cg-image-filter"
141
+ "https://github.com/moonwhaler/comfyui-seedvr2-tilingups"
142
+ )
143
+
144
+ # Extra pip packages (installed after nodes)
145
+ PIP_PACKAGES=(
146
+ # "package-name"
147
+ )
148
+
149
+ # =============================================================================
150
+ # Functions
151
+ # =============================================================================
152
+
153
+ print_header() {
154
+ echo ""
155
+ echo "=============================================="
156
+ echo " ComfyUI Provisioning — Vast.ai"
157
+ echo "=============================================="
158
+ echo " Workspace: ${WORKSPACE}"
159
+ echo " ComfyUI: ${COMFYUI_DIR}"
160
+ echo " HF_TOKEN: ${HF_TOKEN:+set}${HF_TOKEN:-MISSING}"
161
+ echo " CIVITAI: ${CIVITAI_TOKEN:+set}${CIVITAI_TOKEN:-MISSING}"
162
+ echo "=============================================="
163
+ echo ""
164
+ }
165
+
166
+ # Install aria2c if not present (vast.ai containers are typically Debian/Ubuntu)
167
+ install_aria2() {
168
+ if command -v aria2c &>/dev/null; then
169
+ return 0
170
+ fi
171
+ echo "Installing aria2c for fast parallel downloads..."
172
+ if [ "$(id -u)" -eq 0 ]; then
173
+ apt-get update -qq && apt-get install -y -qq aria2
174
+ elif command -v sudo &>/dev/null; then
175
+ sudo apt-get update -qq && sudo apt-get install -y -qq aria2
176
+ else
177
+ echo "ERROR: aria2 not found and cannot install (not root, no sudo)."
178
+ echo "Falling back to wget."
179
+ return 1
180
+ fi
181
+ }
182
+
183
+ # Validate that a HuggingFace token is valid
184
+ validate_hf_token() {
185
+ if [ -z "${HF_TOKEN:-}" ]; then
186
+ echo "WARNING: HF_TOKEN is not set. Private HuggingFace downloads will fail."
187
+ return 1
188
+ fi
189
+ local status
190
+ status=$(curl -s -o /dev/null -w "%{http_code}" \
191
+ -H "Authorization: Bearer ${HF_TOKEN}" \
192
+ "https://huggingface.co/api/whoami-v2")
193
+ if [ "$status" -eq 200 ]; then
194
+ echo "HF_TOKEN: validated"
195
+ return 0
196
  else
197
+ echo "WARNING: HF_TOKEN validation failed (HTTP ${status}). Private downloads may fail."
198
+ return 1
199
  fi
200
  }
201
 
202
+ # Validate that a CivitAI token is valid
203
+ validate_civitai_token() {
204
+ if [ -z "${CIVITAI_TOKEN:-}" ]; then
205
+ echo "WARNING: CIVITAI_TOKEN is not set. CivitAI downloads will fail."
206
+ return 1
207
+ fi
208
+ local status
209
+ status=$(curl -s -o /dev/null -w "%{http_code}" \
210
+ -H "Authorization: Bearer ${CIVITAI_TOKEN}" \
211
+ "https://civitai.com/api/v1/models?hidden=1&limit=1")
212
+ if [ "$status" -eq 200 ]; then
213
+ echo "CIVITAI_TOKEN: validated"
214
+ return 0
215
+ else
216
+ echo "WARNING: CIVITAI_TOKEN validation failed (HTTP ${status}). CivitAI downloads may fail."
217
+ return 1
218
+ fi
219
+ }
220
+
221
+ # Download a file if it doesn't already exist
222
+ # Uses aria2c with 16 parallel connections for speed
223
+ # Falls back to wget if aria2c is unavailable
224
+ #
225
+ # Usage: download_if_missing <dir> <filename> <url> [auth_header]
226
+ download_if_missing() {
227
+ local dir="$1"
228
+ local filename="$2"
229
+ local url="$3"
230
+ local auth_header="${4:-}"
231
+
232
+ mkdir -p "$dir"
233
+
234
+ if [ -f "${dir}/${filename}" ]; then
235
+ echo " [skip] ${filename}"
236
+ return 0
237
+ fi
238
+
239
+ echo " [downloading] ${filename}..."
240
+
241
+ if command -v aria2c &>/dev/null; then
242
+ if [ -n "$auth_header" ]; then
243
+ aria2c -x 16 -s 16 -k 1M -c \
244
+ --header="Authorization: Bearer ${auth_header}" \
245
+ -d "$dir" -o "$filename" "$url" 2>&1 | tail -1
246
+ else
247
+ aria2c -x 16 -s 16 -k 1M -c \
248
+ -d "$dir" -o "$filename" "$url" 2>&1 | tail -1
249
+ fi
250
+ else
251
+ # Fallback: wget
252
+ if [ -n "$auth_header" ]; then
253
+ wget -q --show-progress \
254
+ --header="Authorization: Bearer ${auth_header}" \
255
+ -O "${dir}/${filename}" "$url"
256
+ else
257
+ wget -q --show-progress -O "${dir}/${filename}" "$url"
258
+ fi
259
+ fi
260
+
261
+ # Verify file was actually downloaded (not a 0-byte error)
262
+ if [ ! -s "${dir}/${filename}" ]; then
263
+ echo " [FAILED] ${filename} — downloaded file is empty, removing"
264
+ rm -f "${dir}/${filename}"
265
+ return 1
266
+ fi
267
+ }
268
+
269
+ # Download a batch of files from an array of "filename|url" entries
270
+ # Usage: download_batch <dir> <auth_token> <array_entries...>
271
+ download_batch() {
272
+ local dir="$1"
273
+ local auth_token="$2"
274
+ shift 2
275
+
276
+ local failed=0
277
+ for entry in "$@"; do
278
+ local filename="${entry%%|*}"
279
+ local url="${entry#*|}"
280
+ download_if_missing "$dir" "$filename" "$url" "$auth_token" || ((failed++)) || true
281
+ done
282
+
283
+ if [ "$failed" -gt 0 ]; then
284
+ echo " WARNING: ${failed} download(s) failed in ${dir}"
285
+ fi
286
+ }
287
+
288
+ # Install/update custom nodes
289
+ install_nodes() {
290
+ if [ ${#NODES[@]} -eq 0 ]; then
291
+ return 0
292
+ fi
293
+
294
+ echo "=== Installing Custom Nodes ==="
295
+ mkdir -p "$NODES_DIR"
296
+
297
+ for repo in "${NODES[@]}"; do
298
+ local dirname="${repo##*/}"
299
+ local path="${NODES_DIR}/${dirname}"
300
+ local requirements="${path}/requirements.txt"
301
+
302
+ if [ -d "$path" ]; then
303
+ echo " [update] ${dirname}"
304
+ (cd "$path" && git pull -q)
305
+ else
306
+ echo " [clone] ${dirname}"
307
+ git clone --recursive -q "$repo" "$path"
308
+ fi
309
+
310
+ if [ -f "$requirements" ]; then
311
+ pip install --no-cache-dir -q -r "$requirements"
312
+ fi
313
+ done
314
+ echo ""
315
+ }
316
+
317
+ # Install extra pip packages
318
+ install_pip_packages() {
319
+ if [ ${#PIP_PACKAGES[@]} -eq 0 ]; then
320
+ return 0
321
+ fi
322
+ echo "=== Installing pip packages ==="
323
+ pip install --no-cache-dir -q "${PIP_PACKAGES[@]}"
324
+ echo ""
325
+ }
326
+
327
+ # =============================================================================
328
+ # Main
329
+ # =============================================================================
330
+
331
+ print_header
332
+
333
+ # Install aria2c for fast downloads
334
+ install_aria2 || true
335
+
336
+ # Validate tokens (non-fatal — script continues with warnings)
337
+ validate_hf_token || true
338
+ validate_civitai_token || true
339
+ echo ""
340
+
341
+ # Create all model directories
342
+ mkdir -p "$LORA_DIR" "$VAE_DIR" "$CKPT_DIR"
343
+
344
+ # --- Custom Nodes ---
345
+ install_nodes
346
+
347
+ # --- Pip Packages ---
348
+ install_pip_packages
349
+
350
+ # --- HuggingFace Private LoRAs ---
351
+ echo "=== HuggingFace Private LoRAs (cozyga/test) ==="
352
+ download_batch "$LORA_DIR" "${HF_TOKEN:-}" "${HF_PRIVATE_LORAS[@]}"
353
+ echo ""
354
+
355
+ # --- HuggingFace Public LoRAs ---
356
+ echo "=== HuggingFace Public LoRAs ==="
357
+ download_batch "$LORA_DIR" "${HF_TOKEN:-}" "${HF_PUBLIC_LORAS[@]}"
358
+ echo ""
359
+
360
+ # --- CivitAI LoRAs ---
361
+ echo "=== CivitAI LoRAs ==="
362
+ download_batch "$LORA_DIR" "${CIVITAI_TOKEN:-}" "${CIVITAI_LORAS[@]}"
363
+ echo ""
364
+
365
+ # --- CivitAI VAE ---
366
+ echo "=== CivitAI VAE ==="
367
+ download_batch "$VAE_DIR" "${CIVITAI_TOKEN:-}" "${CIVITAI_VAE[@]}"
368
+ echo ""
369
+
370
+ # --- CivitAI Checkpoints ---
371
+ echo "=== CivitAI Checkpoints ==="
372
+ download_batch "$CKPT_DIR" "${CIVITAI_TOKEN:-}" "${CIVITAI_CHECKPOINTS[@]}"
373
+ echo ""
374
+
375
+ # =============================================================================
376
+ # Summary
377
+ # =============================================================================
378
+
379
+ echo "=============================================="
380
+ echo " Provisioning complete"
381
+ echo "=============================================="
382
+ echo ""
383
+ echo "LoRAs:"
384
+ ls -1 "$LORA_DIR"/*.safetensors 2>/dev/null | wc -l | xargs -I{} echo " {} files in ${LORA_DIR}"
385
+ echo ""
386
+ echo "VAE:"
387
+ ls -1 "$VAE_DIR"/*.safetensors 2>/dev/null | wc -l | xargs -I{} echo " {} files in ${VAE_DIR}"
388
+ echo ""
389
+ echo "Checkpoints:"
390
+ ls -1 "$CKPT_DIR"/*.safetensors 2>/dev/null | wc -l | xargs -I{} echo " {} files in ${CKPT_DIR}"
391
+ echo ""
392
+ echo "Application will start now."