diff --git a/.gitignore b/.gitignore index 49b363f..e9f5e39 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ python/ node/ node_modules/ /models/ -__pycache__/ +**/__pycache__/ cache/ temp/ downloads/ diff --git a/ACE-Step-1.5/.gitignore b/ACE-Step-1.5/.gitignore index 3cf4712..f20aa41 100644 --- a/ACE-Step-1.5/.gitignore +++ b/ACE-Step-1.5/.gitignore @@ -10,7 +10,7 @@ data/ *.wav # Byte-compiled / optimized / DLL files -__pycache__/ +**/_pycache__/ *.py[codz] *$py.class diff --git a/ACE-Step-1.5/acestep/models/__pycache__/__init__.cpython-312.pyc b/ACE-Step-1.5/acestep/models/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 5b7ab36..0000000 Binary files a/ACE-Step-1.5/acestep/models/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/ACE-Step-1.5/acestep/models/common/__pycache__/__init__.cpython-312.pyc b/ACE-Step-1.5/acestep/models/common/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index ae6a298..0000000 Binary files a/ACE-Step-1.5/acestep/models/common/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/ACE-Step-1.5/acestep/models/common/__pycache__/apg_guidance.cpython-312.pyc b/ACE-Step-1.5/acestep/models/common/__pycache__/apg_guidance.cpython-312.pyc deleted file mode 100644 index 7be9fb7..0000000 Binary files a/ACE-Step-1.5/acestep/models/common/__pycache__/apg_guidance.cpython-312.pyc and /dev/null differ diff --git a/ACE-Step-1.5/acestep/models/common/__pycache__/configuration_acestep_v15.cpython-312.pyc b/ACE-Step-1.5/acestep/models/common/__pycache__/configuration_acestep_v15.cpython-312.pyc deleted file mode 100644 index eeb0206..0000000 Binary files a/ACE-Step-1.5/acestep/models/common/__pycache__/configuration_acestep_v15.cpython-312.pyc and /dev/null differ diff --git a/ACE-Step-1.5/acestep/models/mlx/__pycache__/__init__.cpython-312.pyc b/ACE-Step-1.5/acestep/models/mlx/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index db0e016..0000000 Binary files a/ACE-Step-1.5/acestep/models/mlx/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/ACE-Step-1.5/acestep/models/mlx/__pycache__/dit_generate.cpython-312.pyc b/ACE-Step-1.5/acestep/models/mlx/__pycache__/dit_generate.cpython-312.pyc deleted file mode 100644 index ab8d6c2..0000000 Binary files a/ACE-Step-1.5/acestep/models/mlx/__pycache__/dit_generate.cpython-312.pyc and /dev/null differ diff --git a/app/server/src/services/gradio-client.ts b/app/server/src/services/gradio-client.ts index 51822a1..5051e94 100644 --- a/app/server/src/services/gradio-client.ts +++ b/app/server/src/services/gradio-client.ts @@ -1,5 +1,6 @@ import { Client } from "@gradio/client"; import { config } from '../config/index.js'; +import { pipelineManager } from './pipeline-manager.js'; let clientInstance: Client | null = null; let connectionPromise: Promise | null = null; @@ -9,6 +10,11 @@ let connectionPromise: Promise | null = null; * Caches the connection for reuse across requests. */ export async function getGradioClient(): Promise { + const { state, message } = pipelineManager.getStatus(); + if (state !== 'ready') { + throw new Error(`Pipeline is not ready (${state}): ${message}`); + } + if (clientInstance) return clientInstance; if (connectionPromise) return connectionPromise; diff --git a/app/server/src/services/pipeline-manager.ts b/app/server/src/services/pipeline-manager.ts index d3121df..3248127 100644 --- a/app/server/src/services/pipeline-manager.ts +++ b/app/server/src/services/pipeline-manager.ts @@ -92,7 +92,7 @@ class PipelineManager { this.process = spawn(pythonPath, args, { cwd: aceStepDir, windowsHide: true, - stdio: ['ignore', 'pipe', 'inherit'], // stderr=inherit for tqdm progress bars + stdio: ['ignore', 'pipe', 'pipe'], // pipe stderr so we can detect Gradio ready signal env: { ...process.env, PYTHONUNBUFFERED: '1', @@ -109,7 +109,13 @@ class PipelineManager { this.parseStdout(text); }); - // stderr is inherited — writes directly to console (tqdm works) + // Pipe stderr: forward to process.stderr (tqdm still visible) and parse for readiness + this.process.stderr!.on('data', (data: Buffer) => { + const text = data.toString(); + process.stderr.write(text); + this.parseStdout(text); // Gradio 6 prints "Running on local URL:" to stderr + this.parseStderr(text); + }); this.process.on('exit', (code, signal) => { console.log(`[Pipeline] Process exited: code=${code} signal=${signal}`); @@ -173,7 +179,7 @@ class PipelineManager { if (text.includes('Initializing 5Hz LM') || text.includes('loading 5Hz LM tokenizer')) { this.message = 'Loading language model...'; } - if (text.includes('Running on local URL') || text.includes('Running on')) { + if (text.includes('Running on local URL') || text.includes('Uvicorn running on')) { this.onReady(); } } @@ -190,6 +196,7 @@ class PipelineManager { } private onReady() { + if (this.state === 'ready') return; this.state = 'ready'; this.message = 'Pipeline running'; this.startedAt = Date.now(); diff --git a/download_model.sh b/download_model.sh new file mode 100755 index 0000000..d4e76a7 --- /dev/null +++ b/download_model.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +export HF_HOME="$SCRIPT_DIR/models" +export HUGGINGFACE_HUB_CACHE="$SCRIPT_DIR/models" +export HF_HUB_ENABLE_HF_TRANSFER=1 + +if [ ! -f "venv/bin/python" ]; then + echo "ERROR: Python venv not found! Run install.sh first." + exit 1 +fi + +PYTHON="$SCRIPT_DIR/venv/bin/python" + +echo "========================================" +echo " ACE-Step Studio - Download Models" +echo "========================================" +echo "" +echo "Select model to download:" +echo "" +echo " 1. XL Turbo - 18.8 GB, fast, 8 steps" +echo " 2. XL SFT - 18.8 GB, best quality, 50 steps" +echo " 3. XL Turbo BF16 - 7.5 GB, compact, less VRAM" +echo " 4. Download all three" +echo "" +read -rp "Enter number 1-4: " MODEL_CHOICE + +case "$MODEL_CHOICE" in + 1) + echo "" + echo "Downloading ACE-Step XL Turbo..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + ACE-Step/acestep-v15-xl-turbo \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-turbo" + ;; + 2) + echo "" + echo "Downloading ACE-Step XL SFT..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + ACE-Step/acestep-v15-xl-sft \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-sft" + ;; + 3) + echo "" + echo "Downloading ACE-Step XL Turbo BF16..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + marcorez8/acestep-v15-xl-turbo-bf16 \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-turbo-bf16" + ;; + 4) + echo "" + echo "Downloading all three models..." + echo "" + echo "[1/3] XL Turbo..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + ACE-Step/acestep-v15-xl-turbo \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-turbo" + echo "" + echo "[2/3] XL SFT..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + ACE-Step/acestep-v15-xl-sft \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-sft" + echo "" + echo "[3/3] XL Turbo BF16..." + "$PYTHON" -m huggingface_hub.commands.huggingface_cli download \ + marcorez8/acestep-v15-xl-turbo-bf16 \ + --local-dir "ACE-Step-1.5/checkpoints/acestep-v15-xl-turbo-bf16" + ;; + *) + echo "Invalid choice!" + exit 1 + ;; +esac + +echo "" +echo "========================================" +echo " Download complete!" +echo "========================================" diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..b98893c --- /dev/null +++ b/install.sh @@ -0,0 +1,232 @@ +#!/bin/bash +set -euo pipefail + +echo "========================================" +echo " ACE-Step Studio - Install" +echo "========================================" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +export TMPDIR="$SCRIPT_DIR/temp" +mkdir -p downloads temp models cache app/data app/server/public/audio + +OS="$(uname -s)" +ARCH="$(uname -m)" + +# ============================================================ +# Step 1: GPU / compute backend selection +# ============================================================ +echo "" + +if [ "$OS" = "Darwin" ]; then + echo "Select your compute backend:" + echo "" + echo " 1. Apple Silicon (MPS)" + echo " 2. CPU only" + echo "" + read -rp "Enter number (1-2): " GPU_CHOICE + case "$GPU_CHOICE" in + 1) CUDA_VERSION="mps"; CUDA_NAME="Apple Silicon (MPS)";; + 2) CUDA_VERSION="cpu"; CUDA_NAME="CPU only";; + *) echo "Invalid choice!"; exit 1;; + esac +else + echo "Select your GPU:" + echo "" + echo " 1. NVIDIA GTX 10xx (Pascal)" + echo " 2. NVIDIA RTX 20xx (Turing)" + echo " 3. NVIDIA RTX 30xx (Ampere)" + echo " 4. NVIDIA RTX 40xx (Ada Lovelace)" + echo " 5. NVIDIA RTX 50xx (Blackwell)" + echo " 6. CPU only (no GPU)" + echo "" + read -rp "Enter number (1-6): " GPU_CHOICE + case "$GPU_CHOICE" in + 1) CUDA_VERSION="cu118"; CUDA_NAME="CUDA 11.8 (GTX 10xx)";; + 2) CUDA_VERSION="cu126"; CUDA_NAME="CUDA 12.6 (RTX 20xx)";; + 3) CUDA_VERSION="cu126"; CUDA_NAME="CUDA 12.6 (RTX 30xx)";; + 4) CUDA_VERSION="cu128"; CUDA_NAME="CUDA 12.8 (RTX 40xx)";; + 5) CUDA_VERSION="cu128"; CUDA_NAME="CUDA 12.8 (RTX 50xx)";; + 6) CUDA_VERSION="cpu"; CUDA_NAME="CPU only";; + *) echo "Invalid choice!"; exit 1;; + esac +fi + +TORCH_VERSION="2.7.1" +TORCHAUDIO_VERSION="2.7.1" + +echo "" +echo "Selected: $CUDA_NAME" +echo "" + +# ============================================================ +# Step 2: Python virtual environment +# ============================================================ +if [ -f "venv/bin/python" ]; then + echo "[OK] Python venv already exists" +else + echo "[1/7] Setting up Python virtual environment..." + PYTHON_CMD="" + for py in python3.12 python3.11 python3.10 python3; do + if command -v "$py" &>/dev/null; then + PYTHON_CMD="$py" + break + fi + done + if [ -z "$PYTHON_CMD" ]; then + echo "ERROR: Python 3.10+ not found! Install Python 3.12 first." + echo " Linux: sudo apt install python3.12 python3.12-venv" + echo " Mac: brew install python@3.12" + exit 1 + fi + "$PYTHON_CMD" -m venv venv + echo "[OK] Python venv created using $PYTHON_CMD" +fi + +PYTHON="$SCRIPT_DIR/venv/bin/python" + +# ============================================================ +# Step 3: pip +# ============================================================ +echo "[2/7] Upgrading pip..." +"$PYTHON" -m pip install --upgrade pip --quiet + +# ============================================================ +# Step 4: PyTorch +# ============================================================ +echo "[3/7] Installing PyTorch $TORCH_VERSION ($CUDA_NAME)..." +if [ "$OS" = "Darwin" ]; then + "$PYTHON" -m pip install \ + torch==$TORCH_VERSION torchaudio==$TORCHAUDIO_VERSION torchvision +else + "$PYTHON" -m pip install \ + torch==$TORCH_VERSION torchaudio==$TORCHAUDIO_VERSION torchvision \ + --index-url "https://download.pytorch.org/whl/$CUDA_VERSION" +fi + +# ============================================================ +# Step 5: ACE-Step dependencies +# ============================================================ +echo "[4/7] Installing ACE-Step dependencies..." +"$PYTHON" -m pip install hatchling editables + +"$PYTHON" -m pip install \ + -e ACE-Step-1.5/acestep/third_parts/nano-vllm/ + +"$PYTHON" -m pip install \ + "transformers>=4.51.0,<4.58.0" diffusers gradio==6.2.0 \ + matplotlib scipy soundfile loguru einops accelerate fastapi diskcache \ + "uvicorn[standard]" numba vector-quantize-pytorch torchcodec \ + "torchao>=0.16.0,<0.17.0" toml peft modelscope tensorboard \ + typer-slim hf_transfer hf_xet lightning lycoris-lora safetensors xxhash + +if [ "$CUDA_VERSION" != "cpu" ] && [ "$CUDA_VERSION" != "mps" ]; then + echo "Installing Triton for torch.compile..." + "$PYTHON" -m pip install "triton>=3.0.0,<3.4" +fi + +if [ "$CUDA_VERSION" = "cu128" ] && [ "$OS" != "Darwin" ]; then + echo "Installing Flash Attention 2..." + "$PYTHON" -m pip install flash-attn --no-build-isolation || \ + echo "WARNING: Flash Attention failed to install. Continuing without it." +fi + +"$PYTHON" -m pip install -e ACE-Step-1.5/ --no-deps + +# ============================================================ +# Step 6: Node.js +# ============================================================ +NODE_VERSION="22.18.0" + +if [ -f "node/bin/node" ]; then + echo "[OK] Node.js already installed" +else + echo "[5/7] Downloading Node.js 22 LTS..." + mkdir -p node + + if [ "$OS" = "Darwin" ]; then + if [ "$ARCH" = "arm64" ]; then + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-darwin-arm64.tar.gz" + else + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-darwin-x64.tar.gz" + fi + curl -fL "$NODE_URL" -o downloads/node.tar.gz + tar -xzf downloads/node.tar.gz -C node/ --strip-components=1 + else + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" + curl -fL "$NODE_URL" -o downloads/node.tar.xz + tar -xJf downloads/node.tar.xz -C node/ --strip-components=1 + fi + echo "[OK] Node.js 22 LTS installed" +fi + +export PATH="$SCRIPT_DIR/node/bin:$PATH" + +# ============================================================ +# Step 7: npm dependencies +# ============================================================ +echo "[6/7] Installing npm dependencies..." + +echo " Installing frontend deps..." +cd "$SCRIPT_DIR/app" +"$SCRIPT_DIR/node/bin/npm" install + +echo " Installing server deps..." +cd "$SCRIPT_DIR/app/server" +"$SCRIPT_DIR/node/bin/npm" install + +# ============================================================ +# Step 8: Build frontend +# ============================================================ +echo "[7/7] Building frontend..." +cd "$SCRIPT_DIR/app" +"$SCRIPT_DIR/node/bin/npx" vite build + +# ============================================================ +# Step 9: FFmpeg +# ============================================================ +cd "$SCRIPT_DIR" + +if [ -f "ffmpeg/ffmpeg" ]; then + echo "[OK] FFmpeg already installed" +elif command -v ffmpeg &>/dev/null; then + echo "[OK] FFmpeg found in system PATH" +else + echo "Downloading FFmpeg..." + mkdir -p ffmpeg + + if [ "$OS" = "Darwin" ]; then + if [ "$ARCH" = "arm64" ]; then + FFMPEG_URL="https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" + else + FFMPEG_URL="https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" + fi + curl -fL "$FFMPEG_URL" -o downloads/ffmpeg.zip + unzip -q downloads/ffmpeg.zip -d ffmpeg/ + chmod +x ffmpeg/ffmpeg + else + FFMPEG_URL="https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz" + curl -fL "$FFMPEG_URL" -o downloads/ffmpeg.tar.xz + mkdir -p downloads/ffmpeg-extract + tar -xJf downloads/ffmpeg.tar.xz -C downloads/ffmpeg-extract/ --strip-components=1 + cp downloads/ffmpeg-extract/bin/ffmpeg ffmpeg/ffmpeg + cp downloads/ffmpeg-extract/bin/ffprobe ffmpeg/ffprobe + rm -rf downloads/ffmpeg-extract + chmod +x ffmpeg/ffmpeg ffmpeg/ffprobe + fi + echo "[OK] FFmpeg installed" +fi + +# ============================================================ +# Save GPU config +# ============================================================ +echo "$CUDA_VERSION" > cuda_version.txt + +echo "" +echo "========================================" +echo " Installation complete!" +echo "" +echo " To start: ./run.sh" +echo " Models download automatically on first run." +echo "========================================" diff --git a/minimal-install-linux.sh b/minimal-install-linux.sh new file mode 100755 index 0000000..1e8d57a --- /dev/null +++ b/minimal-install-linux.sh @@ -0,0 +1,233 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "===========================================" +echo " ACE-Step Studio - Minimal Linux Install" +echo "===========================================" +echo "" + +# ================================================================ +# Phase 1: Dependency checks (collect ALL issues before failing) +# ================================================================ +ERRORS=() +WARNINGS=() + +# --- CUDA drivers --- +if command -v nvidia-smi &>/dev/null; then + CUDA_DRIVER="$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1 || true)" + CUDA_VERSION_DETECTED="$(nvidia-smi | grep -oP 'CUDA Version: \K[0-9.]+' 2>/dev/null || true)" + echo "[OK] NVIDIA driver: $CUDA_DRIVER (CUDA $CUDA_VERSION_DETECTED)" +else + WARNINGS+=("nvidia-smi not found - GPU acceleration unavailable. PyTorch will run on CPU.") + CUDA_VERSION_DETECTED="" +fi + +# --- conda --- +CONDA_CMD="" +if command -v conda &>/dev/null; then + CONDA_CMD="conda" + echo "[OK] conda: $(conda --version)" +elif command -v mamba &>/dev/null; then + CONDA_CMD="mamba" + echo "[OK] mamba: $(mamba --version | head -1)" +else + ERRORS+=("conda/mamba not found. Install Miniconda: https://docs.conda.io/en/latest/miniconda.html") +fi + +# --- Python (via conda env or system) --- +PYTHON="" +CONDA_ENV_NAME="acestep" +if [ -n "$CONDA_CMD" ]; then + if conda env list 2>/dev/null | grep -q "^${CONDA_ENV_NAME}[[:space:]]"; then + PYTHON="$(conda run -n "$CONDA_ENV_NAME" which python 2>/dev/null || true)" + if [ -n "$PYTHON" ]; then + PY_VER="$("$PYTHON" --version 2>&1)" + echo "[OK] conda env '$CONDA_ENV_NAME': $PY_VER" + fi + fi +fi +if [ -z "$PYTHON" ]; then + for py in python3.12 python3.11 python3.10; do + if command -v "$py" &>/dev/null; then + PYTHON="$(command -v "$py")" + echo "[OK] System Python: $("$PYTHON" --version)" + break + fi + done +fi +if [ -z "$PYTHON" ]; then + ERRORS+=("Python 3.10+ not found. Run: conda create -n acestep python=3.12") +fi + +# --- pip --- +if [ -n "$PYTHON" ] && ! "$PYTHON" -m pip --version &>/dev/null 2>&1; then + ERRORS+=("pip not available for $PYTHON. Run: $PYTHON -m ensurepip") +fi + +# --- Node.js --- +NODE_MIN=18 +if command -v node &>/dev/null; then + NODE_VER_FULL="$(node --version)" + NODE_MAJOR="${NODE_VER_FULL#v}" + NODE_MAJOR="${NODE_MAJOR%%.*}" + if [ "$NODE_MAJOR" -ge "$NODE_MIN" ]; then + echo "[OK] node: $NODE_VER_FULL" + else + ERRORS+=("Node.js $NODE_VER_FULL is too old (need v${NODE_MIN}+). Install: https://nodejs.org/en/download") + fi +else + ERRORS+=("node not found. Install: https://nodejs.org/en/download or sudo apt install nodejs npm") +fi + +# --- npm --- +if command -v npm &>/dev/null; then + echo "[OK] npm: $(npm --version)" +else + ERRORS+=("npm not found. Install alongside Node.js.") +fi + +# --- ffmpeg --- +if command -v ffmpeg &>/dev/null; then + FFMPEG_VER="$(ffmpeg -version 2>&1 | head -1 | grep -oP 'ffmpeg version \K\S+')" + echo "[OK] ffmpeg: $FFMPEG_VER" +else + WARNINGS+=("ffmpeg not found - video rendering will not work. Fix: sudo apt install ffmpeg") +fi + +# --- git --- +if command -v git &>/dev/null; then + echo "[OK] git: $(git --version)" +else + ERRORS+=("git not found. Fix: sudo apt install git") +fi + +# --- ACE-Step source --- +if [ ! -d "ACE-Step-1.5" ]; then + ERRORS+=("ACE-Step-1.5/ source directory not found in $SCRIPT_DIR") +fi + +# --- Print warnings --- +if [ ${#WARNINGS[@]} -gt 0 ]; then + echo "" + for w in "${WARNINGS[@]}"; do + echo " [WARN] $w" + done +fi + +# --- Abort on errors --- +if [ ${#ERRORS[@]} -gt 0 ]; then + echo "" + echo "==========================================" + echo " Missing dependencies - cannot proceed:" + echo "==========================================" + for e in "${ERRORS[@]}"; do + echo " [MISSING] $e" + done + echo "" + echo "Install the above, then re-run this script." + exit 1 +fi + +echo "" +echo "All required dependencies found. Proceeding with install..." +echo "" + +# ============================================================ +# Phase 2: Conda environment +# ============================================================ +if ! conda env list 2>/dev/null | grep -q "^${CONDA_ENV_NAME}[[:space:]]"; then + echo "[1/4] Creating conda environment '$CONDA_ENV_NAME' (Python 3.12)..." + $CONDA_CMD create -y -n "$CONDA_ENV_NAME" python=3.12 + echo "[OK] Conda env created" +else + echo "[1/4] Conda env '$CONDA_ENV_NAME' already exists" +fi + +PYTHON="$(conda run -n "$CONDA_ENV_NAME" which python)" + +# ============================================================ +# Phase 3: Python packages +# ============================================================ +echo "[2/4] Installing Python packages..." + +# Detect CUDA version for PyTorch index +if [ -n "$CUDA_VERSION_DETECTED" ]; then + CUDA_MAJOR="${CUDA_VERSION_DETECTED%%.*}" + CUDA_MINOR="$(echo "$CUDA_VERSION_DETECTED" | cut -d. -f2)" + CUDA_NUM="${CUDA_MAJOR}${CUDA_MINOR}" + if [ "$CUDA_NUM" -ge 128 ]; then TORCH_INDEX="cu128" + elif [ "$CUDA_NUM" -ge 126 ]; then TORCH_INDEX="cu126" + elif [ "$CUDA_NUM" -ge 118 ]; then TORCH_INDEX="cu118" + else TORCH_INDEX="cpu" + fi +else + TORCH_INDEX="cpu" +fi + +echo " PyTorch index: $TORCH_INDEX" + +conda run -n "$CONDA_ENV_NAME" pip install --upgrade pip --quiet + +conda run -n "$CONDA_ENV_NAME" pip install \ + torch==2.7.1 torchaudio==2.7.1 torchvision \ + --index-url "https://download.pytorch.org/whl/$TORCH_INDEX" + +conda run -n "$CONDA_ENV_NAME" pip install hatchling editables + +conda run -n "$CONDA_ENV_NAME" pip install \ + -e ACE-Step-1.5/acestep/third_parts/nano-vllm/ --quiet + +conda run -n "$CONDA_ENV_NAME" pip install \ + "transformers>=4.51.0,<4.58.0" diffusers gradio==6.2.0 \ + matplotlib scipy soundfile loguru einops accelerate fastapi diskcache \ + "uvicorn[standard]" numba vector-quantize-pytorch torchcodec \ + "torchao>=0.16.0,<0.17.0" toml peft modelscope tensorboard \ + typer-slim hf_transfer hf_xet lightning lycoris-lora safetensors xxhash + +if [ "$TORCH_INDEX" != "cpu" ]; then + conda run -n "$CONDA_ENV_NAME" pip install "triton>=3.0.0,<3.4" || \ + echo " [WARN] triton install failed - torch.compile will be unavailable" +fi + +conda run -n "$CONDA_ENV_NAME" pip install -e ACE-Step-1.5/ --no-deps + +echo "[OK] Python packages installed" + +# ============================================================ +# Phase 4: npm dependencies + frontend build +# ============================================================ +echo "[3/4] Installing npm dependencies..." + +mkdir -p app/data app/server/public/audio + +cd "$SCRIPT_DIR/app" +npm install + +cd "$SCRIPT_DIR/app/server" +npm install + +echo "[4/4] Building frontend..." +cd "$SCRIPT_DIR/app" +npx vite build + +# ============================================================ +# Save config +# ============================================================ +cd "$SCRIPT_DIR" +echo "$TORCH_INDEX" > cuda_version.txt +echo "conda:$CONDA_ENV_NAME" > python_backend.txt + +echo "" +echo "========================================" +echo " Install complete!" +echo "" +echo " Conda env : $CONDA_ENV_NAME" +echo " PyTorch : $TORCH_INDEX" +echo "" +echo " To start : conda run -n $CONDA_ENV_NAME bash run.sh" +echo " Or activate first:" +echo " conda activate $CONDA_ENV_NAME && ./run.sh" +echo "========================================" diff --git a/python_backend.txt b/python_backend.txt new file mode 100644 index 0000000..1f330bc --- /dev/null +++ b/python_backend.txt @@ -0,0 +1 @@ +conda:acestep diff --git a/reinstall.sh b/reinstall.sh new file mode 100755 index 0000000..078f33f --- /dev/null +++ b/reinstall.sh @@ -0,0 +1,112 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "========================================" +echo " ACE-Step Studio - Clean Reinstall" +echo "========================================" +echo "" +echo " This will DELETE and reinstall:" +echo " - venv/ (Python + all packages)" +echo " - node/ (Node.js runtime)" +echo " - app/node_modules (npm packages)" +echo " - app/server/node_modules" +echo " - app/dist (frontend build)" +echo " - downloads/ (cached installers)" +echo "" +echo " This will KEEP (safe):" +echo " - models/ (downloaded models)" +echo " - output/ (generated audio)" +echo " - cache/ (HF cache with models)" +echo " - app/data/ (database, settings)" +echo " - app/server/public/audio/ (saved songs)" +echo " - datasets/ (training data)" +echo " - ffmpeg/ (ffmpeg binary)" +echo " - lora_output/ (trained LoRAs)" +echo " - ACE-Step-1.5/ (source code, not deps)" +echo " - cuda_version.txt (GPU config)" +echo "" + +read -rp "Type YES to continue: " CONFIRM +if [ "$CONFIRM" != "YES" ]; then + echo "Cancelled." + exit 0 +fi + +echo "" +echo "============================================================" +echo " Cleaning software directories..." +echo "============================================================" + +echo "IMPORTANT: Close ACE-Step Studio (run.sh) before continuing!" +echo "If the app is running, files may be locked and cleanup will fail." +echo "" + +if [ -d "venv" ]; then + echo "Removing venv/..." + rm -rf venv + echo " [OK] venv removed" +fi + +if [ -d "node" ]; then + echo "Removing node/..." + rm -rf node + echo " [OK] node removed" +fi + +if [ -d "app/node_modules" ]; then + echo "Removing app/node_modules/..." + rm -rf app/node_modules + echo " [OK] app/node_modules removed" +fi + +if [ -d "app/server/node_modules" ]; then + echo "Removing app/server/node_modules/..." + rm -rf app/server/node_modules + echo " [OK] app/server/node_modules removed" +fi + +if [ -d "app/dist" ]; then + echo "Removing app/dist/..." + rm -rf app/dist + echo " [OK] app/dist removed" +fi + +if [ -d "downloads" ]; then + echo "Removing downloads/..." + rm -rf downloads + echo " [OK] downloads removed" +fi + +[ -f "app/package-lock.json" ] && rm -f app/package-lock.json +[ -f "app/server/package-lock.json" ] && rm -f app/server/package-lock.json + +# ============================================================ +# Pull latest code before installing +# ============================================================ +if command -v git &>/dev/null && [ -d ".git" ]; then + echo "" + echo "Pulling latest code..." + git stash 2>/dev/null || true + git pull + git stash pop 2>/dev/null || true + echo " [OK] Code updated" +fi + +if [ -f "cuda_version.txt" ]; then + SAVED_CUDA="$(cat cuda_version.txt)" + echo "" + echo "NOTE: Your previous GPU config was: $SAVED_CUDA" + echo " install.sh will ask you to select GPU again." + echo " Choose the same option to keep your config." +fi + +echo "" +echo "============================================================" +echo " Starting fresh install..." +echo "============================================================" +echo "" + +bash "$SCRIPT_DIR/install.sh" diff --git a/run-dev.sh b/run-dev.sh new file mode 100755 index 0000000..98ba057 --- /dev/null +++ b/run-dev.sh @@ -0,0 +1,125 @@ +#!/bin/bash +set -euo pipefail + +echo "========================================" +echo " ACE-Step Studio" +echo "========================================" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# === Checks === +if [ ! -f "venv/bin/python" ]; then + echo "ERROR: Python venv not found! Run install.sh first" + exit 1 +fi +if [ ! -f "node/bin/node" ]; then + echo "ERROR: Node.js not found! Run install.sh first" + exit 1 +fi +if [ ! -d "ACE-Step-1.5" ]; then + echo "ERROR: ACE-Step-1.5 not found!" + exit 1 +fi + +# === Environment isolation === +export TMPDIR="$SCRIPT_DIR/temp" +mkdir -p "$TMPDIR" + +export HF_HOME="$SCRIPT_DIR/models" +export HUGGINGFACE_HUB_CACHE="$SCRIPT_DIR/models" +export TRANSFORMERS_CACHE="$SCRIPT_DIR/models" +export HF_HUB_ENABLE_HF_TRANSFER=1 +mkdir -p "$HF_HOME" + +export TORCH_HOME="$SCRIPT_DIR/models/torch" +mkdir -p "$TORCH_HOME" + +export XDG_CACHE_HOME="$SCRIPT_DIR/cache" +mkdir -p "$XDG_CACHE_HOME" + +if [ -f "$SCRIPT_DIR/ffmpeg/ffmpeg" ]; then + export PATH="$SCRIPT_DIR/ffmpeg:$PATH" +fi + +export PYTHONIOENCODING=utf-8 +export PYTHONUNBUFFERED=1 +export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True + +export PATH="$SCRIPT_DIR/node/bin:$PATH" + +# === Default model === +export DEFAULT_MODEL="acestep-v15-xl-turbo" +export ACESTEP_API_URL="http://localhost:8001" +export ACESTEP_PATH="$SCRIPT_DIR/ACE-Step-1.5" +export PYTHON_PATH="$SCRIPT_DIR/venv/bin/python" + +if [ -f "cuda_version.txt" ]; then + CUDA_VERSION="$(cat cuda_version.txt)" + echo "GPU: $CUDA_VERSION" +fi + +# === Install npm deps if needed === +if [ ! -d "app/node_modules" ]; then + echo "Installing npm dependencies..." + cd app + "$SCRIPT_DIR/node/bin/npm" install + cd "$SCRIPT_DIR" +fi + +# === Create output dirs === +mkdir -p app/data app/server/public/audio + +echo "" +echo "Starting 3 services:" +echo " [1] Gradio pipeline (port 8001)" +echo " [2] Express backend (port 3001)" +echo " [3] Vite frontend (port 3000)" +echo "" + +# === Cleanup on exit === +GRADIO_PID="" +EXPRESS_PID="" + +cleanup() { + echo "" + echo "Shutting down..." + [ -n "$GRADIO_PID" ] && kill "$GRADIO_PID" 2>/dev/null || true + [ -n "$EXPRESS_PID" ] && kill "$EXPRESS_PID" 2>/dev/null || true + echo "Done." +} +trap cleanup EXIT INT TERM + +# === Start Gradio pipeline === +echo "Starting Gradio pipeline with $DEFAULT_MODEL..." +cd "$SCRIPT_DIR/ACE-Step-1.5" +"$SCRIPT_DIR/venv/bin/python" -m acestep.acestep_v15_pipeline \ + --config_path "$DEFAULT_MODEL" \ + --port 8001 \ + --init_service true \ + --init_llm true & +GRADIO_PID=$! + +echo "Waiting for Gradio to initialize..." +sleep 5 + +# === Start Express backend === +echo "Starting Express backend..." +cd "$SCRIPT_DIR/app/server" +"$SCRIPT_DIR/node/bin/node" \ + "$SCRIPT_DIR/app/server/node_modules/tsx/dist/cli.mjs" \ + src/index.ts & +EXPRESS_PID=$! + +sleep 2 + +# === Start Vite frontend (foreground) === +echo "" +echo "========================================" +echo " UI will open at http://localhost:3000" +echo " Press Ctrl+C to stop all services" +echo "========================================" +echo "" + +cd "$SCRIPT_DIR/app" +"$SCRIPT_DIR/node/bin/npx" vite --open diff --git a/run-linux.sh b/run-linux.sh new file mode 100755 index 0000000..e665b66 --- /dev/null +++ b/run-linux.sh @@ -0,0 +1,109 @@ +#!/bin/bash +set -euo pipefail + +echo "========================================" +echo " ACE-Step Studio (Single Terminal)" +echo "========================================" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# === Resolve Python backend === +CONDA_ENV_NAME="acestep" +if [ -f "python_backend.txt" ]; then + BACKEND="$(cat python_backend.txt)" + if [[ "$BACKEND" == conda:* ]]; then + CONDA_ENV_NAME="${BACKEND#conda:}" + fi +fi + +# === Checks === +if ! conda env list 2>/dev/null | grep -q "^${CONDA_ENV_NAME}[[:space:]]"; then + echo "ERROR: conda env '$CONDA_ENV_NAME' not found! Run minimal-install-linux.sh first" + exit 1 +fi + +PYTHON="$(conda run -n "$CONDA_ENV_NAME" which python 2>/dev/null || true)" +if [ -z "$PYTHON" ]; then + echo "ERROR: Python not found in conda env '$CONDA_ENV_NAME'" + exit 1 +fi + +if ! command -v node &>/dev/null; then + echo "ERROR: node not found! Install Node.js 18+ from https://nodejs.org" + exit 1 +fi + +if [ ! -d "ACE-Step-1.5" ]; then + echo "ERROR: ACE-Step-1.5 not found!" + exit 1 +fi + +# === Environment isolation === +export TMPDIR="$SCRIPT_DIR/temp" +mkdir -p "$TMPDIR" + +export HF_HOME="$SCRIPT_DIR/models" +export HUGGINGFACE_HUB_CACHE="$SCRIPT_DIR/models" +export TRANSFORMERS_CACHE="$SCRIPT_DIR/models" +export HF_HUB_ENABLE_HF_TRANSFER=1 +mkdir -p "$HF_HOME" + +export TORCH_HOME="$SCRIPT_DIR/models/torch" +mkdir -p "$TORCH_HOME" + +export XDG_CACHE_HOME="$SCRIPT_DIR/cache" +mkdir -p "$XDG_CACHE_HOME" + +if [ -f "$SCRIPT_DIR/ffmpeg/ffmpeg" ]; then + export PATH="$SCRIPT_DIR/ffmpeg:$PATH" +fi + +export PYTHONIOENCODING=utf-8 +export PYTHONUNBUFFERED=1 +export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True + +# === Pipeline config === +export PYTHON_PATH="$PYTHON" +export ACESTEP_PATH="$SCRIPT_DIR/ACE-Step-1.5" +export DEFAULT_MODEL="marcorez8/acestep-v15-xl-turbo-bf16" +export MANAGE_PIPELINE=true + +if [ -f "cuda_version.txt" ]; then + CUDA_VERSION="$(cat cuda_version.txt)" + echo "GPU: $CUDA_VERSION" +fi + +# === Install npm deps if needed === +if [ ! -d "app/node_modules" ]; then + echo "Installing npm dependencies..." + npm install --prefix "$SCRIPT_DIR/app" +fi + +if [ ! -d "app/server/node_modules" ]; then + echo "Installing server npm dependencies..." + npm install --prefix "$SCRIPT_DIR/app/server" +fi + +# === Build frontend if dist/ missing === +if [ ! -d "app/dist" ]; then + echo "Building frontend..." + npx --prefix "$SCRIPT_DIR/app" vite build +fi + +# === Create output dirs === +mkdir -p app/data app/server/public/audio + +echo "" +echo "========================================" +echo " Single terminal mode" +echo " Express + Pipeline + Frontend" +echo " UI: http://localhost:3001" +echo " Press Ctrl+C to stop" +echo "========================================" +echo "" + +# === Start Express (manages everything, opens browser when pipeline ready) === +node \ + "$SCRIPT_DIR/app/server/node_modules/tsx/dist/cli.mjs" \ + "$SCRIPT_DIR/app/server/src/index.ts" diff --git a/run-no-lm.sh b/run-no-lm.sh new file mode 100755 index 0000000..8ea1c58 --- /dev/null +++ b/run-no-lm.sh @@ -0,0 +1,94 @@ +#!/bin/bash +set -euo pipefail + +echo "========================================" +echo " ACE-Step Studio (NO LM mode)" +echo "========================================" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# === Checks === +if [ ! -f "venv/bin/python" ]; then + echo "ERROR: Python venv not found! Run install.sh first" + exit 1 +fi +if [ ! -f "node/bin/node" ]; then + echo "ERROR: Node.js not found! Run install.sh first" + exit 1 +fi +if [ ! -d "ACE-Step-1.5" ]; then + echo "ERROR: ACE-Step-1.5 not found!" + exit 1 +fi + +# === Environment isolation === +export TMPDIR="$SCRIPT_DIR/temp" +mkdir -p "$TMPDIR" + +export HF_HOME="$SCRIPT_DIR/models" +export HUGGINGFACE_HUB_CACHE="$SCRIPT_DIR/models" +export TRANSFORMERS_CACHE="$SCRIPT_DIR/models" +export HF_HUB_ENABLE_HF_TRANSFER=1 +mkdir -p "$HF_HOME" + +export TORCH_HOME="$SCRIPT_DIR/models/torch" +mkdir -p "$TORCH_HOME" + +export XDG_CACHE_HOME="$SCRIPT_DIR/cache" +mkdir -p "$XDG_CACHE_HOME" + +if [ -f "$SCRIPT_DIR/ffmpeg/ffmpeg" ]; then + export PATH="$SCRIPT_DIR/ffmpeg:$PATH" +fi + +export PYTHONIOENCODING=utf-8 +export PYTHONUNBUFFERED=1 +export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True + +export PATH="$SCRIPT_DIR/node/bin:$PATH" + +# === Pipeline config === +export PYTHON_PATH="$SCRIPT_DIR/venv/bin/python" +export ACESTEP_PATH="$SCRIPT_DIR/ACE-Step-1.5" +export DEFAULT_MODEL="marcorez8/acestep-v15-xl-turbo-bf16" +export MANAGE_PIPELINE=true +export INIT_LLM=false + +if [ -f "cuda_version.txt" ]; then + CUDA_VERSION="$(cat cuda_version.txt)" + echo "GPU: $CUDA_VERSION" +fi + +# === Install npm deps if needed === +if [ ! -d "app/node_modules" ]; then + echo "Installing npm dependencies..." + cd app + "$SCRIPT_DIR/node/bin/npm" install + cd "$SCRIPT_DIR" +fi + +# === Build frontend if dist/ missing === +if [ ! -d "app/dist" ]; then + echo "Building frontend..." + cd app + "$SCRIPT_DIR/node/bin/npx" vite build + cd "$SCRIPT_DIR" +fi + +# === Create output dirs === +mkdir -p app/data app/server/public/audio + +echo "" +echo "========================================" +echo " NO LM mode (more VRAM for DiT)" +echo " Express + Pipeline + Frontend" +echo " UI: http://localhost:3001" +echo " Press Ctrl+C to stop" +echo "========================================" +echo "" + +# === Start Express (manages everything, opens browser when pipeline ready) === +"$SCRIPT_DIR/node/bin/node" \ + "$SCRIPT_DIR/app/server/node_modules/tsx/dist/cli.mjs" \ + "$SCRIPT_DIR/app/server/src/index.ts" diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..712848c --- /dev/null +++ b/run.sh @@ -0,0 +1,93 @@ +#!/bin/bash +set -euo pipefail + +echo "========================================" +echo " ACE-Step Studio (Single Terminal)" +echo "========================================" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# === Checks === +if [ ! -f "venv/bin/python" ]; then + echo "ERROR: Python venv not found! Run install.sh first" + exit 1 +fi +if [ ! -f "node/bin/node" ]; then + echo "ERROR: Node.js not found! Run install.sh first" + exit 1 +fi +if [ ! -d "ACE-Step-1.5" ]; then + echo "ERROR: ACE-Step-1.5 not found!" + exit 1 +fi + +# === Environment isolation === +export TMPDIR="$SCRIPT_DIR/temp" +mkdir -p "$TMPDIR" + +export HF_HOME="$SCRIPT_DIR/models" +export HUGGINGFACE_HUB_CACHE="$SCRIPT_DIR/models" +export TRANSFORMERS_CACHE="$SCRIPT_DIR/models" +export HF_HUB_ENABLE_HF_TRANSFER=1 +mkdir -p "$HF_HOME" + +export TORCH_HOME="$SCRIPT_DIR/models/torch" +mkdir -p "$TORCH_HOME" + +export XDG_CACHE_HOME="$SCRIPT_DIR/cache" +mkdir -p "$XDG_CACHE_HOME" + +if [ -f "$SCRIPT_DIR/ffmpeg/ffmpeg" ]; then + export PATH="$SCRIPT_DIR/ffmpeg:$PATH" +fi + +export PYTHONIOENCODING=utf-8 +export PYTHONUNBUFFERED=1 +export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True + +export PATH="$SCRIPT_DIR/node/bin:$PATH" + +# === Pipeline config === +export PYTHON_PATH="$SCRIPT_DIR/venv/bin/python" +export ACESTEP_PATH="$SCRIPT_DIR/ACE-Step-1.5" +export DEFAULT_MODEL="marcorez8/acestep-v15-xl-turbo-bf16" +export MANAGE_PIPELINE=true + +if [ -f "cuda_version.txt" ]; then + CUDA_VERSION="$(cat cuda_version.txt)" + echo "GPU: $CUDA_VERSION" +fi + +# === Install npm deps if needed === +if [ ! -d "app/node_modules" ]; then + echo "Installing npm dependencies..." + cd app + "$SCRIPT_DIR/node/bin/npm" install + cd "$SCRIPT_DIR" +fi + +# === Build frontend if dist/ missing === +if [ ! -d "app/dist" ]; then + echo "Building frontend..." + cd app + "$SCRIPT_DIR/node/bin/npx" vite build + cd "$SCRIPT_DIR" +fi + +# === Create output dirs === +mkdir -p app/data app/server/public/audio + +echo "" +echo "========================================" +echo " Single terminal mode" +echo " Express + Pipeline + Frontend" +echo " UI: http://localhost:3001" +echo " Press Ctrl+C to stop" +echo "========================================" +echo "" + +# === Start Express (manages everything, opens browser when pipeline ready) === +"$SCRIPT_DIR/node/bin/node" \ + "$SCRIPT_DIR/app/server/node_modules/tsx/dist/cli.mjs" \ + "$SCRIPT_DIR/app/server/src/index.ts" diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..4462457 --- /dev/null +++ b/update.sh @@ -0,0 +1,90 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "========================================" +echo " ACE-Step Studio - Update" +echo "========================================" + +if ! command -v git &>/dev/null; then + echo "ERROR: Git not found! https://git-scm.com/downloads" + exit 1 +fi + +# ============================================================ +# Step 1: Pull latest code +# ============================================================ +if [ -d ".git" ]; then + echo "" + echo "[1/5] Updating ACE-Step Studio..." + git stash 2>/dev/null || true + git pull + git stash pop 2>/dev/null || true +else + echo "[1/5] No git repo, skipping code update" +fi + +# ============================================================ +# Step 2: Update Python deps +# ============================================================ +if [ -f "venv/bin/python" ]; then + PYTHON="$SCRIPT_DIR/venv/bin/python" + echo "" + echo "[2/5] Updating Python dependencies..." + "$PYTHON" -m pip install --upgrade pip + + if [ -d "ACE-Step-1.5/acestep/third_parts/nano-vllm" ]; then + "$PYTHON" -m pip install -e ACE-Step-1.5/acestep/third_parts/nano-vllm/ + fi + + "$PYTHON" -m pip install --upgrade \ + "transformers>=4.51.0,<4.58.0" diffusers gradio==6.2.0 \ + matplotlib scipy soundfile loguru einops accelerate fastapi diskcache \ + "uvicorn[standard]" numba vector-quantize-pytorch torchcodec \ + "torchao>=0.16.0,<0.17.0" toml peft modelscope tensorboard \ + typer-slim hf_transfer hf_xet lightning lycoris-lora safetensors xxhash + + "$PYTHON" -m pip install -e ACE-Step-1.5/ --no-deps +else + echo "[2/5] Python venv not found, skipping. Run install.sh first!" +fi + +# ============================================================ +# Step 3-5: Update npm deps + rebuild frontend +# ============================================================ +if [ -f "node/bin/node" ]; then + export PATH="$SCRIPT_DIR/node/bin:$PATH" + + echo "" + echo "[3/5] Updating frontend dependencies..." + if [ -f "app/package.json" ]; then + cd "$SCRIPT_DIR/app" + "$SCRIPT_DIR/node/bin/npm" install + cd "$SCRIPT_DIR" + fi + + echo "" + echo "[4/5] Updating server dependencies..." + if [ -f "app/server/package.json" ]; then + cd "$SCRIPT_DIR/app/server" + "$SCRIPT_DIR/node/bin/npm" install + cd "$SCRIPT_DIR" + fi + + echo "" + echo "[5/5] Rebuilding frontend..." + if [ -f "app/vite.config.ts" ]; then + cd "$SCRIPT_DIR/app" + "$SCRIPT_DIR/node/bin/npx" vite build + cd "$SCRIPT_DIR" + fi +else + echo "[3-5/5] Node.js not found, skipping npm steps. Run install.sh first!" +fi + +echo "" +echo "========================================" +echo " Update complete!" +echo "========================================"