diff --git a/src-tauri/src/transcription/crispasr.rs b/src-tauri/src/transcription/crispasr.rs index 01068ad..3ddb46d 100644 --- a/src-tauri/src/transcription/crispasr.rs +++ b/src-tauri/src/transcription/crispasr.rs @@ -1,4 +1,5 @@ use std::path::PathBuf; +use std::process::Command; use serde::{Deserialize, Serialize}; @@ -34,16 +35,46 @@ impl Transcriber for CrispAsrTranscriber { return Err(AppError::ModelNotInstalled(input.options.model_id)); }; - if self.config.sidecar_name.is_none() { + if !model_path.exists() { + return Err(AppError::InvalidModel(format!( + "modelo não encontrado em {}", + model_path.display() + ))); + } + + let Some(sidecar_name) = &self.config.sidecar_name else { return Err(AppError::SidecarNotConfigured); + }; + + let threads = default_thread_count().to_string(); + let output = Command::new(sidecar_name) + .arg("-m") + .arg(model_path) + .arg("-f") + .arg(&input.audio_path) + .arg("-t") + .arg(&threads) + .output() + .map_err(|error| AppError::Transcription(error.to_string()))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); + return Err(AppError::Transcription(if stderr.is_empty() { + format!("sidecar encerrou com status {}", output.status) + } else { + stderr + })); + } + + let text = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if text.is_empty() { + return Err(AppError::Transcription( + "sidecar não retornou texto transcrito".to_string(), + )); } Ok(TranscriptionResult { - text: format!( - "Transcrição local pendente via CrispASR para {} usando {}.", - input.audio_path.display(), - model_path.display() - ), + text, backend: "crispasr".to_string(), model_id: input.options.model_id, detected_language: input.options.language, @@ -51,6 +82,13 @@ impl Transcriber for CrispAsrTranscriber { } } +fn default_thread_count() -> usize { + std::thread::available_parallelism() + .map(|count| count.get()) + .unwrap_or(2) + .clamp(1, 4) +} + #[cfg(test)] mod tests { use std::path::PathBuf; @@ -75,6 +113,9 @@ mod tests { }) .expect_err("modelo ausente deve falhar"); - assert_eq!(err, AppError::ModelNotInstalled(DEFAULT_MODEL_ID.to_string())); + assert_eq!( + err, + AppError::ModelNotInstalled(DEFAULT_MODEL_ID.to_string()) + ); } } diff --git a/src-tauri/src/ui_commands.rs b/src-tauri/src/ui_commands.rs index 54aa8cf..7b08e87 100644 --- a/src-tauri/src/ui_commands.rs +++ b/src-tauri/src/ui_commands.rs @@ -46,7 +46,7 @@ pub(crate) fn stop_recording_and_transcribe( .clone(); let transcriber = CrispAsrTranscriber::new(CrispAsrConfig { - sidecar_name: None, + sidecar_name: Some("parakeet-main".to_string()), model_path: Some(default_model_path(&state.model_dir)), });