async_openai/types/images/
sdk.rs

1#![cfg(not(target_family = "wasm"))]
2use crate::{
3    download::{download_url, save_b64},
4    error::OpenAIError,
5    types::images::{Image, ImagesResponse},
6    util::create_all_dir,
7};
8use std::path::{Path, PathBuf};
9
10impl ImagesResponse {
11    /// Save each image in a dedicated Tokio task and return paths to saved files.
12    /// For `ResponseFormat::Url`` each file is downloaded in dedicated Tokio task.
13    pub async fn save<P: AsRef<Path>>(&self, dir: P) -> Result<Vec<PathBuf>, OpenAIError> {
14        create_all_dir(dir.as_ref())?;
15
16        let mut handles = vec![];
17        for id in self.data.clone() {
18            let dir_buf = PathBuf::from(dir.as_ref());
19            handles.push(tokio::spawn(async move { id.save(dir_buf).await }));
20        }
21
22        let results = futures::future::join_all(handles).await;
23        let mut errors = vec![];
24        let mut paths = vec![];
25
26        for result in results {
27            match result {
28                Ok(inner) => match inner {
29                    Ok(path) => paths.push(path),
30                    Err(e) => errors.push(e),
31                },
32                Err(e) => errors.push(OpenAIError::FileSaveError(e.to_string())),
33            }
34        }
35
36        if errors.is_empty() {
37            Ok(paths)
38        } else {
39            Err(OpenAIError::FileSaveError(
40                errors
41                    .into_iter()
42                    .map(|e| e.to_string())
43                    .collect::<Vec<String>>()
44                    .join("; "),
45            ))
46        }
47    }
48}
49
50impl Image {
51    async fn save<P: AsRef<Path>>(&self, dir: P) -> Result<PathBuf, OpenAIError> {
52        match self {
53            Image::Url { url, .. } => download_url(url, dir).await,
54            Image::B64Json { b64_json, .. } => save_b64(b64_json, dir).await,
55        }
56    }
57}