diff --git a/Cargo.lock b/Cargo.lock index 0d1e805..02aecc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4070,6 +4070,7 @@ dependencies = [ "crossterm", "dirs", "futures-util", + "hound", "predicates", "qwen3-tts", "ratatui", diff --git a/Cargo.toml b/Cargo.toml index b3d0418..a3687e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tempfile = "3" rodio = "0.20" +hound = "3" qwen3-tts = { git = "https://github.com/TrevorS/qwen3-tts-rs", features = ["hub"], default-features = false } ratatui = "0.29" crossterm = "0.28" diff --git a/src/backend/kokoro.rs b/src/backend/kokoro.rs index 22f10f0..a3f8e4b 100644 --- a/src/backend/kokoro.rs +++ b/src/backend/kokoro.rs @@ -1,13 +1,13 @@ -//! Kokoro TTS backend — pure Rust ONNX inference via Python kokoro-onnx bridge. +//! Kokoro TTS backend — ONNX model via Python kokoro-onnx bridge. //! -//! Cross-platform, no GPU required. Model files (~80MB) downloaded separately. +//! 82M param model, cross-platform. Model files (~80MB) downloaded separately. +//! Note: uses Python subprocess for now. Pure Rust port tracked as future work. use std::process::Command; use anyhow::{Context, Result}; use super::{SpeakOptions, TtsBackend}; -use crate::audio; use crate::config; const MODEL_FILE: &str = "kokoro-v1.0.onnx"; @@ -122,7 +122,22 @@ sf.write("{out}", samples, sr) anyhow::bail!("Kokoro TTS failed: {stderr}"); } - audio::play_wav_blocking(&wav_path)?; + // Use afplay on macOS (more reliable), rodio on other platforms + #[cfg(target_os = "macos")] + { + let status = Command::new("afplay") + .arg(&wav_path) + .status() + .context("failed to play audio")?; + if !status.success() { + anyhow::bail!("afplay failed"); + } + } + #[cfg(not(target_os = "macos"))] + { + crate::audio::play_wav_blocking(&wav_path)?; + } + let _ = std::fs::remove_file(&wav_path); Ok(()) }