#![allow(clippy::uninlined_format_args)]
#![allow(clippy::no_effect_underscore_binding)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::unused_async)]
#![allow(clippy::useless_vec)]
#![allow(dead_code)]
use openai_ergonomic::Client;
#[derive(Debug, Clone)]
pub struct FileMetadata {
pub id: String,
pub filename: String,
pub bytes: usize,
pub purpose: String,
pub created_at: i64,
}
impl FileMetadata {
pub fn new(
id: impl Into<String>,
filename: impl Into<String>,
bytes: usize,
purpose: impl Into<String>,
) -> Self {
Self {
id: id.into(),
filename: filename.into(),
bytes,
purpose: purpose.into(),
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() as i64,
}
}
pub fn formatted_size(&self) -> String {
if self.bytes < 1024 {
format!("{} B", self.bytes)
} else if self.bytes < 1024 * 1024 {
format!("{:.2} KB", self.bytes as f64 / 1024.0)
} else if self.bytes < 1024 * 1024 * 1024 {
format!("{:.2} MB", self.bytes as f64 / (1024.0 * 1024.0))
} else {
format!("{:.2} GB", self.bytes as f64 / (1024.0 * 1024.0 * 1024.0))
}
}
pub fn formatted_created_at(&self) -> String {
format!("Unix timestamp: {}", self.created_at)
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" OpenAI Ergonomic - Comprehensive Files Example\n");
let client = match Client::from_env() {
Ok(client_builder) => {
println!(" Client initialized successfully");
client_builder.build()
}
Err(e) => {
eprintln!(" Failed to initialize client: {e}");
eprintln!(" Make sure OPENAI_API_KEY is set in your environment");
return Err(e.into());
}
};
println!("\n Example 1: Upload Text File");
println!("================================");
match upload_text_file_example(&client).await {
Ok(file_id) => {
println!(" Text file uploaded successfully: {}", file_id);
}
Err(e) => {
eprintln!(" Text file upload failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 2: Upload JSON File");
println!("================================");
match upload_json_file_example(&client).await {
Ok(file_id) => {
println!(" JSON file uploaded successfully: {}", file_id);
}
Err(e) => {
eprintln!(" JSON file upload failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 3: List Files");
println!("=========================");
match list_files_example(&client).await {
Ok(count) => {
println!(" Listed {} files successfully", count);
}
Err(e) => {
eprintln!(" List files failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 4: Retrieve File Metadata");
println!("======================================");
match retrieve_file_example(&client).await {
Ok(()) => {
println!(" File metadata retrieved successfully");
}
Err(e) => {
eprintln!(" Retrieve file failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 5: Download File Content");
println!("======================================");
match download_file_example(&client).await {
Ok(size) => {
println!(" Downloaded {} bytes successfully", size);
}
Err(e) => {
eprintln!(" Download file failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 6: Delete File");
println!("===========================");
match delete_file_example(&client).await {
Ok(()) => {
println!(" File deleted successfully");
}
Err(e) => {
eprintln!(" Delete file failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n Example 7: File Management Workflow");
println!("========================================");
match file_workflow_example(&client).await {
Ok(()) => {
println!(" File workflow completed successfully");
}
Err(e) => {
eprintln!(" File workflow failed: {e}");
handle_file_error(e.as_ref());
}
}
println!("\n All examples completed! Check the console output above for results.");
println!("\nNote: This example simulates API responses. Replace the simulated sections with");
println!("real client.files() calls when you're ready to interact with the API.");
Ok(())
}
async fn upload_text_file_example(_client: &Client) -> Result<String, Box<dyn std::error::Error>> {
println!("Uploading a text file for assistants...");
let content = "This is a sample document for the assistants API.\n\
It contains information that can be searched and referenced.\n\
The file format is plain text for simplicity.";
println!(" Filename: document.txt");
println!(" Size: {} bytes", content.len());
println!(" Purpose: assistants");
let file_id = "file-abc123";
println!(" Upload initiated...");
println!(" File uploaded successfully");
println!(" File ID: {}", file_id);
println!(" Status: processed");
Ok(file_id.to_string())
}
async fn upload_json_file_example(_client: &Client) -> Result<String, Box<dyn std::error::Error>> {
println!("Uploading a JSON file for batch processing...");
let batch_data = serde_json::json!({
"custom_id": "request-1",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "gpt-4",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
}
});
let content = serde_json::to_string_pretty(&batch_data)?;
println!(" Filename: batch_request.jsonl");
println!(" Size: {} bytes", content.len());
println!(" Purpose: batch");
println!(" Content preview:");
println!("{}", content);
let file_id = "file-batch456";
println!("\n Upload initiated...");
println!(" File uploaded successfully");
println!(" File ID: {}", file_id);
println!(" Status: processed");
Ok(file_id.to_string())
}
async fn list_files_example(_client: &Client) -> Result<usize, Box<dyn std::error::Error>> {
println!("Listing files with filtering...");
let simulated_files = vec![
FileMetadata::new("file-abc123", "document.txt", 1024, "assistants"),
FileMetadata::new("file-def456", "training.jsonl", 2048, "fine-tune"),
FileMetadata::new("file-ghi789", "batch_request.jsonl", 512, "batch"),
];
println!("\n Listing all files:");
println!(" Found {} files", simulated_files.len());
for (i, file) in simulated_files.iter().enumerate() {
println!("\n {}. {}", i + 1, file.filename);
println!(" ID: {}", file.id);
println!(" Size: {}", file.formatted_size());
println!(" Purpose: {}", file.purpose);
println!(" Created: {}", file.formatted_created_at());
}
println!("\n Filtering options:");
println!(" - Filter by purpose (fine-tune, assistants, batch, vision)");
println!(" - Limit results (default: 20)");
println!(" - Order by creation time (asc/desc)");
Ok(simulated_files.len())
}
async fn retrieve_file_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
println!("Retrieving file metadata...");
let file_id = "file-abc123";
println!(" Looking up file: {}", file_id);
let file = FileMetadata::new(file_id, "document.txt", 1024, "assistants");
println!("\n File metadata retrieved:");
println!(" ID: {}", file.id);
println!(" Filename: {}", file.filename);
println!(" Size: {}", file.formatted_size());
println!(" Purpose: {}", file.purpose);
println!(" Created: {}", file.formatted_created_at());
println!(" Status: processed");
Ok(())
}
async fn download_file_example(_client: &Client) -> Result<usize, Box<dyn std::error::Error>> {
println!("Downloading file content...");
let file_id = "file-abc123";
println!(" Downloading file: {}", file_id);
let content = "This is a sample document for the assistants API.\n\
It contains information that can be searched and referenced.\n\
The file format is plain text for simplicity.";
println!("\n File downloaded successfully");
println!(" Size: {} bytes", content.len());
println!("\n Content preview:");
let preview_len = 100.min(content.len());
println!("{}", &content[..preview_len]);
if content.len() > preview_len {
println!(" ... (truncated)");
}
println!("\n Download options:");
println!(" - download() - Returns content as String");
println!(" - download_bytes() - Returns content as Vec<u8>");
Ok(content.len())
}
async fn delete_file_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
println!("Deleting a file...");
let file_id = "file-temp123";
println!(" Deleting file: {}", file_id);
println!("\n File deleted successfully");
println!(" File ID: {}", file_id);
println!(" Deleted: true");
println!("\n Important notes:");
println!(" - Deleted files cannot be recovered");
println!(" - Files in use by jobs cannot be deleted");
println!(" - Check file dependencies before deletion");
Ok(())
}
async fn file_workflow_example(_client: &Client) -> Result<(), Box<dyn std::error::Error>> {
println!("Demonstrating a complete file management workflow...");
println!("\n Workflow steps:");
println!(" 1. Create training data");
println!(" 2. Upload file");
println!(" 3. Verify upload");
println!(" 4. List files");
println!(" 5. Clean up");
println!("\n Step 1: Creating training data...");
let training_data = vec![
serde_json::json!({
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is AI?"},
{"role": "assistant", "content": "AI stands for Artificial Intelligence..."}
]
}),
serde_json::json!({
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain machine learning"},
{"role": "assistant", "content": "Machine learning is a subset of AI..."}
]
}),
];
let jsonl_content: Vec<String> = training_data
.iter()
.map(|obj| serde_json::to_string(obj).unwrap())
.collect();
let content = jsonl_content.join("\n");
println!(" Created {} training examples", training_data.len());
println!(" Total size: {} bytes", content.len());
println!("\n Step 2: Uploading file...");
let file_id = "file-workflow789";
println!(" File uploaded: {}", file_id);
println!("\n Step 3: Verifying upload...");
println!(" File verified:");
println!(" Filename: training.jsonl");
println!(" Status: processed");
println!(" Size: {} bytes", content.len());
println!("\n Step 4: Listing all files...");
println!(" Total files: 4");
println!(" Including our new file: {}", file_id);
println!("\n Step 5: Cleanup (optional)...");
println!(" Skipping deletion - file may be used for training");
println!(" ℹ To delete: client.files().delete(&file_id).await");
println!("\n Workflow completed successfully!");
println!("\n Best practices:");
println!(" 1. Validate file format before upload");
println!(" 2. Check file size limits (max 512 MB per file)");
println!(" 3. Use appropriate purpose for each file");
println!(" 4. Verify file status after upload");
println!(" 5. Clean up unused files to save storage");
println!(" 6. Use JSONL format for training data");
println!(" 7. Handle upload errors gracefully");
Ok(())
}
fn handle_file_error(error: &dyn std::error::Error) {
eprintln!(" File Error: {}", error);
if let Some(source) = error.source() {
eprintln!(" Caused by: {}", source);
}
eprintln!("\n Troubleshooting tips:");
eprintln!(" - Check your API key and network connection");
eprintln!(" - Verify file format matches the purpose");
eprintln!(" - Ensure file size is within limits (max 512 MB)");
eprintln!(" - Check file ID is valid for retrieve/download/delete");
eprintln!(" - For fine-tuning: Use JSONL format");
eprintln!(" - For batch: Follow batch API format");
eprintln!(" - For assistants: Check supported file types");
}