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