openai_req/files/
mod.rs

1use reqwest::RequestBuilder;
2use super::OpenAiClient;
3use async_trait::async_trait;
4use crate::{ByUrlRequest, DeleteResponse, DownloadRequest, FormRequest, GetRequest};
5use std::io;
6use std::io::{Error, ErrorKind};
7use std::path::PathBuf;
8use reqwest::multipart::{Form, Part};
9use serde::{Serialize, Deserialize};
10use with_id::WithRefId;
11use crate::conversions::AsyncTryFrom;
12use crate::file_to_part;
13use derive_more::*;
14use crate::fine_tunes::FineTuneFileInfo;
15
16/// Gets list of available files. More details at
17/// https://platform.openai.com/docs/api-reference/files/list
18/// # Usage example
19///```
20/// use openai_req::files::FileListResponse;
21/// use openai_req::GetRequest;
22///
23/// let files = FileListResponse::get(&client).await?;
24///```
25#[derive(Serialize, Deserialize, Debug, Clone)]
26pub struct FileListResponse {
27    pub data: Vec<FileInfo>,
28    pub object: String,
29}
30
31#[async_trait]
32impl GetRequest for FileListResponse {
33    const ENDPOINT: &'static str = "/files";
34}
35
36
37#[derive(Serialize, Deserialize, Debug, Clone, WithRefId)]
38pub struct FileInfo {
39    pub id: String,
40    pub object: String,
41    pub bytes: i64,
42    pub created_at: i64,
43    pub filename: String,
44    pub purpose: String,
45}
46
47impl From<FineTuneFileInfo> for FileInfo{
48    fn from(value: FineTuneFileInfo) -> Self {
49        FileInfo{
50            id: value.id,
51            object: value.object,
52            bytes: value.bytes,
53            created_at: value.created_at,
54            filename: value.filename,
55            purpose: value.purpose,
56        }
57    }
58}
59
60/// File delete request allows to delete file in OpenAI storage
61/// https://platform.openai.com/docs/api-reference/files/delete
62/// # Usage example
63///```
64/// use openai_req::ByUrlRequest;
65/// use openai_req::files::FileDeleteRequest;
66///
67/// let req = FileDeleteRequest::new("{file_id}".to_string());
68/// let delete_result = req.run(&client).await?;
69///```
70#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
71pub struct FileDeleteRequest{
72    #[id]
73    file_id:String
74}
75
76impl From<FileInfo> for FileDeleteRequest {
77    fn from(value: FileInfo) -> Self {
78        FileDeleteRequest{
79            file_id:value.id
80        }
81    }
82}
83
84impl ByUrlRequest<DeleteResponse> for FileDeleteRequest{
85    const ENDPOINT: &'static str = "/files/";
86    const SUFFIX: &'static str = "";
87
88    fn builder(client: &OpenAiClient, final_url: String) -> RequestBuilder {
89        client.client.delete(final_url)
90    }
91}
92
93///Gets info about single uploaded file.
94///Refer to https://platform.openai.com/docs/api-reference/files/retrieve for additional details
95///# Usage example
96///```
97/// use openai_req::ByUrlRequest;
98/// use openai_req::files::FileInfoRequest;
99///
100/// let info_request = FileInfoRequest::new("{file_id}".to_string());
101/// let info = info_request.run(&client).await?;
102///```
103#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
104pub struct FileInfoRequest{
105    #[id]
106    file_id:String
107}
108
109impl ByUrlRequest<FileInfo> for FileInfoRequest{
110    const ENDPOINT: &'static str = "/files/";
111    const SUFFIX: &'static str = "";
112}
113///Request to download file.
114/// More details at https://platform.openai.com/docs/api-reference/files/retrieve-content
115/// # Usage example
116/// ```
117///  use openai_req::DownloadRequest;
118///  use openai_req::files::FileDownloadRequest;
119///
120///  let req = FileDownloadRequest::new("{file_id}".to_string());
121///  req.download_to_file(&client, "C:/Downloads/fine-name.ext").await?;
122///```
123#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
124pub struct FileDownloadRequest{
125    #[id]
126    file_id:String
127}
128
129impl DownloadRequest for FileDownloadRequest{
130    const ENDPOINT: &'static str = "/files/";
131    const SUFFIX: &'static str = "/content";
132}
133
134impl From<FileInfo> for FileDownloadRequest {
135    fn from(value: FileInfo) -> Self {
136        FileDownloadRequest{
137            file_id:value.id
138        }
139    }
140}
141
142///Upload local file to OpenAI storage(usually for the purpose of fine-tuning).
143///More details at https://platform.openai.com/docs/api-reference/files/upload
144/// # Usage example
145///```
146/// use openai_req::files::FileUploadRequest;
147/// use openai_req::FormRequest;
148///
149/// let file = FileUploadRequest::with_str("tests/fine-tune.json","fine-tune");
150/// let response = file.run(&client).await?;
151/// ```
152#[derive(Serialize, Deserialize, Debug, Clone)]
153pub struct FileUploadRequest{
154    file:PathBuf,
155    purpose:String
156}
157
158
159impl FormRequest<FileInfo> for FileUploadRequest{
160    const ENDPOINT: &'static str = "/files";
161}
162
163impl FileUploadRequest {
164
165    ///basic constructor, takes path to file and file purpose
166    pub fn new(file:PathBuf, purpose:String) ->Result<FileUploadRequest,Error>{
167        if file.exists() {
168            Ok(
169                FileUploadRequest {
170                    file,
171                    purpose
172                }
173            )
174        }else {
175            Err(Error::new(ErrorKind::NotFound, "File does not exist"))
176        }
177    }
178    ///same arguments as in ::new, but as str refs for convenience
179    pub fn with_str(file:&str,purpose:&str)->Result<FileUploadRequest,Error>{
180        let path = PathBuf::from(file);
181        if path.exists() {
182            Ok(
183                FileUploadRequest {
184                    file: path,
185                    purpose: purpose.to_string()
186                }
187            )
188        }else {
189            Err(io::Error::new(ErrorKind::NotFound, "File does not exist"))
190        }
191    }
192}
193
194#[async_trait]
195impl AsyncTryFrom<FileUploadRequest> for Form{
196    type Error = io::Error;
197
198    async fn try_from(value: FileUploadRequest) -> anyhow::Result<Self, Self::Error> {
199        let form =
200            Form::new()
201                .part("purpose",Part::text(value.purpose))
202                .part("file",file_to_part(&value.file).await?);
203        Ok(form)
204    }
205}
206
207