use serde::{Deserialize, Serialize};
use crate::audio::{AudioOutput, AudioResponse, TextToSpeechRequest, TranscriptionResponse};
use crate::value_objects::Meta;
const DEFAULT_VOICE_ID: &str = "21m00Tcm4TlvDq8ikWAM";
const DEFAULT_AUDIO_MIME_TYPE: &str = "audio/mpeg";
#[derive(Debug, Serialize)]
pub struct SpeechApiRequest {
pub text: String,
pub model_id: String,
}
pub fn speech_endpoint_path(request: &TextToSpeechRequest) -> String {
let voice_id = request.voice.as_deref().unwrap_or(DEFAULT_VOICE_ID);
format!("text-to-speech/{voice_id}")
}
pub fn build_speech_request(request: &TextToSpeechRequest) -> SpeechApiRequest {
SpeechApiRequest {
text: request.input.clone(),
model_id: request.model.clone(),
}
}
pub fn parse_speech_response(data: Vec<u8>, mime_type: Option<String>) -> AudioResponse {
AudioResponse {
audio: AudioOutput {
data,
mime_type: mime_type.unwrap_or_else(|| DEFAULT_AUDIO_MIME_TYPE.to_string()),
},
meta: Meta::default(),
}
}
#[derive(Debug, Deserialize)]
pub struct TranscriptionApiResponse {
pub text: String,
}
pub fn parse_transcription_response(response: TranscriptionApiResponse) -> TranscriptionResponse {
TranscriptionResponse {
text: response.text,
meta: Meta::default(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn speech_endpoint_path_uses_the_default_voice_when_none_is_set() {
let request = TextToSpeechRequest::new("eleven_flash_v2_5", "hello");
assert_eq!(
speech_endpoint_path(&request),
format!("text-to-speech/{DEFAULT_VOICE_ID}")
);
}
#[test]
fn speech_endpoint_path_uses_the_requested_voice_when_set() {
let mut request = TextToSpeechRequest::new("eleven_flash_v2_5", "hello");
request.voice = Some("custom-voice-id".to_string());
assert_eq!(
speech_endpoint_path(&request),
"text-to-speech/custom-voice-id"
);
}
}