#!/usr/bin/env bash # setup_comfyui_wan22_fixed.sh # Script corrigido para instalação do ComfyUI com Wan 2.2 set -euo pipefail # ----------------------------- # Cores para output # ----------------------------- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[!]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } # ----------------------------- # Configuração # ----------------------------- COMFY_DIR="/root/comfy/ComfyUI" MODELS_DIR="$COMFY_DIR/models" COMFY_HOST="${COMFY_HOST:-0.0.0.0}" COMFY_PORT="${COMFY_PORT:-8818}" CIVITAI_TOKEN="${CIVITAI_TOKEN:-4fcb2834969399006a736ee402b061e5}" HF_TOKEN="${HF_TOKEN:-}" # Token opcional do HuggingFace para login # Configurações de performance export MAX_JOBS=32 export NVCC_APPEND_FLAGS="--threads 8" export UV_SYSTEM_PYTHON=1 export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True" export HF_HUB_ENABLE_HF_TRANSFER=1 export HF_TRANSFER_CONCURRENCY=16 export EXT_PARALLEL=4 # ----------------------------- # Lista de downloads # ----------------------------- # Formato: "URL|TIPO|NOME_ARQUIVO_OPCIONAL" readonly DOWNLOAD_FILES=( # Wan 2.2 models "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/diffusion_models/wan2.2_fun_control_low_noise_14B_fp8_scaled.safetensors|diffusion_models|" "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/diffusion_models/wan2.2_fun_control_high_noise_14B_fp8_scaled.safetensors|diffusion_models|" "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/loras/wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors|loras|" "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/loras/wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors|loras|" "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/vae/wan_2.1_vae.safetensors|vae|" "hf://Comfy-Org/Wan_2.2_ComfyUI_Repackaged/split_files/text_encoders/umt5_xxl_fp16.safetensors|text_encoders|" # Wan 2.1 clip vision "hf://Comfy-Org/Wan_2.1_ComfyUI_repackaged/split_files/clip_vision/clip_vision_h.safetensors|clip_vision|" # ControlNet "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/UniAnimate-Wan2.1-14B-Lora-12000-fp16.safetensors|loras|UniAnimate-Wan2.1-14B-Lora-12000-fp16.safetensors" "hf://xinsir/controlnet-union-sdxl-1.0/diffusion_pytorch_model_promax.safetensors|controlnet|controlnet-union.safetensors" "https://huggingface.co/ABDALLALSWAITI/Upscalers/resolve/main/anime/2x-AnimeSharpV2_MoSR_Soft.pth|upscale_models|2x-AnimeSharpV2_MoSR_Soft.pth" # Civitai model "https://civitai.com/api/download/models/2122278?type=Model&format=SafeTensor&size=pruned&fp=fp16|checkpoints|raehoshiIllustXL_v60.safetensors" ) # Custom nodes para instalar readonly CUSTOM_NODES=( "https://github.com/kijai/ComfyUI-Florence2" "https://github.com/kijai/ComfyUI-WanVideoWrapper" "https://github.com/Fannovel16/ComfyUI-Frame-Interpolation" "https://github.com/kijai/ComfyUI-GIMM-VFI" "https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite" "https://github.com/kijai/ComfyUI-KJNodes" "https://github.com/Fannovel16/comfyui_controlnet_aux" "https://github.com/Artificial-Sweetener/comfyui-WhiteRabbit" "https://github.com/shiimizu/ComfyUI_smZNodes" "https://github.com/CoreyCorza/ComfyUI-CRZnodes" "https://github.com/yuvraj108c/ComfyUI-Dwpose-Tensorrt" "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes" "https://github.com/grmchn/ComfyUI-ProportionChanger" ) # ----------------------------- # Funções auxiliares # ----------------------------- command_exists() { command -v "$1" >/dev/null 2>&1 } # Adicionar token do Civitai se necessário add_civitai_token() { local url="$1" if [[ "$url" == *"civitai.com/api/download"* ]] && [[ "$url" != *"token="* ]]; then echo "${url}&token=${CIVITAI_TOKEN}" else echo "$url" fi } # Download HuggingFace usando huggingface-cli com hf_transfer download_hf() { local repo="$1" local file_path="$2" local target_dir="$3" local filename="$4" # Extrair nome do arquivo se não fornecido if [ -z "$filename" ]; then filename=$(basename "$file_path") fi local target_file="$target_dir/$filename" # Se arquivo já existe e tem tamanho razoável, pular if [ -f "$target_file" ] && [ $(stat -c%s "$target_file" 2>/dev/null || echo 0) -gt 1000000 ]; then log_success "Arquivo já existe: $filename" return 0 fi log_info "Baixando de HF: $filename" # Usar huggingface-cli com hf_transfer habilitado para velocidade máxima if HF_HUB_ENABLE_HF_TRANSFER=1 huggingface-cli download "$repo" "$file_path" \ --local-dir "$target_dir" \ --local-dir-use-symlinks False \ --resume-download 2>/dev/null; then # Verificar se arquivo foi baixado if [ -f "$target_file" ]; then log_success "Download concluído: $filename" return 0 fi # Procurar arquivo em subdiretórios se não estiver no local esperado local downloaded_file=$(find "$target_dir" -name "$filename" -type f 2>/dev/null | head -1) if [ -n "$downloaded_file" ] && [ "$downloaded_file" != "$target_file" ]; then mv "$downloaded_file" "$target_file" log_success "Download concluído e movido: $filename" return 0 fi fi log_error "Falha ao baixar: $filename" return 1 } # Download genérico com aria2c, wget ou curl download_file() { local url="$1" local target_dir="$2" local filename="$3" # Adicionar token Civitai se necessário url=$(add_civitai_token "$url") # Se arquivo já existe e tem tamanho razoável, pular if [ -n "$filename" ] && [ -f "$target_dir/$filename" ] && [ $(stat -c%s "$target_dir/$filename" 2>/dev/null || echo 0) -gt 1000000 ]; then log_success "Arquivo já existe: $filename" return 0 fi log_info "Baixando: ${filename:-$(basename "$url" | cut -d'?' -f1)}" # Tentar com aria2c primeiro (mais rápido) if command_exists aria2c; then local aria_opts="-c -s 16 -x 16 -k 1M --console-log-level=warn --summary-interval=10" if [ -n "$filename" ]; then aria2c $aria_opts --dir="$target_dir" --out="$filename" "$url" && return 0 else aria2c $aria_opts --dir="$target_dir" "$url" && return 0 fi fi # Fallback para wget if command_exists wget; then if [ -n "$filename" ]; then wget -q --show-progress -c -O "$target_dir/$filename" "$url" && return 0 else wget -q --show-progress -c --content-disposition -P "$target_dir" "$url" && return 0 fi fi # Último recurso: curl if command_exists curl; then if [ -n "$filename" ]; then curl -L -# -C - -o "$target_dir/$filename" "$url" && return 0 else local headers=$(curl -sI -L "$url") local detected_name=$(echo "$headers" | grep -i "content-disposition" | sed -n 's/.*filename="\([^"]*\)".*/\1/p' | tr -d '\r') if [ -z "$detected_name" ]; then detected_name="downloaded_$(date +%s).safetensors" fi curl -L -# -C - -o "$target_dir/$detected_name" "$url" && return 0 fi fi log_error "Falha ao baixar: $url" return 1 } # Processar lista de downloads process_downloads() { local failed_count=0 for entry in "${DOWNLOAD_FILES[@]}"; do IFS='|' read -r url type filename <<< "$entry" # Limpar espaços url=$(echo "$url" | xargs) type=$(echo "$type" | xargs) filename=$(echo "$filename" | xargs) # Determinar diretório de destino local target_dir="$MODELS_DIR" case "$type" in checkpoints) target_dir="$MODELS_DIR/checkpoints" ;; loras) target_dir="$MODELS_DIR/loras" ;; vae) target_dir="$MODELS_DIR/vae" ;; text_encoders) target_dir="$MODELS_DIR/text_encoders" ;; clip_vision) target_dir="$MODELS_DIR/clip_vision" ;; controlnet) target_dir="$MODELS_DIR/controlnet" ;; upscale_models) target_dir="$MODELS_DIR/upscale_models" ;; *) target_dir="$MODELS_DIR/$type" ;; esac # Criar diretório se não existir mkdir -p "$target_dir" # Processar URL if [[ "$url" == hf://* ]]; then # HuggingFace download url="${url#hf://}" # Remove prefixo hf:// repo=$(echo "$url" | cut -d'/' -f1-2) file_path=$(echo "$url" | cut -d'/' -f3-) download_hf "$repo" "$file_path" "$target_dir" "$filename" || ((failed_count++)) else # Download normal (HTTP/HTTPS) download_file "$url" "$target_dir" "$filename" || ((failed_count++)) fi done # Limpar arquivos órfãos em split_files (se existirem) if [ -d "$MODELS_DIR/diffusion_models/split_files" ]; then log_info "Movendo arquivos de split_files para diretórios corretos..." find "$MODELS_DIR" -path "*/split_files/*" -name "*.safetensors" | while read -r file; do local base_dir=$(dirname "$(dirname "$file")") local target_name=$(basename "$file") if [ ! -f "$base_dir/$target_name" ]; then mv "$file" "$base_dir/" 2>/dev/null && log_success "Movido: $target_name" fi done # Remover diretórios split_files vazios find "$MODELS_DIR" -type d -name "split_files" -empty -delete 2>/dev/null fi return $failed_count } # Clonar ou atualizar repositório git clone_or_update() { local url="$1" local dest="$2" local node_name=$(basename "$dest") # Timeout de 60 segundos para operações git if [ -d "$dest/.git" ]; then log_info "Atualizando $node_name..." timeout 60 git -C "$dest" pull --ff-only 2>/dev/null || { log_warn "Timeout ou erro ao atualizar $node_name" return 0 # Não falhar, apenas avisar } else log_info "Clonando $node_name..." timeout 60 git clone --recursive --depth 1 "$url" "$dest" 2>/dev/null || { log_warn "Falha ao clonar $node_name" return 0 # Não falhar, apenas avisar } fi # Instalar requirements se existir (com timeout) if [ -f "$dest/requirements.txt" ]; then timeout 120 python3 -m pip install --no-warn-script-location -q -r "$dest/requirements.txt" 2>/dev/null || { log_warn "Falha ao instalar requirements para $node_name" } fi return 0 } # ----------------------------- # Instalação principal # ----------------------------- echo "" log_info "=========================================" log_info " ComfyUI + Wan 2.2 Setup (Fixed)" log_info "=========================================" echo "" # [1] Verificar e instalar dependências log_info "[1/8] Verificando e instalando dependências..." # Instalar aria2c do sistema se não existir if ! command_exists aria2c; then log_info "Instalando aria2c do sistema..." apt-get update -qq && apt-get install -y -qq aria2 2>/dev/null fi for cmd in python3 git wget curl; do if ! command_exists "$cmd"; then log_error "Dependência faltando: $cmd" exit 1 fi done log_success "Dependências OK" # [2] Atualizar pip e instalar ferramentas log_info "[2/8] Preparando ferramentas Python..." python3 -m pip install --upgrade pip wheel setuptools -q # Instalar huggingface_hub com CLI e hf_transfer para velocidade máxima python3 -m pip install --upgrade "huggingface_hub[cli]>=0.26.0" hf_transfer comfy-cli -q # Configurar token HF se disponível (opcional) HF_TOKEN="${HF_TOKEN:-}" if [ -n "$HF_TOKEN" ]; then if huggingface-cli login --token "$HF_TOKEN" 2>/dev/null; then log_success "Login HF configurado" else log_warn "Falha ao configurar login HF, continuando sem autenticação" fi fi # Verificar se hf está disponível if command_exists huggingface-cli; then log_success "huggingface-cli disponível" else log_warn "huggingface-cli não encontrado" fi log_success "Ferramentas instaladas" # [3] Instalar PyTorch com CUDA 12.8 log_info "[3/8] Instalando PyTorch com CUDA 12.8..." python3 -m pip install --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128 log_success "PyTorch com CUDA 12.8 instalado" # [4] Instalar ComfyUI log_info "[4/8] Instalando ComfyUI..." if [ -f "$COMFY_DIR/main.py" ]; then log_warn "ComfyUI já existe, pulando instalação base" else comfy --skip-prompt install --fast-deps --nvidia # Verificar instalação if [ ! -f "$COMFY_DIR/main.py" ]; then log_error "ComfyUI não foi instalado corretamente!" exit 1 fi fi log_success "ComfyUI instalado em: $COMFY_DIR" # [5] Instalar SageAttention (wheel pré-compilada) log_info "[5/8] Instalando SageAttention..." if command_exists nvcc || python3 -c "import torch; print(torch.cuda.is_available())" 2>/dev/null | grep -q "True"; then log_info "Instalando SageAttention pré-compilada..." python3 -m pip install "https://huggingface.co/adbrasi/comfywheel/resolve/main/sageattention-2.2.0-cp311-cp311-linux_x86_64.whl" -q # Verificar instalação if python3 -c "import sageattention" 2>/dev/null; then log_success "SageAttention instalado com sucesso" else log_warn "SageAttention instalado mas não pôde ser importado" fi else log_warn "CUDA não detectado, pulando SageAttention" fi # [6] Baixar modelos log_info "[6/8] Baixando modelos..." mkdir -p "$MODELS_DIR"/{diffusion_models,loras,vae,text_encoders,clip_vision,controlnet,upscale_models} # Verificar ferramentas de download if command_exists aria2c; then log_success "Usando aria2c para downloads (rápido)" else log_warn "aria2c não encontrado, usando wget/curl (mais lento)" fi # Processar downloads if process_downloads; then log_success "Todos os modelos baixados com sucesso" else log_warn "Alguns downloads falharam, mas continuando..." fi # [7] Instalar custom nodes log_info "[7/8] Instalando custom nodes..." CN_DIR="$COMFY_DIR/custom_nodes" mkdir -p "$CN_DIR" # Instalar nodes sequencialmente para evitar travamentos for repo_url in "${CUSTOM_NODES[@]}"; do node_name=$(basename "$repo_url") clone_or_update "$repo_url" "$CN_DIR/$node_name" done log_success "Custom nodes instalados" # [8] Verificação final echo "" log_info "[8/8] Verificando instalação..." # Verificar arquivos principais check_critical_files() { local files=( "$COMFY_DIR/main.py" "$MODELS_DIR/diffusion_models/wan2.2_fun_control_low_noise_14B_fp8_scaled.safetensors" "$MODELS_DIR/diffusion_models/wan2.2_fun_control_high_noise_14B_fp8_scaled.safetensors" "$MODELS_DIR/vae/wan_2.1_vae.safetensors" "$MODELS_DIR/text_encoders/umt5_xxl_fp16.safetensors" ) local missing=0 for file in "${files[@]}"; do if [ -f "$file" ]; then log_success "✓ $(basename "$file")" else log_error "✗ $(basename "$file") não encontrado" ((missing++)) fi done return $missing } if check_critical_files; then log_success "Instalação concluída com sucesso!" echo "" log_info "=========================================" log_info "Iniciando ComfyUI..." log_info "URL: http://localhost:$COMFY_PORT" log_info "=========================================" # Tentar usar SageAttention se disponível SAGE_FLAG="" if python3 -c "import sageattention" 2>/dev/null; then SAGE_FLAG="--use-sage-attention" log_info "SageAttention habilitado" fi cd "$COMFY_DIR" exec comfy launch -- $SAGE_FLAG --listen "$COMFY_HOST" --port "$COMFY_PORT" else log_error "Arquivos críticos faltando. Verifique os erros acima." # Mostrar onde os arquivos podem estar log_info "Procurando arquivos mal posicionados..." find "$MODELS_DIR" -name "*.safetensors" -type f | head -20 exit 1 fi