use serde::Serialize;
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum VoiceProviderKind {
Stt,
Tts,
}
#[derive(Debug, Clone, Serialize)]
pub struct VoiceProviderInfo {
pub id: &'static str,
pub kind: VoiceProviderKind,
pub available: bool,
pub description: &'static str,
}
pub fn list_voice_providers() -> Vec<VoiceProviderInfo> {
vec![
VoiceProviderInfo {
id: "elevenlabs",
kind: VoiceProviderKind::Stt,
available: true,
description: "ElevenLabs Scribe cloud STT (requires API key)",
},
VoiceProviderInfo {
id: "whisper_cpp",
kind: VoiceProviderKind::Stt,
available: true,
description: "In-process Whisper via whisper.cpp \
(Metal on Apple Silicon, CPU elsewhere); \
model file downloaded on first use",
},
VoiceProviderInfo {
id: "parakeet",
kind: VoiceProviderKind::Stt,
available: cfg!(feature = "parakeet"),
description: "NVIDIA Parakeet TDT via ONNX Runtime — \
requires `parakeet` cargo feature",
},
VoiceProviderInfo {
id: "apple_speech",
kind: VoiceProviderKind::Stt,
available: cfg!(target_os = "macos"),
description: "macOS SFSpeechRecognizer — on-device, free, \
multilingual, no model download (macOS 10.15+); \
host must call requestAuthorization at startup",
},
VoiceProviderInfo {
id: "elevenlabs",
kind: VoiceProviderKind::Tts,
available: true,
description: "ElevenLabs cloud TTS (requires API key)",
},
VoiceProviderInfo {
id: "local",
kind: VoiceProviderKind::Tts,
available: true,
description: "OpenAI-compatible /v1/audio/speech HTTP client \
(e.g. mlx-audio, Piper) — requires a separate server",
},
VoiceProviderInfo {
id: "kokoro",
kind: VoiceProviderKind::Tts,
available: cfg!(all(
target_os = "macos",
target_arch = "aarch64",
not(car_skip_mlx)
)),
description: "In-process Kokoro-82M TTS via MLX/Metal — \
Apple Silicon macOS only; model downloaded on first use",
},
VoiceProviderInfo {
id: "apple_speech",
kind: VoiceProviderKind::Tts,
available: cfg!(target_os = "macos"),
description: "macOS AVSpeechSynthesizer — built-in, no model \
download, no MLX dependency (macOS 10.14+)",
},
]
}
pub fn list_voice_providers_json() -> String {
serde_json::to_string(&list_voice_providers())
.expect("VoiceProviderInfo serialization is infallible")
}