adbrasi commited on
Commit
7e3c5a2
·
verified ·
1 Parent(s): a908f31

Upload wanForProduction4.sh

Browse files
Files changed (1) hide show
  1. wanForProduction4.sh +558 -0
wanForProduction4.sh ADDED
@@ -0,0 +1,558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # setup_comfyui_wan22.sh
3
+ # Script baseado no CODE1 com modelos/nodes do CODE2 e melhorias de robustez
4
+
5
+ set -euo pipefail
6
+
7
+ # Cores para output
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ BLUE='\033[0;34m'
12
+ NC='\033[0m'
13
+
14
+ log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
15
+ log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
16
+ log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
17
+ log_error() { echo -e "${RED}[✗]${NC} $1"; }
18
+
19
+ # Configuração
20
+ COMFY_DIR="${COMFY_DIR:-/root/comfy/ComfyUI}"
21
+ MODELS_DIR="$COMFY_DIR/models"
22
+ COMFY_HOST="${COMFY_HOST:-0.0.0.0}"
23
+ COMFY_PORT="${COMFY_PORT:-8818}"
24
+ CIVITAI_TOKEN="${CIVITAI_TOKEN:-}"
25
+ HF_TOKEN="${HF_TOKEN:-}"
26
+ VENV_DIR="${VENV_DIR:-/root/comfy/.venv}"
27
+
28
+ # Suprimir avisos do pip quando executado como root
29
+ export PIP_ROOT_USER_ACTION=ignore
30
+
31
+ # Performance
32
+ export MAX_JOBS="${MAX_JOBS:-32}"
33
+ export HF_HUB_ENABLE_HF_TRANSFER=1
34
+ export HF_TRANSFER_CONCURRENCY="${HF_TRANSFER_CONCURRENCY:-16}"
35
+ export NVCC_APPEND_FLAGS="${NVCC_APPEND_FLAGS:---threads 8}"
36
+ export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True"
37
+
38
+ PYTHON_BIN=""
39
+
40
+ # Lista de downloads (formato: URL|TIPO|NOME_OPCIONAL)
41
+ DOWNLOAD_FILES=(
42
+ "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/I2V/Wan2_2-I2V-A14B-LOW_fp8_e4m3fn_scaled_KJ.safetensors|diffusion_models|"
43
+ "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/I2V/Wan2_2-I2V-A14B-HIGH_fp8_e4m3fn_scaled_KJ.safetensors|diffusion_models|"
44
+ "https://huggingface.co/jrewingwannabe/Wan2.2-Lightning_I2V-A14B-4steps-lora/resolve/main/Wan2.2-Lightning_I2V-A14B-4steps-lora_HIGH_fp16.safetensors|loras|"
45
+ "https://huggingface.co/jrewingwannabe/Wan2.2-Lightning_I2V-A14B-4steps-lora/resolve/main/Wan2.2-Lightning_I2V-A14B-4steps-lora_LOW_fp16.safetensors|loras|"
46
+ "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/LoRAs/AniSora/Wan2_2_I2V_AniSora_3_2_HIGH_rank_64_fp16.safetensors|loras|"
47
+ "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/Wan2_1_VAE_bf16.safetensors|vae|"
48
+ "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/open-clip-xlm-roberta-large-vit-huge-14_visual_fp16.safetensors|clip_vision|"
49
+ "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/umt5-xxl-enc-bf16.safetensors|text_encoders|"
50
+ "https://huggingface.co/ABDALLALSWAITI/Upscalers/resolve/main/general/Swin2SR_ClassicalSR_X2_64.pth|upscale_models|"
51
+ "https://huggingface.co/adbrasi/download_models/resolve/main/22-nsfw-HIGH-e6.safetensors|loras|"
52
+ "https://huggingface.co/adbrasi/download_models/resolve/main/NSFW-22-H-e8.safetensors|loras|"
53
+ "https://huggingface.co/adbrasi/download_models/resolve/main/NSFW-22-L-e8.safetensors|loras|"
54
+ "https://huggingface.co/adbrasi/download_models/resolve/main/smoothLoopv2_000002450_high_noise.safetensors|loras|"
55
+ "https://huggingface.co/adbrasi/download_models/resolve/main/smoothLoopv2_000002450_low_noise.safetensors|loras|"
56
+ "https://huggingface.co/adbrasi/download_models/resolve/main/ultimate_sex_000006500_high_noise.safetensors|loras|"
57
+ "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/audio_encoders/wav2vec2_large_english_fp16.safetensors|audio_encoders|"
58
+ "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/InfiniteTalk/Wan2_1-InfiniteTalk-Single_fp8_e4m3fn_scaled_KJ.safetensors|diffusion_models|"
59
+ "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/clip_vision/clip_vision_h.safetensors|clip_vision|"
60
+ "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/I2V/Wan2_1-I2V-14B-720p_fp8_e4m3fn_scaled_KJ.safetensors|diffusion_models|"
61
+ "https://huggingface.co/adbrasi/download_models/resolve/main/ultimate_sex_000006500_low_noise.safetensors|loras|"
62
+ )
63
+
64
+ # Custom nodes (do CODE2)
65
+ CUSTOM_NODES=(
66
+ "https://github.com/kijai/ComfyUI-Florence2"
67
+ "https://github.com/adbrasi/groqrouter"
68
+ "https://github.com/kijai/ComfyUI-WanVideoWrapper"
69
+ "https://github.com/Fannovel16/ComfyUI-Frame-Interpolation"
70
+ "https://github.com/kijai/ComfyUI-GIMM-VFI"
71
+ "https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite"
72
+ "https://github.com/kijai/ComfyUI-KJNodes"
73
+ "https://github.com/Artificial-Sweetener/comfyui-WhiteRabbit"
74
+ "https://github.com/shiimizu/ComfyUI_smZNodes"
75
+ "https://github.com/CoreyCorza/ComfyUI-CRZnodes"
76
+ "https://github.com/pythongosssss/ComfyUI-Custom-Scripts"
77
+ "https://github.com/pythongosssss/ComfyUI-WD14-Tagger"
78
+ "https://github.com/WASasquatch/was-node-suite-comfyui"
79
+ "https://github.com/justUmen/Bjornulf_custom_nodes"
80
+ "https://github.com/mingsky-ai/ComfyUI-MingNodes"
81
+ "https://github.com/adbrasi/upavidito"
82
+ "https://github.com/wallish77/wlsh_nodes"
83
+ "https://github.com/raindrop313/ComfyUI-WanVideoStartEndFrames"
84
+ "https://github.com/MushroomFleet/DJZ-Nodes"
85
+ "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes"
86
+ "https://github.com/MoonGoblinDev/Civicomfy"
87
+ )
88
+
89
+ download_hf() {
90
+ local hf_path="$1"
91
+ local target_dir="$2"
92
+ local filename="$3"
93
+ local revision="${4:-}"
94
+
95
+ if [[ -z "$filename" ]]; then
96
+ filename="$(basename "${hf_path%%\?*}")"
97
+ fi
98
+
99
+ mkdir -p "$target_dir"
100
+ if [[ -f "$target_dir/$filename" ]]; then
101
+ local existing_size
102
+ existing_size=$(stat -c%s "$target_dir/$filename" 2>/dev/null || echo 0)
103
+ if [[ "$existing_size" -gt 1048576 ]]; then
104
+ log_success "Já existe: $filename"
105
+ return 0
106
+ fi
107
+ fi
108
+
109
+ local owner="${hf_path%%/*}"
110
+ local remainder="${hf_path#*/}"
111
+ if [[ "$owner" == "$hf_path" ]]; then
112
+ log_error "Caminho HuggingFace inválido: $hf_path"
113
+ return 1
114
+ fi
115
+
116
+ local repo_segment="${remainder%%/*}"
117
+ if [[ "$repo_segment" == "$remainder" ]]; then
118
+ log_error "Arquivo não especificado no caminho: $hf_path"
119
+ return 1
120
+ fi
121
+
122
+ remainder="${remainder#*/}"
123
+ if [[ -z "$remainder" ]]; then
124
+ log_error "Arquivo não especificado no caminho: $hf_path"
125
+ return 1
126
+ fi
127
+
128
+ if [[ "$repo_segment" == *@* ]]; then
129
+ if [[ -z "$revision" ]]; then
130
+ revision="${repo_segment#*@}"
131
+ fi
132
+ repo_segment="${repo_segment%@*}"
133
+ fi
134
+
135
+ local repo_id="$owner/$repo_segment"
136
+ local file_path="$remainder"
137
+ local attempt success temp_dir
138
+ for attempt in 1 2 3; do
139
+ temp_dir="$(mktemp -d)"
140
+ success=false
141
+
142
+ log_info "[HF] Tentativa $attempt/3: ${repo_id}/${file_path}${revision:+ @}${revision:+$revision}"
143
+
144
+ if command -v hf >/dev/null 2>&1; then
145
+ local hf_cmd=(hf download "$repo_id" "$file_path")
146
+ if [[ -n "$revision" ]]; then
147
+ hf_cmd+=(--revision "$revision")
148
+ fi
149
+ hf_cmd+=(--local-dir "$temp_dir" --quiet)
150
+ if [[ -n "$HF_TOKEN" ]]; then
151
+ hf_cmd+=(--token "$HF_TOKEN")
152
+ fi
153
+ if HF_HUB_ENABLE_HF_TRANSFER=1 "${hf_cmd[@]}"; then
154
+ success=true
155
+ fi
156
+ fi
157
+
158
+ if [[ "$success" == false ]]; then
159
+ local fallback_revision="${revision:-main}"
160
+ local direct_url="https://huggingface.co/${repo_id}/resolve/${fallback_revision}/${file_path}"
161
+ log_warn "[HF] Tentativa $attempt usando fallback HTTP"
162
+ if command -v aria2c >/dev/null 2>&1; then
163
+ local aria_cmd=(aria2c -c -s 16 -x 16 -k 1M --console-log-level=warn --summary-interval=10 --dir "$temp_dir" --out "$filename")
164
+ if [[ -n "$HF_TOKEN" ]]; then
165
+ aria_cmd+=(--header="Authorization: Bearer $HF_TOKEN")
166
+ fi
167
+ aria_cmd+=("$direct_url")
168
+ if "${aria_cmd[@]}"; then
169
+ success=true
170
+ fi
171
+ fi
172
+ if [[ "$success" == false ]] && command -v curl >/dev/null 2>&1; then
173
+ local curl_cmd=(curl -L -# -o "$temp_dir/$filename")
174
+ if [[ -n "$HF_TOKEN" ]]; then
175
+ curl_cmd+=(-H "Authorization: Bearer $HF_TOKEN")
176
+ fi
177
+ curl_cmd+=("$direct_url")
178
+ if "${curl_cmd[@]}"; then
179
+ success=true
180
+ fi
181
+ fi
182
+ if [[ "$success" == false ]] && command -v wget >/dev/null 2>&1; then
183
+ local wget_cmd=(wget -q --show-progress -c -O "$temp_dir/$filename")
184
+ if [[ -n "$HF_TOKEN" ]]; then
185
+ wget_cmd+=(--header="Authorization: Bearer $HF_TOKEN")
186
+ fi
187
+ wget_cmd+=("$direct_url")
188
+ if "${wget_cmd[@]}"; then
189
+ success=true
190
+ fi
191
+ fi
192
+ fi
193
+
194
+ if [[ "$success" == true ]]; then
195
+ local downloaded
196
+ downloaded="$(find "$temp_dir" -type f -name "$filename" -print -quit)"
197
+ if [[ -z "$downloaded" ]]; then
198
+ downloaded="$(find "$temp_dir" -type f -print -quit)"
199
+ fi
200
+ if [[ -n "$downloaded" ]]; then
201
+ mv "$downloaded" "$target_dir/$filename"
202
+ rm -rf "$temp_dir"
203
+ if [[ -s "$target_dir/$filename" ]]; then
204
+ log_success "Download concluído: $filename"
205
+ return 0
206
+ fi
207
+ log_warn "Arquivo vazio após download: $filename"
208
+ rm -f "$target_dir/$filename"
209
+ fi
210
+ fi
211
+
212
+ rm -rf "$temp_dir"
213
+ log_warn "Tentativa $attempt falhou para $filename"
214
+ sleep $((2 * attempt))
215
+ done
216
+
217
+ log_error "Falha ao baixar: $filename"
218
+ return 1
219
+ }
220
+
221
+
222
+ download_file() {
223
+ local url="$1"
224
+ local target_dir="$2"
225
+ local filename="$3"
226
+
227
+ if [[ "$url" == *"civitai.com/api/download"* ]] && [[ "$url" != *"token="* ]] && [[ -n "$CIVITAI_TOKEN" ]]; then
228
+ if [[ "$url" == *"?"* ]]; then
229
+ url="${url}&token=${CIVITAI_TOKEN}"
230
+ else
231
+ url="${url}?token=${CIVITAI_TOKEN}"
232
+ fi
233
+ fi
234
+ mkdir -p "$target_dir"
235
+
236
+ local final_name="$filename"
237
+ if [[ -z "$final_name" ]]; then
238
+ final_name="$(basename "${url%%\?*}")"
239
+ fi
240
+
241
+ if [[ -f "$target_dir/$final_name" ]]; then
242
+ local existing_size
243
+ existing_size=$(stat -c%s "$target_dir/$final_name" 2>/dev/null || echo 0)
244
+ if [[ "$existing_size" -gt 524288 ]]; then
245
+ log_success "Já existe: $final_name"
246
+ return 0
247
+ fi
248
+ fi
249
+
250
+ local attempt success
251
+ for attempt in 1 2 3; do
252
+ success=false
253
+ log_info "[DL] Tentativa $attempt/3: ${final_name}"
254
+ if command -v aria2c >/dev/null 2>&1; then
255
+ if aria2c -c -s 16 -x 16 -k 1M --console-log-level=warn --summary-interval=10 --dir "$target_dir" --out "$final_name" "$url"; then
256
+ success=true
257
+ fi
258
+ fi
259
+ if [[ "$success" == false ]] && command -v wget >/dev/null 2>&1; then
260
+ if wget -q --show-progress -c -O "$target_dir/$final_name" "$url"; then
261
+ success=true
262
+ fi
263
+ fi
264
+ if [[ "$success" == false ]] && command -v curl >/dev/null 2>&1; then
265
+ if curl -L -# -C - -o "$target_dir/$final_name" "$url"; then
266
+ success=true
267
+ fi
268
+ fi
269
+ if [[ "$success" == true ]]; then
270
+ if [[ -s "$target_dir/$final_name" ]]; then
271
+ log_success "Download concluído: $final_name"
272
+ return 0
273
+ fi
274
+ log_warn "Arquivo vazio após download: $final_name"
275
+ rm -f "$target_dir/$final_name"
276
+ fi
277
+ log_warn "Tentativa $attempt falhou para $final_name"
278
+ sleep $((2 * attempt))
279
+ done
280
+
281
+ log_error "Falha ao baixar: $final_name"
282
+ return 1
283
+ }
284
+
285
+ download_mega() {
286
+ local url="$1"
287
+ local target_dir="$2"
288
+
289
+ url="${url#mega://}"
290
+ mkdir -p "$target_dir"
291
+
292
+ if ! command -v megadl >/dev/null 2>&1; then
293
+ log_warn "megadl não encontrado; tente instalar megatools manualmente"
294
+ return 1
295
+ fi
296
+
297
+ local attempt
298
+ for attempt in 1 2 3; do
299
+ log_info "[MEGA] Tentativa $attempt/3"
300
+ local temp_dir
301
+ temp_dir="$(mktemp -d)"
302
+ if megadl --limit-speed 0 --path "$temp_dir" "$url"; then
303
+ local moved=0
304
+ while IFS= read -r -d '' file; do
305
+ if [[ ! -f "$file" ]]; then
306
+ continue
307
+ fi
308
+ local base
309
+ base="$(basename "$file")"
310
+ if [[ -f "$target_dir/$base" ]]; then
311
+ log_success "Já existe: $base"
312
+ else
313
+ if mv "$file" "$target_dir/$base"; then
314
+ log_success "Download Mega.nz concluído: $base"
315
+ else
316
+ log_warn "Falha ao mover $base para destino final"
317
+ continue
318
+ fi
319
+ fi
320
+ moved=1
321
+ done < <(find "$temp_dir" -type f -print0)
322
+
323
+ rm -rf "$temp_dir"
324
+ if (( moved )); then
325
+ return 0
326
+ fi
327
+ log_warn "[MEGA] Nenhum arquivo detectado após download"
328
+ sleep $((2 * attempt))
329
+ else
330
+ log_warn "Tentativa $attempt falhou para Mega.nz"
331
+ rm -rf "$temp_dir"
332
+ sleep $((2 * attempt))
333
+ fi
334
+ done
335
+
336
+ log_error "Falha ao baixar de Mega.nz: $url"
337
+ return 1
338
+ }
339
+
340
+
341
+
342
+ process_downloads() {
343
+ local failed=0
344
+ for entry in "${DOWNLOAD_FILES[@]}"; do
345
+ IFS='|' read -r raw_url type filename <<< "$entry"
346
+ local target_dir="$MODELS_DIR/$type"
347
+ mkdir -p "$target_dir"
348
+
349
+ if [[ "$raw_url" == mega://* ]]; then
350
+ if ! download_mega "$raw_url" "$target_dir"; then
351
+ ((failed++))
352
+ fi
353
+ elif [[ "$raw_url" == hf://* ]]; then
354
+ local hf_path="${raw_url#hf://}"
355
+ if ! download_hf "$hf_path" "$target_dir" "$filename"; then
356
+ ((failed++))
357
+ fi
358
+ elif [[ "$raw_url" == https://huggingface.co/* ]]; then
359
+ local sanitized_url="${raw_url%%\?*}"
360
+ local hf_relative="${sanitized_url#https://huggingface.co/}"
361
+ IFS='/' read -ra hf_parts <<< "$hf_relative"
362
+ if (( ${#hf_parts[@]} >= 4 )) && [[ "${hf_parts[2]}" == "resolve" || "${hf_parts[2]}" == "blob" || "${hf_parts[2]}" == "raw" ]]; then
363
+ local hf_owner="${hf_parts[0]}"
364
+ local hf_repo="${hf_parts[1]}"
365
+ local hf_revision="${hf_parts[3]}"
366
+ local start_index=4
367
+ local hf_file_path=""
368
+ for ((i=start_index; i<${#hf_parts[@]}; i++)); do
369
+ if [[ -n "$hf_file_path" ]]; then
370
+ hf_file_path+='/'
371
+ fi
372
+ hf_file_path+="${hf_parts[i]}"
373
+ done
374
+ if [[ -n "$hf_file_path" ]]; then
375
+ local hf_path_combined="${hf_owner}/${hf_repo}/${hf_file_path}"
376
+ if ! download_hf "$hf_path_combined" "$target_dir" "$filename" "$hf_revision"; then
377
+ ((failed++))
378
+ fi
379
+ else
380
+ if ! download_file "$raw_url" "$target_dir" "$filename"; then
381
+ ((failed++))
382
+ fi
383
+ fi
384
+ else
385
+ if ! download_file "$raw_url" "$target_dir" "$filename"; then
386
+ ((failed++))
387
+ fi
388
+ fi
389
+ else
390
+ if ! download_file "$raw_url" "$target_dir" "$filename"; then
391
+ ((failed++))
392
+ fi
393
+ fi
394
+ done
395
+
396
+ if (( failed > 0 )); then
397
+ return 1
398
+ fi
399
+ return 0
400
+ }
401
+
402
+ clone_repo() {
403
+ local url="$1"
404
+ local dest="$2"
405
+
406
+ local name
407
+ name="$(basename "$dest")"
408
+
409
+ if [[ -d "$dest/.git" ]]; then
410
+ if ! git -C "$dest" pull --ff-only --no-rebase >/dev/null 2>&1; then
411
+ log_warn "Falha ao atualizar $name"
412
+ else
413
+ log_success "Atualizado: $name"
414
+ fi
415
+ else
416
+ if ! git clone --depth 1 "$url" "$dest" >/dev/null 2>&1; then
417
+ log_warn "Falha ao clonar $name"
418
+ return
419
+ fi
420
+ log_success "Clonado: $name"
421
+ fi
422
+
423
+ if [[ -f "$dest/requirements.txt" ]]; then
424
+ if [[ -n "$PYTHON_BIN" ]]; then
425
+ if ! "$PYTHON_BIN" -m pip install -q -r "$dest/requirements.txt" >/dev/null 2>&1; then
426
+ log_warn "Falha ao instalar requirements de $name"
427
+ else
428
+ log_info "Dependências instaladas para $name"
429
+ fi
430
+ else
431
+ log_warn "PYTHON_BIN não definido; pulei requirements de $name"
432
+ fi
433
+ fi
434
+ }
435
+
436
+ # ========== INSTALAÇÃO ==========
437
+ log_info "========================================="
438
+ log_info " ComfyUI + Wan 2.2 Setup"
439
+ log_info "========================================="
440
+
441
+ # 1. Dependências
442
+ log_info "[1/7] Instalando dependências do sistema..."
443
+ if command -v apt-get >/dev/null 2>&1; then
444
+ apt-get update -qq || log_warn "apt-get update falhou; seguindo assim mesmo"
445
+ apt-get install -y -qq python3-venv aria2 megatools git wget curl || log_warn "apt-get install retornou erro"
446
+ else
447
+ log_warn "apt-get indisponível; certifique-se de que python3-venv, aria2, megatools, git, wget e curl estão instalados"
448
+ fi
449
+ log_success "Dependências do sistema tratadas"
450
+
451
+ # 2. Preparar ambiente virtual
452
+ log_info "[2/7] Preparando ambiente virtual..."
453
+ if [[ ! -d "$VENV_DIR/bin" ]]; then
454
+ python3 -m venv "$VENV_DIR"
455
+ log_success "Ambiente virtual criado em $VENV_DIR"
456
+ else
457
+ log_info "Ambiente virtual já existe em $VENV_DIR"
458
+ fi
459
+ . "$VENV_DIR/bin/activate"
460
+ PYTHON_BIN="$VENV_DIR/bin/python"
461
+
462
+ "$PYTHON_BIN" -m pip install -U pip wheel setuptools -q || log_warn "Falha na atualização do pip"
463
+ "$PYTHON_BIN" -m pip install -U "huggingface_hub[cli,hf_transfer]" comfy-cli -q || log_warn "Falha instalando huggingface_hub/comfy-cli"
464
+ log_success "Ambiente virtual pronto e comfy-cli instalado"
465
+
466
+ # 3. Instalar ComfyUI
467
+ log_info "[3/7] Instalando ComfyUI..."
468
+ if [[ -f "$COMFY_DIR/main.py" ]]; then
469
+ log_warn "ComfyUI já presente"
470
+ else
471
+ comfy --skip-prompt install --fast-deps --nvidia || log_error "Instalação do ComfyUI falhou"
472
+ fi
473
+
474
+ REQ_FILE="$COMFY_DIR/requirements.txt"
475
+ if [[ -f "$REQ_FILE" ]]; then
476
+ log_info "Verificando dependências do ComfyUI em: $REQ_FILE"
477
+ if [[ -n "$PYTHON_BIN" ]]; then
478
+ if "$PYTHON_BIN" -m pip install -q -r "$REQ_FILE"; then
479
+ log_success "Requirements do ComfyUI instalados/validados"
480
+ else
481
+ log_warn "Falha ao instalar requirements do ComfyUI; verifique o log acima e reexecute se necessário"
482
+ fi
483
+ else
484
+ log_warn "PYTHON_BIN não definido; pulei requirements do ComfyUI"
485
+ fi
486
+ else
487
+ log_warn "requirements.txt do ComfyUI não encontrado em $REQ_FILE"
488
+ fi
489
+
490
+ log_success "ComfyUI pronto"
491
+
492
+ # 4. Instalar PyTorch (CUDA 12.8)
493
+ log_info "[4/7] Instalando PyTorch CUDA 12.8..."
494
+ "$PYTHON_BIN" -m pip install --force --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128 || log_error "Falha ao instalar PyTorch"
495
+ log_success "PyTorch configurado"
496
+
497
+ # 5. Instalar SageAttention (condicional)
498
+ log_info "[5/7] Instalando SageAttention..."
499
+ if "$PYTHON_BIN" - <<'PY' >/dev/null 2>&1
500
+ import torch, sys
501
+ sys.exit(0 if torch.cuda.is_available() else 1)
502
+ PY
503
+ then
504
+ if "$PYTHON_BIN" -m pip install "https://huggingface.co/adbrasi/comfywheel/resolve/main/sageattention-2.2.0-cp312-cp312-linux_x86_64.whl" -q; then
505
+ if "$PYTHON_BIN" - <<'PY' >/dev/null 2>&1
506
+ import sageattention
507
+ PY
508
+ then
509
+ log_success "SageAttention instalado"
510
+ else
511
+ log_warn "SageAttention instalado, mas não pôde ser importado"
512
+ fi
513
+ else
514
+ log_warn "Falha ao instalar SageAttention"
515
+ fi
516
+ else
517
+ log_warn "CUDA indisponível; pulando SageAttention"
518
+ fi
519
+
520
+ # 6. Downloads de modelos
521
+ log_info "[6/7] Baixando modelos..."
522
+ mkdir -p "$MODELS_DIR"
523
+ if process_downloads; then
524
+ log_success "Downloads concluídos (ou já presentes)"
525
+ else
526
+ log_warn "Alguns downloads falharam; reexecute o script para tentar novamente"
527
+ fi
528
+
529
+ # 7. Custom nodes
530
+ log_info "[7/7] Instalando custom nodes..."
531
+ CN_DIR="$COMFY_DIR/custom_nodes"
532
+ mkdir -p "$CN_DIR"
533
+ node_total=${#CUSTOM_NODES[@]}
534
+ node_index=0
535
+ set +e
536
+ for repo in "${CUSTOM_NODES[@]}"; do
537
+ ((node_index++))
538
+ log_info "[$node_index/$node_total] $(basename "$repo")"
539
+ clone_repo "$repo" "$CN_DIR/$(basename "$repo")"
540
+ done
541
+ set -e
542
+ log_success "Custom nodes processados"
543
+
544
+
545
+ SAGE_FLAG=""
546
+ if "$PYTHON_BIN" - <<'PY' >/dev/null 2>&1
547
+ import sageattention
548
+ PY
549
+ then
550
+ SAGE_FLAG="--use-sage-attention"
551
+ fi
552
+
553
+ log_info "========================================="
554
+ log_info "Iniciando ComfyUI em http://${COMFY_HOST}:${COMFY_PORT}"
555
+ log_info "========================================="
556
+
557
+ cd "$COMFY_DIR"
558
+ exec comfy launch -- ${SAGE_FLAG:+$SAGE_FLAG} --listen "$COMFY_HOST" --port "$COMFY_PORT"