pub mod dedup;
pub mod groq;
pub mod local_parakeet;
pub mod local_vosk;
#[cfg(feature = "local-whisper")]
pub mod local_whisper;
#[cfg(not(feature = "local-whisper"))]
pub mod local_whisper {
pub struct LocalWhisperBackend;
impl LocalWhisperBackend {
pub fn new(_model_path: String) -> Self {
Self
}
}
#[async_trait::async_trait]
impl super::TranscriptionBackend for LocalWhisperBackend {
async fn transcribe(
&self,
_audio: &[u8],
_config: &super::TranscriptionConfig,
) -> anyhow::Result<String> {
anyhow::bail!("local-whisper feature not enabled — rebuild with: cargo build --features local-whisper")
}
}
}
pub mod openai_realtime;
pub mod openai_rest;
use async_trait::async_trait;
use tokio::sync::mpsc;
use crate::audio::AudioChunk;
#[derive(Debug, Clone)]
pub struct TranscriptionConfig {
pub language: String,
pub model: String,
pub prompt: Option<String>,
}
#[async_trait]
pub trait TranscriptionBackend: Send + Sync {
async fn transcribe(
&self,
audio: &[u8],
config: &TranscriptionConfig,
) -> anyhow::Result<String>;
async fn transcribe_stream(
&self,
mut audio_rx: mpsc::Receiver<AudioChunk>,
text_tx: mpsc::Sender<String>,
config: &TranscriptionConfig,
) -> anyhow::Result<()> {
use crate::audio::capture::encode_wav;
let mut all_samples: Vec<i16> = Vec::new();
while let Some(chunk) = audio_rx.recv().await {
all_samples.extend_from_slice(&chunk);
}
if all_samples.is_empty() {
return Ok(());
}
let wav_data = encode_wav(&all_samples)?;
let text = self.transcribe(&wav_data, config).await?;
if !text.is_empty() {
text_tx.send(text).await.ok();
}
Ok(())
}
fn supports_streaming(&self) -> bool {
false
}
}