flynn_openai/types/
impls.rs

1use std::{
2    fmt::Display,
3    path::{Path, PathBuf},
4};
5
6use crate::{
7    download::{download_url, save_b64},
8    error::OpenAIError,
9    types::InputSource,
10    util::{create_all_dir, create_file_part},
11};
12
13use bytes::Bytes;
14
15use super::{
16    AudioInput, AudioResponseFormat, ChatCompletionFunctionCall, ChatCompletionFunctions,
17    ChatCompletionNamedToolChoice, ChatCompletionRequestAssistantMessage,
18    ChatCompletionRequestAssistantMessageContent, ChatCompletionRequestFunctionMessage,
19    ChatCompletionRequestMessage, ChatCompletionRequestMessageContentPartImage,
20    ChatCompletionRequestMessageContentPartText, ChatCompletionRequestSystemMessage,
21    ChatCompletionRequestSystemMessageContent, ChatCompletionRequestToolMessage,
22    ChatCompletionRequestToolMessageContent, ChatCompletionRequestUserMessage,
23    ChatCompletionRequestUserMessageContent, ChatCompletionRequestUserMessageContentPart,
24    ChatCompletionToolChoiceOption, CreateFileRequest, CreateImageEditRequest,
25    CreateImageVariationRequest, CreateMessageRequestContent, CreateSpeechResponse,
26    CreateTranscriptionRequest, CreateTranslationRequest, DallE2ImageSize, EmbeddingInput,
27    FileInput, FilePurpose, FunctionName, Image, ImageInput, ImageModel, ImageResponseFormat,
28    ImageSize, ImageUrl, ImagesResponse, ModerationInput, Prompt, Role, Stop, TimestampGranularity,
29};
30
31/// for `impl_from!(T, Enum)`, implements
32/// - `From<T>`
33/// - `From<Vec<T>>`
34/// - `From<&Vec<T>>`
35/// - `From<[T; N]>`
36/// - `From<&[T; N]>`
37///
38/// for `T: Into<String>` and `Enum` having variants `String(String)` and `StringArray(Vec<String>)`
39macro_rules! impl_from {
40    ($from_typ:ty, $to_typ:ty) => {
41        // From<T> -> String variant
42        impl From<$from_typ> for $to_typ {
43            fn from(value: $from_typ) -> Self {
44                <$to_typ>::String(value.into())
45            }
46        }
47
48        // From<Vec<T>> -> StringArray variant
49        impl From<Vec<$from_typ>> for $to_typ {
50            fn from(value: Vec<$from_typ>) -> Self {
51                <$to_typ>::StringArray(value.iter().map(|v| v.to_string()).collect())
52            }
53        }
54
55        // From<&Vec<T>> -> StringArray variant
56        impl From<&Vec<$from_typ>> for $to_typ {
57            fn from(value: &Vec<$from_typ>) -> Self {
58                <$to_typ>::StringArray(value.iter().map(|v| v.to_string()).collect())
59            }
60        }
61
62        // From<[T; N]> -> StringArray variant
63        impl<const N: usize> From<[$from_typ; N]> for $to_typ {
64            fn from(value: [$from_typ; N]) -> Self {
65                <$to_typ>::StringArray(value.into_iter().map(|v| v.to_string()).collect())
66            }
67        }
68
69        // From<&[T; N]> -> StringArray variatn
70        impl<const N: usize> From<&[$from_typ; N]> for $to_typ {
71            fn from(value: &[$from_typ; N]) -> Self {
72                <$to_typ>::StringArray(value.into_iter().map(|v| v.to_string()).collect())
73            }
74        }
75    };
76}
77
78// From String "family" to Prompt
79impl_from!(&str, Prompt);
80impl_from!(String, Prompt);
81impl_from!(&String, Prompt);
82
83// From String "family" to Stop
84impl_from!(&str, Stop);
85impl_from!(String, Stop);
86impl_from!(&String, Stop);
87
88// From String "family" to ModerationInput
89impl_from!(&str, ModerationInput);
90impl_from!(String, ModerationInput);
91impl_from!(&String, ModerationInput);
92
93// From String "family" to EmbeddingInput
94impl_from!(&str, EmbeddingInput);
95impl_from!(String, EmbeddingInput);
96impl_from!(&String, EmbeddingInput);
97
98/// for `impl_default!(Enum)`, implements `Default` for `Enum` as `Enum::String("")` where `Enum` has `String` variant
99macro_rules! impl_default {
100    ($for_typ:ty) => {
101        impl Default for $for_typ {
102            fn default() -> Self {
103                Self::String("".into())
104            }
105        }
106    };
107}
108
109impl_default!(Prompt);
110impl_default!(ModerationInput);
111impl_default!(EmbeddingInput);
112
113impl Default for InputSource {
114    fn default() -> Self {
115        InputSource::Path {
116            path: PathBuf::new(),
117        }
118    }
119}
120
121/// for `impl_input!(Struct)` where
122/// ```text
123/// Struct {
124///     source: InputSource
125/// }
126/// ```
127/// implements methods `from_bytes` and `from_vec_u8`,
128/// and `From<P>` for `P: AsRef<Path>`
129macro_rules! impl_input {
130    ($for_typ:ty) => {
131        impl $for_typ {
132            pub fn from_bytes(filename: String, bytes: Bytes) -> Self {
133                Self {
134                    source: InputSource::Bytes { filename, bytes },
135                }
136            }
137
138            pub fn from_vec_u8(filename: String, vec: Vec<u8>) -> Self {
139                Self {
140                    source: InputSource::VecU8 { filename, vec },
141                }
142            }
143        }
144
145        impl<P: AsRef<Path>> From<P> for $for_typ {
146            fn from(path: P) -> Self {
147                let path_buf = path.as_ref().to_path_buf();
148                Self {
149                    source: InputSource::Path { path: path_buf },
150                }
151            }
152        }
153    };
154}
155
156impl_input!(AudioInput);
157impl_input!(FileInput);
158impl_input!(ImageInput);
159
160impl Display for ImageSize {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        write!(
163            f,
164            "{}",
165            match self {
166                Self::S256x256 => "256x256",
167                Self::S512x512 => "512x512",
168                Self::S1024x1024 => "1024x1024",
169                Self::S1792x1024 => "1792x1024",
170                Self::S1024x1792 => "1024x1792",
171            }
172        )
173    }
174}
175
176impl Display for DallE2ImageSize {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        write!(
179            f,
180            "{}",
181            match self {
182                Self::S256x256 => "256x256",
183                Self::S512x512 => "512x512",
184                Self::S1024x1024 => "1024x1024",
185            }
186        )
187    }
188}
189
190impl Display for ImageModel {
191    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192        write!(
193            f,
194            "{}",
195            match self {
196                Self::DallE2 => "dall-e-2",
197                Self::DallE3 => "dall-e-3",
198                Self::Other(other) => other,
199            }
200        )
201    }
202}
203
204impl Display for ImageResponseFormat {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        write!(
207            f,
208            "{}",
209            match self {
210                Self::Url => "url",
211                Self::B64Json => "b64_json",
212            }
213        )
214    }
215}
216
217impl Display for AudioResponseFormat {
218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219        write!(
220            f,
221            "{}",
222            match self {
223                AudioResponseFormat::Json => "json",
224                AudioResponseFormat::Srt => "srt",
225                AudioResponseFormat::Text => "text",
226                AudioResponseFormat::VerboseJson => "verbose_json",
227                AudioResponseFormat::Vtt => "vtt",
228            }
229        )
230    }
231}
232
233impl Display for TimestampGranularity {
234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235        write!(
236            f,
237            "{}",
238            match self {
239                TimestampGranularity::Word => "word",
240                TimestampGranularity::Segment => "segment",
241            }
242        )
243    }
244}
245
246impl Display for Role {
247    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248        write!(
249            f,
250            "{}",
251            match self {
252                Role::User => "user",
253                Role::System => "system",
254                Role::Assistant => "assistant",
255                Role::Function => "function",
256                Role::Tool => "tool",
257            }
258        )
259    }
260}
261
262impl Display for FilePurpose {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        write!(
265            f,
266            "{}",
267            match self {
268                Self::Assistants => "assistants",
269                Self::Batch => "batch",
270                Self::FineTune => "fine-tune",
271                Self::Vision => "vision",
272                Self::FileExtract => "file-extract",
273            }
274        )
275    }
276}
277
278impl ImagesResponse {
279    /// Save each image in a dedicated Tokio task and return paths to saved files.
280    /// For [ResponseFormat::Url] each file is downloaded in dedicated Tokio task.
281    pub async fn save<P: AsRef<Path>>(&self, dir: P) -> Result<Vec<PathBuf>, OpenAIError> {
282        create_all_dir(dir.as_ref())?;
283
284        let mut handles = vec![];
285        for id in self.data.clone() {
286            let dir_buf = PathBuf::from(dir.as_ref());
287            handles.push(tokio::spawn(async move { id.save(dir_buf).await }));
288        }
289
290        let results = futures::future::join_all(handles).await;
291        let mut errors = vec![];
292        let mut paths = vec![];
293
294        for result in results {
295            match result {
296                Ok(inner) => match inner {
297                    Ok(path) => paths.push(path),
298                    Err(e) => errors.push(e),
299                },
300                Err(e) => errors.push(OpenAIError::FileSaveError(e.to_string())),
301            }
302        }
303
304        if errors.is_empty() {
305            Ok(paths)
306        } else {
307            Err(OpenAIError::FileSaveError(
308                errors
309                    .into_iter()
310                    .map(|e| e.to_string())
311                    .collect::<Vec<String>>()
312                    .join("; "),
313            ))
314        }
315    }
316}
317
318impl CreateSpeechResponse {
319    pub async fn save<P: AsRef<Path>>(&self, file_path: P) -> Result<(), OpenAIError> {
320        let dir = file_path.as_ref().parent();
321
322        if let Some(dir) = dir {
323            create_all_dir(dir)?;
324        }
325
326        tokio::fs::write(file_path, &self.bytes)
327            .await
328            .map_err(|e| OpenAIError::FileSaveError(e.to_string()))?;
329
330        Ok(())
331    }
332}
333
334impl Image {
335    async fn save<P: AsRef<Path>>(&self, dir: P) -> Result<PathBuf, OpenAIError> {
336        match self {
337            Image::Url { url, .. } => download_url(url, dir).await,
338            Image::B64Json { b64_json, .. } => save_b64(b64_json, dir).await,
339        }
340    }
341}
342
343macro_rules! impl_from_for_integer_array {
344    ($from_typ:ty, $to_typ:ty) => {
345        impl<const N: usize> From<[$from_typ; N]> for $to_typ {
346            fn from(value: [$from_typ; N]) -> Self {
347                Self::IntegerArray(value.to_vec())
348            }
349        }
350
351        impl<const N: usize> From<&[$from_typ; N]> for $to_typ {
352            fn from(value: &[$from_typ; N]) -> Self {
353                Self::IntegerArray(value.to_vec())
354            }
355        }
356
357        impl From<Vec<$from_typ>> for $to_typ {
358            fn from(value: Vec<$from_typ>) -> Self {
359                Self::IntegerArray(value)
360            }
361        }
362
363        impl From<&Vec<$from_typ>> for $to_typ {
364            fn from(value: &Vec<$from_typ>) -> Self {
365                Self::IntegerArray(value.clone())
366            }
367        }
368    };
369}
370
371impl_from_for_integer_array!(u32, EmbeddingInput);
372impl_from_for_integer_array!(u16, Prompt);
373
374macro_rules! impl_from_for_array_of_integer_array {
375    ($from_typ:ty, $to_typ:ty) => {
376        impl From<Vec<Vec<$from_typ>>> for $to_typ {
377            fn from(value: Vec<Vec<$from_typ>>) -> Self {
378                Self::ArrayOfIntegerArray(value)
379            }
380        }
381
382        impl From<&Vec<Vec<$from_typ>>> for $to_typ {
383            fn from(value: &Vec<Vec<$from_typ>>) -> Self {
384                Self::ArrayOfIntegerArray(value.clone())
385            }
386        }
387
388        impl<const M: usize, const N: usize> From<[[$from_typ; N]; M]> for $to_typ {
389            fn from(value: [[$from_typ; N]; M]) -> Self {
390                Self::ArrayOfIntegerArray(value.iter().map(|inner| inner.to_vec()).collect())
391            }
392        }
393
394        impl<const M: usize, const N: usize> From<[&[$from_typ; N]; M]> for $to_typ {
395            fn from(value: [&[$from_typ; N]; M]) -> Self {
396                Self::ArrayOfIntegerArray(value.iter().map(|inner| inner.to_vec()).collect())
397            }
398        }
399
400        impl<const M: usize, const N: usize> From<&[[$from_typ; N]; M]> for $to_typ {
401            fn from(value: &[[$from_typ; N]; M]) -> Self {
402                Self::ArrayOfIntegerArray(value.iter().map(|inner| inner.to_vec()).collect())
403            }
404        }
405
406        impl<const M: usize, const N: usize> From<&[&[$from_typ; N]; M]> for $to_typ {
407            fn from(value: &[&[$from_typ; N]; M]) -> Self {
408                Self::ArrayOfIntegerArray(value.iter().map(|inner| inner.to_vec()).collect())
409            }
410        }
411
412        impl<const N: usize> From<[Vec<$from_typ>; N]> for $to_typ {
413            fn from(value: [Vec<$from_typ>; N]) -> Self {
414                Self::ArrayOfIntegerArray(value.to_vec())
415            }
416        }
417
418        impl<const N: usize> From<&[Vec<$from_typ>; N]> for $to_typ {
419            fn from(value: &[Vec<$from_typ>; N]) -> Self {
420                Self::ArrayOfIntegerArray(value.to_vec())
421            }
422        }
423
424        impl<const N: usize> From<[&Vec<$from_typ>; N]> for $to_typ {
425            fn from(value: [&Vec<$from_typ>; N]) -> Self {
426                Self::ArrayOfIntegerArray(value.into_iter().map(|inner| inner.clone()).collect())
427            }
428        }
429
430        impl<const N: usize> From<&[&Vec<$from_typ>; N]> for $to_typ {
431            fn from(value: &[&Vec<$from_typ>; N]) -> Self {
432                Self::ArrayOfIntegerArray(
433                    value
434                        .to_vec()
435                        .into_iter()
436                        .map(|inner| inner.clone())
437                        .collect(),
438                )
439            }
440        }
441
442        impl<const N: usize> From<Vec<[$from_typ; N]>> for $to_typ {
443            fn from(value: Vec<[$from_typ; N]>) -> Self {
444                Self::ArrayOfIntegerArray(value.into_iter().map(|inner| inner.to_vec()).collect())
445            }
446        }
447
448        impl<const N: usize> From<&Vec<[$from_typ; N]>> for $to_typ {
449            fn from(value: &Vec<[$from_typ; N]>) -> Self {
450                Self::ArrayOfIntegerArray(value.into_iter().map(|inner| inner.to_vec()).collect())
451            }
452        }
453
454        impl<const N: usize> From<Vec<&[$from_typ; N]>> for $to_typ {
455            fn from(value: Vec<&[$from_typ; N]>) -> Self {
456                Self::ArrayOfIntegerArray(value.into_iter().map(|inner| inner.to_vec()).collect())
457            }
458        }
459
460        impl<const N: usize> From<&Vec<&[$from_typ; N]>> for $to_typ {
461            fn from(value: &Vec<&[$from_typ; N]>) -> Self {
462                Self::ArrayOfIntegerArray(value.into_iter().map(|inner| inner.to_vec()).collect())
463            }
464        }
465    };
466}
467
468impl_from_for_array_of_integer_array!(u32, EmbeddingInput);
469impl_from_for_array_of_integer_array!(u16, Prompt);
470
471impl From<&str> for ChatCompletionFunctionCall {
472    fn from(value: &str) -> Self {
473        match value {
474            "auto" => Self::Auto,
475            "none" => Self::None,
476            _ => Self::Function { name: value.into() },
477        }
478    }
479}
480
481impl From<&str> for FunctionName {
482    fn from(value: &str) -> Self {
483        Self { name: value.into() }
484    }
485}
486
487impl From<String> for FunctionName {
488    fn from(value: String) -> Self {
489        Self { name: value }
490    }
491}
492
493impl From<&str> for ChatCompletionNamedToolChoice {
494    fn from(value: &str) -> Self {
495        Self {
496            r#type: super::ChatCompletionToolType::Function,
497            function: value.into(),
498        }
499    }
500}
501
502impl From<String> for ChatCompletionNamedToolChoice {
503    fn from(value: String) -> Self {
504        Self {
505            r#type: super::ChatCompletionToolType::Function,
506            function: value.into(),
507        }
508    }
509}
510
511impl From<&str> for ChatCompletionToolChoiceOption {
512    fn from(value: &str) -> Self {
513        match value {
514            "auto" => Self::Auto,
515            "none" => Self::None,
516            _ => Self::Named(value.into()),
517        }
518    }
519}
520
521impl From<String> for ChatCompletionToolChoiceOption {
522    fn from(value: String) -> Self {
523        match value.as_str() {
524            "auto" => Self::Auto,
525            "none" => Self::None,
526            _ => Self::Named(value.into()),
527        }
528    }
529}
530
531impl From<(String, serde_json::Value)> for ChatCompletionFunctions {
532    fn from(value: (String, serde_json::Value)) -> Self {
533        Self {
534            name: value.0,
535            description: None,
536            parameters: value.1,
537        }
538    }
539}
540
541// todo: write macro for bunch of same looking From trait implementations below
542
543impl From<ChatCompletionRequestUserMessage> for ChatCompletionRequestMessage {
544    fn from(value: ChatCompletionRequestUserMessage) -> Self {
545        Self::User(value)
546    }
547}
548
549impl From<ChatCompletionRequestSystemMessage> for ChatCompletionRequestMessage {
550    fn from(value: ChatCompletionRequestSystemMessage) -> Self {
551        Self::System(value)
552    }
553}
554
555impl From<ChatCompletionRequestAssistantMessage> for ChatCompletionRequestMessage {
556    fn from(value: ChatCompletionRequestAssistantMessage) -> Self {
557        Self::Assistant(value)
558    }
559}
560
561impl From<ChatCompletionRequestFunctionMessage> for ChatCompletionRequestMessage {
562    fn from(value: ChatCompletionRequestFunctionMessage) -> Self {
563        Self::Function(value)
564    }
565}
566
567impl From<ChatCompletionRequestToolMessage> for ChatCompletionRequestMessage {
568    fn from(value: ChatCompletionRequestToolMessage) -> Self {
569        Self::Tool(value)
570    }
571}
572
573impl From<ChatCompletionRequestUserMessageContent> for ChatCompletionRequestUserMessage {
574    fn from(value: ChatCompletionRequestUserMessageContent) -> Self {
575        Self {
576            content: value,
577            name: None,
578        }
579    }
580}
581
582impl From<ChatCompletionRequestSystemMessageContent> for ChatCompletionRequestSystemMessage {
583    fn from(value: ChatCompletionRequestSystemMessageContent) -> Self {
584        Self {
585            content: value,
586            name: None,
587        }
588    }
589}
590
591impl From<ChatCompletionRequestAssistantMessageContent> for ChatCompletionRequestAssistantMessage {
592    fn from(value: ChatCompletionRequestAssistantMessageContent) -> Self {
593        Self {
594            content: Some(value),
595            ..Default::default()
596        }
597    }
598}
599
600impl From<&str> for ChatCompletionRequestUserMessageContent {
601    fn from(value: &str) -> Self {
602        ChatCompletionRequestUserMessageContent::Text(value.into())
603    }
604}
605
606impl From<String> for ChatCompletionRequestUserMessageContent {
607    fn from(value: String) -> Self {
608        ChatCompletionRequestUserMessageContent::Text(value)
609    }
610}
611
612impl From<&str> for ChatCompletionRequestSystemMessageContent {
613    fn from(value: &str) -> Self {
614        ChatCompletionRequestSystemMessageContent::Text(value.into())
615    }
616}
617
618impl From<String> for ChatCompletionRequestSystemMessageContent {
619    fn from(value: String) -> Self {
620        ChatCompletionRequestSystemMessageContent::Text(value)
621    }
622}
623
624impl From<&str> for ChatCompletionRequestAssistantMessageContent {
625    fn from(value: &str) -> Self {
626        ChatCompletionRequestAssistantMessageContent::Text(value.into())
627    }
628}
629
630impl From<String> for ChatCompletionRequestAssistantMessageContent {
631    fn from(value: String) -> Self {
632        ChatCompletionRequestAssistantMessageContent::Text(value)
633    }
634}
635
636impl From<&str> for ChatCompletionRequestToolMessageContent {
637    fn from(value: &str) -> Self {
638        ChatCompletionRequestToolMessageContent::Text(value.into())
639    }
640}
641
642impl From<String> for ChatCompletionRequestToolMessageContent {
643    fn from(value: String) -> Self {
644        ChatCompletionRequestToolMessageContent::Text(value)
645    }
646}
647
648impl From<&str> for ChatCompletionRequestUserMessage {
649    fn from(value: &str) -> Self {
650        ChatCompletionRequestUserMessageContent::Text(value.into()).into()
651    }
652}
653
654impl From<String> for ChatCompletionRequestUserMessage {
655    fn from(value: String) -> Self {
656        value.as_str().into()
657    }
658}
659
660impl From<&str> for ChatCompletionRequestSystemMessage {
661    fn from(value: &str) -> Self {
662        ChatCompletionRequestSystemMessageContent::Text(value.into()).into()
663    }
664}
665
666impl From<String> for ChatCompletionRequestSystemMessage {
667    fn from(value: String) -> Self {
668        value.as_str().into()
669    }
670}
671
672impl From<&str> for ChatCompletionRequestAssistantMessage {
673    fn from(value: &str) -> Self {
674        ChatCompletionRequestAssistantMessageContent::Text(value.into()).into()
675    }
676}
677
678impl From<String> for ChatCompletionRequestAssistantMessage {
679    fn from(value: String) -> Self {
680        value.as_str().into()
681    }
682}
683
684impl From<Vec<ChatCompletionRequestUserMessageContentPart>>
685    for ChatCompletionRequestUserMessageContent
686{
687    fn from(value: Vec<ChatCompletionRequestUserMessageContentPart>) -> Self {
688        ChatCompletionRequestUserMessageContent::Array(value)
689    }
690}
691
692impl From<ChatCompletionRequestMessageContentPartText>
693    for ChatCompletionRequestUserMessageContentPart
694{
695    fn from(value: ChatCompletionRequestMessageContentPartText) -> Self {
696        ChatCompletionRequestUserMessageContentPart::Text(value)
697    }
698}
699
700impl From<ChatCompletionRequestMessageContentPartImage>
701    for ChatCompletionRequestUserMessageContentPart
702{
703    fn from(value: ChatCompletionRequestMessageContentPartImage) -> Self {
704        ChatCompletionRequestUserMessageContentPart::ImageUrl(value)
705    }
706}
707
708impl From<&str> for ChatCompletionRequestMessageContentPartText {
709    fn from(value: &str) -> Self {
710        ChatCompletionRequestMessageContentPartText { text: value.into() }
711    }
712}
713
714impl From<String> for ChatCompletionRequestMessageContentPartText {
715    fn from(value: String) -> Self {
716        ChatCompletionRequestMessageContentPartText { text: value }
717    }
718}
719
720impl From<&str> for ImageUrl {
721    fn from(value: &str) -> Self {
722        Self {
723            url: value.into(),
724            detail: Default::default(),
725        }
726    }
727}
728
729impl From<String> for ImageUrl {
730    fn from(value: String) -> Self {
731        Self {
732            url: value,
733            detail: Default::default(),
734        }
735    }
736}
737
738impl From<String> for CreateMessageRequestContent {
739    fn from(value: String) -> Self {
740        Self::Content(value)
741    }
742}
743
744impl From<&str> for CreateMessageRequestContent {
745    fn from(value: &str) -> Self {
746        Self::Content(value.to_string())
747    }
748}
749
750impl Default for ChatCompletionRequestUserMessageContent {
751    fn default() -> Self {
752        ChatCompletionRequestUserMessageContent::Text("".into())
753    }
754}
755
756impl Default for CreateMessageRequestContent {
757    fn default() -> Self {
758        Self::Content("".into())
759    }
760}
761
762impl Default for ChatCompletionRequestSystemMessageContent {
763    fn default() -> Self {
764        ChatCompletionRequestSystemMessageContent::Text("".into())
765    }
766}
767
768impl Default for ChatCompletionRequestToolMessageContent {
769    fn default() -> Self {
770        ChatCompletionRequestToolMessageContent::Text("".into())
771    }
772}
773
774// start: types to multipart from
775
776#[async_convert::async_trait]
777impl async_convert::TryFrom<CreateTranscriptionRequest> for reqwest::multipart::Form {
778    type Error = OpenAIError;
779
780    async fn try_from(request: CreateTranscriptionRequest) -> Result<Self, Self::Error> {
781        let audio_part = create_file_part(request.file.source).await?;
782
783        let mut form = reqwest::multipart::Form::new()
784            .part("file", audio_part)
785            .text("model", request.model);
786
787        if let Some(prompt) = request.prompt {
788            form = form.text("prompt", prompt);
789        }
790
791        if let Some(response_format) = request.response_format {
792            form = form.text("response_format", response_format.to_string())
793        }
794
795        if let Some(temperature) = request.temperature {
796            form = form.text("temperature", temperature.to_string())
797        }
798
799        if let Some(language) = request.language {
800            form = form.text("language", language);
801        }
802
803        if let Some(timestamp_granularities) = request.timestamp_granularities {
804            for tg in timestamp_granularities {
805                form = form.text("timestamp_granularities[]", tg.to_string());
806            }
807        }
808
809        Ok(form)
810    }
811}
812
813#[async_convert::async_trait]
814impl async_convert::TryFrom<CreateTranslationRequest> for reqwest::multipart::Form {
815    type Error = OpenAIError;
816
817    async fn try_from(request: CreateTranslationRequest) -> Result<Self, Self::Error> {
818        let audio_part = create_file_part(request.file.source).await?;
819
820        let mut form = reqwest::multipart::Form::new()
821            .part("file", audio_part)
822            .text("model", request.model);
823
824        if let Some(prompt) = request.prompt {
825            form = form.text("prompt", prompt);
826        }
827
828        if let Some(response_format) = request.response_format {
829            form = form.text("response_format", response_format.to_string())
830        }
831
832        if let Some(temperature) = request.temperature {
833            form = form.text("temperature", temperature.to_string())
834        }
835        Ok(form)
836    }
837}
838
839#[async_convert::async_trait]
840impl async_convert::TryFrom<CreateImageEditRequest> for reqwest::multipart::Form {
841    type Error = OpenAIError;
842
843    async fn try_from(request: CreateImageEditRequest) -> Result<Self, Self::Error> {
844        let image_part = create_file_part(request.image.source).await?;
845
846        let mut form = reqwest::multipart::Form::new()
847            .part("image", image_part)
848            .text("prompt", request.prompt);
849
850        if let Some(mask) = request.mask {
851            let mask_part = create_file_part(mask.source).await?;
852            form = form.part("mask", mask_part);
853        }
854
855        if let Some(model) = request.model {
856            form = form.text("model", model.to_string())
857        }
858
859        if request.n.is_some() {
860            form = form.text("n", request.n.unwrap().to_string())
861        }
862
863        if request.size.is_some() {
864            form = form.text("size", request.size.unwrap().to_string())
865        }
866
867        if request.response_format.is_some() {
868            form = form.text(
869                "response_format",
870                request.response_format.unwrap().to_string(),
871            )
872        }
873
874        if request.user.is_some() {
875            form = form.text("user", request.user.unwrap())
876        }
877        Ok(form)
878    }
879}
880
881#[async_convert::async_trait]
882impl async_convert::TryFrom<CreateImageVariationRequest> for reqwest::multipart::Form {
883    type Error = OpenAIError;
884
885    async fn try_from(request: CreateImageVariationRequest) -> Result<Self, Self::Error> {
886        let image_part = create_file_part(request.image.source).await?;
887
888        let mut form = reqwest::multipart::Form::new().part("image", image_part);
889
890        if let Some(model) = request.model {
891            form = form.text("model", model.to_string())
892        }
893
894        if request.n.is_some() {
895            form = form.text("n", request.n.unwrap().to_string())
896        }
897
898        if request.size.is_some() {
899            form = form.text("size", request.size.unwrap().to_string())
900        }
901
902        if request.response_format.is_some() {
903            form = form.text(
904                "response_format",
905                request.response_format.unwrap().to_string(),
906            )
907        }
908
909        if request.user.is_some() {
910            form = form.text("user", request.user.unwrap())
911        }
912        Ok(form)
913    }
914}
915
916#[async_convert::async_trait]
917impl async_convert::TryFrom<CreateFileRequest> for reqwest::multipart::Form {
918    type Error = OpenAIError;
919
920    async fn try_from(request: CreateFileRequest) -> Result<Self, Self::Error> {
921        let file_part = create_file_part(request.file.source).await?;
922        let form = reqwest::multipart::Form::new()
923            .part("file", file_part)
924            .text("purpose", request.purpose.to_string());
925        Ok(form)
926    }
927}
928
929// end: types to multipart form