portkey_sdk/service/
files.rs

1//! Files API service.
2//!
3//! Provides access to file upload and management endpoints.
4
5use std::future::Future;
6
7use crate::client::PortkeyClient;
8use crate::error::Result;
9use crate::model::{DeleteFileResponse, FileObject, ListFilesResponse, UploadFileRequest};
10
11/// Service trait for file operations.
12pub trait FilesService {
13    /// Upload a file that can be used across various endpoints.
14    ///
15    /// # Arguments
16    ///
17    /// * `request` - The file upload request with file bytes, filename, and purpose
18    ///
19    /// # Example
20    ///
21    /// ```no_run
22    /// # use portkey_sdk::{PortkeyClient, Result};
23    /// # use portkey_sdk::service::FilesService;
24    /// # use portkey_sdk::model::UploadFileRequest;
25    /// # async fn example() -> Result<()> {
26    /// let client = PortkeyClient::from_env()?;
27    ///
28    /// let request = UploadFileRequest {
29    ///     file: vec![/* file bytes */],
30    ///     filename: "training_data.jsonl".to_string(),
31    ///     purpose: "fine-tune".to_string(),
32    /// };
33    ///
34    /// let file = client.upload_file(request).await?;
35    /// println!("Uploaded file: {}", file.id);
36    /// # Ok(())
37    /// # }
38    /// ```
39    fn upload_file(&self, request: UploadFileRequest) -> impl Future<Output = Result<FileObject>>;
40
41    /// Returns a list of files that belong to the user's organization.
42    ///
43    /// # Example
44    ///
45    /// ```no_run
46    /// # use portkey_sdk::{PortkeyClient, Result};
47    /// # use portkey_sdk::service::FilesService;
48    /// # async fn example() -> Result<()> {
49    /// let client = PortkeyClient::from_env()?;
50    ///
51    /// let files = client.list_files().await?;
52    /// println!("Found {} files", files.data.len());
53    /// # Ok(())
54    /// # }
55    /// ```
56    fn list_files(&self) -> impl Future<Output = Result<ListFilesResponse>>;
57
58    /// Returns information about a specific file.
59    ///
60    /// # Arguments
61    ///
62    /// * `file_id` - The ID of the file to retrieve
63    ///
64    /// # Example
65    ///
66    /// ```no_run
67    /// # use portkey_sdk::{PortkeyClient, Result};
68    /// # use portkey_sdk::service::FilesService;
69    /// # async fn example() -> Result<()> {
70    /// let client = PortkeyClient::from_env()?;
71    ///
72    /// let file = client.retrieve_file("file-abc123").await?;
73    /// println!("File: {}", file.filename);
74    /// # Ok(())
75    /// # }
76    /// ```
77    fn retrieve_file(&self, file_id: &str) -> impl Future<Output = Result<FileObject>>;
78
79    /// Returns the contents of the specified file.
80    ///
81    /// # Arguments
82    ///
83    /// * `file_id` - The ID of the file to retrieve content from
84    ///
85    /// # Example
86    ///
87    /// ```no_run
88    /// # use portkey_sdk::{PortkeyClient, Result};
89    /// # use portkey_sdk::service::FilesService;
90    /// # async fn example() -> Result<()> {
91    /// let client = PortkeyClient::from_env()?;
92    ///
93    /// let content = client.retrieve_file_content("file-abc123").await?;
94    /// println!("File size: {} bytes", content.len());
95    /// # Ok(())
96    /// # }
97    /// ```
98    fn retrieve_file_content(&self, file_id: &str) -> impl Future<Output = Result<Vec<u8>>>;
99
100    /// Delete a file.
101    ///
102    /// # Arguments
103    ///
104    /// * `file_id` - The ID of the file to delete
105    ///
106    /// # Example
107    ///
108    /// ```no_run
109    /// # use portkey_sdk::{PortkeyClient, Result};
110    /// # use portkey_sdk::service::FilesService;
111    /// # async fn example() -> Result<()> {
112    /// let client = PortkeyClient::from_env()?;
113    ///
114    /// let response = client.delete_file("file-abc123").await?;
115    /// assert!(response.deleted);
116    /// # Ok(())
117    /// # }
118    /// ```
119    fn delete_file(&self, file_id: &str) -> impl Future<Output = Result<DeleteFileResponse>>;
120}
121
122impl FilesService for PortkeyClient {
123    #[cfg_attr(
124        feature = "tracing",
125        tracing::instrument(skip(self, request), fields(filename = %request.filename, purpose = %request.purpose))
126    )]
127    async fn upload_file(&self, request: UploadFileRequest) -> Result<FileObject> {
128        #[cfg(feature = "tracing")]
129        tracing::debug!(
130            target: crate::TRACING_TARGET_SERVICE,
131            "Uploading file"
132        );
133
134        let part =
135            reqwest::multipart::Part::bytes(request.file).file_name(request.filename.clone());
136
137        let form = reqwest::multipart::Form::new()
138            .part("file", part)
139            .text("purpose", request.purpose);
140
141        let response = self
142            .send_multipart(reqwest::Method::POST, "/files", form)
143            .await?
144            .error_for_status()?
145            .json::<FileObject>()
146            .await?;
147
148        #[cfg(feature = "tracing")]
149        tracing::info!(
150            target: crate::TRACING_TARGET_SERVICE,
151            id = %response.id,
152            filename = %response.filename,
153            "File uploaded successfully"
154        );
155
156        Ok(response)
157    }
158
159    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
160    async fn list_files(&self) -> Result<ListFilesResponse> {
161        #[cfg(feature = "tracing")]
162        tracing::debug!(
163            target: crate::TRACING_TARGET_SERVICE,
164            "Listing files"
165        );
166
167        let response = self
168            .send(reqwest::Method::GET, "/files")
169            .await?
170            .error_for_status()?
171            .json::<ListFilesResponse>()
172            .await?;
173
174        #[cfg(feature = "tracing")]
175        tracing::info!(
176            target: crate::TRACING_TARGET_SERVICE,
177            count = response.data.len(),
178            "Files listed successfully"
179        );
180
181        Ok(response)
182    }
183
184    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), fields(file_id)))]
185    async fn retrieve_file(&self, file_id: &str) -> Result<FileObject> {
186        #[cfg(feature = "tracing")]
187        tracing::debug!(
188            target: crate::TRACING_TARGET_SERVICE,
189            "Retrieving file"
190        );
191
192        let response = self
193            .send(reqwest::Method::GET, &format!("/files/{}", file_id))
194            .await?
195            .error_for_status()?
196            .json::<FileObject>()
197            .await?;
198
199        #[cfg(feature = "tracing")]
200        tracing::info!(
201            target: crate::TRACING_TARGET_SERVICE,
202            id = %response.id,
203            filename = %response.filename,
204            "File retrieved successfully"
205        );
206
207        Ok(response)
208    }
209
210    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), fields(file_id)))]
211    async fn retrieve_file_content(&self, file_id: &str) -> Result<Vec<u8>> {
212        #[cfg(feature = "tracing")]
213        tracing::debug!(
214            target: crate::TRACING_TARGET_SERVICE,
215            "Retrieving file content"
216        );
217
218        let response = self
219            .send(reqwest::Method::GET, &format!("/files/{}/content", file_id))
220            .await?
221            .error_for_status()?
222            .bytes()
223            .await?;
224
225        #[cfg(feature = "tracing")]
226        tracing::info!(
227            target: crate::TRACING_TARGET_SERVICE,
228            size = response.len(),
229            "File content retrieved successfully"
230        );
231
232        Ok(response.to_vec())
233    }
234
235    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), fields(file_id)))]
236    async fn delete_file(&self, file_id: &str) -> Result<DeleteFileResponse> {
237        #[cfg(feature = "tracing")]
238        tracing::debug!(
239            target: crate::TRACING_TARGET_SERVICE,
240            "Deleting file"
241        );
242
243        let response = self
244            .send(reqwest::Method::DELETE, &format!("/files/{}", file_id))
245            .await?
246            .error_for_status()?
247            .json::<DeleteFileResponse>()
248            .await?;
249
250        #[cfg(feature = "tracing")]
251        tracing::info!(
252            target: crate::TRACING_TARGET_SERVICE,
253            id = %response.id,
254            deleted = response.deleted,
255            "File deleted"
256        );
257
258        Ok(response)
259    }
260}