use std::path::Path;
use std::sync::Arc;
use polyvoice::{Embedder, EmbedderError, ResNet34Adapter};
pub const EMBEDDING_DIM: usize = 256;
pub const SEGMENT_SAMPLES: usize = 24000;
#[derive(Clone)]
pub struct SharedEmbedder(Arc<ResNet34Adapter>);
impl Embedder for SharedEmbedder {
fn dim(&self) -> usize {
self.0.dim()
}
fn embed(&self, audio: &[f32]) -> Result<Vec<f32>, EmbedderError> {
self.0.embed(audio)
}
fn embed_batch(&self, audios: &[&[f32]]) -> Result<Vec<Vec<f32>>, EmbedderError> {
self.0.embed_batch(audios)
}
}
pub fn load_extractor(model_dir: &Path, pool_size: usize) -> anyhow::Result<SharedEmbedder> {
let path = model_dir.join("wespeaker_resnet34.onnx");
if !path.exists() {
anyhow::bail!(
"wespeaker_resnet34.onnx not found in {}",
model_dir.display()
);
}
let adapter = ResNet34Adapter::new(&path, pool_size, polyvoice::onnx::ExecutionProvider::Cpu)
.map_err(|e| anyhow::anyhow!("{e:#}"))?;
Ok(SharedEmbedder(Arc::new(adapter)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_embedding_dim_constant() {
assert_eq!(EMBEDDING_DIM, 256);
}
#[test]
fn test_segment_samples_constant() {
assert_eq!(SEGMENT_SAMPLES, 24000);
}
#[test]
fn test_load_extractor_missing_file() {
let result = load_extractor(Path::new("/nonexistent/path"), 1);
assert!(result.is_err());
let err = result.err().unwrap();
let msg = format!("{err}");
assert!(msg.contains("wespeaker_resnet34.onnx"));
}
}