Skip to main content

openai_interface/fine_tuning/jobs/
create.rs

1//! Create a fine-tuning job via `POST /fine_tuning/jobs`.
2//!
3//! > ![warn] This module is untested!
4//! > If you encounter any issues, please report them on the repository.
5
6use serde::{Deserialize, Serialize};
7use url::Url;
8
9use crate::{
10    errors::OapiError,
11    fine_tuning::FineTuningJob,
12    rest::post::{Post, PostNoStream},
13};
14
15/// The method used for fine-tuning.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(tag = "type", rename_all = "snake_case")]
18pub enum FineTuneMethod {
19    /// Supervised fine-tuning.
20    Supervised {
21        /// The hyperparameters of the supervised run, as raw JSON (each
22        /// field a number or `"auto"`).
23        #[serde(skip_serializing_if = "Option::is_none")]
24        hyperparameters: Option<serde_json::Value>,
25    },
26    /// Direct preference optimization.
27    Dpo {
28        /// The hyperparameters of the DPO run, as raw JSON (each field
29        /// a number or `"auto"`).
30        #[serde(skip_serializing_if = "Option::is_none")]
31        hyperparameters: Option<serde_json::Value>,
32    },
33    /// Reinforcement learning with verifiable rewards.
34    Reinforcement {
35        /// The reinforcement learning configuration, as raw JSON
36        /// (`grader`, `hyperparameters`, ...).
37        #[serde(skip_serializing_if = "Option::is_none")]
38        grader: Option<serde_json::Value>,
39        #[serde(skip_serializing_if = "Option::is_none")]
40        hyperparameters: Option<serde_json::Value>,
41    },
42}
43
44/// An integration hook for a fine-tuning job (e.g. Weights & Biases),
45/// as defined by the official API.
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct FineTuneIntegration {
48    /// The integration type, e.g. `wandb`.
49    #[serde(rename = "type")]
50    pub kind: String,
51    /// Whether the integration is enabled.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub enabled: Option<bool>,
54    /// The integration-specific settings, as raw JSON.
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub settings: Option<serde_json::Value>,
57    /// The project metadata of the integration, as raw JSON.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub metadata: Option<serde_json::Value>,
60}
61
62/// The body of `POST /fine_tuning/jobs`.
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct CreateFineTuningJobRequest {
65    /// The base model to fine-tune.
66    pub model: String,
67    /// The ID of the uploaded JSONL training file.
68    pub training_file: String,
69    /// The ID of the uploaded JSONL validation file.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub validation_file: Option<String>,
72    /// The hyperparameters of the job, as raw JSON (each field a
73    /// number or `"auto"`).
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub hyperparameters: Option<serde_json::Value>,
76    /// A suffix of up to 18 characters appended to the fine-tuned
77    /// model name.
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub suffix: Option<String>,
80    /// The integration hooks for the job.
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub integrations: Option<Vec<FineTuneIntegration>>,
83    /// The seed controlling the reproducibility of the job.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub seed: Option<u64>,
86    /// The fine-tuning method to use.
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub method: Option<FineTuneMethod>,
89    /// Arbitrary key-value metadata (up to 16 pairs) attached to the
90    /// job.
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub metadata: Option<std::collections::HashMap<String, String>>,
93    /// Additional JSON properties flattened into the request body, for
94    /// fields not covered by the typed struct.
95    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
96    pub extra_body_map: Option<serde_json::Map<String, serde_json::Value>>,
97}
98
99impl Post for CreateFineTuningJobRequest {
100    fn is_streaming(&self) -> bool {
101        false
102    }
103
104    /// Builds the URL for the request.
105    ///
106    /// `base_url` should be like <https://api.openai.com/v1>
107    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
108        let mut url = Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
109        url.path_segments_mut()
110            .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
111            .push("fine_tuning")
112            .push("jobs");
113        Ok(url.to_string())
114    }
115}
116
117impl PostNoStream for CreateFineTuningJobRequest {
118    type Response = FineTuningJob;
119}