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