openai-interface 0.10.0

A low-level Rust interface for the OpenAI API
Documentation
//! Create a fine-tuning job via `POST /fine_tuning/jobs`.
//!
//! > ![warn] This module is untested!
//! > If you encounter any issues, please report them on the repository.

use serde::Serialize;
use url::Url;

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

/// The method used for fine-tuning.
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum FineTuneMethod {
    /// Supervised fine-tuning.
    Supervised {
        /// The hyperparameters of the supervised run, as raw JSON (each
        /// field a number or `"auto"`).
        #[serde(skip_serializing_if = "Option::is_none")]
        hyperparameters: Option<serde_json::Value>,
    },
    /// Direct preference optimization.
    Dpo {
        /// The hyperparameters of the DPO run, as raw JSON (each field
        /// a number or `"auto"`).
        #[serde(skip_serializing_if = "Option::is_none")]
        hyperparameters: Option<serde_json::Value>,
    },
    /// Reinforcement learning with verifiable rewards.
    Reinforcement {
        /// The reinforcement learning configuration, as raw JSON
        /// (`grader`, `hyperparameters`, ...).
        #[serde(skip_serializing_if = "Option::is_none")]
        grader: Option<serde_json::Value>,
        #[serde(skip_serializing_if = "Option::is_none")]
        hyperparameters: Option<serde_json::Value>,
    },
}

/// An integration hook for a fine-tuning job (e.g. Weights & Biases),
/// as defined by the official API.
#[derive(Debug, Clone, Serialize)]
pub struct FineTuneIntegration {
    /// The integration type, e.g. `wandb`.
    #[serde(rename = "type")]
    pub kind: String,
    /// Whether the integration is enabled.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub enabled: Option<bool>,
    /// The integration-specific settings, as raw JSON.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub settings: Option<serde_json::Value>,
    /// The project metadata of the integration, as raw JSON.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// The body of `POST /fine_tuning/jobs`.
#[derive(Debug, Clone, Serialize)]
pub struct CreateFineTuningJobRequest {
    /// The base model to fine-tune.
    pub model: String,
    /// The ID of the uploaded JSONL training file.
    pub training_file: String,
    /// The ID of the uploaded JSONL validation file.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validation_file: Option<String>,
    /// The hyperparameters of the job, as raw JSON (each field a
    /// number or `"auto"`).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hyperparameters: Option<serde_json::Value>,
    /// A suffix of up to 18 characters appended to the fine-tuned
    /// model name.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub suffix: Option<String>,
    /// The integration hooks for the job.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub integrations: Option<Vec<FineTuneIntegration>>,
    /// The seed controlling the reproducibility of the job.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub seed: Option<u64>,
    /// The fine-tuning method to use.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub method: Option<FineTuneMethod>,
    /// Arbitrary key-value metadata (up to 16 pairs) attached to the
    /// job.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<std::collections::HashMap<String, String>>,
    /// Additional JSON properties flattened into the request body, for
    /// fields not covered by the typed struct.
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub extra_body: Option<serde_json::Map<String, serde_json::Value>>,
}

impl Post for CreateFineTuningJobRequest {
    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("fine_tuning")
            .push("jobs");
        Ok(url.to_string())
    }
}

impl PostNoStream for CreateFineTuningJobRequest {
    type Response = FineTuningJob;
}