1#![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::cast_precision_loss)]
41#![allow(clippy::unused_async)]
42#![allow(clippy::useless_vec)]
43#![allow(dead_code)]
44
45use openai_ergonomic::Client;
46
47#[derive(Debug, Clone)]
49pub struct FileMetadata {
50 pub id: String,
52 pub filename: String,
54 pub bytes: usize,
56 pub purpose: String,
58 pub created_at: i64,
60}
61
62impl FileMetadata {
63 pub fn new(
65 id: impl Into<String>,
66 filename: impl Into<String>,
67 bytes: usize,
68 purpose: impl Into<String>,
69 ) -> Self {
70 Self {
71 id: id.into(),
72 filename: filename.into(),
73 bytes,
74 purpose: purpose.into(),
75 created_at: std::time::SystemTime::now()
76 .duration_since(std::time::UNIX_EPOCH)
77 .unwrap()
78 .as_secs() as i64,
79 }
80 }
81
82 pub fn formatted_size(&self) -> String {
84 if self.bytes < 1024 {
85 format!("{} B", self.bytes)
86 } else if self.bytes < 1024 * 1024 {
87 format!("{:.2} KB", self.bytes as f64 / 1024.0)
88 } else if self.bytes < 1024 * 1024 * 1024 {
89 format!("{:.2} MB", self.bytes as f64 / (1024.0 * 1024.0))
90 } else {
91 format!("{:.2} GB", self.bytes as f64 / (1024.0 * 1024.0 * 1024.0))
92 }
93 }
94
95 pub fn formatted_created_at(&self) -> String {
97 format!("Unix timestamp: {}", self.created_at)
98 }
99}
100
101#[tokio::main]
102async fn main() -> Result<(), Box<dyn std::error::Error>> {
103 println!(" OpenAI Ergonomic - Comprehensive Files Example\n");
104
105 let client = match Client::from_env() {
107 Ok(client_builder) => {
108 println!(" Client initialized successfully");
109 client_builder.build()
110 }
111 Err(e) => {
112 eprintln!(" Failed to initialize client: {e}");
113 eprintln!(" Make sure OPENAI_API_KEY is set in your environment");
114 return Err(e.into());
115 }
116 };
117
118 println!("\n Example 1: Upload Text File");
120 println!("================================");
121
122 match upload_text_file_example(&client).await {
123 Ok(file_id) => {
124 println!(" Text file uploaded successfully: {}", file_id);
125 }
126 Err(e) => {
127 eprintln!(" Text file upload failed: {e}");
128 handle_file_error(e.as_ref());
129 }
130 }
131
132 println!("\n Example 2: Upload JSON File");
134 println!("================================");
135
136 match upload_json_file_example(&client).await {
137 Ok(file_id) => {
138 println!(" JSON file uploaded successfully: {}", file_id);
139 }
140 Err(e) => {
141 eprintln!(" JSON file upload failed: {e}");
142 handle_file_error(e.as_ref());
143 }
144 }
145
146 println!("\n Example 3: List Files");
148 println!("=========================");
149
150 match list_files_example(&client).await {
151 Ok(count) => {
152 println!(" Listed {} files successfully", count);
153 }
154 Err(e) => {
155 eprintln!(" List files failed: {e}");
156 handle_file_error(e.as_ref());
157 }
158 }
159
160 println!("\n Example 4: Retrieve File Metadata");
162 println!("======================================");
163
164 match retrieve_file_example(&client).await {
165 Ok(()) => {
166 println!(" File metadata retrieved successfully");
167 }
168 Err(e) => {
169 eprintln!(" Retrieve file failed: {e}");
170 handle_file_error(e.as_ref());
171 }
172 }
173
174 println!("\n Example 5: Download File Content");
176 println!("======================================");
177
178 match download_file_example(&client).await {
179 Ok(size) => {
180 println!(" Downloaded {} bytes successfully", size);
181 }
182 Err(e) => {
183 eprintln!(" Download file failed: {e}");
184 handle_file_error(e.as_ref());
185 }
186 }
187
188 println!("\n Example 6: Delete File");
190 println!("===========================");
191
192 match delete_file_example(&client).await {
193 Ok(()) => {
194 println!(" File deleted successfully");
195 }
196 Err(e) => {
197 eprintln!(" Delete file failed: {e}");
198 handle_file_error(e.as_ref());
199 }
200 }
201
202 println!("\n Example 7: File Management Workflow");
204 println!("========================================");
205
206 match file_workflow_example(&client).await {
207 Ok(()) => {
208 println!(" File workflow completed successfully");
209 }
210 Err(e) => {
211 eprintln!(" File workflow failed: {e}");
212 handle_file_error(e.as_ref());
213 }
214 }
215
216 println!("\n All examples completed! Check the console output above for results.");
217 println!("\nNote: This example simulates API responses. Replace the simulated sections with");
218 println!("real client.files() calls when you're ready to interact with the API.");
219
220 Ok(())
221}
222
223async fn upload_text_file_example(_client: &Client) -> Result<String, Box<dyn std::error::Error>> {
225 println!("Uploading a text file for assistants...");
226
227 let content = "This is a sample document for the assistants API.\n\
229 It contains information that can be searched and referenced.\n\
230 The file format is plain text for simplicity.";
231
232 println!(" Filename: document.txt");
233 println!(" Size: {} bytes", content.len());
234 println!(" Purpose: assistants");
235
236 let file_id = "file-abc123";
246 println!(" Upload initiated...");
247 println!(" File uploaded successfully");
248 println!(" File ID: {}", file_id);
249 println!(" Status: processed");
250
251 Ok(file_id.to_string())
252}
253
254async fn upload_json_file_example(_client: &Client) -> Result<String, Box<dyn std::error::Error>> {
256 println!("Uploading a JSON file for batch processing...");
257
258 let batch_data = serde_json::json!({
260 "custom_id": "request-1",
261 "method": "POST",
262 "url": "/v1/chat/completions",
263 "body": {
264 "model": "gpt-4",
265 "messages": [
266 {"role": "system", "content": "You are a helpful assistant."},
267 {"role": "user", "content": "Hello!"}
268 ]
269 }
270 });
271
272 let content = serde_json::to_string_pretty(&batch_data)?;
273
274 println!(" Filename: batch_request.jsonl");
275 println!(" Size: {} bytes", content.len());
276 println!(" Purpose: batch");
277 println!(" Content preview:");
278 println!("{}", content);
279
280 let file_id = "file-batch456";
291 println!("\n Upload initiated...");
292 println!(" File uploaded successfully");
293 println!(" File ID: {}", file_id);
294 println!(" Status: processed");
295
296 Ok(file_id.to_string())
297}
298
299async fn list_files_example(_client: &Client) -> Result<usize, Box<dyn std::error::Error>> {
301 println!("Listing files with filtering...");
302
303 let simulated_files = vec![
318 FileMetadata::new("file-abc123", "document.txt", 1024, "assistants"),
319 FileMetadata::new("file-def456", "training.jsonl", 2048, "fine-tune"),
320 FileMetadata::new("file-ghi789", "batch_request.jsonl", 512, "batch"),
321 ];
322
323 println!("\n Listing all files:");
324 println!(" Found {} files", simulated_files.len());
325
326 for (i, file) in simulated_files.iter().enumerate() {
327 println!("\n {}. {}", i + 1, file.filename);
328 println!(" ID: {}", file.id);
329 println!(" Size: {}", file.formatted_size());
330 println!(" Purpose: {}", file.purpose);
331 println!(" Created: {}", file.formatted_created_at());
332 }
333
334 println!("\n Filtering options:");
335 println!(" - Filter by purpose (fine-tune, assistants, batch, vision)");
336 println!(" - Limit results (default: 20)");
337 println!(" - Order by creation time (asc/desc)");
338
339 Ok(simulated_files.len())
340}
341
342async fn retrieve_file_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
344 println!("Retrieving file metadata...");
345
346 let file_id = "file-abc123";
347 println!(" Looking up file: {}", file_id);
348
349 let file = FileMetadata::new(file_id, "document.txt", 1024, "assistants");
361
362 println!("\n File metadata retrieved:");
363 println!(" ID: {}", file.id);
364 println!(" Filename: {}", file.filename);
365 println!(" Size: {}", file.formatted_size());
366 println!(" Purpose: {}", file.purpose);
367 println!(" Created: {}", file.formatted_created_at());
368 println!(" Status: processed");
369
370 Ok(())
371}
372
373async fn download_file_example(_client: &Client) -> Result<usize, Box<dyn std::error::Error>> {
375 println!("Downloading file content...");
376
377 let file_id = "file-abc123";
378 println!(" Downloading file: {}", file_id);
379
380 let content = "This is a sample document for the assistants API.\n\
389 It contains information that can be searched and referenced.\n\
390 The file format is plain text for simplicity.";
391
392 println!("\n File downloaded successfully");
393 println!(" Size: {} bytes", content.len());
394 println!("\n Content preview:");
395 let preview_len = 100.min(content.len());
396 println!("{}", &content[..preview_len]);
397 if content.len() > preview_len {
398 println!(" ... (truncated)");
399 }
400
401 println!("\n Download options:");
402 println!(" - download() - Returns content as String");
403 println!(" - download_bytes() - Returns content as Vec<u8>");
404
405 Ok(content.len())
406}
407
408async fn delete_file_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
410 println!("Deleting a file...");
411
412 let file_id = "file-temp123";
413 println!(" Deleting file: {}", file_id);
414
415 println!("\n File deleted successfully");
422 println!(" File ID: {}", file_id);
423 println!(" Deleted: true");
424
425 println!("\n Important notes:");
426 println!(" - Deleted files cannot be recovered");
427 println!(" - Files in use by jobs cannot be deleted");
428 println!(" - Check file dependencies before deletion");
429
430 Ok(())
431}
432
433async fn file_workflow_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
435 println!("Demonstrating a complete file management workflow...");
436
437 println!("\n Workflow steps:");
438 println!(" 1. Create training data");
439 println!(" 2. Upload file");
440 println!(" 3. Verify upload");
441 println!(" 4. List files");
442 println!(" 5. Clean up");
443
444 println!("\n Step 1: Creating training data...");
446 let training_data = vec![
447 serde_json::json!({
448 "messages": [
449 {"role": "system", "content": "You are a helpful assistant."},
450 {"role": "user", "content": "What is AI?"},
451 {"role": "assistant", "content": "AI stands for Artificial Intelligence..."}
452 ]
453 }),
454 serde_json::json!({
455 "messages": [
456 {"role": "system", "content": "You are a helpful assistant."},
457 {"role": "user", "content": "Explain machine learning"},
458 {"role": "assistant", "content": "Machine learning is a subset of AI..."}
459 ]
460 }),
461 ];
462
463 let jsonl_content: Vec<String> = training_data
464 .iter()
465 .map(|obj| serde_json::to_string(obj).unwrap())
466 .collect();
467 let content = jsonl_content.join("\n");
468
469 println!(" Created {} training examples", training_data.len());
470 println!(" Total size: {} bytes", content.len());
471
472 println!("\n Step 2: Uploading file...");
474 let file_id = "file-workflow789";
482 println!(" File uploaded: {}", file_id);
483
484 println!("\n Step 3: Verifying upload...");
486 println!(" File verified:");
493 println!(" Filename: training.jsonl");
494 println!(" Status: processed");
495 println!(" Size: {} bytes", content.len());
496
497 println!("\n Step 4: Listing all files...");
499 println!(" Total files: 4");
504 println!(" Including our new file: {}", file_id);
505
506 println!("\n Step 5: Cleanup (optional)...");
508 println!(" Skipping deletion - file may be used for training");
509 println!(" ℹ To delete: client.files().delete(&file_id).await");
510
511 println!("\n Workflow completed successfully!");
512
513 println!("\n Best practices:");
514 println!(" 1. Validate file format before upload");
515 println!(" 2. Check file size limits (max 512 MB per file)");
516 println!(" 3. Use appropriate purpose for each file");
517 println!(" 4. Verify file status after upload");
518 println!(" 5. Clean up unused files to save storage");
519 println!(" 6. Use JSONL format for training data");
520 println!(" 7. Handle upload errors gracefully");
521
522 Ok(())
523}
524
525fn handle_file_error(error: &dyn std::error::Error) {
527 eprintln!(" File Error: {}", error);
528
529 if let Some(source) = error.source() {
530 eprintln!(" Caused by: {}", source);
531 }
532
533 eprintln!("\n Troubleshooting tips:");
534 eprintln!(" - Check your API key and network connection");
535 eprintln!(" - Verify file format matches the purpose");
536 eprintln!(" - Ensure file size is within limits (max 512 MB)");
537 eprintln!(" - Check file ID is valid for retrieve/download/delete");
538 eprintln!(" - For fine-tuning: Use JSONL format");
539 eprintln!(" - For batch: Follow batch API format");
540 eprintln!(" - For assistants: Check supported file types");
541}