Skip to main content

openai_types/fine_tuning/
manual.rs

1// Hand-crafted fine-tuning types for openai-types.
2// These types mirror the original src/types/fine_tuning.rs but are standalone (no crate:: imports).
3
4use serde::{Deserialize, Serialize};
5
6/// Status of a fine-tuning job.
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
9#[non_exhaustive]
10pub enum FineTuningStatus {
11    #[serde(rename = "validating_files")]
12    ValidatingFiles,
13    #[serde(rename = "queued")]
14    Queued,
15    #[serde(rename = "running")]
16    Running,
17    #[serde(rename = "succeeded")]
18    Succeeded,
19    #[serde(rename = "failed")]
20    Failed,
21    #[serde(rename = "cancelled")]
22    Cancelled,
23}
24
25/// Event severity level.
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
28#[non_exhaustive]
29pub enum FineTuningEventLevel {
30    #[serde(rename = "info")]
31    Info,
32    #[serde(rename = "warn")]
33    Warn,
34    #[serde(rename = "error")]
35    Error,
36}
37
38// -- Request types --
39
40/// Request body for `POST /fine_tuning/jobs`.
41#[derive(Debug, Clone, Serialize)]
42pub struct FineTuningJobCreateRequest {
43    /// Base model to fine-tune.
44    pub model: String,
45
46    /// Training file ID.
47    pub training_file: String,
48
49    /// Hyperparameters for the job.
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub hyperparameters: Option<Hyperparameters>,
52
53    /// Suffix for the fine-tuned model name (max 64 chars).
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub suffix: Option<String>,
56
57    /// Validation file ID.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub validation_file: Option<String>,
60
61    /// Seed for reproducibility.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub seed: Option<i64>,
64}
65
66impl FineTuningJobCreateRequest {
67    pub fn new(model: impl Into<String>, training_file: impl Into<String>) -> Self {
68        Self {
69            model: model.into(),
70            training_file: training_file.into(),
71            hyperparameters: None,
72            suffix: None,
73            validation_file: None,
74            seed: None,
75        }
76    }
77}
78
79/// Hyperparameters for fine-tuning.
80///
81/// Each field accepts either `"auto"` or a numeric value as a string.
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct Hyperparameters {
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub n_epochs: Option<String>,
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub batch_size: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub learning_rate_multiplier: Option<String>,
90}
91
92// -- Response types --
93
94/// Error info for a failed fine-tuning job.
95#[derive(Debug, Clone, Deserialize)]
96pub struct FineTuningError {
97    pub code: String,
98    pub message: String,
99    #[serde(default)]
100    pub param: Option<String>,
101}
102
103/// A fine-tuning job object.
104#[derive(Debug, Clone, Deserialize)]
105pub struct FineTuningJob {
106    pub id: String,
107    pub object: String,
108    pub created_at: i64,
109    pub model: String,
110    pub training_file: String,
111    pub status: FineTuningStatus,
112    #[serde(default)]
113    pub fine_tuned_model: Option<String>,
114    #[serde(default)]
115    pub finished_at: Option<i64>,
116    #[serde(default)]
117    pub error: Option<FineTuningError>,
118    #[serde(default)]
119    pub hyperparameters: Option<Hyperparameters>,
120    pub organization_id: String,
121    #[serde(default)]
122    pub result_files: Vec<String>,
123    #[serde(default)]
124    pub trained_tokens: Option<i64>,
125    #[serde(default)]
126    pub validation_file: Option<String>,
127    #[serde(default)]
128    pub estimated_finish: Option<i64>,
129    pub seed: i64,
130}
131
132/// List of fine-tuning jobs.
133#[derive(Debug, Clone, Deserialize)]
134pub struct FineTuningJobList {
135    pub object: String,
136    pub data: Vec<FineTuningJob>,
137    /// Whether there are more results available.
138    #[serde(default)]
139    pub has_more: Option<bool>,
140}
141
142/// A fine-tuning job event.
143#[derive(Debug, Clone, Deserialize)]
144pub struct FineTuningJobEvent {
145    pub id: String,
146    pub object: String,
147    pub created_at: i64,
148    pub level: FineTuningEventLevel,
149    pub message: String,
150    /// Unstructured event data -- varies by event type (metrics, checkpoints, etc.).
151    /// Kept as `serde_json::Value` because the shape is genuinely dynamic.
152    #[serde(default)]
153    pub data: Option<serde_json::Value>,
154    #[serde(default, rename = "type")]
155    pub type_: Option<String>,
156}
157
158/// List of fine-tuning job events.
159#[derive(Debug, Clone, Deserialize)]
160pub struct FineTuningJobEventList {
161    pub object: String,
162    pub data: Vec<FineTuningJobEvent>,
163    /// Whether there are more results available.
164    #[serde(default)]
165    pub has_more: Option<bool>,
166}
167
168/// Parameters for listing fine-tuning jobs with pagination.
169#[derive(Debug, Clone, Default)]
170pub struct FineTuningJobListParams {
171    /// Cursor for pagination -- fetch results after this job ID.
172    pub after: Option<String>,
173    /// Maximum number of results per page (1-100).
174    pub limit: Option<i64>,
175}
176
177impl FineTuningJobListParams {
178    pub fn new() -> Self {
179        Self::default()
180    }
181
182    pub fn after(mut self, after: impl Into<String>) -> Self {
183        self.after = Some(after.into());
184        self
185    }
186
187    pub fn limit(mut self, limit: i64) -> Self {
188        self.limit = Some(limit);
189        self
190    }
191
192    /// Convert to query parameter pairs for the HTTP request.
193    pub fn to_query(&self) -> Vec<(String, String)> {
194        let mut q = Vec::new();
195        if let Some(ref after) = self.after {
196            q.push(("after".into(), after.clone()));
197        }
198        if let Some(limit) = self.limit {
199            q.push(("limit".into(), limit.to_string()));
200        }
201        q
202    }
203}
204
205/// Parameters for listing fine-tuning job events with pagination.
206#[derive(Debug, Clone, Default)]
207pub struct FineTuningEventListParams {
208    /// Cursor for pagination -- fetch results after this event ID.
209    pub after: Option<String>,
210    /// Maximum number of results per page (1-100).
211    pub limit: Option<i64>,
212}
213
214impl FineTuningEventListParams {
215    pub fn new() -> Self {
216        Self::default()
217    }
218
219    pub fn after(mut self, after: impl Into<String>) -> Self {
220        self.after = Some(after.into());
221        self
222    }
223
224    pub fn limit(mut self, limit: i64) -> Self {
225        self.limit = Some(limit);
226        self
227    }
228
229    /// Convert to query parameter pairs for the HTTP request.
230    pub fn to_query(&self) -> Vec<(String, String)> {
231        let mut q = Vec::new();
232        if let Some(ref after) = self.after {
233            q.push(("after".into(), after.clone()));
234        }
235        if let Some(limit) = self.limit {
236            q.push(("limit".into(), limit.to_string()));
237        }
238        q
239    }
240}