JCscrew commited on
Commit
230069d
·
verified ·
1 Parent(s): 60593c9

Upload 2 files

Browse files
Files changed (2) hide show
  1. script_nightly1.sh +375 -0
  2. script_nightly2.sh +378 -0
script_nightly1.sh ADDED
@@ -0,0 +1,375 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -uo pipefail
3
+ set +H
4
+
5
+ export PIP_NO_CACHE_DIR=1
6
+ export PIP_DISABLE_PIP_VERSION_CHECK=1
7
+ export GIT_TERMINAL_PROMPT=0
8
+
9
+ source /venv/main/bin/activate
10
+ COMFYUI_DIR="${WORKSPACE:-/workspace}/ComfyUI"
11
+ if [ -f "/venv/main/bin/python" ]; then
12
+ PYTHON_BIN="/venv/main/bin/python"
13
+ PIP_BIN="/venv/main/bin/pip"
14
+ else
15
+ PYTHON_BIN="python3"
16
+ PIP_BIN="pip3"
17
+ fi
18
+
19
+ APT_PACKAGES=(
20
+ "aria2"
21
+ )
22
+ PIP_PACKAGES=(
23
+ )
24
+ NODES=(
25
+ "https://github.com/ltdrdata/ComfyUI-Impact-Pack.git"
26
+ "https://github.com/ltdrdata/ComfyUI-Impact-Subpack.git"
27
+ "https://github.com/cubiq/ComfyUI_IPAdapter_plus.git"
28
+ "https://github.com/ka-puna/comfyui-yanc.git"
29
+ "https://github.com/godmt/ComfyUI-List-Utils.git"
30
+ )
31
+ BBOX_MODELS=(
32
+
33
+ )
34
+ CHECKPOINT_MODELS=(
35
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/checkpoints/waiNSFWIllustrious_v150.safetensors"
36
+ )
37
+ CLIP_VISION_MODELS=(
38
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/clip_vision/CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
39
+ )
40
+ DINO_MODELS=(
41
+
42
+ )
43
+ FASHION_MODELS=(
44
+
45
+ )
46
+ IPADAPTER_MODELS=(
47
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/ipadapter/ip-adapter-plus-face_sdxl_vit-h.safetensors"
48
+ )
49
+ LORAS_MODELS=(
50
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/Better_detailed_pussy_and_anus_v3.0.safetensors"
51
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/deal360acv_illustrious_006.safetensors"
52
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/Hugkissingbreast_press_pov_Illustrious-000005.safetensors"
53
+ )
54
+ RMBG_MODELS=(
55
+
56
+ )
57
+ SAM2_MODELS=(
58
+
59
+ )
60
+ SAMS_MODELS=(
61
+
62
+ )
63
+ UPSCALE_MODELS=(
64
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/upscale_models/RealESRGAN_x4plus_anime_6B.pth"
65
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/upscale_models/4x-UltraSharpV2.pth"
66
+ )
67
+ WORKFLOWS=
68
+ WORKFLOWS=(
69
+ )
70
+
71
+ log_info() { echo "--> $1"; }
72
+ log_warn() { echo " ⚠️ $1"; }
73
+ log_error() { echo " ❌ $1"; }
74
+ log_success() { echo " ✅ $1"; }
75
+ log_step() { echo ""; echo "=== [Step $1] $2 ==="; }
76
+
77
+ package_installed() {
78
+ $PYTHON_BIN -c "import $1" 2>/dev/null && return 0 || return 1
79
+ }
80
+
81
+ filter_requirements() {
82
+ local req_file="$1"
83
+ local tmp_file="${req_file}.filtered"
84
+ > "$tmp_file"
85
+ while IFS= read -r line; do
86
+ [[ -z "$line" || "$line" =~ ^# ]] && continue
87
+ local pkg_name
88
+ pkg_name=$(echo "$line" | sed 's/[<>=!].*//' | xargs)
89
+ if [[ -z "$pkg_name" ]]; then continue; fi
90
+ local module_name="${pkg_name//-/_}"
91
+ if package_installed "$module_name"; then
92
+ log_info "跳過已安裝套件: $pkg_name"
93
+ else
94
+ echo "$line" >> "$tmp_file"
95
+ fi
96
+ done < "$req_file"
97
+ if [ -s "$tmp_file" ]; then
98
+ mv "$tmp_file" "$req_file"
99
+ return 0
100
+ else
101
+ rm -f "$tmp_file"
102
+ log_info "所有套件都已安裝"
103
+ return 1
104
+ fi
105
+ }
106
+
107
+ provisioning_has_valid_hf_token() {
108
+ [[ -n "${HF_TOKEN:-}" ]] || return 1
109
+ local response
110
+ response=$(curl -o /dev/null -s -w "%{http_code}" -X GET "https://huggingface.co/api/whoami-v2" -H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json")
111
+ [ "$response" -eq 200 ]
112
+ }
113
+
114
+ provisioning_has_valid_civitai_token() {
115
+ [[ -n "${CIVITAI_TOKEN:-}" ]] || return 1
116
+ local response
117
+ response=$(curl -o /dev/null -s -w "%{http_code}" -X GET "https://civitai.com/api/v1/models?hidden=1&limit=1" -H "Authorization: Bearer $CIVITAI_TOKEN" -H "Content-Type: application/json")
118
+ [ "$response" -eq 200 ]
119
+ }
120
+
121
+ install_node() {
122
+ local repo_url="$1"
123
+ local repo_name
124
+ repo_name=$(basename "$repo_url" .git)
125
+ local install_path="${COMFYUI_DIR}/custom_nodes/${repo_name}"
126
+
127
+ if [ -d "$install_path" ]; then
128
+ if [[ "${AUTO_UPDATE:-true}" != "false" ]]; then
129
+ log_info "更新節點: $repo_name"
130
+ (cd "$install_path" && git pull -q 2>&1 | grep -v "Already up to date" || true)
131
+ else
132
+ log_info "'$repo_name' 已存在,跳過"
133
+ return
134
+ fi
135
+ else
136
+ log_info "克隆節點: $repo_name"
137
+ git clone --depth 1 --single-branch "$repo_url" "$install_path" -q 2>&1 || true
138
+ fi
139
+
140
+ if [ -f "$install_path/requirements.txt" ]; then
141
+ log_info "處理 $repo_name 的依賴..."
142
+ sed -i -e '/^torch/d' -e '/^sam2/d' "$install_path/requirements.txt" 2>/dev/null || true
143
+ if filter_requirements "$install_path/requirements.txt"; then
144
+ log_info "安裝 $repo_name 的新依賴..."
145
+ $PIP_BIN install -q --no-cache-dir -r "$install_path/requirements.txt" 2>&1 | grep -v "Requirement already satisfied" || log_warn "部分依賴安裝失敗"
146
+ fi
147
+ fi
148
+
149
+ if [ -f "$install_path/install.py" ]; then
150
+ log_info "運行 $repo_name 的安裝腳本..."
151
+ $PYTHON_BIN "$install_path/install.py" 2>&1 || log_warn "安裝腳本執行失敗"
152
+ fi
153
+ }
154
+
155
+ download_file() {
156
+ local dest_path="$1"
157
+ local url="$2"
158
+ local filename
159
+ filename=$(basename "$dest_path")
160
+ local tmp_path="${dest_path}.tmp"
161
+
162
+ mkdir -p "$(dirname "$dest_path")"
163
+ if [ -s "$dest_path" ]; then
164
+ log_info "檔案 '$filename' 已存在且完整,跳過下載"
165
+ return 0
166
+ fi
167
+
168
+ log_info "下載: $filename"
169
+ local max_retries=3
170
+ local attempt=0
171
+ local auth_header=""
172
+ local success=1
173
+
174
+ if [[ "$url" =~ huggingface\.co ]] && provisioning_has_valid_hf_token; then
175
+ auth_header="Authorization: Bearer $HF_TOKEN"
176
+ log_info "使用 HuggingFace Token"
177
+ elif [[ "$url" =~ civitai\.com ]] && provisioning_has_valid_civitai_token; then
178
+ auth_header="Authorization: Bearer $CIVITAI_TOKEN"
179
+ log_info "使用 CivitAI Token"
180
+ fi
181
+
182
+ while [ "$attempt" -lt "$max_retries" ]; do
183
+ attempt=$((attempt + 1))
184
+ [ "$attempt" -gt 1 ] && sleep 10
185
+ if command -v aria2c >/dev/null 2>&1; then
186
+ log_info "使用 aria2c (3 線程) 下載: $filename (嘗試 $attempt/$max_retries)"
187
+ local aria_opts=(--console-log-level=error -c -x 3 -s 3 -k 1M --max-connection-per-server=3 --max-tries=3 --retry-wait=5 --timeout=180 --file-allocation=falloc --auto-file-renaming=false -d "$(dirname "$dest_path")" -o "${filename}.tmp")
188
+ [[ -n "$auth_header" ]] && aria_opts+=(--header="$auth_header")
189
+ aria2c "${aria_opts[@]}" "$url"
190
+ if [ $? -eq 0 ]; then success=0; break; fi
191
+ else
192
+ log_info "使用 wget 下載: $filename (嘗試 $attempt/$max_retries)"
193
+ local wget_opts=(-O "$tmp_path" -c --timeout=60 --tries=3 --content-disposition --show-progress)
194
+ [[ -n "$auth_header" ]] && wget_opts+=(--header="$auth_header")
195
+ wget "${wget_opts[@]}" "$url"
196
+ if [ $? -eq 0 ]; then success=0; break; fi
197
+ fi
198
+ done
199
+
200
+ if [ "$success" -eq 0 ] && [ -s "$tmp_path" ]; then
201
+ mv "$tmp_path" "$dest_path"
202
+ log_success "下載完成: $filename"
203
+ return 0
204
+ else
205
+ log_error "下載失敗: $filename"
206
+ rm -f "$tmp_path"
207
+ return 1
208
+ fi
209
+ }
210
+
211
+ download_to_directory() {
212
+ local dest_dir="$1"; shift; local urls=("$@")
213
+ if [ ${#urls[@]} -eq 0 ]; then return 0; fi
214
+ mkdir -p "$dest_dir"
215
+ log_info "下載 ${#urls[@]} 個文件到 $dest_dir"
216
+ local MAX_PARALLEL=3
217
+ for url in "${urls[@]}"; do
218
+ while [ $(jobs -r | wc -l) -ge $MAX_PARALLEL ]; do sleep 1; done
219
+ local filename
220
+ filename=$(basename "$url" | sed 's/?.*//')
221
+ download_file "${dest_dir}/${filename}" "$url" &
222
+ done
223
+ wait
224
+ }
225
+
226
+ verify_and_retry_downloads() {
227
+ local dest_dir="$1"; shift; local urls=("$@")
228
+ if [ ${#urls[@]} -eq 0 ]; then return 0; fi
229
+ log_info "檢查 $dest_dir 中的文件..."
230
+ local missing_files=()
231
+ for url in "${urls[@]}"; do
232
+ local filename
233
+ filename=$(basename "$url" | sed 's/?.*//')
234
+ local dest_path="${dest_dir}/${filename}"
235
+ if [ ! -s "$dest_path" ]; then
236
+ log_warn "檔案缺失或不完整: $filename"
237
+ missing_files+=("$url")
238
+ fi
239
+ done
240
+ if [ ${#missing_files[@]} -gt 0 ]; then
241
+ log_warn "發現 ${#missing_files[@]} 個缺失/不完整文件,重新下載..."
242
+ download_to_directory "$dest_dir" "${missing_files[@]}"
243
+ else
244
+ log_success "所有文件已確認存在且完整"
245
+ fi
246
+ }
247
+
248
+ provisioning_print_header() {
249
+ echo ""; echo "##############################################"
250
+ echo "# #"
251
+ echo "# Provisioning Container #"
252
+ echo "# #"
253
+ echo "# This will take some time #"
254
+ echo "# #"
255
+ echo "##############################################"; echo ""
256
+ }
257
+
258
+ provisioning_print_end() {
259
+ echo ""; echo "##############################################"
260
+ echo "# #"
261
+ echo "# Provisioning Complete! #"
262
+ echo "# #"
263
+ echo "# Total time: $((END_TIME - START_TIME)) seconds #"
264
+ echo "# #"
265
+ echo "##############################################"; echo ""
266
+ }
267
+
268
+ provisioning_step1_install_core_deps() {
269
+ log_step "1" "安裝系統與 ComfyUI 核心依賴"
270
+ if [ ${#APT_PACKAGES[@]} -gt 0 ]; then
271
+ log_info "準備安裝 ${#APT_PACKAGES[@]} 個系統套件..."
272
+ local packages_to_install=()
273
+ for pkg in "${APT_PACKAGES[@]}"; do
274
+ if ! dpkg -s "$pkg" >/dev/null 2>&1; then
275
+ packages_to_install+=("$pkg")
276
+ else
277
+ log_success "$pkg 已安裝,跳過"
278
+ fi
279
+ done
280
+ if [ ${#packages_to_install[@]} -gt 0 ]; then
281
+ log_info "正在安裝: ${packages_to_install[*]}"
282
+ apt-get update -qq && apt-get install -y -qq "${packages_to_install[@]}" && log_success "系統套件安裝完成" || log_warn "部分系統套件安裝失敗"
283
+ fi
284
+ fi
285
+
286
+ local comfyui_req_file="${COMFYUI_DIR}/requirements.txt"
287
+ if [ -f "$comfyui_req_file" ]; then
288
+ log_info "處理 ComfyUI 核心依賴: $comfyui_req_file"
289
+ if filter_requirements "$comfyui_req_file"; then
290
+ log_info "安裝 ComfyUI 的新依賴..."
291
+ $PIP_BIN install -q --no-cache-dir -r "$comfyui_req_file" 2>&1 | grep -v "Requirement already satisfied" || log_warn "ComfyUI 部分核心依賴安裝失敗"
292
+ fi
293
+ else
294
+ log_warn "找不到 ComfyUI 的核心 requirements.txt 文件!"
295
+ fi
296
+ }
297
+
298
+ provisioning_step2_nodes() {
299
+ log_step "2" "安裝節點與額外套件"
300
+ if [ ${#NODES[@]} -gt 0 ]; then
301
+ cd "${COMFYUI_DIR}/custom_nodes" || exit 1
302
+ log_info "並行安裝 ${#NODES[@]} 個節點..."
303
+ local MAX_PARALLEL=2
304
+ for node in "${NODES[@]}"; do
305
+ while [ $(jobs -r | wc -l) -ge $MAX_PARALLEL ]; do sleep 1; done
306
+ install_node "$node" &
307
+ done
308
+ wait
309
+ log_success "節點安裝完成"
310
+ cd "${COMFYUI_DIR}" || exit 1
311
+ fi
312
+ }
313
+
314
+ provisioning_step3_downloads() {
315
+ log_step "3" "下載模型與工作流文件"
316
+ download_to_directory "${COMFYUI_DIR}/models/checkpoints" "${CHECKPOINT_MODELS[@]}"
317
+ download_to_directory "${COMFYUI_DIR}/models/clip_vision" "${CLIP_VISION_MODELS[@]}"
318
+ download_to_directory "${COMFYUI_DIR}/models/grounding-dino" "${DINO_MODELS[@]}"
319
+ download_to_directory "${COMFYUI_DIR}/models/ipadapter" "${IPADAPTER_MODELS[@]}"
320
+ download_to_directory "${COMFYUI_DIR}/models/loras" "${LORAS_MODELS[@]}"
321
+ download_to_directory "${COMFYUI_DIR}/models/RMBG/RMBG-2.0" "${RMBG_MODELS[@]}"
322
+ download_to_directory "${COMFYUI_DIR}/models/RMBG/segformer_fashion" "${FASHION_MODELS[@]}"
323
+ download_to_directory "${COMFYUI_DIR}/models/sam2" "${SAM2_MODELS[@]}"
324
+ download_to_directory "${COMFYUI_DIR}/models/sams" "${SAMS_MODELS[@]}"
325
+ download_to_directory "${COMFYUI_DIR}/models/ultralytics/bbox" "${BBOX_MODELS[@]}"
326
+ download_to_directory "${COMFYUI_DIR}/models/upscale_models" "${UPSCALE_MODELS[@]}"
327
+ if [ ${#WORKFLOWS[@]} -gt 0 ]; then
328
+ log_info "下載工作流文件..."
329
+ download_to_directory "${COMFYUI_DIR}/user/default/workflows" "${WORKFLOWS[@]}"
330
+ fi
331
+ }
332
+
333
+ if [ -f "/workspace/.provision_complete" ]; then
334
+ log_success "環境已配置,跳過重複執行"
335
+ log_info "如需重新配置,請刪除 /workspace/.provision_complete"
336
+ exit 0
337
+ fi
338
+ if [[ -f /.noprovisioning ]]; then
339
+ log_warn "檢測到 /.noprovisioning 文件,跳過配置"
340
+ exit 0
341
+ fi
342
+
343
+ START_TIME=$(date +%s)
344
+ provisioning_print_header
345
+ cd "${COMFYUI_DIR}" || exit 1
346
+
347
+ provisioning_step1_install_core_deps
348
+
349
+ provisioning_step2_nodes &
350
+ NODE_PID=$!
351
+ provisioning_step3_downloads
352
+ wait $NODE_PID
353
+
354
+ log_step "4" "驗證下載完整性"
355
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/checkpoints" "${CHECKPOINT_MODELS[@]}"
356
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/clip_vision" "${CLIP_VISION_MODELS[@]}"
357
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/grounding-dino" "${DINO_MODELS[@]}"
358
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/ipadapter" "${IPADAPTER_MODELS[@]}"
359
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/loras" "${LORAS_MODELS[@]}"
360
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/RMBG/RMBG-2.0" "${RMBG_MODELS[@]}"
361
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/RMBG/segformer_fashion" "${FASHION_MODELS[@]}"
362
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/sam2" "${SAM2_MODELS[@]}"
363
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/sams" "${SAMS_MODELS[@]}"
364
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/ultralytics/bbox" "${BBOX_MODELS[@]}"
365
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/upscale_models" "${UPSCALE_MODELS[@]}"
366
+ verify_and_retry_downloads "${COMFYUI_DIR}/user/default/workflows" "${WORKFLOWS[@]}"
367
+
368
+ log_step "5" "完成配置"
369
+ touch "/workspace/.provision_complete"
370
+ log_success "配置標記文件已創建"
371
+
372
+ END_TIME=$(date +%s)
373
+ provisioning_print_end
374
+ log_success "所有配置步驟已完成!"
375
+ exit 0
script_nightly2.sh ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -uo pipefail
3
+ set +H
4
+
5
+ export PIP_NO_CACHE_DIR=1
6
+ export PIP_DISABLE_PIP_VERSION_CHECK=1
7
+ export GIT_TERMINAL_PROMPT=0
8
+
9
+ source /venv/main/bin/activate
10
+ COMFYUI_DIR="${WORKSPACE:-/workspace}/ComfyUI"
11
+ if [ -f "/venv/main/bin/python" ]; then
12
+ PYTHON_BIN="/venv/main/bin/python"
13
+ PIP_BIN="/venv/main/bin/pip"
14
+ else
15
+ PYTHON_BIN="python3"
16
+ PIP_BIN="pip3"
17
+ fi
18
+
19
+ APT_PACKAGES=(
20
+ "aria2"
21
+ )
22
+ PIP_PACKAGES=(
23
+ )
24
+ NODES=(
25
+ "https://github.com/ltdrdata/ComfyUI-Impact-Pack.git"
26
+ "https://github.com/ltdrdata/ComfyUI-Impact-Subpack.git"
27
+ "https://github.com/cubiq/ComfyUI_IPAdapter_plus.git"
28
+ "https://github.com/ka-puna/comfyui-yanc.git"
29
+ "https://github.com/ltdrdata/ComfyUI-Inspire-Pack.git"
30
+ "https://github.com/1038lab/ComfyUI-RMBG.git"
31
+ "https://github.com/godmt/ComfyUI-List-Utils.git"
32
+ "https://github.com/ltdrdata/was-node-suite-comfyui.git"
33
+ )
34
+ BBOX_MODELS=(
35
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/ultralytics/bbox/face_yolov9c.pt"
36
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/ultralytics/bbox/hand_yolov9c.pt"
37
+ )
38
+ CHECKPOINT_MODELS=(
39
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/checkpoints/waiNSFWIllustrious_v150.safetensors"
40
+ )
41
+ CLIP_VISION_MODELS=(
42
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/clip_vision/CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
43
+ )
44
+ DINO_MODELS=(
45
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/grounding-dino/groundingdino_swinb_cogcoor.pth"
46
+ )
47
+ IPADAPTER_MODELS=(
48
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/ipadapter/ip-adapter-plus-face_sdxl_vit-h.safetensors"
49
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/ipadapter/ip-adapter-plus_sdxl_vit-h.safetensors"
50
+ )
51
+ LORAS_MODELS=(
52
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/Better_detailed_pussy_and_anus_v3.0.safetensors"
53
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/Hugkissingbreast_press_pov_Illustrious-000005.safetensors"
54
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/loras/Miki.safetensors"
55
+ )
56
+ RMBG_MODELS=(
57
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/RMBG/RMBG-2.0/BiRefNet_config.py"
58
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/RMBG/RMBG-2.0/birefnet.py"
59
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/RMBG/RMBG-2.0/config.json"
60
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/RMBG/RMBG-2.0/model.safetensors"
61
+ )
62
+ SAM2_MODELS=(
63
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/sam2/sam2.1_hiera_large.safetensors"
64
+ )
65
+ SAMS_MODELS=(
66
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/sams/sam_vit_h_4b8939.pth"
67
+ )
68
+ UPSCALE_MODELS=(
69
+ "https://huggingface.co/JCscrew/RisuAI_asset_generator/resolve/main/models/upscale_models/RealESRGAN_x4plus_anime_6B.pth"
70
+ )
71
+ WORKFLOWS=(
72
+ )
73
+
74
+ log_info() { echo "--> $1"; }
75
+ log_warn() { echo " ⚠️ $1"; }
76
+ log_error() { echo " ❌ $1"; }
77
+ log_success() { echo " ✅ $1"; }
78
+ log_step() { echo ""; echo "=== [Step $1] $2 ==="; }
79
+
80
+ package_installed() {
81
+ $PYTHON_BIN -c "import $1" 2>/dev/null && return 0 || return 1
82
+ }
83
+
84
+ filter_requirements() {
85
+ local req_file="$1"
86
+ local tmp_file="${req_file}.filtered"
87
+ > "$tmp_file"
88
+ while IFS= read -r line; do
89
+ [[ -z "$line" || "$line" =~ ^# ]] && continue
90
+ local pkg_name
91
+ pkg_name=$(echo "$line" | sed 's/[<>=!].*//' | xargs)
92
+ if [[ -z "$pkg_name" ]]; then continue; fi
93
+ local module_name="${pkg_name//-/_}"
94
+ if package_installed "$module_name"; then
95
+ log_info "跳過已安裝套件: $pkg_name"
96
+ else
97
+ echo "$line" >> "$tmp_file"
98
+ fi
99
+ done < "$req_file"
100
+ if [ -s "$tmp_file" ]; then
101
+ mv "$tmp_file" "$req_file"
102
+ return 0
103
+ else
104
+ rm -f "$tmp_file"
105
+ log_info "所有套件都已安裝"
106
+ return 1
107
+ fi
108
+ }
109
+
110
+ provisioning_has_valid_hf_token() {
111
+ [[ -n "${HF_TOKEN:-}" ]] || return 1
112
+ local response
113
+ response=$(curl -o /dev/null -s -w "%{http_code}" -X GET "https://huggingface.co/api/whoami-v2" -H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json")
114
+ [ "$response" -eq 200 ]
115
+ }
116
+
117
+ provisioning_has_valid_civitai_token() {
118
+ [[ -n "${CIVITAI_TOKEN:-}" ]] || return 1
119
+ local response
120
+ response=$(curl -o /dev/null -s -w "%{http_code}" -X GET "https://civitai.com/api/v1/models?hidden=1&limit=1" -H "Authorization: Bearer $CIVITAI_TOKEN" -H "Content-Type: application/json")
121
+ [ "$response" -eq 200 ]
122
+ }
123
+
124
+ install_node() {
125
+ local repo_url="$1"
126
+ local repo_name
127
+ repo_name=$(basename "$repo_url" .git)
128
+ local install_path="${COMFYUI_DIR}/custom_nodes/${repo_name}"
129
+
130
+ if [ -d "$install_path" ]; then
131
+ if [[ "${AUTO_UPDATE:-true}" != "false" ]]; then
132
+ log_info "更新節點: $repo_name"
133
+ (cd "$install_path" && git pull -q 2>&1 | grep -v "Already up to date" || true)
134
+ else
135
+ log_info "'$repo_name' 已存在,跳過"
136
+ return
137
+ fi
138
+ else
139
+ log_info "克隆節點: $repo_name"
140
+ git clone --depth 1 --single-branch "$repo_url" "$install_path" -q 2>&1 || true
141
+ fi
142
+
143
+ if [ -f "$install_path/requirements.txt" ]; then
144
+ log_info "處理 $repo_name 的依賴..."
145
+ sed -i -e '/^torch/d' -e '/^sam2/d' "$install_path/requirements.txt" 2>/dev/null || true
146
+ if filter_requirements "$install_path/requirements.txt"; then
147
+ log_info "安裝 $repo_name 的新依賴..."
148
+ $PIP_BIN install -q --no-cache-dir -r "$install_path/requirements.txt" 2>&1 | grep -v "Requirement already satisfied" || log_warn "部分依賴安裝失敗"
149
+ fi
150
+ fi
151
+
152
+ if [ -f "$install_path/install.py" ]; then
153
+ log_info "運行 $repo_name 的安裝腳本..."
154
+ $PYTHON_BIN "$install_path/install.py" 2>&1 || log_warn "安裝腳本執行失敗"
155
+ fi
156
+ }
157
+
158
+ download_file() {
159
+ local dest_path="$1"
160
+ local url="$2"
161
+ local filename
162
+ filename=$(basename "$dest_path")
163
+ local tmp_path="${dest_path}.tmp"
164
+
165
+ mkdir -p "$(dirname "$dest_path")"
166
+ if [ -s "$dest_path" ]; then
167
+ log_info "檔案 '$filename' 已存在且完整,跳過下載"
168
+ return 0
169
+ fi
170
+
171
+ log_info "下載: $filename"
172
+ local max_retries=3
173
+ local attempt=0
174
+ local auth_header=""
175
+ local success=1
176
+
177
+ if [[ "$url" =~ huggingface\.co ]] && provisioning_has_valid_hf_token; then
178
+ auth_header="Authorization: Bearer $HF_TOKEN"
179
+ log_info "使用 HuggingFace Token"
180
+ elif [[ "$url" =~ civitai\.com ]] && provisioning_has_valid_civitai_token; then
181
+ auth_header="Authorization: Bearer $CIVITAI_TOKEN"
182
+ log_info "使用 CivitAI Token"
183
+ fi
184
+
185
+ while [ "$attempt" -lt "$max_retries" ]; do
186
+ attempt=$((attempt + 1))
187
+ [ "$attempt" -gt 1 ] && sleep 10
188
+ if command -v aria2c >/dev/null 2>&1; then
189
+ log_info "使用 aria2c (3 線程) 下載: $filename (嘗試 $attempt/$max_retries)"
190
+ local aria_opts=(--console-log-level=error -c -x 3 -s 3 -k 1M --max-connection-per-server=3 --max-tries=3 --retry-wait=5 --timeout=180 --file-allocation=falloc --auto-file-renaming=false -d "$(dirname "$dest_path")" -o "${filename}.tmp")
191
+ [[ -n "$auth_header" ]] && aria_opts+=(--header="$auth_header")
192
+ aria2c "${aria_opts[@]}" "$url"
193
+ if [ $? -eq 0 ]; then success=0; break; fi
194
+ else
195
+ log_info "使用 wget 下載: $filename (嘗試 $attempt/$max_retries)"
196
+ local wget_opts=(-O "$tmp_path" -c --timeout=60 --tries=3 --content-disposition --show-progress)
197
+ [[ -n "$auth_header" ]] && wget_opts+=(--header="$auth_header")
198
+ wget "${wget_opts[@]}" "$url"
199
+ if [ $? -eq 0 ]; then success=0; break; fi
200
+ fi
201
+ done
202
+
203
+ if [ "$success" -eq 0 ] && [ -s "$tmp_path" ]; then
204
+ mv "$tmp_path" "$dest_path"
205
+ log_success "下載完成: $filename"
206
+ return 0
207
+ else
208
+ log_error "下載失敗: $filename"
209
+ rm -f "$tmp_path"
210
+ return 1
211
+ fi
212
+ }
213
+
214
+ download_to_directory() {
215
+ local dest_dir="$1"; shift; local urls=("$@")
216
+ if [ ${#urls[@]} -eq 0 ]; then return 0; fi
217
+ mkdir -p "$dest_dir"
218
+ log_info "下載 ${#urls[@]} 個文件到 $dest_dir"
219
+ local MAX_PARALLEL=3
220
+ for url in "${urls[@]}"; do
221
+ while [ $(jobs -r | wc -l) -ge $MAX_PARALLEL ]; do sleep 1; done
222
+ local filename
223
+ filename=$(basename "$url" | sed 's/?.*//')
224
+ download_file "${dest_dir}/${filename}" "$url" &
225
+ done
226
+ wait
227
+ }
228
+
229
+ verify_and_retry_downloads() {
230
+ local dest_dir="$1"; shift; local urls=("$@")
231
+ if [ ${#urls[@]} -eq 0 ]; then return 0; fi
232
+ log_info "檢查 $dest_dir 中的文件..."
233
+ local missing_files=()
234
+ for url in "${urls[@]}"; do
235
+ local filename
236
+ filename=$(basename "$url" | sed 's/?.*//')
237
+ local dest_path="${dest_dir}/${filename}"
238
+ if [ ! -s "$dest_path" ]; then
239
+ log_warn "檔案缺失或不完整: $filename"
240
+ missing_files+=("$url")
241
+ fi
242
+ done
243
+ if [ ${#missing_files[@]} -gt 0 ]; then
244
+ log_warn "發現 ${#missing_files[@]} 個缺失/不完整文件,重新下載..."
245
+ download_to_directory "$dest_dir" "${missing_files[@]}"
246
+ else
247
+ log_success "所有文件已確認存在且完整"
248
+ fi
249
+ }
250
+
251
+ provisioning_print_header() {
252
+ echo ""; echo "##############################################"
253
+ echo "# #"
254
+ echo "# Provisioning Container #"
255
+ echo "# #"
256
+ echo "# This will take some time #"
257
+ echo "# #"
258
+ echo "##############################################"; echo ""
259
+ }
260
+
261
+ provisioning_print_end() {
262
+ echo ""; echo "##############################################"
263
+ echo "# #"
264
+ echo "# Provisioning Complete! #"
265
+ echo "# #"
266
+ echo "# Total time: $((END_TIME - START_TIME)) seconds #"
267
+ echo "# #"
268
+ echo "##############################################"; echo ""
269
+ }
270
+
271
+ provisioning_step1_install_core_deps() {
272
+ log_step "1" "安裝系統與 ComfyUI 核心依賴"
273
+ if [ ${#APT_PACKAGES[@]} -gt 0 ]; then
274
+ log_info "準備安裝 ${#APT_PACKAGES[@]} 個系統套件..."
275
+ local packages_to_install=()
276
+ for pkg in "${APT_PACKAGES[@]}"; do
277
+ if ! dpkg -s "$pkg" >/dev/null 2>&1; then
278
+ packages_to_install+=("$pkg")
279
+ else
280
+ log_success "$pkg 已安裝,跳過"
281
+ fi
282
+ done
283
+ if [ ${#packages_to_install[@]} -gt 0 ]; then
284
+ log_info "正在安裝: ${packages_to_install[*]}"
285
+ apt-get update -qq && apt-get install -y -qq "${packages_to_install[@]}" && log_success "系統套件安裝完成" || log_warn "部分系統套件安裝失敗"
286
+ fi
287
+ fi
288
+
289
+ local comfyui_req_file="${COMFYUI_DIR}/requirements.txt"
290
+ if [ -f "$comfyui_req_file" ]; then
291
+ log_info "處理 ComfyUI 核心依賴: $comfyui_req_file"
292
+ if filter_requirements "$comfyui_req_file"; then
293
+ log_info "安裝 ComfyUI 的新依賴..."
294
+ $PIP_BIN install -q --no-cache-dir -r "$comfyui_req_file" 2>&1 | grep -v "Requirement already satisfied" || log_warn "ComfyUI 部分核心依賴安裝失敗"
295
+ fi
296
+ else
297
+ log_warn "找不到 ComfyUI 的核心 requirements.txt 文件!"
298
+ fi
299
+ }
300
+
301
+ provisioning_step2_nodes() {
302
+ log_step "2" "安裝節點與額外套件"
303
+ if [ ${#NODES[@]} -gt 0 ]; then
304
+ cd "${COMFYUI_DIR}/custom_nodes" || exit 1
305
+ log_info "並行安裝 ${#NODES[@]} 個節點..."
306
+ local MAX_PARALLEL=2
307
+ for node in "${NODES[@]}"; do
308
+ while [ $(jobs -r | wc -l) -ge $MAX_PARALLEL ]; do sleep 1; done
309
+ install_node "$node" &
310
+ done
311
+ wait
312
+ log_success "節點安裝完成"
313
+ cd "${COMFYUI_DIR}" || exit 1
314
+ fi
315
+ }
316
+
317
+ provisioning_step3_downloads() {
318
+ log_step "3" "下載模型與工作流文件"
319
+ download_to_directory "${COMFYUI_DIR}/models/checkpoints" "${CHECKPOINT_MODELS[@]}"
320
+ download_to_directory "${COMFYUI_DIR}/models/clip_vision" "${CLIP_VISION_MODELS[@]}"
321
+ download_to_directory "${COMFYUI_DIR}/models/grounding-dino" "${DINO_MODELS[@]}"
322
+ download_to_directory "${COMFYUI_DIR}/models/ipadapter" "${IPADAPTER_MODELS[@]}"
323
+ download_to_directory "${COMFYUI_DIR}/models/loras" "${LORAS_MODELS[@]}"
324
+ download_to_directory "${COMFYUI_DIR}/models/RMBG/RMBG-2.0" "${RMBG_MODELS[@]}"
325
+ download_to_directory "${COMFYUI_DIR}/models/RMBG/segformer_fashion" "${FASHION_MODELS[@]}"
326
+ download_to_directory "${COMFYUI_DIR}/models/sam2" "${SAM2_MODELS[@]}"
327
+ download_to_directory "${COMFYUI_DIR}/models/sams" "${SAMS_MODELS[@]}"
328
+ download_to_directory "${COMFYUI_DIR}/models/ultralytics/bbox" "${BBOX_MODELS[@]}"
329
+ download_to_directory "${COMFYUI_DIR}/models/upscale_models" "${UPSCALE_MODELS[@]}"
330
+ if [ ${#WORKFLOWS[@]} -gt 0 ]; then
331
+ log_info "下載工作流文件..."
332
+ download_to_directory "${COMFYUI_DIR}/user/default/workflows" "${WORKFLOWS[@]}"
333
+ fi
334
+ }
335
+
336
+ if [ -f "/workspace/.provision_complete" ]; then
337
+ log_success "環境已配置,跳過重複執行"
338
+ log_info "如需重新配置,請刪除 /workspace/.provision_complete"
339
+ exit 0
340
+ fi
341
+ if [[ -f /.noprovisioning ]]; then
342
+ log_warn "檢測到 /.noprovisioning 文件,跳過配置"
343
+ exit 0
344
+ fi
345
+
346
+ START_TIME=$(date +%s)
347
+ provisioning_print_header
348
+ cd "${COMFYUI_DIR}" || exit 1
349
+
350
+ provisioning_step1_install_core_deps
351
+
352
+ provisioning_step2_nodes &
353
+ NODE_PID=$!
354
+ provisioning_step3_downloads
355
+ wait $NODE_PID
356
+
357
+ log_step "4" "驗證下載完整性"
358
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/checkpoints" "${CHECKPOINT_MODELS[@]}"
359
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/clip_vision" "${CLIP_VISION_MODELS[@]}"
360
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/grounding-dino" "${DINO_MODELS[@]}"
361
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/ipadapter" "${IPADAPTER_MODELS[@]}"
362
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/loras" "${LORAS_MODELS[@]}"
363
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/RMBG/RMBG-2.0" "${RMBG_MODELS[@]}"
364
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/RMBG/segformer_fashion" "${FASHION_MODELS[@]}"
365
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/sam2" "${SAM2_MODELS[@]}"
366
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/sams" "${SAMS_MODELS[@]}"
367
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/ultralytics/bbox" "${BBOX_MODELS[@]}"
368
+ verify_and_retry_downloads "${COMFYUI_DIR}/models/upscale_models" "${UPSCALE_MODELS[@]}"
369
+ verify_and_retry_downloads "${COMFYUI_DIR}/user/default/workflows" "${WORKFLOWS[@]}"
370
+
371
+ log_step "5" "完成配置"
372
+ touch "/workspace/.provision_complete"
373
+ log_success "配置標記文件已創建"
374
+
375
+ END_TIME=$(date +%s)
376
+ provisioning_print_end
377
+ log_success "所有配置步驟已完成!"
378
+ exit 0