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
4 changes: 4 additions & 0 deletions .github/scripts/test-rust.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ rm -rf sr-data
./run-speaker-embedding-cosine-similarity.sh
rm -f wespeaker_zh_cnceleb_resnet34.onnx fangjun-sr-1.wav fangjun-sr-2.wav leijun-sr-1.wav

./run-offline-speaker-diarization.sh
rm -rf sherpa-onnx-pyannote-segmentation-3-0
rm -f 3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx 0-four-speakers-zh.wav

./run-vits-en.sh
rm -rf vits-piper-en_US-amy-low

Expand Down
8 changes: 8 additions & 0 deletions rust-api-examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export RUSTFLAGS="-C link-arg=-Wl,-rpath,$SHERPA_ONNX_LIB_DIR"
| 30 | [speaker_embedding_extractor](#example-30-speaker-embedding-extractor) | Compute a speaker embedding from a wave file |
| 31 | [speaker_embedding_manager](#example-31-speaker-embedding-manager) | Register, search, verify, and remove speakers using embeddings |
| 32 | [speaker_embedding_cosine_similarity](#example-32-speaker-embedding-cosine-similarity) | Compute cosine similarity from three speaker embeddings |
| 33 | [offline_speaker_diarization](#example-33-offline-speaker-diarization) | Offline speaker diarization with pyannote segmentation and 3D-Speaker embeddings |

## Run it

Expand Down Expand Up @@ -270,3 +271,10 @@ to check the RPATH.
```bash
./run-speaker-embedding-cosine-similarity.sh
```


### Example 33: Offline speaker diarization

```bash
./run-offline-speaker-diarization.sh
```
46 changes: 46 additions & 0 deletions rust-api-examples/examples/offline_speaker_diarization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use sherpa_onnx::{
FastClusteringConfig, OfflineSpeakerDiarization, OfflineSpeakerDiarizationConfig,
OfflineSpeakerSegmentationModelConfig, OfflineSpeakerSegmentationPyannoteModelConfig,
SpeakerEmbeddingExtractorConfig, Wave,
};

fn main() {
let config = OfflineSpeakerDiarizationConfig {
segmentation: OfflineSpeakerSegmentationModelConfig {
pyannote: OfflineSpeakerSegmentationPyannoteModelConfig {
model: Some("./sherpa-onnx-pyannote-segmentation-3-0/model.onnx".into()),
},
..Default::default()
},
embedding: SpeakerEmbeddingExtractorConfig {
model: Some("./3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx".into()),
..Default::default()
},
clustering: FastClusteringConfig {
num_clusters: 4,
..Default::default()
},
..Default::default()
};

let sd = OfflineSpeakerDiarization::create(&config)
.expect("Failed to initialize offline speaker diarization");

let wave = Wave::read("./0-four-speakers-zh.wav").expect("Failed to read wave");

assert_eq!(
sd.sample_rate(),
wave.sample_rate(),
"Unexpected sample rate"
);

let result = sd
.process(wave.samples())
.expect("Failed to do speaker diarization");
println!("Number of speakers: {}", result.num_speakers());
println!("Number of segments: {}", result.num_segments());

for s in result.sort_by_start_time() {
println!("{:.3} -- {:.3} speaker_{:02}", s.start, s.end, s.speaker);
}
}
18 changes: 18 additions & 0 deletions rust-api-examples/run-offline-speaker-diarization.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -ex

if [ ! -f ./sherpa-onnx-pyannote-segmentation-3-0/model.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-segmentation-models/sherpa-onnx-pyannote-segmentation-3-0.tar.bz2
tar xvf sherpa-onnx-pyannote-segmentation-3-0.tar.bz2
rm sherpa-onnx-pyannote-segmentation-3-0.tar.bz2
fi

if [ ! -f ./3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a typo in the URL: recongition should be recognition. While the current URL with the typo works because a release with the typo exists, it's better to use the corrected URL for future-proofing and clarity, as a corrected release tag also exists.

Suggested change
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recognition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path segment speaker-recongition-models appears misspelled (likely speaker-recognition-models). If the release tag uses the correct spelling, this will 404 and break CI. Please verify the release URL and correct the typo if needed.

Suggested change
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recognition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx

Copilot uses AI. Check for mistakes.
fi

if [ ! -f ./0-four-speakers-zh.wav ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-segmentation-models/0-four-speakers-zh.wav
fi

cargo run --example offline_speaker_diarization
2 changes: 2 additions & 0 deletions sherpa-onnx/rust/sherpa-onnx-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern "C" {

pub mod audio_tagging;
pub mod offline_asr;
pub mod offline_speaker_diarization;
pub mod online_asr;
pub mod online_punctuation;
pub mod speaker_embedding;
Expand All @@ -23,6 +24,7 @@ pub mod wave;

pub use audio_tagging::*;
pub use offline_asr::*;
pub use offline_speaker_diarization::*;
pub use online_asr::*;
pub use online_punctuation::*;
pub use speaker_embedding::*;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use std::os::raw::{c_char, c_float};

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct OfflineSpeakerSegmentationPyannoteModelConfig {
pub model: *const c_char,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct OfflineSpeakerSegmentationModelConfig {
pub pyannote: OfflineSpeakerSegmentationPyannoteModelConfig,
pub num_threads: i32,
pub debug: i32,
pub provider: *const c_char,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct FastClusteringConfig {
pub num_clusters: i32,
pub threshold: c_float,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct OfflineSpeakerDiarizationConfig {
pub segmentation: OfflineSpeakerSegmentationModelConfig,
pub embedding: crate::speaker_embedding::SpeakerEmbeddingExtractorConfig,
pub clustering: FastClusteringConfig,
pub min_duration_on: c_float,
pub min_duration_off: c_float,
}

#[repr(C)]
pub struct OfflineSpeakerDiarization {
_private: [u8; 0],
}

#[repr(C)]
pub struct OfflineSpeakerDiarizationResult {
_private: [u8; 0],
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct OfflineSpeakerDiarizationSegment {
pub start: c_float,
pub end: c_float,
pub speaker: i32,
}

extern "C" {
pub fn SherpaOnnxCreateOfflineSpeakerDiarization(
config: *const OfflineSpeakerDiarizationConfig,
) -> *const OfflineSpeakerDiarization;

pub fn SherpaOnnxDestroyOfflineSpeakerDiarization(sd: *const OfflineSpeakerDiarization);

pub fn SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(
sd: *const OfflineSpeakerDiarization,
) -> i32;

pub fn SherpaOnnxOfflineSpeakerDiarizationSetConfig(
sd: *const OfflineSpeakerDiarization,
config: *const OfflineSpeakerDiarizationConfig,
);

pub fn SherpaOnnxOfflineSpeakerDiarizationResultGetNumSpeakers(
r: *const OfflineSpeakerDiarizationResult,
) -> i32;

pub fn SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(
r: *const OfflineSpeakerDiarizationResult,
) -> i32;

pub fn SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(
r: *const OfflineSpeakerDiarizationResult,
) -> *const OfflineSpeakerDiarizationSegment;

pub fn SherpaOnnxOfflineSpeakerDiarizationDestroySegment(
s: *const OfflineSpeakerDiarizationSegment,
);

pub fn SherpaOnnxOfflineSpeakerDiarizationProcess(
sd: *const OfflineSpeakerDiarization,
samples: *const c_float,
n: i32,
) -> *const OfflineSpeakerDiarizationResult;

pub fn SherpaOnnxOfflineSpeakerDiarizationDestroyResult(
r: *const OfflineSpeakerDiarizationResult,
);
}
2 changes: 2 additions & 0 deletions sherpa-onnx/rust/sherpa-onnx/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod audio_tagging;
mod display;
mod offline_asr;
mod offline_speaker_diarization;
mod offline_speech_denoiser;
mod online_asr;
mod online_punctuation;
Expand All @@ -15,6 +16,7 @@ mod wave;
pub use audio_tagging::*;
pub use display::*;
pub use offline_asr::*;
pub use offline_speaker_diarization::*;
pub use offline_speech_denoiser::*;
pub use online_asr::*;
pub use online_punctuation::*;
Expand Down
Loading
Loading