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