openai-interface 0.14.0

A low-level Rust interface for the OpenAI API
Documentation
//! The Uploads API: upload large files in multiple parts via `/uploads`.
//!
//! > ![warn] This module is untested!
//! > If you encounter any issues, please report them on the repository.
//!
//! The Uploads API lets you upload large files (up to 8 GB per part
//! upload) in multiple parts, which is more resilient to network
//! interruptions than a single multipart request through
//! [`files::create`](crate::files::create). The workflow is:
//!
//! 1. `create` — start an upload, declaring the total byte size.
//! 2. `parts` — upload each chunk (up to 64 MB per part, except the
//!    last).
//! 3. `complete` — finalize the upload with the ordered part IDs,
//!    yielding a [`FileObject`](crate::files::FileObject).
//!
//! A started-but-incomplete upload can be discarded via [`cancel`].
//!
//! See [the OpenAI Uploads API reference](https://platform.openai.com/docs/api-reference/uploads).

pub mod cancel;
pub mod complete;
pub mod parts;

use serde::{Deserialize, Serialize};
use url::Url;

use crate::{
    errors::OapiError,
    rest::post::{Post, PostNoStream},
};

/// The status of an upload.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UploadStatus {
    /// The upload is in progress; parts can still be added.
    Pending,
    /// The upload was completed and its file is ready.
    Completed,
    /// The upload was cancelled.
    Cancelled,
}

/// A single uploaded part of a multi-part upload.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct UploadPart {
    /// The part ID, e.g. `part_...`.
    pub id: String,
    /// Unix timestamp (seconds) of when the part was created.
    #[serde(default)]
    pub created_at: Option<u64>,
    /// The ID of the upload this part belongs to.
    #[serde(default)]
    pub upload_id: Option<String>,
    /// The object type, always `upload.part`.
    #[serde(default)]
    pub object: Option<String>,
}

crate::impl_from_str!(UploadPart);

/// An upload session.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Upload {
    /// The upload ID, e.g. `upload_...`.
    pub id: String,
    /// Unix timestamp (seconds) of when the upload was created.
    #[serde(default)]
    pub created_at: Option<u64>,
    /// The name of the file being uploaded.
    pub filename: String,
    /// The intended purpose of the uploaded file, e.g. `batch`.
    pub purpose: String,
    /// The size of the file being uploaded, in bytes.
    pub bytes: u64,
    /// The current status.
    pub status: UploadStatus,
    /// The ready [`FileObject`](crate::files::FileObject) ID once the
    /// upload is completed.
    #[serde(default)]
    pub file_id: Option<String>,
    /// Unix timestamp (seconds) of when the upload expires.
    #[serde(default)]
    pub expires_at: Option<u64>,
    /// The object type, always `upload`.
    #[serde(default)]
    pub object: Option<String>,
}

crate::impl_from_str!(Upload);

/// Starts an upload session via `POST /uploads`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateUploadRequest {
    /// The name of the file to upload.
    pub filename: String,
    /// The intended purpose of the uploaded file. One of `assistants`,
    /// `batch`, `fine-tune`, `vision`, or `user_data`.
    pub purpose: String,
    /// The number of bytes in the file to be uploaded.
    pub bytes: u64,
    /// The MIME type of the file to be uploaded.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mime_type: Option<String>,
    /// Additional JSON properties flattened into the request body, for
    /// fields not covered by the typed struct.
    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
    pub extra_body_map: Option<serde_json::Map<String, serde_json::Value>>,
}

impl Post for CreateUploadRequest {
    fn is_streaming(&self) -> bool {
        false
    }

    /// Builds the URL for the request.
    ///
    /// `base_url` should be like <https://api.openai.com/v1>
    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
        let mut url = Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
        url.path_segments_mut()
            .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
            .push("uploads");
        Ok(url.to_string())
    }
}

impl PostNoStream for CreateUploadRequest {
    type Response = Upload;
}