mod audio;
mod config;
mod controller;
mod engine;
mod hotkey;
mod model;
mod output;
pub use audio::{AudioData, AudioRecorder};
pub use config::{HotkeyConfig, HotkeyMode, OutputMode, SttConfig};
pub use controller::SttFeature;
pub use engine::{TranscriptionResult, WhisperEngine};
pub use hotkey::{HotkeyEvent, HotkeyManager};
pub use output::OutputHandler;
pub use model::{DownloadProgress, DownloadStatus, ModelInfo, ModelManager};
pub use crate::ml::{
ModelManager as SharedModelManager, ModelType, get_ml_data_dir as get_stt_data_dir,
get_models_dir, get_whisper_models_dir,
};
use crate::error::Result;
use std::sync::{Arc, Mutex};
#[allow(dead_code)]
pub struct SttController {
config: SttConfig,
audio_recorder: Option<AudioRecorder>,
engine: Option<WhisperEngine>,
model_manager: ModelManager,
hotkey_manager: Option<HotkeyManager>,
output_handler: Option<OutputHandler>,
is_recording: Arc<Mutex<bool>>,
last_transcription: Arc<Mutex<Option<String>>>,
}
impl SttController {
pub fn new() -> Result<Self> {
let config = SttConfig::load().unwrap_or_default();
let model_manager = ModelManager::new()?;
Ok(Self {
config,
audio_recorder: None,
engine: None,
model_manager,
hotkey_manager: None,
output_handler: None,
is_recording: Arc::new(Mutex::new(false)),
last_transcription: Arc::new(Mutex::new(None)),
})
}
pub fn config(&self) -> &SttConfig {
&self.config
}
pub fn config_mut(&mut self) -> &mut SttConfig {
&mut self.config
}
pub fn model_manager(&self) -> &ModelManager {
&self.model_manager
}
pub fn model_manager_mut(&mut self) -> &mut ModelManager {
&mut self.model_manager
}
pub fn is_recording(&self) -> bool {
*self.is_recording.lock().unwrap()
}
pub fn last_transcription(&self) -> Option<String> {
self.last_transcription.lock().unwrap().clone()
}
pub fn initialize(&mut self) -> Result<()> {
self.audio_recorder = Some(AudioRecorder::new()?);
self.output_handler = Some(OutputHandler::new(self.config.output_mode)?);
if let Some(model_path) = self.model_manager.get_model_path(&self.config.model_id) {
let mut engine = WhisperEngine::new();
if engine.load_model(&model_path).is_ok() {
self.engine = Some(engine);
}
}
Ok(())
}
pub fn start_recording(&mut self) -> Result<()> {
if let Some(ref mut recorder) = self.audio_recorder {
recorder.start_recording()?;
*self.is_recording.lock().unwrap() = true;
}
Ok(())
}
pub fn stop_recording(&mut self) -> Result<Option<String>> {
*self.is_recording.lock().unwrap() = false;
let audio_data = if let Some(ref mut recorder) = self.audio_recorder {
recorder.stop_recording()?
} else {
return Ok(None);
};
let transcription = if let Some(ref mut engine) = self.engine {
let result = engine.transcribe(&audio_data)?;
Some(result.text)
} else {
None
};
if let Some(ref text) = transcription {
*self.last_transcription.lock().unwrap() = Some(text.clone());
if let Some(ref handler) = self.output_handler {
handler.output(text)?;
}
}
Ok(transcription)
}
pub fn save_config(&self) -> Result<()> {
self.config.save()
}
}
impl Default for SttController {
fn default() -> Self {
Self::new().expect("Failed to create STT controller")
}
}