adbrasi commited on
Commit
4b5e9d4
·
verified ·
1 Parent(s): bdf866c

Upload wanForProduction3.sh

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