async_openai/
util.rs

1use std::path::Path;
2
3use reqwest::Body;
4use tokio::fs::File;
5use tokio_util::codec::{BytesCodec, FramedRead};
6
7use crate::error::OpenAIError;
8use crate::types::InputSource;
9
10pub(crate) async fn file_stream_body(source: InputSource) -> Result<Body, OpenAIError> {
11    let body = match source {
12        InputSource::Path { path } => {
13            let file = File::open(path)
14                .await
15                .map_err(|e| OpenAIError::FileReadError(e.to_string()))?;
16            let stream = FramedRead::new(file, BytesCodec::new());
17            Body::wrap_stream(stream)
18        }
19        _ => {
20            return Err(OpenAIError::FileReadError(
21                "Cannot create stream from non-file source".to_string(),
22            ))
23        }
24    };
25    Ok(body)
26}
27
28/// Creates the part for the given file for multipart upload.
29pub(crate) async fn create_file_part(
30    source: InputSource,
31) -> Result<reqwest::multipart::Part, OpenAIError> {
32    let (stream, file_name) = match source {
33        InputSource::Path { path } => {
34            let file_name = path
35                .file_name()
36                .ok_or_else(|| {
37                    OpenAIError::FileReadError(format!(
38                        "cannot extract file name from {}",
39                        path.display()
40                    ))
41                })?
42                .to_str()
43                .unwrap()
44                .to_string();
45
46            (
47                file_stream_body(InputSource::Path { path }).await?,
48                file_name,
49            )
50        }
51        InputSource::Bytes { filename, bytes } => (Body::from(bytes), filename),
52        InputSource::VecU8 { filename, vec } => (Body::from(vec), filename),
53    };
54
55    let file_part = reqwest::multipart::Part::stream(stream)
56        .file_name(file_name)
57        .mime_str("application/octet-stream")
58        .unwrap();
59
60    Ok(file_part)
61}
62
63pub(crate) fn create_all_dir<P: AsRef<Path>>(dir: P) -> Result<(), OpenAIError> {
64    let exists = match Path::try_exists(dir.as_ref()) {
65        Ok(exists) => exists,
66        Err(e) => return Err(OpenAIError::FileSaveError(e.to_string())),
67    };
68
69    if !exists {
70        std::fs::create_dir_all(dir.as_ref())
71            .map_err(|e| OpenAIError::FileSaveError(e.to_string()))?;
72    }
73
74    Ok(())
75}