Update CI: test build.sh deployment script instead of separate aceste… #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | ||
| on: | ||
| release: | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: "Release tag (e.g. v1.0.0)" | ||
| required: true | ||
| default: "v0.0.0-dev" | ||
| concurrency: | ||
| group: release-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| env: | ||
| ACESTEP_CPP_REPO: https://github.com/audiohacking/acestep.cpp.git | ||
| NODE_VERSION: "20" | ||
| jobs: | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| # 1. Build the React frontend (platform-independent) | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| build-frontend: | ||
| name: Build frontend | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
| cache: "npm" | ||
| - name: Install & build | ||
| run: npm ci && npm run build | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: frontend-dist | ||
| path: dist/ | ||
| retention-days: 1 | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| # 2. Compile the Node.js server (platform-independent JS) | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| build-server: | ||
| name: Build Node.js server | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: server | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ env.NODE_VERSION }} | ||
| cache: "npm" | ||
| cache-dependency-path: server/package-lock.json | ||
| - name: Install, compile & prune to production deps | ||
| run: | | ||
| npm ci | ||
| npm run build | ||
| npm prune --production | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: server-bundle | ||
| path: | | ||
| server/dist/ | ||
| server/node_modules/ | ||
| server/package.json | ||
| retention-days: 1 | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| # 3. Per-platform: assemble the bundle with build + model scripts | ||
| # acestep.cpp is NOT compiled here — it is compiled on the user's machine | ||
| # by build.sh / build.bat on first launch, which detects the actual GPU. | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| build-platform: | ||
| name: Bundle ${{ matrix.label }} | ||
| needs: [build-frontend, build-server] | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - label: linux-x64 | ||
| os: linux | ||
| - label: linux-arm64 | ||
| os: linux | ||
| - label: macos-arm64 | ||
| os: macos | ||
| - label: windows-x64 | ||
| os: windows | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| # ── Download pre-built UI artifacts ───────────────────────────────── | ||
| - uses: actions/download-artifact@v4 | ||
| with: | ||
| name: frontend-dist | ||
| path: _release/dist | ||
| - uses: actions/download-artifact@v4 | ||
| with: | ||
| name: server-bundle | ||
| path: _release/server-bundle | ||
| # ── Assemble the release bundle ────────────────────────────────────── | ||
| - name: Assemble bundle | ||
| shell: bash | ||
| run: | | ||
| set -e | ||
| APP=acestep-cpp-ui | ||
| mkdir -p "$APP/bin" "$APP/dist" "$APP/server/dist" "$APP/server/node_modules" \ | ||
| "$APP/data" "$APP/public/audio" "$APP/logs" "$APP/models" | ||
| # Node.js server (compiled JS + production node_modules) | ||
| cp -r _release/server-bundle/dist/. "$APP/server/dist/" | ||
| cp -r _release/server-bundle/node_modules/. "$APP/server/node_modules/" | ||
| cp _release/server-bundle/package.json "$APP/server/" | ||
| # React frontend (served by the API server) | ||
| cp -r _release/dist/. "$APP/dist/" | ||
| # .env template | ||
| cp .env.example "$APP/.env.example" | ||
| # Build scripts — compile acestep.cpp with GPU detection on first run | ||
| cp build.sh "$APP/build.sh" | ||
| chmod +x "$APP/build.sh" | ||
| cp build.bat "$APP/build.bat" | ||
| # Model download scripts | ||
| cp models.sh "$APP/models.sh" | ||
| chmod +x "$APP/models.sh" | ||
| cp models.bat "$APP/models.bat" | ||
| # ── start.sh (Linux / macOS) ────────────────────────────────────── | ||
| cat > "$APP/start.sh" << 'SH' | ||
| #!/bin/bash | ||
| # ACE-Step UI — start | ||
| # On first launch: compiles acestep.cpp for your GPU and downloads base models. | ||
| set -e | ||
| DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| cd "$DIR" | ||
| # Load .env if present | ||
| [ -f .env ] && export $(grep -v '^#' .env | grep -v '^\s*$' | xargs) | ||
| # ── First-run: compile acestep.cpp ─────────────────────────────────────────── | ||
| if [ ! -x "$DIR/bin/ace-qwen3" ] || [ ! -x "$DIR/bin/dit-vae" ]; then | ||
| echo "═══════════════════════════════════════════════════════" | ||
| echo " First run: building acestep.cpp for your hardware" | ||
| echo " GPU support (CUDA / ROCm / Vulkan / Metal) is" | ||
| echo " detected automatically from your system." | ||
| echo " This takes a few minutes and only happens once." | ||
| echo "═══════════════════════════════════════════════════════" | ||
| echo "" | ||
| bash "$DIR/build.sh" | ||
| echo "" | ||
| fi | ||
| # ── First-run: download models ─────────────────────────────────────────────── | ||
| : "${MODELS_DIR:=$DIR/models}" | ||
| if ! ls "$MODELS_DIR"/*.gguf &>/dev/null 2>&1; then | ||
| echo "═══════════════════════════════════════════════════════" | ||
| echo " First run: downloading base GGUF models (~8 GB)" | ||
| echo " VAE + Text Encoder + LM-4B + DiT-Turbo (Q8_0)" | ||
| echo " Requires: curl or wget" | ||
| echo "═══════════════════════════════════════════════════════" | ||
| echo "" | ||
| bash "$DIR/models.sh" --dir "$MODELS_DIR" | ||
| echo "" | ||
| fi | ||
| # ── Start the server ───────────────────────────────────────────────────────── | ||
| : "${ACE_QWEN3_BIN:=$DIR/bin/ace-qwen3}" | ||
| : "${DIT_VAE_BIN:=$DIR/bin/dit-vae}" | ||
| : "${PORT:=3001}" | ||
| mkdir -p logs data public/audio | ||
| echo "Starting ACE-Step UI on port $PORT ..." | ||
| ACE_QWEN3_BIN="$ACE_QWEN3_BIN" \ | ||
| DIT_VAE_BIN="$DIT_VAE_BIN" \ | ||
| MODELS_DIR="$MODELS_DIR" \ | ||
| PORT="$PORT" \ | ||
| DATABASE_PATH="$DIR/data/acestep.db" \ | ||
| AUDIO_DIR="$DIR/public/audio" \ | ||
| FRONTEND_URL="http://localhost:$PORT" \ | ||
| node "$DIR/server/dist/index.js" & | ||
| NODE_PID=$! | ||
| sleep 2 | ||
| echo "" | ||
| echo "ACE-Step UI → http://localhost:$PORT" | ||
| echo "" | ||
| trap 'kill $NODE_PID 2>/dev/null; exit 0' INT TERM | ||
| wait $NODE_PID | ||
| SH | ||
| chmod +x "$APP/start.sh" | ||
| # ── start.bat (Windows) ─────────────────────────────────────────── | ||
| cat > "$APP/start.bat" << 'BAT' | ||
| @echo off | ||
| :: ACE-Step UI — start | ||
| :: On first launch: compiles acestep.cpp for your GPU and downloads base models. | ||
| setlocal EnableDelayedExpansion | ||
| set DIR=%~dp0 | ||
| cd /d "%DIR%" | ||
| :: Load .env if present | ||
| if exist ".env" ( | ||
| for /f "usebackq tokens=* delims=" %%l in (".env") do ( | ||
| set line=%%l | ||
| if not "!line:~0,1!"=="#" if not "!line!"=="" set %%l | ||
| ) | ||
| ) | ||
| :: First-run: compile acestep.cpp | ||
| if not exist "%DIR%bin\ace-qwen3.exe" ( | ||
| echo ═══════════════════════════════════════════════════════ | ||
| echo First run: building acestep.cpp for your hardware | ||
| echo GPU support ^(CUDA / Vulkan^) is detected automatically. | ||
| echo This takes a few minutes and only happens once. | ||
| echo ═══════════════════════════════════════════════════════ | ||
| echo. | ||
| call "%DIR%build.bat" | ||
| if %ERRORLEVEL% NEQ 0 ( echo Build failed. See output above. & pause & exit /b 1 ) | ||
| echo. | ||
| ) | ||
| :: First-run: download models | ||
| if "%MODELS_DIR%"=="" set MODELS_DIR=%DIR%models | ||
| dir /b "%MODELS_DIR%\*.gguf" >nul 2>&1 | ||
| if %ERRORLEVEL% NEQ 0 ( | ||
| echo ═══════════════════════════════════════════════════════ | ||
| echo First run: downloading base GGUF models ~8 GB | ||
| echo VAE + Text Encoder + LM-4B + DiT-Turbo ^(Q8_0^) | ||
| echo ═══════════════════════════════════════════════════════ | ||
| echo. | ||
| call "%DIR%models.bat" --dir "%MODELS_DIR%" | ||
| echo. | ||
| ) | ||
| :: Start the server | ||
| if "%ACE_QWEN3_BIN%"=="" set ACE_QWEN3_BIN=%DIR%bin\ace-qwen3.exe | ||
| if "%DIT_VAE_BIN%"=="" set DIT_VAE_BIN=%DIR%bin\dit-vae.exe | ||
| if "%PORT%"=="" set PORT=3001 | ||
| mkdir logs 2>nul & mkdir data 2>nul & mkdir public\audio 2>nul | ||
| echo Starting ACE-Step UI on port %PORT% ... | ||
| set DATABASE_PATH=%DIR%data\acestep.db | ||
| set AUDIO_DIR=%DIR%public\audio | ||
| set FRONTEND_URL=http://localhost:%PORT% | ||
| node "%DIR%server\dist\index.js" | ||
| BAT | ||
| # ── Release README ──────────────────────────────────────────────── | ||
| cat > "$APP/README.md" << 'MD' | ||
| # ACE-Step UI | ||
| Self-contained release bundle — no Python required. | ||
| Music generation is powered by [acestep.cpp](https://github.com/audiohacking/acestep.cpp). | ||
| ## Requirements | ||
| - **Node.js ≥ 20** — runtime for the API server ([nodejs.org](https://nodejs.org)) | ||
| - **cmake + git** — required by `build.sh` / `build.bat` to compile `acestep.cpp` | ||
| - **curl or wget** — required by `models.sh` to download model files | ||
| - **~8 GB free disk space** — for the default `Q8_0` model set | ||
| ## Quick Start | ||
| ```bash | ||
| # Just run start.sh — it handles everything on first launch: | ||
| # 1. Detects your GPU (CUDA / ROCm / Vulkan / Metal) and compiles acestep.cpp | ||
| # 2. Downloads the base GGUF models (~8 GB) | ||
| # 3. Starts the UI on http://localhost:3001 | ||
| ./start.sh | ||
| ``` | ||
| On Windows: | ||
| ```bat | ||
| start.bat | ||
| ``` | ||
| ## GPU Acceleration | ||
| `build.sh` / `build.bat` automatically detect your GPU on first launch: | ||
| | GPU | Flag used | | ||
| |-----|-----------| | ||
| | NVIDIA (CUDA) | `-DGGML_CUDA=ON` | | ||
| | AMD (ROCm/HIP) | `-DGGML_HIP=ON` | | ||
| | Any (Vulkan) | `-DGGML_VULKAN=ON` | | ||
| | macOS (Metal) | auto-detected by cmake | | ||
| | CPU only | no flags | | ||
| To force a specific backend, run the build script manually: | ||
| ```bash | ||
| ./build.sh --cuda # Force CUDA | ||
| ./build.sh --rocm # Force ROCm/HIP | ||
| ./build.sh --vulkan # Force Vulkan | ||
| ./build.sh --cpu # CPU-only | ||
| ``` | ||
| ## Environment Variables | ||
| | Variable | Default | Description | | ||
| |----------|---------|-------------| | ||
| | `ACE_QWEN3_BIN` | `./bin/ace-qwen3` | Path to the ace-qwen3 LLM binary | | ||
| | `DIT_VAE_BIN` | `./bin/dit-vae` | Path to the dit-vae binary | | ||
| | `MODELS_DIR` | `./models` | Directory containing GGUF model files | | ||
| | `PORT` | `3001` | API + UI server port | | ||
| | `AUDIO_DIR` | `./public/audio` | Where generated audio is stored | | ||
| | `JWT_SECRET` | built-in | Change for multi-user deployments | | ||
| Copy `.env.example` → `.env` to customise these. | ||
| ## Model Management | ||
| Download models manually (useful for selecting a different quantisation): | ||
| ```bash | ||
| ./models.sh # Default: Q8_0 essentials (~8 GB) | ||
| ./models.sh --quant Q5_K_M # Smaller, slightly lower quality | ||
| ./models.sh --all # Every model and quantisation | ||
| ``` | ||
| MD | ||
| echo "Bundle assembled for ${{ matrix.label }}:" | ||
| ls -lh "$APP/" | ||
| # ── Package ────────────────────────────────────────────────────────── | ||
| - name: Create archive (tar.gz) | ||
| if: matrix.os != 'windows' | ||
| shell: bash | ||
| run: | | ||
| TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}" | ||
| [[ "$TAG" != v* ]] && TAG="${{ github.event.inputs.tag || 'v0.0.0-dev' }}" | ||
| ARCHIVE="acestep-cpp-ui-${TAG}-${{ matrix.label }}.tar.gz" | ||
| tar -czf "$ARCHIVE" acestep-cpp-ui/ | ||
| echo "ARCHIVE=$ARCHIVE" >> "$GITHUB_ENV" | ||
| ls -lh "$ARCHIVE" | ||
| - name: Create archive (zip — Windows) | ||
| if: matrix.os == 'windows' | ||
| shell: bash | ||
| run: | | ||
| TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}" | ||
| [[ "$TAG" != v* ]] && TAG="${{ github.event.inputs.tag || 'v0.0.0-dev' }}" | ||
| ARCHIVE="acestep-cpp-ui-${TAG}-${{ matrix.label }}.zip" | ||
| zip -qr "$ARCHIVE" acestep-cpp-ui/ | ||
| echo "ARCHIVE=$ARCHIVE" >> "$GITHUB_ENV" | ||
| ls -lh "$ARCHIVE" | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: release-${{ matrix.label }} | ||
| path: ${{ env.ARCHIVE }} | ||
| retention-days: 7 | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| # 4. Publish GitHub Release | ||
| # ──────────────────────────────────────────────────────────────────────────── | ||
| publish-release: | ||
| name: Publish GitHub Release | ||
| needs: build-platform | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - uses: actions/download-artifact@v4 | ||
| with: | ||
| pattern: release-* | ||
| path: release-artifacts | ||
| merge-multiple: true | ||
| - name: List artifacts | ||
| run: ls -lh release-artifacts/ | ||
| - name: Resolve tag | ||
| id: tag | ||
| run: | | ||
| TAG="${GITHUB_REF_NAME:-}" | ||
| [[ "$TAG" == v* ]] || TAG="${{ github.event.inputs.tag || 'v0.0.0-dev' }}" | ||
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | ||
| - name: Generate changelog | ||
| id: changelog | ||
| run: | | ||
| PREV=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | ||
| if [ -n "$PREV" ]; then | ||
| LOG=$(git log "${PREV}..HEAD" --oneline --no-decorate 2>/dev/null | head -50) | ||
| else | ||
| LOG=$(git log --oneline --no-decorate | head -30) | ||
| fi | ||
| { echo "log<<EOF"; echo "$LOG"; echo "EOF"; } >> "$GITHUB_OUTPUT" | ||
| - name: Create GitHub Release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: ${{ steps.tag.outputs.tag }} | ||
| name: "ACE-Step UI ${{ steps.tag.outputs.tag }}" | ||
| draft: false | ||
| prerelease: ${{ contains(steps.tag.outputs.tag, '-') }} | ||
| body: | | ||
| ## ACE-Step UI ${{ steps.tag.outputs.tag }} | ||
| Self-contained bundle — **no Python required**. | ||
| Music generation is powered by [acestep.cpp](https://github.com/audiohacking/acestep.cpp). | ||
| > **GPU acceleration is built on your machine** — `start.sh` / `start.bat` automatically | ||
| > detects your GPU (CUDA / ROCm / Vulkan / Metal) and compiles `acestep.cpp` on first launch. | ||
| > Models are also downloaded automatically on first run. | ||
| ### Platforms | ||
| | File | OS | Arch | | ||
| |------|----|------| | ||
| | `*-linux-x64.tar.gz` | Linux | x86\_64 | | ||
| | `*-linux-arm64.tar.gz` | Linux | ARM64 | | ||
| | `*-macos-arm64.tar.gz` | macOS | Apple Silicon | | ||
| | `*-windows-x64.zip` | Windows | x86\_64 | | ||
| ### Requirements | ||
| - **Node.js ≥ 20** — [nodejs.org](https://nodejs.org) | ||
| - **cmake + git** — to compile `acestep.cpp` on first launch | ||
| - **curl or wget** — to download GGUF model files on first launch | ||
| ### Quick Start | ||
| ```bash | ||
| tar xzf acestep-cpp-ui-*-linux-x64.tar.gz | ||
| cd acestep-cpp-ui | ||
| ./start.sh # builds acestep.cpp, downloads models, starts UI → http://localhost:3001 | ||
| ``` | ||
| On Windows: extract the `.zip` and run `start.bat`. | ||
| ### What's Changed | ||
| ${{ steps.changelog.outputs.log }} | ||
| files: release-artifacts/* | ||
| fail_on_unmatched_files: false | ||