use anthropic_sdk::{
Anthropic,
FileUploadParams, FileListParams, FilePurpose, FileOrder, FileStatus,
UploadProgress, StorageInfo, FileDownload,
};
use std::{collections::HashMap, time::Duration};
use tokio::time::sleep;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Phase 5.2: Files API Enhancement Demo");
println!("========================================");
let client = match Anthropic::from_env() {
Ok(client) => client,
Err(_) => {
println!("โ ๏ธ ANTHROPIC_API_KEY not set. This is a demo of the Files API structure.");
simulate_files_api_operations().await?;
return Ok(());
}
};
println!("\n๐ค Demo 1: File Upload with Different Purposes");
println!("----------------------------------------------");
demonstrate_file_uploads().await?;
println!("\n๐ Demo 2: Upload Progress Tracking");
println!("-----------------------------------");
simulate_upload_progress().await?;
println!("\n๐ Demo 3: File Listing and Management");
println!("--------------------------------------");
demonstrate_file_listing().await?;
println!("\n๐พ Demo 4: Storage Management");
println!("-----------------------------");
demonstrate_storage_management().await?;
println!("\nโณ Demo 5: File Processing and Status Monitoring");
println!("------------------------------------------------");
simulate_file_processing().await?;
println!("\n๐ง Demo 6: Advanced File Operations");
println!("-----------------------------------");
demonstrate_advanced_operations().await?;
println!("\n๐ Phase 5.2 Files API Enhancement Demo Complete!");
println!("==================================================");
println!("โ
File Upload: Multi-format support with progress tracking");
println!("โ
File Management: List, filter, sort, and organize files");
println!("โ
Storage Monitoring: Quota tracking and usage analytics");
println!("โ
Status Tracking: Real-time processing status monitoring");
println!("โ
Batch Operations: Concurrent uploads and cleanup utilities");
println!("โ
Download & Processing: Content retrieval and format conversion");
Ok(())
}
async fn simulate_files_api_operations() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Simulating Files API operations...");
demonstrate_file_uploads().await?;
simulate_upload_progress().await?;
demonstrate_file_listing().await?;
demonstrate_storage_management().await?;
simulate_file_processing().await?;
demonstrate_advanced_operations().await?;
println!("โ
Files API simulation complete!");
Ok(())
}
async fn demonstrate_file_uploads() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Creating upload parameters for different file types...");
let vision_upload = create_sample_upload(
"sample_image.jpg",
"image/jpeg",
FilePurpose::Vision,
b"fake_jpeg_data"
).with_meta("description", "Sample image for vision analysis");
println!(" โ
Vision upload: {} ({}) - {}",
vision_upload.filename,
vision_upload.content_type,
format_bytes(vision_upload.content.len() as u64)
);
let document_upload = create_sample_upload(
"research_paper.pdf",
"application/pdf",
FilePurpose::Document,
&create_fake_pdf_content()
).with_meta("category", "research")
.with_meta("author", "AI Research Team");
println!(" โ
Document upload: {} ({}) - {}",
document_upload.filename,
document_upload.content_type,
format_bytes(document_upload.content.len() as u64)
);
let batch_upload = create_sample_upload(
"batch_requests.jsonl",
"application/json",
FilePurpose::BatchInput,
&create_sample_jsonl()
);
println!(" โ
Batch input upload: {} ({}) - {}",
batch_upload.filename,
batch_upload.content_type,
format_bytes(batch_upload.content.len() as u64)
);
println!("\n๐ Validating upload parameters...");
if let Err(e) = vision_upload.validate() {
println!(" โ Vision upload validation failed: {}", e);
} else {
println!(" โ
Vision upload parameters valid");
}
if let Err(e) = document_upload.validate() {
println!(" โ Document upload validation failed: {}", e);
} else {
println!(" โ
Document upload parameters valid");
}
if let Err(e) = batch_upload.validate() {
println!(" โ Batch upload validation failed: {}", e);
} else {
println!(" โ
Batch upload parameters valid");
}
Ok(())
}
async fn simulate_upload_progress() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Simulating file upload with progress tracking...");
let file_size = 5 * 1024 * 1024; let mut uploaded = 0u64;
let chunk_size = 256 * 1024;
let start_time = std::time::Instant::now();
while uploaded < file_size {
let chunk = chunk_size.min(file_size - uploaded);
uploaded += chunk;
let elapsed = start_time.elapsed().as_secs_f64();
let speed = if elapsed > 0.0 { uploaded as f64 / elapsed } else { 0.0 };
let progress = UploadProgress::new(uploaded, file_size).with_speed(speed);
println!(" ๐ Upload Progress: {} | {} | Speed: {} | ETA: {}",
progress.percentage_string(),
progress.size_string(),
progress.speed_string().unwrap_or("N/A".to_string()),
progress.eta_string().unwrap_or("N/A".to_string())
);
sleep(Duration::from_millis(100)).await;
}
println!(" โ
Upload completed successfully!");
Ok(())
}
async fn demonstrate_file_listing() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Creating file listing parameters...");
let all_files_params = FileListParams::new()
.limit(50)
.order(FileOrder::NewestFirst);
println!(" ๐ All files query: limit={:?}, order={:?}",
all_files_params.limit,
all_files_params.order
);
let vision_files_params = FileListParams::new()
.purpose(FilePurpose::Vision)
.limit(20)
.order(FileOrder::NewestFirst);
println!(" ๐ผ๏ธ Vision files query: purpose={:?}, limit={:?}",
vision_files_params.purpose,
vision_files_params.limit
);
let paginated_params = FileListParams::new()
.after("file_abc123")
.limit(10);
println!(" ๐ Paginated query: after={:?}, limit={:?}",
paginated_params.after,
paginated_params.limit
);
simulate_file_list_results().await;
Ok(())
}
async fn simulate_file_list_results() {
println!("\n๐ Simulated file listing results:");
let mock_files = vec![
("file_001", "image.jpg", "image/jpeg", FilePurpose::Vision, FileStatus::Processed, 2048576),
("file_002", "document.pdf", "application/pdf", FilePurpose::Document, FileStatus::Processed, 5242880),
("file_003", "batch.jsonl", "application/json", FilePurpose::BatchInput, FileStatus::Processing, 1024),
("file_004", "photo.png", "image/png", FilePurpose::Vision, FileStatus::Error, 3145728),
("file_005", "data.txt", "text/plain", FilePurpose::Upload, FileStatus::Processed, 512),
];
for (id, name, content_type, purpose, status, size) in mock_files {
let status_icon = match status {
FileStatus::Processed => "โ
",
FileStatus::Processing => "โณ",
FileStatus::Error => "โ",
FileStatus::Deleted => "๐๏ธ",
};
let purpose_icon = match purpose {
FilePurpose::Vision => "๐ผ๏ธ",
FilePurpose::Document => "๐",
FilePurpose::BatchInput => "๐ฆ",
FilePurpose::BatchOutput => "๐ค",
FilePurpose::Upload => "๐",
};
println!(" {} {} {} | {} | {} | {}",
status_icon,
purpose_icon,
id,
name,
content_type,
format_bytes(size)
);
}
}
async fn demonstrate_storage_management() -> Result<(), Box<dyn std::error::Error>> {
println!("๐พ Simulating storage information...");
let storage = create_mock_storage_info();
println!(" ๐ Storage Usage: {}", storage.usage_string());
println!(" ๐ Usage Percentage: {:.1}%", storage.usage_percentage());
println!(" ๐ File Count: {}", storage.file_count);
println!(" ๐ฝ Total Quota: {}", storage.quota_string());
if storage.is_nearly_full() {
println!(" โ ๏ธ Storage is nearly full (>90%)");
} else if storage.is_full() {
println!(" ๐จ Storage is full!");
} else {
println!(" โ
Storage has sufficient space");
}
println!("\n ๐ Usage by Purpose:");
for (purpose, bytes) in &storage.usage_by_purpose {
let percentage = if storage.used_bytes > 0 {
(*bytes as f64 / storage.used_bytes as f64) * 100.0
} else {
0.0
};
println!(" {} {} ({:.1}%)",
purpose,
format_bytes(*bytes),
percentage
);
}
Ok(())
}
async fn simulate_file_processing() -> Result<(), Box<dyn std::error::Error>> {
println!("โ๏ธ Simulating file processing status monitoring...");
let file_id = "file_processing_demo";
let statuses = [
(FileStatus::Processing, "File is being validated and processed"),
(FileStatus::Processing, "Extracting content and metadata"),
(FileStatus::Processing, "Running content analysis"),
(FileStatus::Processed, "File processing completed successfully"),
];
for (status, description) in statuses {
let status_icon = match status {
FileStatus::Processing => "โณ",
FileStatus::Processed => "โ
",
FileStatus::Error => "โ",
FileStatus::Deleted => "๐๏ธ",
};
println!(" {} {}: {}", status_icon, file_id, description);
if status.is_ready() {
println!(" ๐ File is ready for use!");
break;
}
sleep(Duration::from_millis(800)).await;
}
Ok(())
}
async fn demonstrate_advanced_operations() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ง Demonstrating advanced file operations...");
println!("\n ๐ฆ Batch Upload (3 files concurrently):");
let uploads = vec![
("file1.txt", "text/plain", 1024),
("file2.jpg", "image/jpeg", 2048576),
("file3.pdf", "application/pdf", 5242880),
];
for (name, content_type, size) in uploads {
println!(" โฌ๏ธ {} ({}) - {}", name, content_type, format_bytes(size));
sleep(Duration::from_millis(200)).await;
}
println!(" โ
All files uploaded successfully!");
println!("\n ๐งน Cleanup Old Files (>30 days):");
let old_files = ["old_file1.txt", "deprecated_image.jpg", "archived_doc.pdf"];
for file in old_files {
println!(" ๐๏ธ Deleting: {}", file);
sleep(Duration::from_millis(100)).await;
}
println!(" โ
Cleaned up {} old files", old_files.len());
println!("\n ๐ฅ File Download and Processing:");
let download = create_mock_download();
println!(" ๐ Downloaded: {} ({}) - {}",
download.filename,
download.content_type,
format_bytes(download.size)
);
if download.content_type.starts_with("text/") {
println!(" ๐ Text content preview: \"{}...\"",
String::from_utf8_lossy(&download.content[..50.min(download.content.len())])
);
} else if download.content_type == "application/json" {
println!(" ๐ JSON structure detected - ready for parsing");
} else {
println!(" ๐ฆ Binary content - {} bytes available", download.content.len());
}
Ok(())
}
fn create_sample_upload(filename: &str, content_type: &str, purpose: FilePurpose, content: &[u8]) -> FileUploadParams {
FileUploadParams::new(
content.to_vec(),
filename,
content_type,
purpose,
)
}
fn create_fake_pdf_content() -> Vec<u8> {
let mut content = b"%PDF-1.4\n".to_vec();
content.extend_from_slice(b"Fake PDF content for demonstration purposes. ");
content.extend_from_slice(b"This would be actual PDF binary data in a real scenario. ");
content.extend_from_slice(&vec![0u8; 1024]); content
}
fn create_sample_jsonl() -> Vec<u8> {
let jsonl_content = r#"{"custom_id": "req1", "method": "POST", "url": "/v1/messages", "body": {"model": "claude-3-5-sonnet-latest", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}}
{"custom_id": "req2", "method": "POST", "url": "/v1/messages", "body": {"model": "claude-3-5-sonnet-latest", "max_tokens": 1024, "messages": [{"role": "user", "content": "World"}]}}
"#;
jsonl_content.as_bytes().to_vec()
}
fn create_mock_storage_info() -> StorageInfo {
let mut usage_by_purpose = HashMap::new();
usage_by_purpose.insert("vision".to_string(), 50 * 1024 * 1024); usage_by_purpose.insert("document".to_string(), 100 * 1024 * 1024); usage_by_purpose.insert("batch_input".to_string(), 10 * 1024 * 1024); usage_by_purpose.insert("upload".to_string(), 25 * 1024 * 1024);
StorageInfo {
quota_bytes: 1024 * 1024 * 1024, used_bytes: 185 * 1024 * 1024, available_bytes: 839 * 1024 * 1024, file_count: 42,
usage_by_purpose,
}
}
fn create_mock_download() -> FileDownload {
let content = b"Sample file content for demonstration.\nThis could be text, JSON, or binary data.".to_vec();
FileDownload {
content: content.clone(),
content_type: "text/plain".to_string(),
filename: "sample_download.txt".to_string(),
size: content.len() as u64,
}
}
fn format_bytes(bytes: u64) -> String {
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
if bytes == 0 {
return "0 B".to_string();
}
let mut size = bytes as f64;
let mut unit_index = 0;
while size >= 1024.0 && unit_index < UNITS.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
if unit_index == 0 {
format!("{} {}", size as u64, UNITS[unit_index])
} else {
format!("{:.1} {}", size, UNITS[unit_index])
}
}