name: Release on: workflow_dispatch: push: tags: - "v*" env: PROVIDER_VERSION: "1.0.0" jobs: # ============================================ # Build TTS Providers (uploaded to R2, not GitHub) # ============================================ build-providers: runs-on: ${{ matrix.platform }} strategy: fail-fast: false matrix: include: # PyTorch CPU provider (Windows) - platform: "windows-latest" provider: "pytorch-cpu" python-version: "3.12" # PyTorch CUDA provider (Windows) - large binary, uploaded to R2 - platform: "windows-latest" provider: "pytorch-cuda" python-version: "3.12" # PyTorch CPU provider (Linux) - platform: "ubuntu-22.04" provider: "pytorch-cpu" python-version: "3.12" # PyTorch CUDA provider (Linux) - large binary, uploaded to R2 - platform: "ubuntu-22.04" provider: "pytorch-cuda" python-version: "3.12" # PyTorch CPU provider (macOS Apple Silicon) - platform: "macos-latest" provider: "pytorch-cpu" python-version: "3.12" # PyTorch CPU provider (macOS Intel) - platform: "macos-15-intel" provider: "pytorch-cpu" python-version: "3.12" steps: - uses: actions/checkout@v4 - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y llvm-dev - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: "pip" - name: Install CPU-only torch (Linux) if: matrix.provider == 'pytorch-cpu' && matrix.platform == 'ubuntu-22.04' run: | python -m pip install --upgrade pip pip install pyinstaller pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu pip install -r providers/pytorch-cpu/requirements.txt pip install -r backend/requirements.txt - name: Install Python dependencies (CPU - non-Linux) if: matrix.provider == 'pytorch-cpu' && matrix.platform != 'ubuntu-22.04' run: | python -m pip install --upgrade pip pip install pyinstaller pip install -r providers/pytorch-cpu/requirements.txt pip install -r backend/requirements.txt - name: Install Python dependencies (CUDA) if: matrix.provider == 'pytorch-cuda' run: | python -m pip install --upgrade pip pip install pyinstaller pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install -r providers/pytorch-cuda/requirements.txt pip install -r backend/requirements.txt - name: Build provider binary shell: bash run: | cd providers/${{ matrix.provider }} python build.py - name: Package provider for distribution shell: bash run: | cd providers/${{ matrix.provider }}/dist # Add platform suffix for archive name if [ "${{ matrix.platform }}" == "windows-latest" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-windows.zip" # On Windows, zip the directory powershell Compress-Archive -Path "tts-provider-${{ matrix.provider }}/*" -DestinationPath "$ARCHIVE_NAME" elif [ "${{ matrix.platform }}" == "macos-latest" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-macos-arm64.tar.gz" tar -czf "$ARCHIVE_NAME" tts-provider-${{ matrix.provider }}/ elif [ "${{ matrix.platform }}" == "macos-15-intel" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-macos-x64.tar.gz" tar -czf "$ARCHIVE_NAME" tts-provider-${{ matrix.provider }}/ else ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-linux.tar.gz" tar -czf "$ARCHIVE_NAME" tts-provider-${{ matrix.provider }}/ fi echo "Created archive: $ARCHIVE_NAME" ls -lh "$ARCHIVE_NAME" - name: Upload provider to R2 shell: bash env: R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }} run: | # Install AWS CLI (compatible with R2) pip install awscli # Configure AWS CLI for R2 aws configure set aws_access_key_id $R2_ACCESS_KEY_ID aws configure set aws_secret_access_key $R2_SECRET_ACCESS_KEY aws configure set region auto # Determine archive name based on platform if [ "${{ matrix.platform }}" == "windows-latest" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-windows.zip" elif [ "${{ matrix.platform }}" == "macos-latest" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-macos-arm64.tar.gz" elif [ "${{ matrix.platform }}" == "macos-15-intel" ]; then ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-macos-x64.tar.gz" else ARCHIVE_NAME="tts-provider-${{ matrix.provider }}-linux.tar.gz" fi # Upload to R2 (bucket: voicebox) aws s3 cp "providers/${{ matrix.provider }}/dist/$ARCHIVE_NAME" \ "s3://voicebox/providers/v${{ env.PROVIDER_VERSION }}/$ARCHIVE_NAME" \ --endpoint-url "$R2_ENDPOINT" echo "Uploaded $ARCHIVE_NAME to R2" # ============================================ # Build Main App (without bundled TTS on Win/Linux) # ============================================ release: permissions: contents: write strategy: fail-fast: false matrix: include: # macOS Apple Silicon - MLX bundled (works out of the box) - platform: "macos-latest" args: "--target aarch64-apple-darwin" python-version: "3.12" backend: "mlx" # macOS Intel - PyTorch bundled (smaller user base, keep simple) - platform: "macos-15-intel" args: "--target x86_64-apple-darwin" python-version: "3.12" backend: "pytorch" # Linux - No TTS bundled, providers downloaded separately - platform: "ubuntu-22.04" args: "" python-version: "3.12" backend: "none" # Windows - PyTorch CPU bundled (works out of the box) - platform: "windows-latest" args: "" python-version: "3.12" backend: "pytorch" runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf llvm-dev libasound2-dev - name: Install LLVM (macOS) if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' run: | brew install llvm@20 echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH echo "LLVM_CONFIG=$(brew --prefix llvm@20)/bin/llvm-config" >> $GITHUB_ENV - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: "pip" - name: Install Python dependencies (with TTS) if: matrix.backend != 'none' run: | python -m pip install --upgrade pip pip install pyinstaller pip install -r backend/requirements.txt - name: Install Python dependencies (without TTS) if: matrix.backend == 'none' run: | python -m pip install --upgrade pip pip install pyinstaller # Install base requirements without PyTorch/Qwen-TTS pip install fastapi uvicorn sqlalchemy librosa soundfile numpy httpx pip install huggingface_hub # For Whisper downloads - name: Install MLX dependencies (Apple Silicon only) if: matrix.backend == 'mlx' run: | pip install -r backend/requirements-mlx.txt - name: Build Python server (Linux/macOS) if: matrix.platform != 'windows-latest' run: | chmod +x scripts/build-server.sh ./scripts/build-server.sh - name: Build Python server (Windows) if: matrix.platform == 'windows-latest' shell: bash run: | cd backend python build_binary.py # Get platform tuple PLATFORM=$(rustc --print host-tuple) # Create binaries directory mkdir -p ../tauri/src-tauri/binaries # Copy with platform suffix cp dist/voicebox-server.exe ../tauri/src-tauri/binaries/voicebox-server-${PLATFORM}.exe echo "Built voicebox-server-${PLATFORM}.exe" - name: Setup Bun uses: oven-sh/setup-bun@v2 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable with: targets: ${{ (matrix.platform == 'macos-latest' && 'aarch64-apple-darwin') || (matrix.platform == 'macos-15-intel' && 'x86_64-apple-darwin') || '' }} - name: Rust cache uses: swatinem/rust-cache@v2 with: workspaces: "./tauri/src-tauri -> target" - name: Install dependencies run: bun install - name: Install Apple API key if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' run: | mkdir -p ~/.appstoreconnect/private_keys/ cd ~/.appstoreconnect/private_keys/ echo ${{ secrets.APPLE_API_KEY_BASE64 }} >> AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 base64 --decode -i AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 -o AuthKey_${{ secrets.APPLE_API_KEY }}.p8 rm AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 - name: Install Codesigning Certificate if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' uses: apple-actions/import-codesign-certs@v3 with: p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_PROVIDER_SHORT_NAME: ${{ secrets.APPLE_PROVIDER_SHORT_NAME }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} with: projectPath: tauri tagName: v__VERSION__ releaseName: "voicebox v__VERSION__" releaseBody: | ## What's Changed See the assets below to download and install this version. ### Installation - **macOS (Apple Silicon)**: Download the `aarch64.dmg` file - uses MLX for fast native inference (works out of the box) - **macOS (Intel)**: Download the `x64.dmg` file - uses PyTorch - **Windows**: Download the `.msi` installer - requires downloading a TTS provider on first use - **Linux**: Download the `.AppImage` or `.deb` package - requires downloading a TTS provider on first use ### TTS Providers Windows and Linux users will be prompted to download a TTS provider on first launch: - **Windows**: PyTorch CPU (~300MB) or PyTorch CUDA (~2.4GB for NVIDIA GPUs) - **Linux**: PyTorch CUDA (~2.4GB) - requires NVIDIA GPU The app includes automatic updates - future updates will be installed automatically. releaseDraft: true prerelease: false args: ${{ matrix.args }} includeUpdaterJson: true # ============================================ # Build and Push Docker Images # ============================================ docker: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Setup Bun uses: oven-sh/setup-bun@v2 - name: Install dependencies and build web UI run: | bun install cd web bun run build - name: Extract version from tag id: version run: | if [[ $GITHUB_REF == refs/tags/v* ]]; then VERSION=${GITHUB_REF#refs/tags/v} else VERSION="dev" fi echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Build and push CPU image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: | ghcr.io/jamiepine/voicebox:latest ghcr.io/jamiepine/voicebox:${{ steps.version.outputs.version }} cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push CUDA image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.cuda platforms: linux/amd64 push: true tags: | ghcr.io/jamiepine/voicebox:latest-cuda ghcr.io/jamiepine/voicebox:${{ steps.version.outputs.version }}-cuda cache-from: type=gha cache-to: type=gha,mode=max