dynamo_async_openai/types/
impls.rs

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