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