openai_dive/v1/endpoints/
audio.rs

1use crate::v1::api::Client;
2use crate::v1::error::APIError;
3use crate::v1::resources::audio::AudioSpeechParameters;
4use crate::v1::resources::audio::AudioSpeechResponse;
5#[cfg(feature = "stream")]
6use crate::v1::resources::audio::AudioSpeechResponseChunkResponse;
7use crate::v1::resources::audio::{AudioTranscriptionParameters, AudioTranslationParameters};
8#[cfg(feature = "stream")]
9use futures::Stream;
10#[cfg(feature = "stream")]
11use futures::StreamExt;
12use serde_json::Value;
13#[cfg(feature = "stream")]
14use std::pin::Pin;
15
16pub struct Audio<'a> {
17    pub client: &'a Client,
18}
19
20impl Client {
21    /// Learn how to turn audio into text or text into audio.
22    pub fn audio(&self) -> Audio<'_> {
23        Audio { client: self }
24    }
25}
26
27impl Audio<'_> {
28    /// Generates audio from the input text.
29    pub async fn create_speech(
30        &self,
31        parameters: AudioSpeechParameters,
32    ) -> Result<AudioSpeechResponse, APIError> {
33        let bytes = self.client.post_raw("/audio/speech", &parameters).await?;
34
35        Ok(AudioSpeechResponse { bytes })
36    }
37
38    /// Transcribes audio into the input language.
39    pub async fn create_transcription(
40        &self,
41        parameters: AudioTranscriptionParameters,
42    ) -> Result<String, APIError> {
43        let mut form = reqwest::multipart::Form::new();
44
45        let file = parameters.file.into_part().await?;
46
47        form = form.part("file", file);
48
49        form = form.text("model", parameters.model);
50
51        if let Some(prompt) = parameters.prompt {
52            form = form.text("prompt", prompt);
53        }
54
55        if let Some(language) = parameters.language {
56            form = form.text("language", language.to_string());
57        }
58
59        if let Some(chunking_strategy) = parameters.chunking_strategy {
60            form = form.text("chunking_strategy", chunking_strategy.to_string());
61        }
62
63        if let Some(response_format) = parameters.response_format {
64            form = form.text("response_format", response_format.to_string());
65        }
66
67        if let Some(stream) = parameters.stream {
68            form = form.text("stream", stream.to_string());
69        }
70
71        if let Some(temperature) = parameters.temperature {
72            form = form.text("temperature", temperature.to_string());
73        }
74
75        if let Some(timestamp_granularities) = parameters.timestamp_granularities {
76            form = form.text(
77                "timestamp_granularities",
78                timestamp_granularities
79                    .iter()
80                    .map(|t| t.to_string())
81                    .collect::<Vec<String>>()
82                    .join(","),
83            );
84        }
85
86        if let Some(extra_body) = parameters.extra_body {
87            match extra_body {
88                Value::Object(map) => {
89                    for (key, value) in map {
90                        form = form.text(key, value.to_string());
91                    }
92                }
93                _ => {
94                    return Err(APIError::BadRequestError(
95                        "extra_body must be formatted as a map of key: value".to_string(),
96                    ));
97                }
98            }
99        }
100
101        let response = self
102            .client
103            .post_with_form("/audio/transcriptions", form)
104            .await?;
105
106        Ok(response)
107    }
108
109    /// Translates audio into English.
110    pub async fn create_translation(
111        &self,
112        parameters: AudioTranslationParameters,
113    ) -> Result<String, APIError> {
114        let mut form = reqwest::multipart::Form::new();
115
116        let file = parameters.file.into_part().await?;
117        form = form.part("file", file);
118
119        form = form.text("model", parameters.model);
120
121        if let Some(prompt) = parameters.prompt {
122            form = form.text("prompt", prompt);
123        }
124
125        if let Some(response_format) = parameters.response_format {
126            form = form.text("response_format", response_format.to_string());
127        }
128
129        if let Some(temperature) = parameters.temperature {
130            form = form.text("temperature", temperature.to_string());
131        }
132
133        let response = self
134            .client
135            .post_with_form("/audio/translations", form)
136            .await?;
137
138        Ok(response)
139    }
140
141    #[cfg(feature = "stream")]
142    /// Generates audio from the input text.
143    pub async fn create_speech_stream(
144        &self,
145        parameters: AudioSpeechParameters,
146    ) -> Result<
147        Pin<Box<dyn Stream<Item = Result<AudioSpeechResponseChunkResponse, APIError>> + Send>>,
148        APIError,
149    > {
150        use crate::v1::resources::audio::StreamAudioSpeechParameters;
151
152        let stream_parameters = StreamAudioSpeechParameters {
153            model: parameters.model,
154            input: parameters.input,
155            voice: parameters.voice,
156            response_format: parameters.response_format,
157            speed: parameters.speed,
158            stream: true,
159        };
160
161        let stream = Box::pin(
162            self.client
163                .post_stream_raw("/audio/speech", &stream_parameters)
164                .await
165                .unwrap()
166                .map(|item| item.map(|bytes| AudioSpeechResponseChunkResponse { bytes })),
167        );
168
169        Ok(stream)
170    }
171}