From d0164aca99edbfc950d6306f18cd84871cc893e4 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Sun, 1 Mar 2026 01:08:03 -0800 Subject: [PATCH 1/4] Add Linux aarch64 release build Add a build-linux-arm job to the release CI that builds on ubuntu-24.04-arm using libtorch from second-state/libtorch-releases. The release job now produces a qwen3-audio-api-linux-aarch64.tar.gz archive alongside the existing x86_64 and macOS builds. Also add the Linux (aarch64) quick start section to the README. Signed-off-by: Michael Yuan Co-Authored-By: Claude Opus 4.6 --- .github/workflows/release-rust.yml | 97 +++++++++++++++++++++++++++++- rust/README.md | 21 +++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-rust.yml b/.github/workflows/release-rust.yml index 45177c6..ca1cbe6 100644 --- a/.github/workflows/release-rust.yml +++ b/.github/workflows/release-rust.yml @@ -98,6 +98,95 @@ jobs: name: linux-x86_64 path: qwen3-audio-api-linux-x86_64.tar.gz + build-linux-arm: + runs-on: ubuntu-24.04-arm + timeout-minutes: 60 + + env: + LIBTORCH_VERSION: "2.7.1" + LIBTORCH_BYPASS_VERSION_CHECK: "1" + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install system dependencies + run: | + sudo apt-get update && sudo apt-get install -y cmake pkg-config \ + nasm libclang-dev libmp3lame-dev libopus-dev patchelf + + - name: Cache libtorch + id: cache-libtorch + uses: actions/cache@v4 + with: + path: libtorch + key: libtorch-cpu-aarch64-${{ env.LIBTORCH_VERSION }} + + - name: Download libtorch + if: steps.cache-libtorch.outputs.cache-hit != 'true' + run: | + wget -q "https://github.com/second-state/libtorch-releases/releases/download/v${LIBTORCH_VERSION}/libtorch-cxx11-abi-aarch64-${LIBTORCH_VERSION}.tar.gz" -O libtorch.tar.gz + tar xzf libtorch.tar.gz + rm libtorch.tar.gz + + - name: Set libtorch environment + run: | + echo "LIBTORCH=$(pwd)/libtorch" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$(pwd)/libtorch/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV + + - name: Cache cargo registry & build + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + rust/target + key: cargo-release-linux-aarch64-v6-${{ hashFiles('rust/Cargo.toml') }} + restore-keys: cargo-release-linux-aarch64-v6- + + - name: Build + working-directory: rust + run: cargo build --release + + - name: Package archive + run: | + mkdir -p staging/qwen3-audio-api-linux-aarch64/lib + + # Copy binary + cp rust/target/release/qwen3-audio-api staging/qwen3-audio-api-linux-aarch64/ + + # Bundle libtorch + cp -r libtorch staging/qwen3-audio-api-linux-aarch64/ + + # Bundle lame/opus shared libraries if dynamically linked + for lib in mp3lame opus; do + so_file=$(ldd rust/target/release/qwen3-audio-api | grep "lib${lib}" | awk '{print $3}') + if [ -n "$so_file" ] && [ -f "$so_file" ]; then + echo "Bundling $so_file" + cp "$so_file" staging/qwen3-audio-api-linux-aarch64/lib/ + fi + done + + # Set RPATH so binary finds bundled libs at runtime + patchelf --set-rpath '$ORIGIN/lib:$ORIGIN/libtorch/lib' \ + staging/qwen3-audio-api-linux-aarch64/qwen3-audio-api + + # Verify + echo "=== Bundled libraries ===" + ls -la staging/qwen3-audio-api-linux-aarch64/lib/ || echo "(no extra libs needed)" + echo "=== RPATH ===" + patchelf --print-rpath staging/qwen3-audio-api-linux-aarch64/qwen3-audio-api + + tar -czf qwen3-audio-api-linux-aarch64.tar.gz -C staging qwen3-audio-api-linux-aarch64 + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: linux-aarch64 + path: qwen3-audio-api-linux-aarch64.tar.gz + build-macos: runs-on: macos-14 timeout-minutes: 60 @@ -178,7 +267,7 @@ jobs: path: qwen3-audio-api-macos-arm64.tar.gz release: - needs: [build-linux, build-macos] + needs: [build-linux, build-linux-arm, build-macos] runs-on: ubuntu-latest permissions: contents: write @@ -189,6 +278,11 @@ jobs: with: name: linux-x86_64 + - name: Download Linux ARM artifact + uses: actions/download-artifact@v4 + with: + name: linux-aarch64 + - name: Download macOS artifact uses: actions/download-artifact@v4 with: @@ -200,4 +294,5 @@ jobs: generate_release_notes: true files: | qwen3-audio-api-linux-x86_64.tar.gz + qwen3-audio-api-linux-aarch64.tar.gz qwen3-audio-api-macos-arm64.tar.gz diff --git a/rust/README.md b/rust/README.md index c10253c..28cb597 100644 --- a/rust/README.md +++ b/rust/README.md @@ -34,6 +34,27 @@ TTS_CUSTOMVOICE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-CustomVoice \ ./qwen3-audio-api ``` +### Linux (aarch64) + +```bash +# Download and extract +curl -LO https://github.com/second-state/qwen3_audio_api/releases/latest/download/qwen3-audio-api-linux-aarch64.tar.gz +tar xzf qwen3-audio-api-linux-aarch64.tar.gz +cd qwen3-audio-api-linux-aarch64 + +# Set libtorch library path (bundled in the archive) +export LD_LIBRARY_PATH=$(pwd)/libtorch/lib:$LD_LIBRARY_PATH + +# Download models (see "Download models" section below) +# ... + +# Run the server with TTS + ASR +TTS_CUSTOMVOICE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-CustomVoice \ + TTS_BASE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-Base \ + ASR_MODEL_PATH=/path/to/models/Qwen3-ASR-0.6B \ + ./qwen3-audio-api +``` + ### macOS (Apple Silicon) ```bash From 336df7fcdc5995afd165351219b8294c29fd5c8b Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Sun, 1 Mar 2026 01:09:43 -0800 Subject: [PATCH 2/4] Remove LD_LIBRARY_PATH from aarch64 quick start The binary has RPATH set to $ORIGIN/libtorch/lib via patchelf, so libtorch is found automatically without LD_LIBRARY_PATH. Signed-off-by: Michael Yuan Co-Authored-By: Claude Opus 4.6 --- rust/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/README.md b/rust/README.md index 28cb597..3574c92 100644 --- a/rust/README.md +++ b/rust/README.md @@ -42,13 +42,11 @@ curl -LO https://github.com/second-state/qwen3_audio_api/releases/latest/downloa tar xzf qwen3-audio-api-linux-aarch64.tar.gz cd qwen3-audio-api-linux-aarch64 -# Set libtorch library path (bundled in the archive) -export LD_LIBRARY_PATH=$(pwd)/libtorch/lib:$LD_LIBRARY_PATH - # Download models (see "Download models" section below) # ... # Run the server with TTS + ASR +# (libtorch is found automatically via RPATH — no LD_LIBRARY_PATH needed) TTS_CUSTOMVOICE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-CustomVoice \ TTS_BASE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-Base \ ASR_MODEL_PATH=/path/to/models/Qwen3-ASR-0.6B \ From f4f171b975df8c2fa6ebf00695f8de36034be9aa Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Sun, 1 Mar 2026 01:10:19 -0800 Subject: [PATCH 3/4] Remove LD_LIBRARY_PATH from x86_64 quick start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as aarch64 — the binary has RPATH set to $ORIGIN/libtorch/lib via patchelf, so libtorch is found automatically. Signed-off-by: Michael Yuan Co-Authored-By: Claude Opus 4.6 --- rust/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/README.md b/rust/README.md index 3574c92..d2ecf6b 100644 --- a/rust/README.md +++ b/rust/README.md @@ -21,13 +21,11 @@ curl -LO https://github.com/second-state/qwen3_audio_api/releases/latest/downloa tar xzf qwen3-audio-api-linux-x86_64.tar.gz cd qwen3-audio-api-linux-x86_64 -# Set libtorch library path (bundled in the archive) -export LD_LIBRARY_PATH=$(pwd)/libtorch/lib:$LD_LIBRARY_PATH - # Download models (see "Download models" section below) # ... # Run the server with TTS + ASR +# (libtorch is found automatically via RPATH — no LD_LIBRARY_PATH needed) TTS_CUSTOMVOICE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-CustomVoice \ TTS_BASE_MODEL_PATH=/path/to/models/Qwen3-TTS-12Hz-0.6B-Base \ ASR_MODEL_PATH=/path/to/models/Qwen3-ASR-0.6B \ From 8616eb791fb722350d4780d967ebe76d251f4ac3 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Sun, 1 Mar 2026 01:12:04 -0800 Subject: [PATCH 4/4] Add Linux aarch64 build-from-source section Add instructions for building on aarch64 using libtorch from second-state/libtorch-releases. Also update libtorch version to 2.7.1 in the x86_64 build-from-source section. Signed-off-by: Michael Yuan Co-Authored-By: Claude Opus 4.6 --- rust/README.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/rust/README.md b/rust/README.md index d2ecf6b..551304c 100644 --- a/rust/README.md +++ b/rust/README.md @@ -288,20 +288,38 @@ All formats are handled natively by the statically-linked ffmpeg library. No ext ffmpeg is built from source and statically linked by default (via the `build-ffmpeg` feature). You do **not** need ffmpeg installed. -### Linux (libtorch backend) +### Linux x86_64 (libtorch backend) ```bash # Install build dependencies sudo apt-get install -y cmake pkg-config nasm libclang-dev libmp3lame-dev libopus-dev # Download libtorch (CPU) -wget -q "https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.7.0%2Bcpu.zip" -O libtorch.zip +wget -q "https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.7.1%2Bcpu.zip" -O libtorch.zip unzip -q libtorch.zip && rm libtorch.zip export LIBTORCH=$(pwd)/libtorch export LD_LIBRARY_PATH=$LIBTORCH/lib:$LD_LIBRARY_PATH # For CUDA 12.8 instead, download: -# wget -q "https://download.pytorch.org/libtorch/cu128/libtorch-cxx11-abi-shared-with-deps-2.7.0%2Bcu128.zip" -O libtorch.zip +# wget -q "https://download.pytorch.org/libtorch/cu128/libtorch-cxx11-abi-shared-with-deps-2.7.1%2Bcu128.zip" -O libtorch.zip + +# Build (ffmpeg is compiled from source and statically linked) +cd rust +cargo build --release +# Binary at: target/release/qwen3-audio-api +``` + +### Linux aarch64 (libtorch backend) + +```bash +# Install build dependencies +sudo apt-get install -y cmake pkg-config nasm libclang-dev libmp3lame-dev libopus-dev + +# Download libtorch (CPU, aarch64) +wget -q "https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-aarch64-2.7.1.tar.gz" -O libtorch.tar.gz +tar xzf libtorch.tar.gz && rm libtorch.tar.gz +export LIBTORCH=$(pwd)/libtorch +export LD_LIBRARY_PATH=$LIBTORCH/lib:$LD_LIBRARY_PATH # Build (ffmpeg is compiled from source and statically linked) cd rust