Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion .github/workflows/release-rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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
45 changes: 40 additions & 5 deletions rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,30 @@ 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 \
./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

# 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 \
Expand Down Expand Up @@ -271,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
Expand Down