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