Skip to main content

taskforceai_sdk/
files.rs

1use crate::client::TaskForceAI;
2use crate::error::TaskForceAIError;
3use bytes::Bytes;
4use chrono::{DateTime, Utc};
5use reqwest::multipart::{Form, Part};
6use serde::{Deserialize, Serialize};
7
8/// Represents an uploaded file.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct File {
11    pub id: String,
12    pub filename: String,
13    pub purpose: String,
14    pub bytes: i64,
15    #[serde(with = "chrono::serde::ts_seconds")]
16    pub created_at: DateTime<Utc>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub mime_type: Option<String>,
19}
20
21/// Options for uploading a file.
22#[derive(Debug, Clone, Default)]
23pub struct FileUploadOptions {
24    pub purpose: Option<String>,
25    pub mime_type: Option<String>,
26}
27
28/// Response containing a list of files.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct FileListResponse {
31    pub files: Vec<File>,
32    pub total: i64,
33}
34
35impl TaskForceAI {
36    /// Uploads a file to the API.
37    pub async fn upload_file(
38        &self,
39        filename: &str,
40        content: Bytes,
41        options: Option<FileUploadOptions>,
42    ) -> Result<File, TaskForceAIError> {
43        let mime_type = options
44            .as_ref()
45            .and_then(|o| o.mime_type.clone())
46            .unwrap_or_else(|| "application/octet-stream".to_string());
47
48        let mut form = Form::new().part(
49            "file",
50            Part::bytes(content.to_vec())
51                .file_name(filename.to_string())
52                .mime_str(&mime_type)
53                .map_err(|e| TaskForceAIError::Other(e.to_string()))?,
54        );
55
56        if let Some(opts) = options {
57            if let Some(purpose) = opts.purpose {
58                form = form.text("purpose", purpose);
59            }
60        }
61
62        let url = format!("{}/files", self.base_url);
63        let mut request = self.client.post(&url).multipart(form);
64
65        if !self.api_key.is_empty() {
66            request = request.bearer_auth(&self.api_key);
67        }
68        request = request.header("X-SDK-Language", "rust");
69
70        let response = request.send().await?;
71        let status = response.status();
72
73        if !status.is_success() {
74            let message = response
75                .text()
76                .await
77                .unwrap_or_else(|_| "Failed to read error message".to_string());
78            return Err(TaskForceAIError::Api { status, message });
79        }
80
81        Ok(response.json().await?)
82    }
83
84    /// Retrieves a list of uploaded files.
85    pub async fn list_files(
86        &self,
87        limit: i32,
88        offset: i32,
89    ) -> Result<FileListResponse, TaskForceAIError> {
90        let path = format!("/files?limit={}&offset={}", limit, offset);
91        self.request(reqwest::Method::GET, &path, None).await
92    }
93
94    /// Retrieves metadata for a specific file.
95    pub async fn get_file(&self, file_id: &str) -> Result<File, TaskForceAIError> {
96        let path = format!("/files/{}", file_id);
97        self.request(reqwest::Method::GET, &path, None).await
98    }
99
100    /// Deletes a file by ID.
101    pub async fn delete_file(&self, file_id: &str) -> Result<(), TaskForceAIError> {
102        let path = format!("/files/{}", file_id);
103        let _: serde_json::Value = self.request(reqwest::Method::DELETE, &path, None).await?;
104        Ok(())
105    }
106
107    /// Downloads the content of a file.
108    pub async fn download_file(&self, file_id: &str) -> Result<Bytes, TaskForceAIError> {
109        let url = format!("{}/files/{}/content", self.base_url, file_id);
110        let mut request = self.client.get(&url);
111
112        if !self.api_key.is_empty() {
113            request = request.bearer_auth(&self.api_key);
114        }
115        request = request.header("X-SDK-Language", "rust");
116
117        let response = request.send().await?;
118        let status = response.status();
119
120        if !status.is_success() {
121            let message = response
122                .text()
123                .await
124                .unwrap_or_else(|_| "Failed to read error message".to_string());
125            return Err(TaskForceAIError::Api { status, message });
126        }
127
128        Ok(response.bytes().await?)
129    }
130}