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