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