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