Build Python wheels for Windows arm64 (#3812)

This commit is contained in:
Fangjun Kuang authored and GitHub committed 2026-07-28 17:05:19 +08:00
1 parent 282e20c846
commit 75e1fc31e7
28 files changed
+637 -237

No files matched your search

+7 -3
View File
@@ -21,7 +21,7 @@ rm -rf sherpa-onnx-cohere-transcribe-14-lang-int8-2026-04-01
log "test Qwen3 ASR"
wget -q https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25.tar.bz2
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25.tar.bz2
tar xvf sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25.tar.bz2
rm sherpa-onnx-qwen3-asr-0.6B-int8-2026-03-25.tar.bz2
@@ -232,7 +232,11 @@ curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-reco
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-segmentation-models/0-four-speakers-zh.wav
python3 ./python-api-examples/offline-speaker-diarization.py
if python3 -c "import librosa" 2>/dev/null; then
python3 ./python-api-examples/offline-speaker-diarization.py
else
log "Skipping offline-speaker-diarization.py (librosa not installed)"
fi
rm -rf *.wav *.onnx ./sherpa-onnx-pyannote-segmentation-3-0
@@ -274,7 +278,7 @@ python3 ./python-api-examples/offline-sense-voice-ctc-decode-files-with-hr.py
rm -rf dict replace.fst test-hr.wav lexicon.txt
if [[ $(uname) == Linux ]]; then
if command -v ffmpeg &> /dev/null; then
# It needs ffmpeg
log "generate subtitles (Chinese)"
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
+2 -2
View File
@@ -287,7 +287,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_aarch64:
@@ -420,4 +420,4 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
+2 -2
View File
@@ -272,7 +272,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_armv7l:
@@ -457,4 +457,4 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
+3 -3
View File
@@ -299,7 +299,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_linux:
needs: [core, test]
@@ -420,7 +420,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
- name: Build sdist
if: matrix.python-version == 'cp38' && matrix.manylinux == 'manylinux2014'
@@ -442,4 +442,4 @@ jobs:
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
shell: bash
run: |
twine upload dist/sherpa*.tar.gz
twine upload --skip-existing --verbose dist/sherpa*.tar.gz
@@ -248,7 +248,7 @@ jobs:
python3 -m pip install $opts wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_macos_arm64:
needs: [core, test]
@@ -338,4 +338,4 @@ jobs:
python3 -m pip install $opts wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -249,7 +249,7 @@ jobs:
python3 -m pip install $opts wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_macos_universal2:
needs: [core, test]
@@ -343,4 +343,4 @@ jobs:
python3 -m pip install $opts wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -246,7 +246,7 @@ jobs:
run: |
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /tmp/wheels/*.whl
twine upload --skip-existing --verbose /tmp/wheels/*.whl
build_wheels_macos_x64:
needs: [core, test]
@@ -341,4 +341,4 @@ jobs:
python3 -m pip install $opts wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -0,0 +1,346 @@
name: build-wheels-win-arm64
on:
push:
branches:
- wheel
workflow_dispatch:
inputs:
publish_sherpa_onnx_bin:
description: "Publish sherpa-onnx-bin"
required: false
default: "true"
type: boolean
env:
SHERPA_ONNX_IS_IN_GITHUB_ACTIONS: 1
concurrency:
group: build-wheels-win-arm64-${{ github.ref }}
cancel-in-progress: true
jobs:
core:
name: core
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-11-arm]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Update version
shell: bash
run: |
./new-release.sh
git diff .
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Python dependencies
shell: bash
run: |
python3 -m pip install wheel twine==5.0.0 setuptools
- name: sccache
uses: mozilla-actions/sccache-action@v0.0.7
- name: Configure CMake
shell: bash
run: |
export CMAKE_C_COMPILER_LAUNCHER=sccache
export CMAKE_CXX_COMPILER_LAUNCHER=sccache
mkdir build
cd build
cmake \
-A ARM64 \
-D SHERPA_ONNX_ENABLE_TTS=ON \
-D CMAKE_BUILD_TYPE=Release \
-D BUILD_SHARED_LIBS=ON \
-D SHERPA_ONNX_BUILD_C_API_EXAMPLES=OFF \
-DCMAKE_INSTALL_PREFIX=./install \
..
- name: Build sherpa-onnx for windows
shell: bash
run: |
cd build
cmake --build . --config Release -- -m:2
cmake --build . --config Release --target install -- -m:2
ls -lh ./bin/Release/sherpa-onnx.exe
- name: Show
shell: bash
run: |
echo "---bin---"
ls -lh build/install/bin
echo "---lib---"
ls -lh build/install/lib
echo "---include---"
ls -lh build/install/include
- name: Copy files
shell: bash
run: |
cd build
echo 'sherpa-onnx-core'
mkdir -p ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/lib
cp -v ./install/lib/onnxruntime.dll ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/lib
cp -v ./install/lib/sherpa-onnx-*.dll ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/lib
# keep the *.lib file so users can write code to link with our dll
cp -v ./install/lib/sherpa-onnx-*.lib ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/lib
mkdir -p ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/include/sherpa-onnx/c-api
cp -v ./install/include/sherpa-onnx/c-api/*.h ../scripts/wheel/sherpa-onnx-core/sherpa_onnx/include/sherpa-onnx/c-api
pushd ../scripts/wheel/sherpa-onnx-core
python3 setup.py bdist_wheel --plat-name=win_arm64
ls -lh dist
popd
echo 'sherpa-onnx-bin'
mkdir -p ../scripts/wheel/sherpa-onnx-bin/bin
cp -v ./install/bin/sherpa-onnx* ../scripts/wheel/sherpa-onnx-bin/bin
pushd ../scripts/wheel/sherpa-onnx-bin
python3 setup.py bdist_wheel --plat-name=win_arm64
ls -lh dist
popd
- name: Collect wheels
shell: bash
run: |
mkdir wheelhouse
cp -v ./scripts/wheel/sherpa-onnx-core/dist/*.whl ./wheelhouse
cp -v ./scripts/wheel/sherpa-onnx-bin/dist/*.whl ./wheelhouse
- uses: actions/upload-artifact@v4
with:
name: wheels-core-win-arm64
path: ./wheelhouse/*.whl
- name: Show wheels
shell: bash
run: |
ls -lh ./scripts/wheel/sherpa-onnx-core/dist
ls -lh ./scripts/wheel/sherpa-onnx-bin/dist
unzip -l ./scripts/wheel/sherpa-onnx-core/dist/*.whl
echo "---"
unzip -l ./scripts/wheel/sherpa-onnx-bin/dist/*.whl
test:
name: test
needs: [core]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-11-arm]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Retrieve artifact from Windows arm64
uses: actions/download-artifact@v4
with:
name: wheels-core-win-arm64
path: /tmp/wheels
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Show
shell: bash
run: |
ls -lh /c/tmp/wheels
- name: Install
shell: bash
run: |
python3 -m pip install /c/tmp/wheels/*.whl
- name: Show version
shell: bash
run: |
sherpa-onnx-version
which sherpa-onnx-version
- name: Show help
shell: bash
run: |
sherpa-onnx --help
echo "---"
sherpa-onnx-offline --help
echo "---"
sherpa-onnx-vad --help
which sherpa-onnx-vad
- name: Publish to huggingface
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
uses: nick-fields/retry@v3
with:
max_attempts: 20
timeout_seconds: 200
shell: bash
command: |
git config --global user.email "csukuangfj@gmail.com"
git config --global user.name "Fangjun Kuang"
rm -rf huggingface
export GIT_LFS_SKIP_SMUDGE=1
export GIT_CLONE_PROTECTION_ACTIVE=false
SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
echo "SHERPA_ONNX_VERSION $SHERPA_ONNX_VERSION"
d=cpu/$SHERPA_ONNX_VERSION
git clone https://csukuangfj2:$HF_TOKEN@huggingface.co/csukuangfj2/sherpa-onnx-wheels huggingface
cd huggingface
git fetch
git pull
git merge -m "merge remote" --ff origin main
mkdir -p $d
cp -v /c/tmp/wheels/*.whl $d/
git status
git add .
git commit -m "add more wheels"
git push https://csukuangfj2:$HF_TOKEN@huggingface.co/csukuangfj2/sherpa-onnx-wheels main
- name: Publish wheels to PyPI ${{ github.event.inputs.publish_sherpa_onnx_bin }}
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
shell: bash
run: |
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload --skip-existing --verbose /c/tmp/wheels/*.whl
build_wheels_win_arm64:
needs: [core, test]
# if: always()
name: ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-11-arm]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Update version
shell: bash
run: |
./new-release.sh
git diff .
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Build wheels (cmd)
shell: bash
run: |
python3 -m pip install setuptools wheel twine
export SHERPA_ONNX_SPLIT_PYTHON_PACKAGE=ON
export SHERPA_ONNX_CMAKE_ARGS="-DSHERPA_ONNX_ENABLE_BINARY=OFF -DSHERPA_ONNX_BUILD_C_API_EXAMPLES=OFF -DSHERPA_ONNX_ENABLE_C_API=OFF -DSHERPA_ONNX_ENABLE_C_API=OFF -DSHERPA_ONNX_ENABLE_WEBSOCKET=OFF"
python3 setup.py bdist_wheel
ls -lh ./dist/
mv dist wheelhouse
- name: Display wheels
shell: bash
run: |
ls -lh ./wheelhouse/
unzip -l ./wheelhouse/*.whl
- uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.python-version }}
path: ./wheelhouse/*.whl
- name: Publish to huggingface
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
uses: nick-fields/retry@v3
with:
max_attempts: 20
timeout_seconds: 200
shell: bash
command: |
git config --global user.email "csukuangfj@gmail.com"
git config --global user.name "Fangjun Kuang"
rm -rf huggingface
export GIT_LFS_SKIP_SMUDGE=1
export GIT_CLONE_PROTECTION_ACTIVE=false
SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
echo "SHERPA_ONNX_VERSION $SHERPA_ONNX_VERSION"
d=cpu/$SHERPA_ONNX_VERSION
git clone https://csukuangfj2:$HF_TOKEN@huggingface.co/csukuangfj2/sherpa-onnx-wheels huggingface
cd huggingface
git fetch
git pull
git merge -m "merge remote" --ff origin main
mkdir -p $d
cp -v ../wheelhouse/*.whl $d/
git status
git add .
git commit -m "add more wheels"
git push https://csukuangfj2:$HF_TOKEN@huggingface.co/csukuangfj2/sherpa-onnx-wheels main
- name: Publish wheels to PyPI
shell: bash
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -1,4 +1,4 @@
name: build-wheels-win64-cuda
name: build-wheels-win-x64-cuda
on:
push:
@@ -10,11 +10,11 @@ env:
SHERPA_ONNX_IS_IN_GITHUB_ACTIONS: 1
concurrency:
group: build-wheels-win64-cuda-${{ github.ref }}
group: build-wheels-win-x64-cuda-${{ github.ref }}
cancel-in-progress: true
jobs:
build_wheels_win64_cuda:
build_wheels_win_x64_cuda:
name: ${{ matrix.python-version }} ${{ matrix.onnxruntime_version }}
runs-on: ${{ matrix.os }}
strategy:
@@ -1,4 +1,4 @@
name: build-wheels-win64
name: build-wheels-win-x64
on:
push:
@@ -16,7 +16,7 @@ env:
SHERPA_ONNX_IS_IN_GITHUB_ACTIONS: 1
concurrency:
group: build-wheels-win64-${{ github.ref }}
group: build-wheels-win-x64-${{ github.ref }}
cancel-in-progress: true
jobs:
@@ -240,7 +240,7 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /d/tmp/wheels/*.whl
twine upload --skip-existing --verbose /d/tmp/wheels/*.whl
build_wheels_win64:
needs: [core, test]
@@ -341,4 +341,4 @@ jobs:
python3 -m pip install wheel twine==5.0.0 setuptools
fi
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -1,4 +1,4 @@
name: build-wheels-win32
name: build-wheels-win-x86
on:
push:
@@ -16,7 +16,7 @@ env:
SHERPA_ONNX_IS_IN_GITHUB_ACTIONS: 1
concurrency:
group: build-wheels-win32-${{ github.ref }}
group: build-wheels-win-x86-${{ github.ref }}
cancel-in-progress: true
jobs:
@@ -239,9 +239,9 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload /d/tmp/wheels/*.whl
twine upload --skip-existing --verbose /d/tmp/wheels/*.whl
build_wheels_win32:
build_wheels_win_x86:
needs: [core, test]
name: ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
@@ -328,4 +328,4 @@ jobs:
python3 -m pip install --upgrade pip
python3 -m pip install wheel twine==5.0.0 setuptools
twine upload ./wheelhouse/*.whl
twine upload --skip-existing --verbose ./wheelhouse/*.whl
@@ -1,107 +0,0 @@
name: run-python-test-macos
on:
push:
branches:
- master
- python
paths:
- '.github/workflows/run-python-test-macos.yaml'
- '.github/scripts/test-python.sh'
- 'cmake/**'
- 'sherpa-onnx/csrc/*'
- 'python-api-examples/**'
workflow_dispatch:
concurrency:
group: run-python-test-macos-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
run-python-test:
name: ${{ matrix.os }} ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# See https://github.com/actions/runner-images
# macos-14 is for arm64
# macos-14-large is for x64
include:
- os: macos-15-intel
python-version: "3.8"
- os: macos-15-intel
python-version: "3.9"
- os: macos-14
python-version: "3.10"
- os: macos-14
python-version: "3.11"
- os: macos-latest
python-version: "3.12"
- os: macos-latest
python-version: "3.13"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Update version
shell: bash
run: |
./new-release.sh
git diff .
- name: Display OS version
shell: bash
run: |
uname -a
sw_vers
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.os }}-python-${{ matrix.python-version }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Python dependencies
shell: bash
run: |
python3 -m pip install --upgrade pip numpy pypinyin sentencepiece>=0.1.96 soundfile setuptools wheel librosa
- name: Install sherpa-onnx
shell: bash
run: |
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake --version
python3 -m pip install .
- name: Test sherpa-onnx
shell: bash
run: |
export OS=${{ matrix.os }}
.github/scripts/test-python.sh
.github/scripts/test-speaker-recognition-python.sh
- uses: actions/upload-artifact@v4
with:
name: source-separation-${{ matrix.os }}-${{ matrix.python-version }}
path: ./source-separation
- uses: actions/upload-artifact@v4
with:
name: tts-generated-test-files-${{ matrix.os }}-${{ matrix.python-version }}
path: tts
+139 -24
View File
@@ -5,9 +5,11 @@ on:
branches:
- master
- python
- wheel-win-arm64
paths:
- '.github/workflows/run-python-test.yaml'
- '.github/scripts/test-python.sh'
- '.github/scripts/test-speaker-recognition-python.sh'
- 'cmake/**'
- 'sherpa-onnx/csrc/*'
- 'python-api-examples/**'
@@ -17,6 +19,7 @@ on:
paths:
- '.github/workflows/run-python-test.yaml'
- '.github/scripts/test-python.sh'
- '.github/scripts/test-speaker-recognition-python.sh'
- 'cmake/**'
- 'sherpa-onnx/csrc/*'
- 'python-api-examples/**'
@@ -29,19 +32,22 @@ concurrency:
permissions:
contents: read
env:
PYTHONIOENCODING: utf-8
jobs:
run-python-test:
name: ${{ matrix.os }} ${{ matrix.python-version }}
name: ${{ matrix.os }} ${{ matrix.python-version }} ${{ matrix.architecture || ((contains(matrix.os, 'arm') || matrix.os == 'macos-14' || matrix.os == 'macos-latest') && 'arm64' || 'x64') }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux x64
- os: ubuntu-latest
python-version: "3.8"
- os: ubuntu-latest
python-version: "3.9"
- os: ubuntu-latest
python-version: "3.10"
- os: ubuntu-latest
@@ -53,6 +59,61 @@ jobs:
- os: ubuntu-latest
python-version: "3.14"
# Linux arm64
- os: ubuntu-24.04-arm
python-version: "3.10"
- os: ubuntu-24.04-arm
python-version: "3.11"
- os: ubuntu-24.04-arm
python-version: "3.12"
- os: ubuntu-24.04-arm
python-version: "3.13"
- os: ubuntu-24.04-arm
python-version: "3.14"
# macOS x64
- os: macos-15-intel
python-version: "3.8"
- os: macos-15-intel
python-version: "3.9"
# macOS arm64
- os: macos-14
python-version: "3.10"
- os: macos-14
python-version: "3.11"
- os: macos-latest
python-version: "3.12"
- os: macos-latest
python-version: "3.13"
# Windows x64
- os: windows-2022
python-version: "3.8"
- os: windows-2022
python-version: "3.9"
- os: windows-2022
python-version: "3.10"
- os: windows-2022
python-version: "3.11"
- os: windows-2022
python-version: "3.12"
- os: windows-2022
python-version: "3.13"
- os: windows-2022
python-version: "3.14"
# Windows arm64
- os: windows-11-arm
python-version: "3.11"
- os: windows-11-arm
python-version: "3.12"
- os: windows-11-arm
python-version: "3.13"
- os: windows-11-arm
python-version: "3.14"
steps:
- uses: actions/checkout@v4
with:
@@ -67,93 +128,137 @@ jobs:
- name: Display OS version
shell: bash
run: |
uname -a
find "/etc" -maxdepth 1 -type f -name "*version" -exec head -n 100 {} \;
uname -a || true
if [[ "${{ runner.os }}" == "Linux" ]]; then
find "/etc" -maxdepth 1 -type f -name "*version" -exec head -n 100 {} \; || true
elif [[ "${{ runner.os }}" == "macOS" ]]; then
sw_vers || true
fi
- name: ccache
if: runner.os != 'Windows'
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.os }}-python-${{ matrix.python-version }}
- name: sccache (Windows)
if: runner.os == 'Windows'
uses: mozilla-actions/sccache-action@v0.0.7
- name: Set up MSVC
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture || ((contains(matrix.os, 'arm') || matrix.os == 'macos-14' || matrix.os == 'macos-latest') && 'arm64' || 'x64') }}
- name: Install Python dependencies
shell: bash
run: |
python3 -m pip install --upgrade pip numpy pypinyin sentencepiece>=0.1.96 soundfile librosa
python3 -m pip install --upgrade pip numpy pypinyin soundfile
python3 -m pip install wheel twine setuptools
- uses: afoley587/setup-ffmpeg@main
id: setup-ffmpeg
with:
ffmpeg-version: release
architecture: ''
github-token: ${{ github.server_url == 'https://github.com' && github.token || '' }}
- name: Install librosa (Linux/macOS)
if: runner.os != 'Windows'
shell: bash
run: |
python3 -m pip install --upgrade librosa
- name: Install ninja
- name: Install ninja (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get install ninja-build
- name: Display ninja version
- name: Display ninja version (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
ninja --version
ninja --help || true
which ninja
- name: Display site packages dir
- name: Display site packages dir (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
python3 -c 'import site; print(site.getsitepackages())'
p=$(python3 -c 'import site; print(site.getsitepackages())')
echo "p: $p"
- name: Install patchelf
- name: Install patchelf (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get update -q
sudo apt-get install -q -y patchelf
patchelf --help
- name: Build sherpa-onnx
- name: Build sherpa-onnx (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
if [[ "${{ runner.os }}" != "Windows" ]]; then
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
fi
cmake --version
export SHERPA_ONNX_CMAKE_ARGS="-G Ninja -DCMAKE_BUILD_TYPE=Release"
export SHERPA_ONNX_MAKE_ARGS="-j 6"
python3 setup.py bdist_wheel
- name: Patch wheels
- name: Patch wheels (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
mkdir ./dist2
sudo ./scripts/wheel/patch_wheel.py --in-dir ./dist --out-dir ./dist2
- name: Install sherpa-onnx
- name: Install sherpa-onnx (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
ls -lh dist2
python3 -m pip install ./dist2/*.whl
- name: Build and install sherpa-onnx (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake --version
python3 -m pip install .
- name: Build and install sherpa-onnx (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
export CMAKE_C_COMPILER_LAUNCHER=sccache
export CMAKE_CXX_COMPILER_LAUNCHER=sccache
python3 -m pip install .
- uses: actions/upload-artifact@v4
if: runner.os == 'Linux'
with:
name: ${{ matrix.os }}-${{ matrix.python-version }}-whl
path: ./dist
- uses: actions/upload-artifact@v4
if: runner.os == 'Linux'
with:
name: ${{ matrix.os }}-${{ matrix.python-version }}-whl-patched
path: ./dist2
- name: Show dependencies
- name: Show dependencies (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
cd dist
@@ -166,7 +271,8 @@ jobs:
readelf -d sherpa_onnx-*.data/data/bin/sherpa-onnx
- name: Show dependencies (patched)
- name: Show dependencies - patched (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
cd dist2
@@ -179,7 +285,8 @@ jobs:
readelf -d sherpa_onnx-*.data/data/bin/sherpa-onnx
- name: Test sherpa-onnx
- name: Test sherpa-onnx (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
export OS=${{ matrix.os }}
@@ -196,9 +303,17 @@ jobs:
.github/scripts/test-python.sh
.github/scripts/test-speaker-recognition-python.sh
- name: Test sherpa-onnx (macOS/Windows)
if: runner.os != 'Linux'
shell: bash
run: |
export OS=${{ matrix.os }}
.github/scripts/test-python.sh
.github/scripts/test-speaker-recognition-python.sh
- uses: actions/upload-artifact@v4
with:
name: source-separation-${{ matrix.os }}-${{ matrix.python-version }}-whl
name: source-separation-${{ matrix.os }}-${{ matrix.python-version }}
path: ./source-separation
- uses: actions/upload-artifact@v4
@@ -23,7 +23,7 @@ jobs:
matrix:
os: [macos-latest]
# version: ["1.11.0", "1.11.1", "1.12.0", "1.12.1", "1.13.1", "1.14.0", "1.14.1", "1.15.0", "1.15.1", "1.16.1", "1.16.2", "1.17.0", "1.17.1", "1.17.3", "1.18.0", "1.18.1", "1.19.0", "1.19.2", "1.20.0", "1.20.1", "1.20.2", "1.21.0", "1.21.1", "1.22.0", "1.22.1", "1.22.2", "1.23.0", "1.23.1", "1.23.2", "1.24.4"]
version: ["1.24.4"]
version: ["1.17.1", "1.24.4", "1.27.1"]
steps:
- uses: actions/checkout@v4
+57 -17
View File
@@ -25,29 +25,29 @@ jobs:
test_pip_install:
if: github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa'
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} ${{ matrix.python-version }}
name: ${{ matrix.os }} ${{ matrix.python-version }} ${{ matrix.architecture || ((contains(matrix.os, 'arm') || matrix.os == 'macos-14' || matrix.os == 'macos-latest') && 'arm64' || 'x64') }}
strategy:
fail-fast: false
matrix:
# See https://github.com/actions/runner-images
include:
- os: ubuntu-22.04
# Linux x64
- os: ubuntu-latest
python-version: "3.8"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.9"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.10"
- os: ubuntu-latest
python-version: "3.11"
- os: ubuntu-24.04
- os: ubuntu-latest
python-version: "3.12"
- os: ubuntu-latest
python-version: "3.13"
- os: ubuntu-latest
python-version: "3.14"
- os: ubuntu-24.04-arm
python-version: "3.8"
- os: ubuntu-24.04-arm
python-version: "3.9"
# Linux arm64
- os: ubuntu-24.04-arm
python-version: "3.10"
- os: ubuntu-24.04-arm
@@ -56,27 +56,30 @@ jobs:
python-version: "3.12"
- os: ubuntu-24.04-arm
python-version: "3.13"
- os: ubuntu-24.04-arm
python-version: "3.14"
# macOS x64
- os: macos-15-intel
python-version: "3.8"
- os: macos-15-intel
python-version: "3.9"
- os: macos-15-intel
python-version: "3.10"
- os: macos-15-intel
python-version: "3.11"
# macOS arm64
- os: macos-14
python-version: "3.12"
python-version: "3.10"
- os: macos-14
python-version: "3.11"
- os: macos-latest
python-version: "3.12"
- os: macos-latest
python-version: "3.13"
# Windows x64
- os: windows-2022
python-version: "3.8"
- os: windows-2022
python-version: "3.9"
- os: windows-2022
python-version: "3.10"
- os: windows-2022
@@ -85,6 +88,41 @@ jobs:
python-version: "3.12"
- os: windows-2022
python-version: "3.13"
- os: windows-2022
python-version: "3.14"
# Windows arm64
- os: windows-11-arm
python-version: "3.11"
- os: windows-11-arm
python-version: "3.12"
- os: windows-11-arm
python-version: "3.13"
- os: windows-11-arm
python-version: "3.14"
# Windows x86
- os: windows-2022
python-version: "3.8"
architecture: x86
- os: windows-2022
python-version: "3.9"
architecture: x86
- os: windows-2022
python-version: "3.10"
architecture: x86
- os: windows-2022
python-version: "3.11"
architecture: x86
- os: windows-2022
python-version: "3.12"
architecture: x86
- os: windows-2022
python-version: "3.13"
architecture: x86
- os: windows-2022
python-version: "3.14"
architecture: x86
steps:
- uses: actions/checkout@v4
@@ -101,11 +139,13 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture || ((contains(matrix.os, 'arm') || matrix.os == 'macos-14' || matrix.os == 'macos-latest') && 'arm64' || 'x64') }}
- name: Install sherpa-onnx
shell: bash
run: |
pip install --verbose -U sherpa-onnx sherpa-onnx-core sherpa-onnx-bin
pip install --verbose -U sherpa-onnx sherpa-onnx-core sherpa-onnx-bin || \
pip install --verbose -U sherpa-onnx sherpa-onnx-core sherpa-onnx-bin -f https://k2-fsa.github.io/sherpa/onnx/cpu.html
- name: Test sherpa-onnx-bin
shell: bash
@@ -18,8 +18,8 @@ rm sherpa-onnx-fire-red-asr2-ctc-zh_en-int8-2026-02-25.tar.bz2
import time
from pathlib import Path
import librosa
import numpy as np
import soundfile as sf
import sherpa_onnx
@@ -73,24 +73,24 @@ def create_recognizer():
def load_audio(filename):
audio, sample_rate = librosa.load(filename, sr=16000)
assert sample_rate == 16000, sample_rate
audio, sample_rate = sf.read(filename, dtype="float32", always_2d=True)
audio = audio[:, 0] # only use the first channel
return np.ascontiguousarray(audio)
return np.ascontiguousarray(audio), sample_rate
def decode_single_file(recognizer, filename):
samples = load_audio(filename)
samples, sample_rate = load_audio(filename)
start_time = time.time()
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
recognizer.decode_stream(stream)
end_time = time.time()
elapsed_seconds = end_time - start_time
audio_duration = len(samples) / 16000
audio_duration = len(samples) / sample_rate
real_time_factor = elapsed_seconds / audio_duration
print("---")
@@ -110,11 +110,11 @@ def decode_multiple_files(recognizer, filenames):
audio_duration = 0
for filename in filenames:
samples = load_audio(filename)
audio_duration += len(samples) / 16000
samples, sample_rate = load_audio(filename)
audio_duration += len(samples) / sample_rate
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
streams.append(stream)
recognizer.decode_streams(streams)
@@ -18,8 +18,8 @@ rm sherpa-onnx-medasr-ctc-en-int8-2025-12-25.tar.bz2
import time
from pathlib import Path
import librosa
import numpy as np
import soundfile as sf
import sherpa_onnx
@@ -67,24 +67,24 @@ def create_recognizer():
def load_audio(filename):
audio, sample_rate = librosa.load(filename, sr=16000)
assert sample_rate == 16000, sample_rate
audio, sample_rate = sf.read(filename, dtype="float32", always_2d=True)
audio = audio[:, 0] # only use the first channel
return np.ascontiguousarray(audio)
return np.ascontiguousarray(audio), sample_rate
def decode_single_file(recognizer, filename):
samples = load_audio(filename)
samples, sample_rate = load_audio(filename)
start_time = time.time()
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
recognizer.decode_stream(stream)
end_time = time.time()
elapsed_seconds = end_time - start_time
audio_duration = len(samples) / 16000
audio_duration = len(samples) / sample_rate
real_time_factor = elapsed_seconds / audio_duration
print("---")
@@ -104,11 +104,11 @@ def decode_multiple_files(recognizer, filenames):
audio_duration = 0
for filename in filenames:
samples = load_audio(filename)
audio_duration += len(samples) / 16000
samples, sample_rate = load_audio(filename)
audio_duration += len(samples) / sample_rate
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
streams.append(stream)
recognizer.decode_streams(streams)
@@ -56,26 +56,22 @@ def create_recognizer():
def load_audio(filename):
audio, sample_rate = sf.read(filename, dtype="float32", always_2d=True)
audio = audio[:, 0] # only use the first channel
if sample_rate != 16000:
import librosa
audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=16000)
return np.ascontiguousarray(audio)
return np.ascontiguousarray(audio), sample_rate
def decode_single_file(recognizer, filename):
samples = load_audio(filename)
samples, sample_rate = load_audio(filename)
start_time = time.time()
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
recognizer.decode_stream(stream)
end_time = time.time()
elapsed_seconds = end_time - start_time
audio_duration = len(samples) / 16000
audio_duration = len(samples) / sample_rate
real_time_factor = elapsed_seconds / audio_duration
print("---")
@@ -95,11 +91,11 @@ def decode_multiple_files(recognizer, filenames):
audio_duration = 0
for filename in filenames:
samples = load_audio(filename)
audio_duration += len(samples) / 16000
samples, sample_rate = load_audio(filename)
audio_duration += len(samples) / sample_rate
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
streams.append(stream)
recognizer.decode_streams(streams)
@@ -54,26 +54,22 @@ def create_recognizer():
def load_audio(filename):
audio, sample_rate = sf.read(filename, dtype="float32", always_2d=True)
audio = audio[:, 0] # only use the first channel
if sample_rate != 16000:
import librosa
audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=16000)
return np.ascontiguousarray(audio)
return np.ascontiguousarray(audio), sample_rate
def decode_single_file(recognizer, filename):
samples = load_audio(filename)
samples, sample_rate = load_audio(filename)
start_time = time.time()
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
recognizer.decode_stream(stream)
end_time = time.time()
elapsed_seconds = end_time - start_time
audio_duration = len(samples) / 16000
audio_duration = len(samples) / sample_rate
real_time_factor = elapsed_seconds / audio_duration
print("---")
@@ -93,11 +89,11 @@ def decode_multiple_files(recognizer, filenames):
audio_duration = 0
for filename in filenames:
samples = load_audio(filename)
audio_duration += len(samples) / 16000
samples, sample_rate = load_audio(filename)
audio_duration += len(samples) / sample_rate
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
stream.accept_waveform(sample_rate=sample_rate, waveform=samples)
streams.append(stream)
recognizer.decode_streams(streams)
@@ -37,9 +37,9 @@ Step 4. Run it
"""
from pathlib import Path
import librosa
import sherpa_onnx
import soundfile as sf
import librosa
def resample_audio(audio, sample_rate, target_sample_rate):
@@ -110,11 +110,11 @@ def main():
# Since we know there are 4 speakers in the above test wave file, we use
# num_speakers 4 here
sd = init_speaker_diarization(num_speakers=4)
# Resample audio to match the expected sample rate
target_sample_rate = sd.sample_rate
audio, sample_rate = resample_audio(audio, sample_rate, target_sample_rate)
if sample_rate != sd.sample_rate:
raise RuntimeError(
f"Expected samples rate: {sd.sample_rate}, given: {sample_rate}"
+3 -4
View File
@@ -32,7 +32,6 @@ import threading
import time
from pathlib import Path
import librosa
import numpy as np
import sherpa_onnx
import soundfile as sf
@@ -197,9 +196,9 @@ def main():
tts = create_tts()
logging.info("Loading model done.")
reference_audio, reference_sample_rate = librosa.load(
reference_audio_file, sr=tts.sample_rate
)
reference_audio, reference_sample_rate = sf.read(reference_audio_file, dtype="float32")
if reference_audio.ndim > 1:
reference_audio = reference_audio[:, 0] # only use the first channel
text = """
I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation.
+3 -4
View File
@@ -30,7 +30,6 @@ for details.
import time
from pathlib import Path
import librosa
import sherpa_onnx
import soundfile as sf
@@ -67,9 +66,9 @@ def main():
tts = create_tts()
reference_audio, sample_rate = librosa.load(
reference_audio_file, sr=tts.sample_rate
)
reference_audio, sample_rate = sf.read(reference_audio_file, dtype="float32")
if reference_audio.ndim > 1:
reference_audio = reference_audio[:, 0] # only use the first channel
text = "I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation."
+3 -2
View File
@@ -34,7 +34,6 @@ import threading
import time
from pathlib import Path
import librosa
import numpy as np
import sherpa_onnx
import soundfile as sf
@@ -165,7 +164,9 @@ def main():
tts = create_tts()
logging.info("Loading model done.")
reference_audio, reference_sample_rate = librosa.load(reference_audio_file, sr=None)
reference_audio, reference_sample_rate = sf.read(reference_audio_file, dtype="float32")
if reference_audio.ndim > 1:
reference_audio = reference_audio[:, 0] # only use the first channel
reference_text = "那还是三十六年前, 一九八七年. 我呢考上了武汉大学的计算机系."
text = """
小米的价值观是真诚, 热爱.
+3 -2
View File
@@ -29,7 +29,6 @@ for details.
import time
from pathlib import Path
import librosa
import sherpa_onnx
import soundfile as sf
@@ -67,7 +66,9 @@ def main():
tts = create_tts()
reference_audio, sample_rate = librosa.load(reference_audio_file, sr=None)
reference_audio, sample_rate = sf.read(reference_audio_file, dtype="float32")
if reference_audio.ndim > 1:
reference_audio = reference_audio[:, 0] # only use the first channel
reference_text = "那还是三十六年前, 一九八七年. 我呢考上了武汉大学的计算机系."
text = "小米的价值观是真诚, 热爱. 真诚,就是不欺人也不自欺. 热爱, 就是全心投入并享受其中."
@@ -150,7 +150,7 @@ class OnlineRecognizerTransducerNeMoImpl : public OnlineRecognizerImpl {
s->SetStates(model_->GetEncoderInitStates());
s->SetNeMoDecoderStates(model_->GetDecoderInitStates());
s->SetNeMoDecoderOut(nullptr);
s->SetNeMoDecoderOut(Ort::Value{nullptr});
// Note: We only update counters. The underlying audio samples
// are not discarded.
+3 -1
View File
@@ -215,7 +215,9 @@ class OnlineStream::Impl {
// states for nemo transducer models
std::vector<Ort::Value> nemo_decoder_states_;
Ort::Value nemo_decoder_out_; // decoder out for nemo transducer models
// decoder out for nemo transducer models
Ort::Value nemo_decoder_out_{nullptr};
std::vector<float> paraformer_feat_cache_;
std::vector<float> paraformer_encoder_out_cache_;
std::vector<float> paraformer_alpha_cache_;
@@ -47,7 +47,8 @@ static void DecodeOne(const float *encoder_out, int32_t num_rows,
std::vector<Ort::Value> &last_decoder_states = s->GetNeMoDecoderStates();
// decoder_output_pair.second returns the next decoder state
std::pair<Ort::Value, std::vector<Ort::Value>> decoder_output_pair;
std::pair<Ort::Value, std::vector<Ort::Value>> decoder_output_pair{
Ort::Value{nullptr}, std::vector<Ort::Value>{}};
if (!last_decoder_out) {
decoder_output_pair = model->RunDecoder(std::move(decoder_input),
@@ -9,6 +9,12 @@
import unittest
from pathlib import Path
try:
import sentencepiece # noqa: F401
has_sentencepiece = True
except ImportError:
has_sentencepiece = False
import sherpa_onnx
d = "/tmp/sherpa-test-data"
@@ -17,6 +23,7 @@ d = "/tmp/sherpa-test-data"
# to download test data for testing
@unittest.skipUnless(has_sentencepiece, "sentencepiece is not installed")
class TestText2Token(unittest.TestCase):
def test_bpe(self):
tokens = f"{d}/text2token/tokens_en.txt"