/*
* OpenAI API
*
* The OpenAI REST API. Please see https://platform.openai.com/docs/api-reference for more details.
*
* The version of the OpenAPI document: 2.3.0
*
* Generated by: https://openapi-generator.tech
*/
#![allow(clippy::needless_return, clippy::into_iter_on_ref)]
use super::{configuration, multipart_helper, ContentType, Error};
use crate::{apis::ResponseContent, models};
use reqwest;
use serde::{de::Error as _, Deserialize, Serialize};
use tokio::fs::File as TokioFile;
use tokio_util::codec::{BytesCodec, FramedRead};
/// struct for typed errors of method [`create_file`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateFileError {
Status400(models::ErrorResponse),
Status429(models::ErrorResponse),
Status500(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`delete_file`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DeleteFileError {
Status404(models::ErrorResponse),
Status429(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`download_file`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DownloadFileError {
Status400(models::ErrorResponse),
Status404(models::ErrorResponse),
Status429(models::ErrorResponse),
Status500(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`list_files`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ListFilesError {
Status400(models::ErrorResponse),
Status404(models::ErrorResponse),
Status429(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`retrieve_file`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RetrieveFileError {
Status404(models::ErrorResponse),
Status429(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// Upload a file that can be used across various endpoints. Individual files can be up to 512 MB, and each project can store up to 2.5 TB of files in total. There is no organization-wide storage limit. Uploads to this endpoint are rate-limited to 1,000 requests per minute per authenticated user. - The Assistants API supports files up to 2 million tokens and of specific file types. See the [Assistants Tools guide](https://developers.openai.com/api/docs/guides/tools) for details. - The Fine-tuning API only supports `.jsonl` files. The input also has certain required formats for fine-tuning [chat](https://developers.openai.com/api/docs/guides/supervised-fine-tuning#formatting-your-data) or [completions](https://developers.openai.com/api/docs/guides/supervised-fine-tuning#formatting-your-data) models. - The Batch API only supports `.jsonl` files up to 200 MB in size. The input also has a specific required [format](https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file). - For Retrieval or `file_search` ingestion, upload files here first. If you need to attach multiple uploaded files to the same vector store, use [`/vector_stores/{vector_store_id}/file_batches`](https://developers.openai.com/api/reference/resources/vector_stores/subresources/file_batches/methods/create) instead of attaching them one by one. Vector store attachment has separate limits from file upload, including 2,000 attached files per minute per organization. Please [contact us](https://help.openai.com/) if you need to increase these storage limits.
#[bon::builder]
pub async fn create_file(
configuration: &configuration::Configuration,
file: std::path::PathBuf,
purpose: &str,
expires_after: Option<models::FileExpirationAfter>,
) -> Result<models::OpenAiFile, Error<CreateFileError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_form_file = file;
let p_form_purpose = purpose;
let p_form_expires_after = expires_after;
let uri_str = format!("{}/files", configuration.base_path);
let mut req_builder = configuration
.client
.request(reqwest::Method::POST, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let mut multipart_form = reqwest::multipart::Form::new();
// Add file to multipart form
multipart_form = multipart_helper::add_file_to_form(multipart_form, &p_form_file, "file")?;
multipart_form = multipart_form.text("purpose", p_form_purpose.to_string());
if let Some(param_value) = p_form_expires_after {
multipart_form = multipart_helper::add_schema_value_to_form(
multipart_form,
"expires_after",
serde_json::to_value(param_value)?,
None,
)?;
}
req_builder = req_builder.multipart(multipart_form);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::OpenAiFile`"))),
ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::OpenAiFile`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<CreateFileError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(Box::new(ResponseContent {
status,
content,
entity,
})))
}
}
/// Delete a file and remove it from all vector stores.
#[bon::builder]
pub async fn delete_file(
configuration: &configuration::Configuration,
file_id: &str,
) -> Result<models::DeleteFileResponse, Error<DeleteFileError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_file_id = file_id;
let uri_str = format!(
"{}/files/{file_id}",
configuration.base_path,
file_id = crate::apis::urlencode(p_path_file_id)
);
let mut req_builder = configuration
.client
.request(reqwest::Method::DELETE, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DeleteFileResponse`"))),
ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::DeleteFileResponse`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<DeleteFileError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(Box::new(ResponseContent {
status,
content,
entity,
})))
}
}
/// Returns a response containing the contents of the specified file.
#[bon::builder]
pub async fn download_file(
configuration: &configuration::Configuration,
file_id: &str,
) -> Result<reqwest::Response, Error<DownloadFileError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_file_id = file_id;
let uri_str = format!(
"{}/files/{file_id}/content",
configuration.base_path,
file_id = crate::apis::urlencode(p_path_file_id)
);
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
if !status.is_client_error() && !status.is_server_error() {
Ok(resp)
} else {
let content = resp.text().await?;
let entity: Option<DownloadFileError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(Box::new(ResponseContent {
status,
content,
entity,
})))
}
}
/// Returns a list of files.
#[bon::builder]
pub async fn list_files(
configuration: &configuration::Configuration,
purpose: Option<&str>,
limit: Option<i32>,
order: Option<&str>,
after: Option<&str>,
) -> Result<models::ListFilesResponse, Error<ListFilesError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_query_purpose = purpose;
let p_query_limit = limit;
let p_query_order = order;
let p_query_after = after;
let uri_str = format!("{}/files", configuration.base_path);
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
if let Some(ref param_value) = p_query_purpose {
req_builder = req_builder.query(&[("purpose", ¶m_value.to_string())]);
}
if let Some(ref param_value) = p_query_limit {
req_builder = req_builder.query(&[("limit", ¶m_value.to_string())]);
}
if let Some(ref param_value) = p_query_order {
req_builder = req_builder.query(&[("order", ¶m_value.to_string())]);
}
if let Some(ref param_value) = p_query_after {
req_builder = req_builder.query(&[("after", ¶m_value.to_string())]);
}
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListFilesResponse`"))),
ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ListFilesResponse`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<ListFilesError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(Box::new(ResponseContent {
status,
content,
entity,
})))
}
}
/// Returns information about a specific file.
#[bon::builder]
pub async fn retrieve_file(
configuration: &configuration::Configuration,
file_id: &str,
) -> Result<models::OpenAiFile, Error<RetrieveFileError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_file_id = file_id;
let uri_str = format!(
"{}/files/{file_id}",
configuration.base_path,
file_id = crate::apis::urlencode(p_path_file_id)
);
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::OpenAiFile`"))),
ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::OpenAiFile`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<RetrieveFileError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(Box::new(ResponseContent {
status,
content,
entity,
})))
}
}