1use bytes::Bytes;
2use serde::Serialize;
3
4use crate::{
5 config::Config,
6 error::OpenAIError,
7 types::{CreateFileRequest, DeleteFileResponse, ListFilesResponse, OpenAIFile},
8 Client,
9};
10
11pub struct Files<'c, C: Config> {
13 client: &'c Client<C>,
14}
15
16impl<'c, C: Config> Files<'c, C> {
17 pub fn new(client: &'c Client<C>) -> Self {
18 Self { client }
19 }
20
21 pub async fn create(&self, request: CreateFileRequest) -> Result<OpenAIFile, OpenAIError> {
31 self.client.post_form("/files", request).await
32 }
33
34 pub async fn list<Q>(&self, query: &Q) -> Result<ListFilesResponse, OpenAIError>
36 where
37 Q: Serialize + ?Sized,
38 {
39 self.client.get_with_query("/files", query).await
40 }
41
42 pub async fn retrieve(&self, file_id: &str) -> Result<OpenAIFile, OpenAIError> {
44 self.client.get(format!("/files/{file_id}").as_str()).await
45 }
46
47 pub async fn delete(&self, file_id: &str) -> Result<DeleteFileResponse, OpenAIError> {
49 self.client
50 .delete(format!("/files/{file_id}").as_str())
51 .await
52 }
53
54 pub async fn content(&self, file_id: &str) -> Result<Bytes, OpenAIError> {
56 self.client
57 .get_raw(format!("/files/{file_id}/content").as_str())
58 .await
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::{
65 types::{CreateFileRequestArgs, FilePurpose},
66 Client,
67 };
68 use crate::config::OpenAIConfig;
69
70 #[tokio::test]
71 async fn test_file_mod() {
72 let test_file_path = "/tmp/test.jsonl";
73 let contents = concat!(
74 "{\"prompt\": \"<prompt text>\", \"completion\": \"<ideal generated text>\"}\n", "{\"prompt\": \"<prompt text>\", \"completion\": \"<ideal generated text>\"}"
76 );
77
78 tokio::fs::write(test_file_path, contents).await.unwrap();
79
80 let api_key = "sk-5574034e4fc9421fb9293c000283eef3"; let config = OpenAIConfig::new()
82 .with_api_key(api_key)
83 .with_api_base("https://dashscope.aliyuncs.com/compatible-mode/v1");
84
85 let client = Client::with_config(config);
86
87 let request = CreateFileRequestArgs::default()
88 .file(test_file_path)
89 .purpose(FilePurpose::FileExtract)
90 .build()
91 .unwrap();
92
93 let openai_file = client.files().create(request).await.unwrap();
94
95 assert_eq!(openai_file.bytes, 135);
96 assert_eq!(openai_file.filename, "test.jsonl");
97 let query = [("purpose", "fine-tune")];
101
102 let list_files = client.files().list(&query).await.unwrap();
103
104 assert_eq!(list_files.data.into_iter().last().unwrap(), openai_file);
105
106 let retrieved_file = client.files().retrieve(&openai_file.id).await.unwrap();
107
108 assert_eq!(openai_file.created_at, retrieved_file.created_at);
109 assert_eq!(openai_file.bytes, retrieved_file.bytes);
110 assert_eq!(openai_file.filename, retrieved_file.filename);
111 assert_eq!(openai_file.purpose, retrieved_file.purpose);
112
113 tokio::time::sleep(std::time::Duration::from_secs(15)).await;
124 let delete_response = client.files().delete(&openai_file.id).await.unwrap();
125
126 assert_eq!(openai_file.id, delete_response.id);
127 assert!(delete_response.deleted);
128 }
129}