pub mod whisper;
use std::collections::VecDeque;
use std::sync::Mutex;
use std::time::Duration;
use tokio::sync::oneshot;
pub use whisper::{SttConfig, WhisperStt};
use crate::error::Result;
pub trait SttEngine: Send {
fn name(&self) -> &str;
fn transcribe(&self, samples: Vec<f32>) -> oneshot::Receiver<Result<String>>;
fn dropped_jobs(&self) -> u64 {
0
}
fn stop(self: Box<Self>) {}
}
#[derive(Debug, Default)]
pub struct MockStt {
replies: Mutex<VecDeque<(Duration, String)>>,
}
impl MockStt {
pub fn new() -> Self {
Self::default()
}
pub fn from_replies<I, S>(replies: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
let mock = Self::new();
for reply in replies {
mock.push_reply(reply);
}
mock
}
pub fn push_reply(&self, text: impl Into<String>) -> &Self {
self.push_delayed(Duration::ZERO, text)
}
pub fn push_delayed(&self, delay: Duration, text: impl Into<String>) -> &Self {
self.replies
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.push_back((delay, text.into()));
self
}
}
impl SttEngine for MockStt {
fn name(&self) -> &str {
"mock-stt"
}
fn transcribe(&self, _samples: Vec<f32>) -> oneshot::Receiver<Result<String>> {
let next = self
.replies
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.pop_front();
let (delay, text) = next.unwrap_or_default();
let (tx, rx) = oneshot::channel();
if delay.is_zero() {
let _ = tx.send(Ok(text));
} else {
tokio::spawn(async move {
tokio::time::sleep(delay).await;
let _ = tx.send(Ok(text));
});
}
rx
}
}