adbrasi commited on
Commit
c638b48
·
verified ·
1 Parent(s): 7d8c0d0

Update image_Studio.sh

Browse files
Files changed (1) hide show
  1. image_Studio.sh +411 -650
image_Studio.sh CHANGED
@@ -1,49 +1,42 @@
1
  #!/usr/bin/env bash
2
- # setup_comfyui_custom_v2.sh
3
- # Script otimizado com suporte para RTX 5090, estado persistente e downloads do Mega
4
 
5
  set -euo pipefail
6
 
7
- # Detectar se está rodando via pipe (não-interativo)
8
- if [ ! -t 0 ] || [ ! -t 1 ]; then
9
- INTERACTIVE=false
10
- else
11
- INTERACTIVE=true
12
- fi
13
-
14
- # -----------------------------
15
- # Cores para output
16
- # -----------------------------
17
- RED='\033[0;31m'
18
- GREEN='\033[0;32m'
19
- YELLOW='\033[1;33m'
20
- BLUE='\033[0;34m'
21
- CYAN='\033[0;36m'
22
- NC='\033[0m'
23
 
 
 
 
 
24
  log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
25
  log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
26
  log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
27
  log_error() { echo -e "${RED}[✗]${NC} $1"; }
28
  log_progress() { echo -e "${CYAN}[→]${NC} $1"; }
29
 
30
- # -----------------------------
31
- # Configuração
32
- # -----------------------------
33
  COMFY_DIR="/root/comfy/ComfyUI"
34
  MODELS_DIR="$COMFY_DIR/models"
35
  COMFY_HOST="${COMFY_HOST:-0.0.0.0}"
36
  COMFY_PORT="${COMFY_PORT:-8818}"
 
 
37
  CIVITAI_TOKEN="${CIVITAI_TOKEN:-4fcb2834969399006a736ee402b061e5}"
38
  HF_TOKEN="${HF_TOKEN:-}"
39
 
40
- # Diretório para salvar estado
41
  STATE_DIR="/root/.comfyui_setup_state"
42
  STATE_FILE="$STATE_DIR/installation_state.txt"
43
  COMPLETED_DOWNLOADS="$STATE_DIR/completed_downloads.txt"
44
  COMPLETED_NODES="$STATE_DIR/completed_nodes.txt"
45
 
46
- # Configurações de performance
47
  export MAX_JOBS=32
48
  export NVCC_APPEND_FLAGS="--threads 8"
49
  export UV_SYSTEM_PYTHON=1
@@ -51,678 +44,446 @@ export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True"
51
  export HF_HUB_ENABLE_HF_TRANSFER=1
52
  export HF_TRANSFER_CONCURRENCY=16
53
  export EXT_PARALLEL=4
 
54
 
55
- # -----------------------------
56
- # Sistema de Estado Persistente
57
- # -----------------------------
58
- init_state() {
59
- mkdir -p "$STATE_DIR"
60
- touch "$STATE_FILE" "$COMPLETED_DOWNLOADS" "$COMPLETED_NODES"
61
- }
62
 
63
- save_state() {
64
- local step="$1"
65
- echo "$step" > "$STATE_FILE"
66
- log_info "Estado salvo: $step"
67
- }
 
 
68
 
69
- get_state() {
70
- if [ -f "$STATE_FILE" ]; then
71
- local state=$(cat "$STATE_FILE" 2>/dev/null)
72
- # Verificar se é um número válido
73
- if [[ "$state" =~ ^[0-9]+$ ]]; then
74
- echo "$state"
75
- else
76
- echo "0"
77
- fi
78
- else
79
- echo "0"
80
- fi
81
  }
 
 
 
 
82
 
83
- mark_download_complete() {
84
- local url="$1"
85
- echo "$url" >> "$COMPLETED_DOWNLOADS"
86
- }
 
87
 
88
- is_download_complete() {
89
- local url="$1"
90
- grep -Fxq "$url" "$COMPLETED_DOWNLOADS" 2>/dev/null
91
- }
92
 
93
- mark_node_complete() {
94
- local node="$1"
95
- echo "$node" >> "$COMPLETED_NODES"
96
- }
97
-
98
- is_node_complete() {
99
- local node="$1"
100
- grep -Fxq "$node" "$COMPLETED_NODES" 2>/dev/null
101
- }
102
 
103
- reset_state() {
104
- log_warn "Resetando estado da instalação..."
105
- rm -rf "$STATE_DIR"
106
- init_state
107
- }
 
108
 
109
- # -----------------------------
110
- # Lista de downloads (ATUALIZADA - sem ControlNet)
111
- # -----------------------------
112
- readonly DOWNLOAD_FILES=(
113
- # LoRA from Mega (PRIMEIRO para falhar rápido se houver problema)
114
- "mega://https://mega.nz/file/gIRTFQSQ#no6Ay3JLE9LVRi7ib9O-Jc0CW7XmG046kCgpCzDg1tY|loras|"
115
-
116
- # Checkpoint mantido
117
- "https://civitai.com/api/download/models/2122278?type=Model&format=SafeTensor&size=pruned&fp=fp16|checkpoints|raehoshiIllustXL_v60.safetensors"
118
-
119
- # LoRAs from Civitai
120
- "https://civitai.com/api/download/models/1268294?type=Model&format=SafeTensor|loras|"
121
- "https://civitai.com/api/download/models/1715330?type=Model&format=SafeTensor|loras|"
122
- "https://civitai.com/api/download/models/1499397?type=Model&format=SafeTensor|loras|"
123
- "https://civitai.com/api/download/models/1779002?type=Model&format=SafeTensor|loras|"
124
- "https://civitai.com/api/download/models/1114313?type=Model&format=SafeTensor|loras|"
125
- "https://civitai.com/api/download/models/1780244?type=Model&format=SafeTensor|loras|"
126
-
127
- # Upscale models - Coleção completa
128
- "https://huggingface.co/Kim2091/AnimeSharp/resolve/main/4x-AnimeSharp.pth|upscale_models|4x-AnimeSharp.pth"
129
- "https://huggingface.co/Kim2091/AnimeSharpV3/resolve/main/2x-AnimeSharpV3.pth|upscale_models|2x-AnimeSharpV3.pth"
130
- "https://huggingface.co/ABDALLALSWAITI/Upscalers/resolve/main/anime/2x-AnimeSharpV2_MoSR_Soft.pth|upscale_models|2x-AnimeSharpV2_MoSR_Soft.pth"
131
- "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2.pth|upscale_models|4x-UltraSharpV2.pth"
132
- "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2_Lite.pth|upscale_models|4x-UltraSharpV2_Lite.pth"
133
- "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2_fp32_op17.onnx|upscale_models|4x-UltraSharpV2_fp32_op17.onnx"
134
-
135
- # Ultralytics model
136
- "https://huggingface.co/adbrasi/testedownload/resolve/main/99coins_anime_girl_face_m_seg.pt|ultralytics/bbox|99coins_anime_girl_face_m_seg.pt"
137
  )
138
 
139
- # Custom nodes para instalar (ATUALIZADA com novos nodes)
140
  readonly CUSTOM_NODES=(
141
- "https://github.com/adbrasi/huggpackreator"
142
- "https://github.com/adbrasi/packreator_processor"
143
- "https://github.com/adbrasi/Packreator_manager"
144
- "https://github.com/adbrasi/cezarsave34"
145
- "https://github.com/adbrasi/pageonetor"
146
- "https://github.com/adbrasi/pakreatorio"
147
- "https://github.com/adbrasi/WaterMark_bumbumzin"
148
- "https://github.com/adbrasi/marcadaguita"
149
- "https://github.com/adbrasi/randomico"
150
- "https://github.com/adbrasi/groqrouter"
151
- "https://github.com/adbrasi/find_charakito"
152
- "https://github.com/adbrasi/randomsizito"
153
- "https://github.com/adbrasi/importex"
154
- "https://github.com/adbrasi/storitadifusita"
155
- "https://github.com/adbrasi/attentionPPM"
156
- "https://github.com/ClownsharkBatwing/RES4LYF"
157
- "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes"
158
- "https://github.com/sipherxyz/comfyui-art-venture"
159
- "https://github.com/pamparamm/sd-perturbed-attention"
160
- "https://github.com/KoreTeknology/ComfyUI-Universal-Styler"
161
- "https://github.com/WASasquatch/was-node-suite-comfyui"
162
- "https://github.com/chflame163/ComfyUI_LayerStyle"
163
- "https://github.com/ltdrdata/ComfyUI-Impact-Pack"
164
- "https://github.com/pythongosssss/ComfyUI-Custom-Scripts"
165
- "https://github.com/rgthree/rgthree-comfy"
166
- "https://github.com/ssitu/ComfyUI_UltimateSDUpscale"
167
- "https://github.com/adbrasi/Importador"
168
- "https://github.com/adbrasi/GetFirstTag"
169
- "https://github.com/adbrasi/comfydodi"
170
- "https://github.com/omar92/ComfyUI-QualityOfLifeSuit_Omar92"
171
- "https://github.com/Cezarsaint/blacklisto"
172
- "https://github.com/TinyTerra/ComfyUI_tinyterraNodes"
173
- "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
174
- "https://github.com/Cezarsaint/rand0micoUploaderLoven"
175
- "https://github.com/adbrasi/pixivmosaic"
176
- "https://github.com/adbrasi/futfilter"
177
- "https://github.com/Artificial-Sweetener/comfyui-WhiteRabbit"
178
- "https://github.com/shiimizu/ComfyUI_smZNodes"
179
- "https://github.com/CoreyCorza/ComfyUI-CRZnodes"
180
  )
181
 
182
- # Custom nodes que precisam de instalação especial via comfy-cli
183
- readonly SPECIAL_NODES=(
184
- "Civicomfy"
185
- "ComfyUI-RMBG"
186
- )
187
 
188
- # -----------------------------
189
- # Funções auxiliares
190
- # -----------------------------
191
- command_exists() {
192
- command -v "$1" >/dev/null 2>&1
 
 
 
 
 
 
193
  }
194
 
195
- # Instalar megatools se necessário
196
- install_megatools() {
197
- if ! command_exists megadl; then
198
- log_info "Instalando megatools para downloads do Mega..."
199
- apt-get update -qq && apt-get install -y -qq megatools 2>/dev/null
200
- if command_exists megadl; then
201
- log_success "Megatools instalado com sucesso"
202
- else
203
- log_warn "Falha ao instalar megatools, downloads do Mega não estarão disponíveis"
204
- fi
205
- fi
206
  }
207
 
208
- # Download do Mega
209
- download_mega() {
210
- local url="$1"
211
- local target_dir="$2"
212
- local filename="$3"
213
-
214
- if ! command_exists megadl; then
215
- log_error "megatools não instalado"
216
- return 1
217
- fi
218
-
219
- # Remover prefixo mega:// se houver
220
- url="${url#mega://}"
221
-
222
- log_info "Executando: megadl '$url'"
223
-
224
- # Usar megadl com timeout
225
- cd "$target_dir"
226
- if timeout 300 megadl "$url"; then
227
- log_success "Download do Mega concluído"
228
- cd - >/dev/null
229
- return 0
230
- else
231
- log_error "Mega falhou ou timeout (5 min)"
232
- cd - >/dev/null
233
- return 1
234
- fi
 
 
 
235
  }
236
 
237
- # Adicionar token do Civitai se necessário
238
- add_civitai_token() {
239
- local url="$1"
240
- if [[ "$url" == *"civitai.com/api/download"* ]] && [[ "$url" != *"token="* ]]; then
241
- echo "${url}&token=${CIVITAI_TOKEN}"
242
- else
243
- echo "$url"
244
- fi
245
  }
246
 
247
- # Download HuggingFace usando hf com hf_transfer
248
- download_hf() {
249
- local repo="$1"
250
- local file_path="$2"
251
- local target_dir="$3"
252
- local filename="$4"
253
-
254
- if [ -z "$filename" ]; then
255
- filename=$(basename "$file_path")
256
- fi
257
-
258
- local target_file="$target_dir/$filename"
259
-
260
- if [ -f "$target_file" ] && [ $(stat -c%s "$target_file" 2>/dev/null || echo 0) -gt 1000000 ]; then
261
- log_success "Arquivo já existe: $filename"
262
- return 0
263
- fi
264
-
265
- log_info "Baixando de HF: $filename"
266
-
267
- local temp_dir=$(mktemp -d)
268
- local download_success=false
269
-
270
- if command_exists hf; then
271
- if HF_HUB_ENABLE_HF_TRANSFER=1 hf download "$repo" "$file_path" \
272
- --local-dir "$temp_dir" \
273
- --local-dir-use-symlinks False 2>/dev/null; then
274
- download_success=true
275
- fi
276
- fi
277
-
278
- if [ "$download_success" = false ] && command_exists huggingface-cli; then
279
- log_warn "Tentando com huggingface-cli..."
280
- if HF_HUB_ENABLE_HF_TRANSFER=1 huggingface-cli download "$repo" "$file_path" \
281
- --local-dir "$temp_dir" \
282
- --local-dir-use-symlinks False 2>/dev/null; then
283
- download_success=true
284
- fi
285
- fi
286
-
287
- if [ "$download_success" = true ]; then
288
- local downloaded_file=$(find "$temp_dir" -type f \( -name "*.safetensors" -o -name "*.pth" -o -name "*.pt" -o -name "*.bin" -o -name "*.onnx" \) 2>/dev/null | head -1)
289
-
290
- if [ -n "$downloaded_file" ]; then
291
- mv "$downloaded_file" "$target_file"
292
- rm -rf "$temp_dir"
293
- log_success "Download concluído: $filename"
294
- return 0
295
- fi
296
- fi
297
-
298
- rm -rf "$temp_dir"
299
- log_error "Falha ao baixar: $filename"
300
- return 1
301
  }
302
 
303
- # Download genérico com aria2c, wget ou curl
304
- download_file() {
305
- local url="$1"
306
- local target_dir="$2"
307
- local filename="$3"
308
-
309
- url=$(add_civitai_token "$url")
310
-
311
- if [ -n "$filename" ] && [ -f "$target_dir/$filename" ] && [ $(stat -c%s "$target_dir/$filename" 2>/dev/null || echo 0) -gt 1000000 ]; then
312
- log_success "Arquivo já existe: $filename"
313
- return 0
314
- fi
315
-
316
- log_info "Baixando: ${filename:-$(basename "$url" | cut -d'?' -f1)}"
317
-
318
- if command_exists aria2c; then
319
- local aria_opts="-c -s 16 -x 16 -k 1M --console-log-level=warn --summary-interval=10"
320
- if [ -n "$filename" ]; then
321
- aria2c $aria_opts --dir="$target_dir" --out="$filename" "$url" && return 0
322
- else
323
- aria2c $aria_opts --dir="$target_dir" "$url" && return 0
324
- fi
325
- fi
326
-
327
- if command_exists wget; then
328
- if [ -n "$filename" ]; then
329
- wget -q --show-progress -c -O "$target_dir/$filename" "$url" && return 0
330
- else
331
- wget -q --show-progress -c --content-disposition -P "$target_dir" "$url" && return 0
332
- fi
333
  fi
334
-
335
- if command_exists curl; then
336
- if [ -n "$filename" ]; then
337
- curl -L -# -C - -o "$target_dir/$filename" "$url" && return 0
338
- else
339
- local headers=$(curl -sI -L "$url")
340
- local detected_name=$(echo "$headers" | grep -i "content-disposition" | sed -n 's/.*filename="\([^"]*\)".*/\1/p' | tr -d '\r')
341
- if [ -z "$detected_name" ]; then
342
- detected_name="downloaded_$(date +%s).safetensors"
343
- fi
344
- curl -L -# -C - -o "$target_dir/$detected_name" "$url" && return 0
345
- fi
346
  fi
347
-
348
- log_error "Falha ao baixar: $url"
349
- return 1
350
- }
351
 
352
- # Processar lista de downloads
353
- process_downloads() {
354
- local total=${#DOWNLOAD_FILES[@]}
355
- local current=0
356
- local failed_count=0
357
-
358
- log_info "Total de downloads: $total"
359
- log_info "Iniciando loop de downloads..."
360
-
361
- for entry in "${DOWNLOAD_FILES[@]}"; do
362
- ((current++))
363
-
364
- log_info "[$current/$total] Processando entrada..."
365
-
366
- # Verificar se já foi baixado
367
- if is_download_complete "$entry"; then
368
- log_success "[$current/$total] Já baixado, pulando..."
369
- continue
370
- fi
371
-
372
- log_info "[$current/$total] Preparando download..."
373
-
374
- IFS='|' read -r url type filename <<< "$entry"
375
-
376
- # Limpar espaços
377
- url=$(echo "$url" | xargs)
378
- type=$(echo "$type" | xargs)
379
- filename=$(echo "$filename" | xargs)
380
-
381
- log_info "[$current/$total] URL: ${url:0:60}..."
382
- log_info "[$current/$total] Tipo: $type"
383
-
384
- # Determinar diretório de destino
385
- local target_dir="$MODELS_DIR"
386
- case "$type" in
387
- checkpoints) target_dir="$MODELS_DIR/checkpoints" ;;
388
- diffusion_models) target_dir="$MODELS_DIR/diffusion_models" ;;
389
- loras) target_dir="$MODELS_DIR/loras" ;;
390
- vae) target_dir="$MODELS_DIR/vae" ;;
391
- vae_approx) target_dir="$MODELS_DIR/vae_approx" ;;
392
- text_encoders) target_dir="$MODELS_DIR/text_encoders" ;;
393
- clip_vision) target_dir="$MODELS_DIR/clip_vision" ;;
394
- upscale_models) target_dir="$MODELS_DIR/upscale_models" ;;
395
- ultralytics/bbox) target_dir="$MODELS_DIR/ultralytics/bbox" ;;
396
- *) target_dir="$MODELS_DIR/$type" ;;
397
- esac
398
-
399
- mkdir -p "$target_dir"
400
-
401
- # Executar download apropriado
402
- local download_result=1
403
-
404
- if [[ "$url" == mega://* ]]; then
405
- log_info "[$current/$total] Download do Mega..."
406
- download_mega "$url" "$target_dir" "$filename" && download_result=0
407
- elif [[ "$url" == hf://* ]]; then
408
- log_info "[$current/$total] Download HuggingFace..."
409
- url="${url#hf://}"
410
- local repo=$(echo "$url" | cut -d'/' -f1-2)
411
- local file_path=$(echo "$url" | cut -d'/' -f3-)
412
- download_hf "$repo" "$file_path" "$target_dir" "$filename" && download_result=0
413
- else
414
- log_info "[$current/$total] Download HTTP..."
415
- download_file "$url" "$target_dir" "$filename" && download_result=0
416
- fi
417
-
418
- if [ $download_result -eq 0 ]; then
419
- mark_download_complete "$entry"
420
- else
421
- ((failed_count++))
422
- log_warn "Falhou, continuando..."
423
- fi
424
- done
425
-
426
- if [ $failed_count -gt 0 ]; then
427
- log_warn "Downloads completos: $((total - failed_count))/$total (${failed_count} falharam)"
428
  else
429
- log_success "Todos os $total downloads completados!"
430
  fi
431
-
432
- return 0
 
 
433
  }
434
 
435
- # Clonar ou atualizar repositório git
436
- clone_or_update() {
437
- local url="$1"
438
- local dest="$2"
439
- local node_name=$(basename "$dest")
440
-
441
- if is_node_complete "$url"; then
442
- log_success "Node já instalado: $node_name"
443
- return 0
 
 
 
 
 
444
  fi
445
-
446
- if [ -d "$dest/.git" ]; then
447
- log_info "Atualizando $node_name..."
448
- timeout 60 git -C "$dest" pull --ff-only 2>/dev/null || {
449
- log_warn "Timeout ou erro ao atualizar $node_name"
450
- return 0
451
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  else
453
- log_info "Clonando $node_name..."
454
- timeout 60 git clone --recursive --depth 1 "$url" "$dest" 2>/dev/null || {
455
- log_warn "Falha ao clonar $node_name"
456
- return 0
457
- }
458
  fi
459
-
460
- if [ -f "$dest/requirements.txt" ]; then
461
- timeout 120 python3 -m pip install --no-warn-script-location -q -r "$dest/requirements.txt" 2>/dev/null || {
462
- log_warn "Falha ao instalar requirements para $node_name"
463
- }
464
  fi
465
-
466
- mark_node_complete "$url"
467
- return 0
 
 
 
 
 
468
  }
469
 
 
 
 
470
 
471
- # -----------------------------
472
- # Menu de opções
473
- # -----------------------------
474
- show_menu() {
475
- echo ""
476
- log_info "========================================="
477
- log_info " ComfyUI Custom Setup v2.0"
478
- log_info "========================================="
479
- echo ""
480
-
481
- local current_state=$(get_state)
482
-
483
- # Verificar se o estado está vazio ou inválido
484
- if [ -z "$current_state" ] || ! [[ "$current_state" =~ ^[0-9]+$ ]]; then
485
- log_info "Iniciando nova instalação..."
486
- reset_state
487
- return 0
488
- fi
489
-
490
- # Se não for interativo, sempre continuar ou começar do zero
491
- if [ "$INTERACTIVE" = false ]; then
492
- if [ "$current_state" != "0" ] && [ "$current_state" -lt "8" ]; then
493
- log_info "Modo não-interativo: continuando instalação anterior (Step: $current_state)"
494
- else
495
- log_info "Modo não-interativo: iniciando nova instalação"
496
- fi
497
- return 0
498
- fi
499
-
500
- if [ "$current_state" != "0" ] && [ "$current_state" -lt "8" ]; then
501
- log_warn "Instalação anterior detectada (Step: $current_state)"
502
- echo ""
503
- echo "Opções:"
504
- echo " 1) Continuar instalação de onde parou"
505
- echo " 2) Reiniciar instalação do zero"
506
- echo " 3) Sair"
507
- echo ""
508
-
509
- # Timeout de 10 segundos, padrão é continuar
510
- read -t 10 -p "Escolha uma opção [1-3] (padrão: 1 em 10s): " choice || choice="1"
511
-
512
- case $choice in
513
- 1|"") return 0 ;;
514
- 2) reset_state; return 0 ;;
515
- 3) exit 0 ;;
516
- *) log_warn "Opção inválida, continuando..."; return 0 ;;
517
- esac
518
- fi
519
-
520
  return 0
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  }
522
 
523
- # -----------------------------
524
- # Instalação principal
525
- # -----------------------------
526
- main() {
527
- # Inicializar sistema de estado
528
- init_state
529
-
530
- # Mostrar menu
531
- show_menu
532
-
533
- local current_state=$(get_state)
534
-
535
- # [STEP 1] Verificar e instalar dependências
536
- if [ "$current_state" -lt "1" ]; then
537
- log_info "[1/6] Verificando e instalando dependências..."
538
-
539
- # Instalar aria2c e megatools
540
- if ! command_exists aria2c; then
541
- log_info "Instalando aria2c..."
542
- apt-get update -qq && apt-get install -y -qq aria2 2>/dev/null
543
- fi
544
-
545
- install_megatools
546
-
547
- for cmd in python3 git wget curl; do
548
- if ! command_exists "$cmd"; then
549
- log_error "Dependência faltando: $cmd"
550
- exit 1
551
- fi
552
- done
553
-
554
- log_success "Dependências OK"
555
- save_state "1"
556
- fi
557
-
558
- # [STEP 2] Atualizar pip e instalar ferramentas
559
- if [ "$current_state" -lt "2" ]; then
560
- log_info "[2/6] Preparando ferramentas Python..."
561
- python3 -m pip install --upgrade pip wheel setuptools -q
562
- python3 -m pip install --upgrade "huggingface_hub[cli,hf_transfer]>=0.26.0" comfy-cli -q
563
-
564
- if [ -n "$HF_TOKEN" ]; then
565
- huggingface-cli login --token "$HF_TOKEN" 2>/dev/null || log_warn "Login HF falhou"
566
- fi
567
-
568
- log_success "Ferramentas instaladas"
569
- save_state "2"
570
- fi
571
-
572
- # [STEP 3] Instalar ComfyUI
573
- if [ "$current_state" -lt "3" ]; then
574
- log_info "[3/6] Instalando ComfyUI..."
575
- if [ -f "$COMFY_DIR/main.py" ]; then
576
- log_warn "ComfyUI já existe"
577
- else
578
- comfy --skip-prompt install --fast-deps --nvidia
579
-
580
- if [ ! -f "$COMFY_DIR/main.py" ]; then
581
- log_error "ComfyUI não foi instalado!"
582
- exit 1
583
- fi
584
- fi
585
- log_success "ComfyUI instalado"
586
- save_state "3"
587
- fi
588
-
589
- # [STEP 4] Corrigir PyTorch para Blackwell se detectado
590
- if [ "$current_state" -lt "4" ]; then
591
- log_info "[4/6] Verificando GPU..."
592
-
593
- # Detectar GPU
594
- local gpu_info=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo "")
595
-
596
- if [[ "$gpu_info" == *"5090"* ]] || [[ "$gpu_info" == *"5080"* ]]; then
597
- log_warn "RTX ${gpu_info} detectada - instalando PyTorch nightly"
598
- # FORÇAR reinstalação do PyTorch nightly
599
- pip uninstall -y torch torchvision torchaudio 2>/dev/null || true
600
- pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu128
601
- log_success "PyTorch nightly instalado"
602
- else
603
- log_info "GPU: ${gpu_info:-Não detectada} - mantendo PyTorch do ComfyUI"
604
- fi
605
- save_state "4"
606
- fi
607
-
608
- # [STEP 5] Baixar modelos
609
- # [STEP 5] Baixar modelos
610
- if [ "$current_state" -lt "5" ]; then
611
- log_info "[5/6] Baixando modelos..."
612
- mkdir -p "$MODELS_DIR"/{diffusion_models,loras,vae,vae_approx,text_encoders,clip_vision,upscale_models,checkpoints,ultralytics/bbox}
613
-
614
- log_info "Chamando process_downloads..."
615
- process_downloads
616
- log_info "process_downloads terminou"
617
-
618
- log_success "Downloads processados"
619
- save_state "5"
620
- fi
621
-
622
- # [STEP 6] Instalar custom nodes
623
- if [ "$current_state" -lt "6" ]; then
624
- log_info "[6/6] Instalando custom nodes..."
625
- CN_DIR="$COMFY_DIR/custom_nodes"
626
- mkdir -p "$CN_DIR"
627
-
628
- for repo_url in "${CUSTOM_NODES[@]}"; do
629
- node_name=$(basename "$repo_url")
630
- clone_or_update "$repo_url" "$CN_DIR/$node_name"
631
- done
632
-
633
- for node_name in "${SPECIAL_NODES[@]}"; do
634
- if ! is_node_complete "special:$node_name"; then
635
- log_info "Instalando $node_name via comfy-cli..."
636
- comfy node install "$node_name" 2>/dev/null && mark_node_complete "special:$node_name" || log_warn "Falha: $node_name"
637
- fi
638
- done
639
-
640
- log_success "Custom nodes instalados"
641
- save_state "6"
642
- fi
643
-
644
- # Verificação final
645
- log_info "Verificando instalação..."
646
-
647
- echo ""
648
- log_info "Estatísticas da instalação:"
649
-
650
- # Verificar ComfyUI
651
- if [ -f "$COMFY_DIR/main.py" ]; then
652
- log_success "✓ ComfyUI instalado"
653
  else
654
- log_error " ComfyUI não encontrado"
655
  fi
656
-
657
- # Contar modelos
658
- echo ""
659
- log_info "Modelos instalados:"
660
- for dir in checkpoints loras vae vae_approx text_encoders clip_vision upscale_models ultralytics; do
661
- if [ -d "$MODELS_DIR/$dir" ]; then
662
- local count=$(find "$MODELS_DIR/$dir" -type f \( -name "*.safetensors" -o -name "*.pth" -o -name "*.pt" -o -name "*.ckpt" -o -name "*.onnx" \) 2>/dev/null | wc -l)
663
- if [ $count -gt 0 ]; then
664
- log_success " $dir: $count arquivo(s)"
665
- fi
666
- fi
 
 
 
 
 
 
 
 
 
 
667
  done
668
-
669
- # Contar nodes
670
- echo ""
671
- local node_count=$(find "$CN_DIR" -maxdepth 1 -type d 2>/dev/null | wc -l)
672
- log_success "Custom nodes: $((node_count - 1)) instalados"
673
-
674
- # Verificar GPU
675
- echo ""
676
- local gpu_info=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo "Não detectada")
677
- log_info "GPU: $gpu_info"
678
-
679
- # Marcar instalação como completa
680
- save_state "6"
681
-
682
- echo ""
683
- log_success "========================================="
684
- log_success " Instalação concluída!"
685
- log_success "========================================="
686
-
687
- # Se não for interativo ou se for via argumento, iniciar direto
688
- if [ "$INTERACTIVE" = false ] || [ "${1:-}" = "--start" ]; then
689
- log_info "Iniciando ComfyUI automaticamente..."
690
- log_info "URL: http://localhost:$COMFY_PORT"
691
- cd "$COMFY_DIR"
692
- exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT"
693
  fi
694
-
695
- echo ""
696
- echo "Opções:"
697
- echo " 1) Iniciar ComfyUI agora"
698
- echo " 2) Resetar estado da instalação"
699
- echo " 3) Sair"
700
- echo ""
701
-
702
- # Timeout de 10 segundos, padrão é iniciar
703
- read -t 10 -p "Escolha uma opção [1-3] (padrão: 1 em 10s): " final_choice || final_choice="1"
704
-
705
- case $final_choice in
706
- 1|"")
707
- log_info "Iniciando ComfyUI..."
708
- log_info "URL: http://localhost:$COMFY_PORT"
709
- cd "$COMFY_DIR"
710
- exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT"
711
- ;;
712
- 2)
713
- reset_state
714
- log_success "Estado resetado. Execute o script novamente para reinstalar."
715
- ;;
716
- 3)
717
- log_info "Saindo..."
718
- ;;
719
- *)
720
- log_info "Iniciando ComfyUI (opção padrão)..."
721
- cd "$COMFY_DIR"
722
- exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT"
723
- ;;
724
- esac
725
  }
726
 
727
- # Executar instalação
728
- main "$@"
 
1
  #!/usr/bin/env bash
2
+ # setup_comfyui_custom_v2.sh (FIX DL HANG + BLACKWELL)
3
+ # Otimizado: timeouts/retries, Civitai headers, estado robusto, Blackwell nightly
4
 
5
  set -euo pipefail
6
 
7
+ # --------------------------------
8
+ # Modo interativo?
9
+ # --------------------------------
10
+ if [ ! -t 0 ] || [ ! -t 1 ]; then INTERACTIVE=false; else INTERACTIVE=true; fi
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ # --------------------------------
13
+ # Cores
14
+ # --------------------------------
15
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'
16
  log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
17
  log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
18
  log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
19
  log_error() { echo -e "${RED}[✗]${NC} $1"; }
20
  log_progress() { echo -e "${CYAN}[→]${NC} $1"; }
21
 
22
+ # --------------------------------
23
+ # Config
24
+ # --------------------------------
25
  COMFY_DIR="/root/comfy/ComfyUI"
26
  MODELS_DIR="$COMFY_DIR/models"
27
  COMFY_HOST="${COMFY_HOST:-0.0.0.0}"
28
  COMFY_PORT="${COMFY_PORT:-8818}"
29
+
30
+ # Mantemos as keys hardcoded como pedido
31
  CIVITAI_TOKEN="${CIVITAI_TOKEN:-4fcb2834969399006a736ee402b061e5}"
32
  HF_TOKEN="${HF_TOKEN:-}"
33
 
 
34
  STATE_DIR="/root/.comfyui_setup_state"
35
  STATE_FILE="$STATE_DIR/installation_state.txt"
36
  COMPLETED_DOWNLOADS="$STATE_DIR/completed_downloads.txt"
37
  COMPLETED_NODES="$STATE_DIR/completed_nodes.txt"
38
 
39
+ # Performance
40
  export MAX_JOBS=32
41
  export NVCC_APPEND_FLAGS="--threads 8"
42
  export UV_SYSTEM_PYTHON=1
 
44
  export HF_HUB_ENABLE_HF_TRANSFER=1
45
  export HF_TRANSFER_CONCURRENCY=16
46
  export EXT_PARALLEL=4
47
+ export PIP_DEFAULT_TIMEOUT=60
48
 
49
+ # Rede (timeouts e headers)
50
+ DOWNLOAD_TIMEOUT="${DOWNLOAD_TIMEOUT:-900}" # 15min hard cap por artefato
51
+ CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-20}" # conexão
52
+ RETRY_COUNT="${RETRY_COUNT:-3}"
53
+ RETRY_WAIT="${RETRY_WAIT:-3}"
54
+ UA="${UA:-Mozilla/5.0 (X11; Linux x86_64) curl/8}"
55
+ CIVITAI_REF="https://civitai.com/"
56
 
57
+ # --------------------------------
58
+ # Estado
59
+ # --------------------------------
60
+ init_state(){ mkdir -p "$STATE_DIR"; :> "$STATE_FILE"; touch "$COMPLETED_DOWNLOADS" "$COMPLETED_NODES"; }
61
+ save_state(){ echo "$1" > "$STATE_FILE"; log_info "Estado salvo: $1"; }
62
+ get_state(){ [[ -f "$STATE_FILE" && "$(cat "$STATE_FILE" || echo 0)" =~ ^[0-9]+$ ]] && cat "$STATE_FILE" || echo 0; }
63
+ reset_state(){ log_warn "Resetando estado da instalação..."; rm -rf "$STATE_DIR"; init_state; }
64
 
65
+ # normaliza "url|type|filename" (trim e remove espaços fantasma)
66
+ normalize_entry(){
67
+ local url="$1"; local type="$2"; local filename="$3"
68
+ url="$(echo -n "$url" | xargs)"; type="$(echo -n "$type" | xargs)"; filename="$(echo -n "${filename:-}" | xargs)"
69
+ echo "${url}|${type}|${filename}"
 
 
 
 
 
 
 
70
  }
71
+ mark_download_complete(){ local key="$1"; echo "$key" >> "$COMPLETED_DOWNLOADS"; }
72
+ is_download_complete(){ local key="$1"; [[ -f "$COMPLETED_DOWNLOADS" ]] && grep -Fxq "$key" "$COMPLETED_DOWNLOADS"; }
73
+ mark_node_complete(){ echo "$1" >> "$COMPLETED_NODES"; }
74
+ is_node_complete(){ [[ -f "$COMPLETED_NODES" ]] && grep -Fxq "$1" "$COMPLETED_NODES"; }
75
 
76
+ # --------------------------------
77
+ # Downloads (lista)
78
+ # --------------------------------
79
+ readonly DOWNLOAD_FILES=(
80
+ "mega://https://mega.nz/file/gIRTFQSQ#no6Ay3JLE9LVRi7ib9O-Jc0CW7XmG046kCgpCzDg1tY|loras|"
81
 
82
+ "https://civitai.com/api/download/models/2122278?type=Model&format=SafeTensor&size=pruned&fp=fp16|checkpoints|raehoshiIllustXL_v60.safetensors"
 
 
 
83
 
84
+ "https://civitai.com/api/download/models/1268294?type=Model&format=SafeTensor|loras|"
85
+ "https://civitai.com/api/download/models/1715330?type=Model&format=SafeTensor|loras|"
86
+ "https://civitai.com/api/download/models/1499397?type=Model&format=SafeTensor|loras|"
87
+ "https://civitai.com/api/download/models/1779002?type=Model&format=SafeTensor|loras|"
88
+ "https://civitai.com/api/download/models/1114313?type=Model&format=SafeTensor|loras|"
89
+ "https://civitai.com/api/download/models/1780244?type=Model&format=SafeTensor|loras|"
 
 
 
90
 
91
+ "https://huggingface.co/Kim2091/AnimeSharp/resolve/main/4x-AnimeSharp.pth|upscale_models|4x-AnimeSharp.pth"
92
+ "https://huggingface.co/Kim2091/AnimeSharpV3/resolve/main/2x-AnimeSharpV3.pth|upscale_models|2x-AnimeSharpV3.pth"
93
+ "https://huggingface.co/ABDALLALSWAITI/Upscalers/resolve/main/anime/2x-AnimeSharpV2_MoSR_Soft.pth|upscale_models|2x-AnimeSharpV2_MoSR_Soft.pth"
94
+ "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2.pth|upscale_models|4x-UltraSharpV2.pth"
95
+ "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2_Lite.pth|upscale_models|4x-UltraSharpV2_Lite.pth"
96
+ "https://huggingface.co/Kim2091/UltraSharpV2/resolve/main/4x-UltraSharpV2_fp32_op17.onnx|upscale_models|4x-UltraSharpV2_fp32_op17.onnx"
97
 
98
+ "https://huggingface.co/adbrasi/testedownload/resolve/main/99coins_anime_girl_face_m_seg.pt|ultralytics/bbox|99coins_anime_girl_face_m_seg.pt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  )
100
 
101
+ # Custom nodes
102
  readonly CUSTOM_NODES=(
103
+ "https://github.com/adbrasi/huggpackreator"
104
+ "https://github.com/adbrasi/packreator_processor"
105
+ "https://github.com/adbrasi/Packreator_manager"
106
+ "https://github.com/adbrasi/cezarsave34"
107
+ "https://github.com/adbrasi/pageonetor"
108
+ "https://github.com/adbrasi/pakreatorio"
109
+ "https://github.com/adbrasi/WaterMark_bumbumzin"
110
+ "https://github.com/adbrasi/marcadaguita"
111
+ "https://github.com/adbrasi/randomico"
112
+ "https://github.com/adbrasi/groqrouter"
113
+ "https://github.com/adbrasi/find_charakito"
114
+ "https://github.com/adbrasi/randomsizito"
115
+ "https://github.com/adbrasi/importex"
116
+ "https://github.com/adbrasi/storitadifusita"
117
+ "https://github.com/adbrasi/attentionPPM"
118
+ "https://github.com/ClownsharkBatwing/RES4LYF"
119
+ "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes"
120
+ "https://github.com/sipherxyz/comfyui-art-venture"
121
+ "https://github.com/pamparamm/sd-perturbed-attention"
122
+ "https://github.com/KoreTeknology/ComfyUI-Universal-Styler"
123
+ "https://github.com/WASasquatch/was-node-suite-comfyui"
124
+ "https://github.com/chflame163/ComfyUI_LayerStyle"
125
+ "https://github.com/ltdrdata/ComfyUI-Impact-Pack"
126
+ "https://github.com/pythongosssss/ComfyUI-Custom-Scripts"
127
+ "https://github.com/rgthree/rgthree-comfy"
128
+ "https://github.com/ssitu/ComfyUI_UltimateSDUpscale"
129
+ "https://github.com/adbrasi/Importador"
130
+ "https://github.com/adbrasi/GetFirstTag"
131
+ "https://github.com/adbrasi/comfydodi"
132
+ "https://github.com/omar92/ComfyUI-QualityOfLifeSuit_Omar92"
133
+ "https://github.com/Cezarsaint/blacklisto"
134
+ "https://github.com/TinyTerra/ComfyUI_tinyterraNodes"
135
+ "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
136
+ "https://github.com/Cezarsaint/rand0micoUploaderLoven"
137
+ "https://github.com/adbrasi/pixivmosaic"
138
+ "https://github.com/adbrasi/futfilter"
139
+ "https://github.com/Artificial-Sweetener/comfyui-WhiteRabbit"
140
+ "https://github.com/shiimizu/ComfyUI_smZNodes"
141
+ "https://github.com/CoreyCorza/ComfyUI-CRZnodes"
142
  )
143
 
144
+ readonly SPECIAL_NODES=("Civicomfy" "ComfyUI-RMBG")
 
 
 
 
145
 
146
+ # --------------------------------
147
+ # Helpers
148
+ # --------------------------------
149
+ command_exists(){ command -v "$1" >/dev/null 2>&1; }
150
+
151
+ install_megatools(){
152
+ if ! command_exists megadl; then
153
+ log_info "Instalando megatools..."
154
+ apt-get update -qq && apt-get install -y -qq megatools >/dev/null 2>&1 || true
155
+ command_exists megadl && log_success "Megatools OK" || log_warn "Megatools falhou (downloads do Mega podem não funcionar)"
156
+ fi
157
  }
158
 
159
+ add_civitai_token(){
160
+ local url="$1"
161
+ if [[ "$url" == *"civitai.com/api/download"* ]] && [[ "$url" != *"token="* ]]; then
162
+ echo "${url}&token=${CIVITAI_TOKEN}"
163
+ else
164
+ echo "$url"
165
+ fi
 
 
 
 
166
  }
167
 
168
+ # HuggingFace (CLI) com timeout
169
+ download_hf(){
170
+ local repo="$1" file_path="$2" target_dir="$3" filename="$4"
171
+ [[ -z "$filename" ]] && filename="$(basename "$file_path")"
172
+ local target_file="$target_dir/$filename"
173
+ if [[ -s "$target_file" && $(stat -c%s "$target_file" 2>/dev/null || echo 0) -gt 1000000 ]]; then
174
+ log_success "Arquivo existe: $filename"; return 0
175
+ fi
176
+
177
+ log_info "Baixando de HF: $repo/$file_path -> $filename"
178
+ local temp_dir; temp_dir="$(mktemp -d)"
179
+ local ok=false
180
+
181
+ if command_exists hf; then
182
+ if timeout "$DOWNLOAD_TIMEOUT" env HF_HUB_ENABLE_HF_TRANSFER=1 hf download "$repo" "$file_path" \
183
+ --local-dir "$temp_dir" --local-dir-use-symlinks False >/dev/null 2>&1; then ok=true; fi
184
+ fi
185
+
186
+ if [[ "$ok" = false && $(command_exists huggingface-cli; echo $?) -eq 0 ]]; then
187
+ log_warn "Tentando com huggingface-cli..."
188
+ if timeout "$DOWNLOAD_TIMEOUT" env HF_HUB_ENABLE_HF_TRANSFER=1 huggingface-cli download "$repo" "$file_path" \
189
+ --local-dir "$temp_dir" --local-dir-use-symlinks False >/dev/null 2>&1; then ok=true; fi
190
+ fi
191
+
192
+ if "$ok"; then
193
+ local f; f="$(find "$temp_dir" -type f \( -name "*.safetensors" -o -name "*.pth" -o -name "*.pt" -o -name "*.bin" -o -name "*.onnx" \) | head -1)"
194
+ if [[ -n "$f" ]]; then mv "$f" "$target_file"; rm -rf "$temp_dir"; log_success "HF OK: $filename"; return 0; fi
195
+ fi
196
+
197
+ rm -rf "$temp_dir"; log_error "HF falhou: $filename"; return 1
198
  }
199
 
200
+ # MEGA com timeout
201
+ download_mega(){
202
+ local url="$1" target_dir="$2"
203
+ command_exists megadl || { log_error "megatools não instalado"; return 1; }
204
+ url="${url#mega://}"
205
+ log_info "MEGA: $url"
206
+ ( cd "$target_dir" && timeout "$DOWNLOAD_TIMEOUT" megadl -q "$url" ) && { log_success "MEGA OK"; return 0; }
207
+ log_error "MEGA falhou/timeout"; return 1
208
  }
209
 
210
+ # Detecta nome via cabeçalho
211
+ detect_remote_name(){
212
+ local url="$1"
213
+ local name
214
+ name="$(timeout 60 curl -I -sSL -4 -A "$UA" -e "$CIVITAI_REF" "$url" \
215
+ | awk -F'filename=' 'BEGIN{IGNORECASE=1}/content-disposition/{gsub(/\"|;|\r/,"",$2); print $2}' | tail -1)"
216
+ [[ -z "$name" ]] && name="$(basename "$(echo "$url" | cut -d'?' -f1)")"
217
+ echo "$name"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  }
219
 
220
+ # Baixador genérico (CURL -> WGET -> ARIA2C), todos com timeout & retries
221
+ download_file(){
222
+ local url="$1" target_dir="$2" filename="$3"
223
+ url="$(add_civitai_token "$url")"
224
+
225
+ if [[ -z "$filename" ]]; then filename="$(detect_remote_name "$url")"; fi
226
+ local out="$target_dir/$filename"
227
+
228
+ if [[ -s "$out" && $(stat -c%s "$out" 2>/dev/null || echo 0) -gt 1000000 ]]; then
229
+ log_success "Arquivo já existe: $filename"; return 0
230
+ fi
231
+
232
+ log_info "HTTP: ${filename} (-> $target_dir)"
233
+
234
+ # 1) CURL
235
+ if command_exists curl; then
236
+ if timeout "$DOWNLOAD_TIMEOUT" curl -fL -4 -A "$UA" -e "$CIVITAI_REF" \
237
+ --connect-timeout "$CONNECT_TIMEOUT" --retry "$RETRY_COUNT" --retry-delay "$RETRY_WAIT" \
238
+ -C - -o "$out" "$url"; then
239
+ log_success "CURL OK: $filename"; return 0
240
+ else
241
+ log_warn "CURL falhou para $filename"
 
 
 
 
 
 
 
 
242
  fi
243
+ fi
244
+
245
+ # 2) WGET
246
+ if command_exists wget; then
247
+ if timeout "$DOWNLOAD_TIMEOUT" wget -q --show-progress -4 --referer="$CIVITAI_REF" --user-agent="$UA" \
248
+ --timeout="$CONNECT_TIMEOUT" --tries="$RETRY_COUNT" -c -O "$out" "$url"; then
249
+ log_success "WGET OK: $filename"; return 0
250
+ else
251
+ log_warn "WGET falhou para $filename"
 
 
 
252
  fi
253
+ fi
 
 
 
254
 
255
+ # 3) ARIA2C
256
+ if command_exists aria2c; then
257
+ local aria_opts="-c -s 16 -x 16 -k 1M --file-allocation=none --allow-overwrite=true --auto-file-renaming=false \
258
+ --summary-interval=10 --console-log-level=warn --timeout=$CONNECT_TIMEOUT --retry-wait=$RETRY_WAIT --max-tries=$RETRY_COUNT --referer=$CIVITAI_REF --user-agent=$UA"
259
+ if timeout "$DOWNLOAD_TIMEOUT" aria2c $aria_opts --dir="$target_dir" --out="$filename" "$url"; then
260
+ log_success "ARIA2C OK: $filename"; return 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  else
262
+ log_warn "ARIA2C falhou para $filename"
263
  fi
264
+ fi
265
+
266
+ log_error "Falha final em: $url"
267
+ return 1
268
  }
269
 
270
+ # Processa a lista de downloads com chave normalizada + logs
271
+ process_downloads(){
272
+ local total="${#DOWNLOAD_FILES[@]}"; local current=0; local failed=0
273
+ log_info "Total de downloads: $total"
274
+ log_info "Iniciando loop de downloads..."
275
+
276
+ for raw in "${DOWNLOAD_FILES[@]}"; do
277
+ ((current++))
278
+ IFS='|' read -r url type filename <<< "$raw"
279
+ url="$(echo -n "$url" | xargs)"; type="$(echo -n "$type" | xargs)"; filename="$(echo -n "${filename:-}" | xargs)"
280
+ local key; key="$(normalize_entry "$url" "$type" "$filename")"
281
+
282
+ if is_download_complete "$key"; then
283
+ log_success "[$current/$total] Já baixado: ${filename:-$(basename "$url" | cut -d'?' -f1)}"; continue
284
  fi
285
+
286
+ local target_dir="$MODELS_DIR"
287
+ case "$type" in
288
+ checkpoints) target_dir="$MODELS_DIR/checkpoints" ;;
289
+ loras) target_dir="$MODELS_DIR/loras" ;;
290
+ upscale_models) target_dir="$MODELS_DIR/upscale_models" ;;
291
+ ultralytics/bbox) target_dir="$MODELS_DIR/ultralytics/bbox" ;;
292
+ *) target_dir="$MODELS_DIR/$type" ;;
293
+ esac
294
+ mkdir -p "$target_dir"
295
+
296
+ log_info "[$current/$total] $type :: $(basename "${filename:-$url}")"
297
+
298
+ local ok=1
299
+ if [[ "$url" == mega://* ]]; then
300
+ download_mega "$url" "$target_dir" && ok=0
301
+ elif [[ "$url" == hf://* ]]; then
302
+ url="${url#hf://}"; local repo="${url%%/*/*}"; repo="${url%/*/*}"; # não usado aqui, mantido por compat
303
+ local repo2="$(echo "$url" | cut -d'/' -f1-2)"
304
+ local file_path="$(echo "$url" | cut -d'/' -f3-)"
305
+ download_hf "$repo2" "$file_path" "$target_dir" "$filename" && ok=0
306
+ elif [[ "$url" == https://huggingface.co/*/resolve/* ]]; then
307
+ # resolve/ direto por HTTP (mais rápido se público)
308
+ download_file "$url" "$target_dir" "$filename" && ok=0
309
  else
310
+ download_file "$url" "$target_dir" "$filename" && ok=0
 
 
 
 
311
  fi
312
+
313
+ if [[ $ok -eq 0 ]]; then
314
+ mark_download_complete "$key"
315
+ else
316
+ ((failed++)); log_warn "[$current/$total] Falhou, segue..."
317
  fi
318
+ done
319
+
320
+ if [[ $failed -gt 0 ]]; then
321
+ log_warn "Downloads: $((total - failed))/$total OK ($failed falharam)"
322
+ else
323
+ log_success "Todos os $total downloads completados!"
324
+ fi
325
+ return 0
326
  }
327
 
328
+ # Git clone/update com pip reqs e timeouts
329
+ clone_or_update(){
330
+ local url="$1" dest="$2" node_name="$(basename "$dest")"
331
 
332
+ if is_node_complete "$url"; then log_success "Node já instalado: $node_name"; return 0; fi
333
+
334
+ if [[ -d "$dest/.git" ]]; then
335
+ log_info "Atualizando $node_name..."
336
+ timeout 120 git -C "$dest" pull --ff-only >/dev/null 2>&1 || log_warn "Timeout/erro ao atualizar $node_name"
337
+ else
338
+ log_info "Clonando $node_name..."
339
+ timeout 180 git clone --recursive --depth 1 "$url" "$dest" >/dev/null 2>&1 || { log_warn "Falha ao clonar $node_name"; return 0; }
340
+ fi
341
+
342
+ if [[ -f "$dest/requirements.txt" ]]; then
343
+ timeout 300 python3 -m pip install --no-warn-script-location -q -r "$dest/requirements.txt" >/dev/null 2>&1 || \
344
+ log_warn "Falha em requirements de $node_name"
345
+ fi
346
+
347
+ mark_node_complete "$url"
348
+ return 0
349
+ }
350
+
351
+ # --------------------------------
352
+ # Menu
353
+ # --------------------------------
354
+ show_menu(){
355
+ echo ""; log_info "========================================="; log_info " ComfyUI Custom Setup v2.0"; log_info "========================================="; echo ""
356
+ local s; s="$(get_state)"
357
+
358
+ if [[ -z "$s" || ! "$s" =~ ^[0-9]+$ ]]; then log_info "Iniciando nova instalação..."; reset_state; return 0; fi
359
+
360
+ if [[ "$INTERACTIVE" = false ]]; then
361
+ if [[ "$s" != "0" && "$s" -lt "8" ]]; then log_info "Modo não-interativo: continuando (Step: $s)"; else log_info "Modo não-interativo: nova instalação"; fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  return 0
363
+ fi
364
+
365
+ if [[ "$s" != "0" && "$s" -lt "8" ]]; then
366
+ log_warn "Instalação anterior detectada (Step: $s)"
367
+ echo -e "\nOpções:\n 1) Continuar\n 2) Reiniciar\n 3) Sair\n"
368
+ read -t 10 -p "Escolha [1-3] (padrão 1): " choice || choice="1"
369
+ case "$choice" in
370
+ 1|"") return 0 ;;
371
+ 2) reset_state; return 0 ;;
372
+ 3) exit 0 ;;
373
+ *) log_warn "Opção inválida, continuando..."; return 0 ;;
374
+ esac
375
+ fi
376
  }
377
 
378
+ # --------------------------------
379
+ # Main
380
+ # --------------------------------
381
+ main(){
382
+ mkdir -p "$COMFY_DIR" "$MODELS_DIR"; init_state
383
+ show_menu
384
+
385
+ local s; s="$(get_state)"
386
+
387
+ # STEP 1: deps
388
+ if [[ "$s" -lt "1" ]]; then
389
+ log_info "[1/6] Dependências..."
390
+ if ! command_exists aria2c; then apt-get update -qq && apt-get install -y -qq aria2 >/dev/null 2>&1 || true; fi
391
+ install_megatools
392
+ for cmd in python3 git wget curl; do command_exists "$cmd" || { log_error "Falta: $cmd"; exit 1; }; done
393
+ log_success "Dependências OK"; save_state "1"
394
+ fi
395
+
396
+ # STEP 2: pip tools
397
+ if [[ "$s" -lt "2" ]]; then
398
+ log_info "[2/6] Ferramentas Python..."
399
+ python3 -m pip install --upgrade --no-cache-dir pip wheel setuptools >/dev/null 2>&1
400
+ python3 -m pip install --upgrade --no-cache-dir "huggingface_hub[cli,hf_transfer]>=0.26.0" comfy-cli >/dev/null 2>&1
401
+ if [[ -n "$HF_TOKEN" ]]; then huggingface-cli login --token "$HF_TOKEN" >/dev/null 2>&1 || log_warn "Login HF falhou"; fi
402
+ log_success "Ferramentas OK"; save_state "2"
403
+ fi
404
+
405
+ # STEP 3: ComfyUI
406
+ if [[ "$s" -lt "3" ]]; then
407
+ log_info "[3/6] Instalando ComfyUI..."
408
+ if [[ -f "$COMFY_DIR/main.py" ]]; then log_warn "ComfyUI já existe"; else comfy --skip-prompt install --fast-deps --nvidia || { log_error "ComfyUI não instalou"; exit 1; }; fi
409
+ log_success "ComfyUI instalado"; save_state "3"
410
+ fi
411
+
412
+ # STEP 4: Blackwell nightly (se 5090/5080)
413
+ if [[ "$s" -lt "4" ]]; then
414
+ log_info "[4/6] Verificando GPU..."
415
+ local gpu_info; gpu_info="$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo "")"
416
+ if [[ "$gpu_info" == *"5090"* || "$gpu_info" == *"5080"* ]]; then
417
+ log_warn "RTX ${gpu_info:-Blackwell} detectada - aplicando PyTorch nightly (como você pediu)"
418
+ # alinhado ao pedido: --pre --upgrade --no-cache-dir + extra-index nightly
419
+ python3 -m pip install --pre --upgrade --no-cache-dir torch --extra-index-url https://download.pytorch.org/whl/nightly/cu128
420
+ python3 -m pip install --pre --upgrade --no-cache-dir torchvision --extra-index-url https://download.pytorch.org/whl/nightly/cu128
421
+ log_success "PyTorch nightly (cu128) pronto"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  else
423
+ log_info "GPU: ${gpu_info:-Não detectada} - mantendo PyTorch padrão"
424
  fi
425
+ save_state "4"
426
+ fi
427
+
428
+ # STEP 5: modelos
429
+ if [[ "$s" -lt "5" ]]; then
430
+ log_info "[5/6] Baixando modelos..."
431
+ mkdir -p "$MODELS_DIR"/{loras,upscale_models,checkpoints,ultralytics/bbox}
432
+ process_downloads
433
+ log_success "Downloads processados"; save_state "5"
434
+ fi
435
+
436
+ # STEP 6: custom nodes
437
+ if [[ "$s" -lt "6" ]]; then
438
+ log_info "[6/6] Instalando custom nodes..."
439
+ local CN_DIR="$COMFY_DIR/custom_nodes"; mkdir -p "$CN_DIR"
440
+ for repo_url in "${CUSTOM_NODES[@]}"; do clone_or_update "$repo_url" "$CN_DIR/$(basename "$repo_url")"; done
441
+ for node_name in "${SPECIAL_NODES[@]}"; do
442
+ if ! is_node_complete "special:$node_name"; then
443
+ log_info "Instalando $node_name via comfy-cli..."
444
+ comfy node install "$node_name" >/dev/null 2>&1 && mark_node_complete "special:$node_name" || log_warn "Falha: $node_name"
445
+ fi
446
  done
447
+ log_success "Custom nodes instalados"; save_state "6"
448
+ fi
449
+
450
+ # Verificação final
451
+ log_info "Verificando instalação..."
452
+ if [[ -f "$COMFY_DIR/main.py" ]]; then log_success "✓ ComfyUI instalado"; else log_error "✗ ComfyUI não encontrado"; fi
453
+
454
+ echo ""; log_info "Modelos instalados:"
455
+ for dir in checkpoints loras vae vae_approx text_encoders clip_vision upscale_models ultralytics; do
456
+ if [[ -d "$MODELS_DIR/$dir" ]]; then
457
+ local c; c="$(find "$MODELS_DIR/$dir" -type f \( -name "*.safetensors" -o -name "*.pth" -o -name "*.pt" -o -name "*.ckpt" -o -name "*.onnx" \) 2>/dev/null | wc -l)"
458
+ [[ "$c" -gt 0 ]] && log_success " $dir: $c arquivo(s)"
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  fi
460
+ done
461
+
462
+ echo ""; local CN_DIR="$COMFY_DIR/custom_nodes"; local node_count; node_count="$(find "$CN_DIR" -maxdepth 1 -type d 2>/dev/null | wc -l)"
463
+ log_success "Custom nodes: $((node_count - 1)) instalados"
464
+
465
+ echo ""; local gpu_info; gpu_info="$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo "Não detectada")"
466
+ log_info "GPU: $gpu_info"
467
+
468
+ save_state "6"
469
+
470
+ echo ""; log_success "========================================="; log_success " Instalação concluída!"; log_success "========================================="
471
+
472
+ if [[ "$INTERACTIVE" = false || "${1:-}" == "--start" ]]; then
473
+ log_info "Iniciando ComfyUI automaticamente..."
474
+ log_info "URL: http://localhost:$COMFY_PORT"
475
+ cd "$COMFY_DIR"
476
+ exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT"
477
+ fi
478
+
479
+ echo -e "\nOpções:\n 1) Iniciar ComfyUI agora\n 2) Resetar estado\n 3) Sair\n"
480
+ read -t 10 -p "Escolha [1-3] (padrão 1): " final_choice || final_choice="1"
481
+ case "$final_choice" in
482
+ 1|"") log_info "Iniciando ComfyUI..."; cd "$COMFY_DIR"; exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT" ;;
483
+ 2) reset_state; log_success "Estado resetado. Rode de novo para reinstalar." ;;
484
+ 3) log_info "Saindo..." ;;
485
+ *) cd "$COMFY_DIR"; exec comfy launch -- --listen "$COMFY_HOST" --port "$COMFY_PORT" ;;
486
+ esac
 
 
 
 
487
  }
488
 
489
+ main "$@"