#[cfg(feature = "tokio")]
use crate::v1::error::APIError;
use crate::v1::resources::shared::FileUpload;
use bytes::Bytes;
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
#[cfg(feature = "tokio")]
use std::path::Path;
#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
#[builder(name = "AudioSpeechParametersBuilder")]
#[builder(setter(into, strip_option), default)]
pub struct AudioSpeechParameters {
pub model: String,
pub input: String,
pub voice: AudioVoice,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<AudioSpeechResponseFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub speed: Option<f32>,
}
#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
#[builder(name = "AudioTranscriptionParametersBuilder")]
#[builder(setter(into, strip_option), default)]
pub struct AudioTranscriptionParameters {
pub file: FileUpload,
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<AudioOutputFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp_granularities: Option<Vec<TimestampGranularity>>,
}
#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
#[builder(name = "AudioTranslationParametersBuilder")]
#[builder(setter(into, strip_option), default)]
pub struct AudioTranslationParameters {
pub file: FileUpload,
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<AudioOutputFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
}
#[derive(Debug, Clone)]
pub struct AudioSpeechResponse {
pub bytes: Bytes,
}
#[cfg(feature = "stream")]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct StreamAudioSpeechParameters {
pub model: String,
pub input: String,
pub voice: AudioVoice,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<AudioSpeechResponseFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub speed: Option<f32>,
pub stream: bool,
}
#[cfg(feature = "stream")]
#[derive(Debug, Clone, PartialEq)]
pub struct AudioSpeechResponseChunkResponse {
pub bytes: Bytes,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum AudioOutputFormat {
Json,
Text,
Srt,
VerboseJson,
Vtt,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AudioSpeechResponseFormat {
Mp3,
Opus,
Aac,
Flac,
Wav,
Pcm,
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AudioVoice {
#[default]
Alloy,
Ash,
Coral,
Echo,
Fable,
Onyx,
Nova,
Sage,
Shimmer,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TimestampGranularity {
Word,
Segment,
}
impl Display for AudioOutputFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
AudioOutputFormat::Json => "json",
AudioOutputFormat::Text => "text",
AudioOutputFormat::Srt => "srt",
AudioOutputFormat::VerboseJson => "verbose_json",
AudioOutputFormat::Vtt => "vtt",
}
)
}
}
impl Display for TimestampGranularity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
TimestampGranularity::Word => "word",
TimestampGranularity::Segment => "segment",
}
)
}
}
impl AudioSpeechResponse {
#[cfg(feature = "tokio")]
pub async fn save<P: AsRef<Path>>(&self, file_path: P) -> Result<(), APIError> {
let directory = file_path.as_ref().parent();
if let Some(directory) = directory {
let is_existing_directory = match Path::try_exists(directory) {
Ok(exists) => exists,
Err(error) => return Err(APIError::FileError(error.to_string())),
};
if !is_existing_directory {
std::fs::create_dir_all(directory)
.map_err(|error| APIError::FileError(error.to_string()))?;
}
}
tokio::fs::write(file_path, &self.bytes)
.await
.map_err(|error| APIError::FileError(error.to_string()))?;
Ok(())
}
}