Skip to main content

openai_compat/resources/
files.rs

1//! `/files` resource, mirroring `resources/files.py`: list, retrieve,
2//! delete, content download, and multipart upload.
3
4use bytes::Bytes;
5use reqwest::Method;
6
7use crate::client::Client;
8use crate::error::OpenAIError;
9use crate::pagination::List;
10use crate::request::{MultipartField, RequestOptions};
11use crate::types::files::{FileObject, FileUpload};
12use crate::types::models::Deleted;
13
14/// The files resource.
15#[derive(Debug, Clone)]
16pub struct Files {
17    client: Client,
18}
19
20impl Files {
21    pub(crate) fn new(client: Client) -> Self {
22        Self { client }
23    }
24
25    /// Upload a file for the given purpose (e.g. `"fine-tune"`, `"batch"`,
26    /// `"assistants"`, `"user_data"`).
27    pub async fn create(
28        &self,
29        file: FileUpload,
30        purpose: &str,
31    ) -> Result<FileObject, OpenAIError> {
32        let fields = vec![
33            MultipartField::File {
34                name: "file".into(),
35                filename: file.filename,
36                bytes: file.bytes,
37                content_type: file.content_type,
38            },
39            MultipartField::Text {
40                name: "purpose".into(),
41                value: purpose.to_string(),
42            },
43        ];
44        self.client
45            .execute(Method::POST, "/files", RequestOptions::multipart(fields))
46            .await
47    }
48
49    /// List files, optionally filtered by purpose. Fetches a single page.
50    pub async fn list(&self, purpose: Option<&str>) -> Result<List<FileObject>, OpenAIError> {
51        let query = purpose
52            .map(|p| vec![("purpose".to_string(), p.to_string())])
53            .unwrap_or_default();
54        self.client
55            .execute(Method::GET, "/files", RequestOptions::query(query))
56            .await
57    }
58
59    /// List all files, following pagination cursors.
60    pub async fn list_all(&self, purpose: Option<&str>) -> Result<Vec<FileObject>, OpenAIError> {
61        let query = purpose
62            .map(|p| vec![("purpose".to_string(), p.to_string())])
63            .unwrap_or_default();
64        self.client.paginate_all("/files", query).await
65    }
66
67    /// Retrieve file metadata.
68    pub async fn retrieve(&self, file_id: &str) -> Result<FileObject, OpenAIError> {
69        self.client
70            .execute(
71                Method::GET,
72                &format!("/files/{file_id}"),
73                RequestOptions::default(),
74            )
75            .await
76    }
77
78    /// Delete a file.
79    pub async fn delete(&self, file_id: &str) -> Result<Deleted, OpenAIError> {
80        self.client
81            .execute(
82                Method::DELETE,
83                &format!("/files/{file_id}"),
84                RequestOptions::default(),
85            )
86            .await
87    }
88
89    /// Download the file's raw content.
90    pub async fn content(&self, file_id: &str) -> Result<Bytes, OpenAIError> {
91        self.client
92            .execute_bytes(
93                Method::GET,
94                &format!("/files/{file_id}/content"),
95                RequestOptions::default(),
96            )
97            .await
98    }
99}