Skip to main content

openai_compat/resources/
uploads.rs

1//! `/uploads` resource, mirroring `resources/uploads/`: create an upload, add
2//! byte parts (multipart), then complete or cancel it.
3
4use reqwest::Method;
5use serde_json::json;
6
7use crate::client::Client;
8use crate::error::OpenAIError;
9use crate::request::{MultipartField, RequestOptions};
10use crate::types::uploads::{Upload, UploadCreateParams, UploadPart};
11
12/// The uploads resource.
13#[derive(Debug, Clone)]
14pub struct Uploads {
15    client: Client,
16}
17
18impl Uploads {
19    pub(crate) fn new(client: Client) -> Self {
20        Self { client }
21    }
22
23    /// Create a resumable upload. Parts are added with [`Uploads::add_part`]
24    /// and finalized with [`Uploads::complete`].
25    pub async fn create(&self, params: UploadCreateParams) -> Result<Upload, OpenAIError> {
26        let body = serde_json::to_value(&params)?;
27        self.client
28            .execute(Method::POST, "/uploads", RequestOptions::json(body))
29            .await
30    }
31
32    /// Add a chunk of bytes to an upload as a multipart `data` field.
33    pub async fn add_part(
34        &self,
35        upload_id: &str,
36        data: Vec<u8>,
37    ) -> Result<UploadPart, OpenAIError> {
38        let fields = vec![MultipartField::File {
39            name: "data".into(),
40            filename: "part".into(),
41            bytes: data,
42            content_type: None,
43        }];
44        self.client
45            .execute(
46                Method::POST,
47                &format!("/uploads/{upload_id}/parts"),
48                RequestOptions::multipart(fields),
49            )
50            .await
51    }
52
53    /// Complete an upload by ordering its parts, optionally verifying the whole
54    /// file against an `md5` checksum.
55    pub async fn complete(
56        &self,
57        upload_id: &str,
58        part_ids: Vec<String>,
59        md5: Option<&str>,
60    ) -> Result<Upload, OpenAIError> {
61        let mut body = json!({ "part_ids": part_ids });
62        if let Some(md5) = md5 {
63            body["md5"] = json!(md5);
64        }
65        self.client
66            .execute(
67                Method::POST,
68                &format!("/uploads/{upload_id}/complete"),
69                RequestOptions::json(body),
70            )
71            .await
72    }
73
74    /// Cancel an upload, invalidating it and its parts.
75    pub async fn cancel(&self, upload_id: &str) -> Result<Upload, OpenAIError> {
76        self.client
77            .execute(
78                Method::POST,
79                &format!("/uploads/{upload_id}/cancel"),
80                RequestOptions::default(),
81            )
82            .await
83    }
84}