use std::path::Path;
use audio::stt::qwen3_asr::Qwen3Asr;
use model_io::speech_family::SpeechFamily;
use crate::whisper::{WhisperSegment, WhisperTranscription};
pub struct Qwen3AsrRunner {
model: Qwen3Asr,
}
impl Qwen3AsrRunner {
pub fn family() -> SpeechFamily {
SpeechFamily::Qwen3Asr
}
pub fn open(model_dir: &Path) -> Result<Self, String> {
let model = Qwen3Asr::load(model_dir).map_err(|error| error.to_string())?;
Ok(Self { model })
}
pub fn transcribe_with_details(
&self,
samples: &[f32],
language: Option<&str>,
) -> Result<audio::stt::qwen3_asr::Qwen3AsrTranscription, String> {
self.model
.transcribe_with_details(samples, language, 512)
.map_err(|e| e.to_string())
}
pub fn transcribe(
&self,
samples: &[f32],
language: Option<&str>,
) -> Result<WhisperTranscription, String> {
let requested = language.filter(|code| !code.is_empty() && *code != "auto");
let details = self
.model
.transcribe_with_details(samples, requested, 512)
.map_err(|error| error.to_string())?;
Ok(WhisperTranscription {
segments: vec![WhisperSegment {
index: 0,
start_seconds: 0.0,
end_seconds: samples.len() as f64 / 16_000.0,
text: details.text,
}],
language: details.language,
})
}
}
#[cfg(test)]
mod tests {
use super::Qwen3AsrRunner;
use model_io::speech_family::SpeechFamily;
#[test]
fn family_wire_string_is_stable() {
assert_eq!(Qwen3AsrRunner::family(), SpeechFamily::Qwen3Asr);
assert_eq!(Qwen3AsrRunner::family().as_str(), "qwen3_asr");
}
#[test]
#[ignore = "requires the pinned Qwen3-ASR checkpoint and the reference WAV"]
fn pinned_checkpoint_transcribes_through_the_runner() {
let model_dir = std::env::var_os("TURBOSPARK_QWEN3_ASR_DIR")
.expect("set TURBOSPARK_QWEN3_ASR_DIR to the pinned checkpoint directory");
let wav = std::env::var_os("TURBOSPARK_QWEN3_ASR_WAV")
.expect("set TURBOSPARK_QWEN3_ASR_WAV to the reference speech clip");
let audio = audio::read_wav_f32(std::path::Path::new(&wav)).unwrap();
assert_eq!(audio.sample_rate, 16_000);
assert_eq!(audio.channels, 1);
let runner = Qwen3AsrRunner::open(std::path::Path::new(&model_dir)).unwrap();
let transcription = runner.transcribe(&audio.samples, None).unwrap();
eprintln!(
"qwen3_asr_runner text={:?} language={:?}",
transcription.segments[0].text, transcription.language
);
assert_eq!(transcription.segments.len(), 1);
assert_eq!(transcription.segments[0].index, 0);
assert_eq!(transcription.segments[0].start_seconds, 0.0);
assert_eq!(
transcription.segments[0].end_seconds,
audio.samples.len() as f64 / 16_000.0
);
assert_eq!(
transcription.segments[0].text,
"The quick brown fox jumps over the lazy dog."
);
}
}