fine_tuning/fine_tuning.rs
1//! Comprehensive fine-tuning example demonstrating model customization with OpenAI.
2//!
3//! This example showcases the OpenAI Fine-tuning API, including:
4//! - Creating fine-tuning jobs with training data
5//! - Listing fine-tuning jobs with pagination
6//! - Retrieving job status and monitoring progress
7//! - Listing events for jobs to track training progress
8//! - Listing checkpoints for jobs
9//! - Cancelling running jobs
10//!
11//! ## Features Demonstrated
12//!
13//! - **Job Creation**: Create fine-tuning jobs with various configurations
14//! - **Job Listing**: List all fine-tuning jobs with filtering
15//! - **Job Monitoring**: Track job progress and view events
16//! - **Checkpoint Management**: View and manage training checkpoints
17//! - **Job Cancellation**: Cancel running jobs when needed
18//! - **Error Handling**: Robust error handling for various scenarios
19//!
20//! ## Prerequisites
21//!
22//! Set your OpenAI API key:
23//! ```bash
24//! export OPENAI_API_KEY="your-key-here"
25//! ```
26//!
27//! ## Usage
28//!
29//! ```bash
30//! cargo run --example fine_tuning
31//! ```
32//!
33//! Note: This example demonstrates the API structure. Fine-tuning requires
34//! properly formatted training data files uploaded to OpenAI.
35
36#![allow(clippy::uninlined_format_args)]
37#![allow(clippy::no_effect_underscore_binding)]
38#![allow(clippy::doc_markdown)]
39#![allow(clippy::cast_possible_wrap)]
40#![allow(clippy::too_many_lines)]
41#![allow(clippy::missing_docs_in_private_items)]
42#![allow(clippy::cast_possible_truncation)]
43#![allow(clippy::cast_lossless)]
44#![allow(unused_variables)]
45#![allow(missing_docs)]
46#![allow(dead_code)]
47
48use openai_ergonomic::{builders::fine_tuning::FineTuningJobBuilder, Client};
49
50/// Fine-tuning job metadata for demonstration
51#[derive(Debug, Clone)]
52pub struct JobInfo {
53 pub id: String,
54 pub model: String,
55 pub status: String,
56 pub training_file: String,
57 pub created_at: i64,
58}
59
60impl JobInfo {
61 pub fn new(
62 id: impl Into<String>,
63 model: impl Into<String>,
64 status: impl Into<String>,
65 training_file: impl Into<String>,
66 ) -> Self {
67 Self {
68 id: id.into(),
69 model: model.into(),
70 status: status.into(),
71 training_file: training_file.into(),
72 created_at: std::time::SystemTime::now()
73 .duration_since(std::time::UNIX_EPOCH)
74 .unwrap()
75 .as_secs() as i64,
76 }
77 }
78
79 pub fn display(&self) {
80 println!(" ID: {}", self.id);
81 println!(" Model: {}", self.model);
82 println!(" Status: {}", self.status);
83 println!(" Training File: {}", self.training_file);
84 println!(" Created At: {}", self.created_at);
85 }
86}
87
88#[tokio::main]
89async fn main() -> Result<(), Box<dyn std::error::Error>> {
90 println!(" OpenAI Ergonomic - Comprehensive Fine-tuning Example\n");
91
92 // Initialize client from environment variables
93 println!(" Initializing OpenAI client...");
94 let client = match Client::from_env() {
95 Ok(c) => {
96 println!(" Client initialized successfully\n");
97 c.build()
98 }
99 Err(e) => {
100 eprintln!(" Failed to initialize client: {}", e);
101 eprintln!(" Make sure OPENAI_API_KEY is set");
102 return Ok(());
103 }
104 };
105
106 // Example 1: Create a fine-tuning job
107 println!();
108 println!(" Example 1: Create Fine-tuning Job");
109 println!("\n");
110
111 // Note: You need to upload a training file first
112 // For demonstration purposes, we'll use a placeholder file ID
113 let training_file_id = "file-training-data";
114
115 println!("Creating fine-tuning job...");
116 println!(" Base Model: gpt-3.5-turbo");
117 println!(" Training File: {}", training_file_id);
118 println!(" Suffix: my-custom-model");
119
120 let builder = FineTuningJobBuilder::new("gpt-3.5-turbo", training_file_id)
121 .suffix("my-custom-model")
122 .epochs(3);
123
124 println!("\n Note: This would create a real fine-tuning job with your API key.");
125 println!(" Commented out to avoid accidental charges.\n");
126
127 // Uncomment to actually create the job:
128 // match client.fine_tuning().create_job(builder).await {
129 // Ok(job) => {
130 // println!(" Fine-tuning job created successfully!");
131 // println!(" Job ID: {}", job.id);
132 // println!(" Status: {}", job.status);
133 // println!(" Model: {}", job.model);
134 // }
135 // Err(e) => {
136 // eprintln!(" Failed to create fine-tuning job: {}", e);
137 // }
138 // }
139
140 // Simulate job creation for demonstration
141 let demo_job = JobInfo::new(
142 "ftjob-demo123",
143 "gpt-3.5-turbo",
144 "validating",
145 training_file_id,
146 );
147 println!(" Demo Job Created:");
148 demo_job.display();
149
150 // Example 2: List fine-tuning jobs
151 println!("\n");
152 println!(" Example 2: List Fine-tuning Jobs");
153 println!("\n");
154
155 println!("Listing fine-tuning jobs (limit: 5)...\n");
156
157 // Uncomment to actually list jobs:
158 // match client.fine_tuning().list_jobs(None, Some(5)).await {
159 // Ok(response) => {
160 // println!(" Found {} fine-tuning jobs", response.data.len());
161 // for (i, job) in response.data.iter().enumerate() {
162 // println!("\n Job {}:", i + 1);
163 // println!(" ID: {}", job.id);
164 // println!(" Model: {}", job.model);
165 // println!(" Status: {}", job.status);
166 // println!(" Created At: {}", job.created_at);
167 // }
168 // }
169 // Err(e) => {
170 // eprintln!(" Failed to list fine-tuning jobs: {}", e);
171 // }
172 // }
173
174 println!(" Demo: Would list your fine-tuning jobs here");
175
176 // Example 3: Get specific fine-tuning job
177 println!("\n");
178 println!(" Example 3: Get Fine-tuning Job Details");
179 println!("\n");
180
181 let job_id = "ftjob-demo123";
182 println!("Retrieving job: {}\n", job_id);
183
184 // Uncomment to actually get job:
185 // match client.fine_tuning().get_job(job_id).await {
186 // Ok(job) => {
187 // println!(" Job retrieved successfully!");
188 // println!(" ID: {}", job.id);
189 // println!(" Model: {}", job.model);
190 // println!(" Status: {}", job.status);
191 // println!(" Created At: {}", job.created_at);
192 // if let Some(finished_at) = job.finished_at {
193 // println!(" Finished At: {}", finished_at);
194 // }
195 // }
196 // Err(e) => {
197 // eprintln!(" Failed to get fine-tuning job: {}", e);
198 // }
199 // }
200
201 println!(" Demo: Would show detailed job information");
202
203 // Example 4: List job events
204 println!("\n");
205 println!(" Example 4: List Fine-tuning Job Events");
206 println!("\n");
207
208 println!("Listing events for job: {}\n", job_id);
209
210 // Uncomment to actually list events:
211 // match client.fine_tuning().list_events(job_id, None, Some(10)).await {
212 // Ok(response) => {
213 // println!(" Found {} events", response.data.len());
214 // for (i, event) in response.data.iter().enumerate() {
215 // println!("\n Event {}:", i + 1);
216 // println!(" Message: {}", event.message);
217 // println!(" Created At: {}", event.created_at);
218 // if let Some(level) = &event.level {
219 // println!(" Level: {}", level);
220 // }
221 // }
222 // }
223 // Err(e) => {
224 // eprintln!(" Failed to list events: {}", e);
225 // }
226 // }
227
228 println!(" Demo: Would show training events like:");
229 println!(" - Job started");
230 println!(" - Training step 1/100 complete");
231 println!(" - Validation loss: 0.452");
232 println!(" - Training complete");
233
234 // Example 5: List job checkpoints
235 println!("\n");
236 println!(" Example 5: List Fine-tuning Job Checkpoints");
237 println!("\n");
238
239 println!("Listing checkpoints for job: {}\n", job_id);
240
241 // Uncomment to actually list checkpoints:
242 // match client.fine_tuning().list_checkpoints(job_id, None, Some(5)).await {
243 // Ok(response) => {
244 // println!(" Found {} checkpoints", response.data.len());
245 // for (i, checkpoint) in response.data.iter().enumerate() {
246 // println!("\n Checkpoint {}:", i + 1);
247 // println!(" ID: {}", checkpoint.id);
248 // println!(" Created At: {}", checkpoint.created_at);
249 // println!(" Step Number: {}", checkpoint.step_number);
250 // }
251 // }
252 // Err(e) => {
253 // eprintln!(" Failed to list checkpoints: {}", e);
254 // }
255 // }
256
257 println!(" Demo: Would show model checkpoints from training");
258
259 // Example 6: Cancel fine-tuning job
260 println!("\n");
261 println!(" Example 6: Cancel Fine-tuning Job");
262 println!("\n");
263
264 println!("Cancelling job: {}\n", job_id);
265
266 // Uncomment to actually cancel job:
267 // match client.fine_tuning().cancel_job(job_id).await {
268 // Ok(job) => {
269 // println!(" Job cancelled successfully!");
270 // println!(" Job ID: {}", job.id);
271 // println!(" Status: {}", job.status);
272 // }
273 // Err(e) => {
274 // eprintln!(" Failed to cancel job: {}", e);
275 // }
276 // }
277
278 println!(" Demo: Would cancel the running fine-tuning job");
279
280 // Example 7: Create job with validation file
281 println!("\n");
282 println!(" Example 7: Create Job with Validation File");
283 println!("\n");
284
285 let validation_file_id = "file-validation-data";
286
287 println!("Creating fine-tuning job with validation...");
288 println!(" Base Model: gpt-3.5-turbo");
289 println!(" Training File: {}", training_file_id);
290 println!(" Validation File: {}", validation_file_id);
291 println!(" Epochs: 5");
292 println!(" Learning Rate Multiplier: 0.1");
293
294 let builder_with_validation = FineTuningJobBuilder::new("gpt-3.5-turbo", training_file_id)
295 .validation_file(validation_file_id)
296 .epochs(5)
297 .learning_rate_multiplier(0.1);
298
299 println!("\n Note: Validation files help monitor overfitting during training");
300
301 // Example 8: Create job with Weights & Biases integration
302 println!("\n");
303 println!(" Example 8: Create Job with W&B Integration");
304 println!("\n");
305
306 println!("Creating fine-tuning job with W&B...");
307 println!(" Base Model: gpt-3.5-turbo");
308 println!(" Training File: {}", training_file_id);
309 println!(" W&B Project: my-finetuning-project");
310
311 let builder_with_wandb = FineTuningJobBuilder::new("gpt-3.5-turbo", training_file_id)
312 .with_wandb("my-finetuning-project");
313
314 println!("\n Note: W&B integration provides detailed training metrics visualization");
315
316 // Summary
317 println!("\n");
318 println!(" Summary");
319 println!("\n");
320
321 println!(" Fine-tuning API examples completed!");
322 println!("\n Key Takeaways:");
323 println!(" • Fine-tuning allows customizing models for specific tasks");
324 println!(" • Jobs can be created with various hyperparameters");
325 println!(" • Progress can be monitored through events and checkpoints");
326 println!(" • Validation files help prevent overfitting");
327 println!(" • Integrations like W&B provide detailed metrics");
328 println!(" • Jobs can be cancelled if needed");
329
330 println!("\n Next Steps:");
331 println!(" 1. Prepare your training data in JSONL format");
332 println!(" 2. Upload training data using the Files API");
333 println!(" 3. Create a fine-tuning job with appropriate parameters");
334 println!(" 4. Monitor progress through events");
335 println!(" 5. Use the fine-tuned model in your applications");
336
337 println!("\n Example completed successfully!");
338
339 Ok(())
340}