307 lines
11 KiB
Rust
307 lines
11 KiB
Rust
//! Real Local Image Upload Test
|
|
//!
|
|
//! This example demonstrates how to upload your actual local image file
|
|
//! and use it with the AI Model Face & Hair Detail Fix template.
|
|
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
use std::sync::Arc;
|
|
use comfyui_sdk::{
|
|
ComfyUIClient, ComfyUIClientConfig, ExecutionOptions,
|
|
AI_MODEL_FACE_HAIR_FIX_TEMPLATE
|
|
};
|
|
use comfyui_sdk::utils::SimpleCallbacks;
|
|
use serde_json::json;
|
|
|
|
/// Test with real local image upload
|
|
async fn test_with_real_local_image() -> Result<(), Box<dyn std::error::Error>> {
|
|
println!("🚀 Starting Real Local Image Upload Test");
|
|
|
|
// Initialize client
|
|
let mut client = ComfyUIClient::new(ComfyUIClientConfig {
|
|
base_url: "http://192.168.0.193:8188".to_string(),
|
|
..Default::default()
|
|
})?;
|
|
|
|
// Connect to ComfyUI server
|
|
println!("📡 Connecting to ComfyUI server...");
|
|
client.connect().await?;
|
|
println!("✅ Connected successfully!");
|
|
|
|
// Register the template
|
|
println!("📝 Registering AI Model Face & Hair Fix template...");
|
|
client.templates().register_from_data(AI_MODEL_FACE_HAIR_FIX_TEMPLATE.clone())?;
|
|
let template = client.templates_ref()
|
|
.get_by_id(&AI_MODEL_FACE_HAIR_FIX_TEMPLATE.metadata.id)
|
|
.ok_or("Failed to register template")?;
|
|
println!("✅ Template registered!");
|
|
|
|
// Your actual local image path
|
|
let local_image_path = "20250808-111737.png";
|
|
|
|
println!("\n📤 Uploading your image: {}", local_image_path);
|
|
println!("⏳ This may take a moment depending on file size and network speed...");
|
|
|
|
match upload_and_execute(&client, template, local_image_path).await {
|
|
Ok(_) => println!("✅ Upload and execution completed successfully!"),
|
|
Err(e) => {
|
|
println!("\n💥 Upload/Execution failed: {}", e);
|
|
show_troubleshooting_tips(&e);
|
|
}
|
|
}
|
|
|
|
// Disconnect
|
|
println!("\n🔌 Disconnecting from ComfyUI server...");
|
|
client.disconnect().await?;
|
|
println!("👋 Disconnected successfully!");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Upload image and execute template
|
|
async fn upload_and_execute(
|
|
client: &ComfyUIClient,
|
|
template: &comfyui_sdk::WorkflowTemplate,
|
|
image_path: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Step 1: Upload image to ComfyUI server
|
|
println!("\n🔄 Step 1: Uploading image to ComfyUI server...");
|
|
|
|
if !Path::new(image_path).exists() {
|
|
return Err(format!("File not found: {}", image_path).into());
|
|
}
|
|
|
|
let upload_response = client.upload_image(image_path, false).await?;
|
|
let uploaded_filename = upload_response.name;
|
|
println!("✅ Upload successful! Server filename: {}", uploaded_filename);
|
|
|
|
// Step 2: Execute AI Model Face & Hair Enhancement
|
|
println!("\n🔄 Step 2: Executing AI Model Face & Hair Enhancement...");
|
|
|
|
// Create execution callbacks
|
|
let callbacks = Arc::new(
|
|
SimpleCallbacks::new()
|
|
.with_progress(|progress| {
|
|
let percentage = (progress.progress as f64 / progress.max as f64 * 100.0) as u32;
|
|
println!("⏳ Progress: {}% ({}/{}) - Node: {}",
|
|
percentage, progress.progress, progress.max, progress.node_id);
|
|
})
|
|
.with_executing(|node_id| {
|
|
println!("🔄 Executing node: {}", node_id);
|
|
})
|
|
.with_executed(|result| {
|
|
println!("✅ Node completed - Prompt ID: {}", result.prompt_id);
|
|
})
|
|
.with_error(|error| {
|
|
println!("❌ Execution error: {}", error.message);
|
|
})
|
|
);
|
|
|
|
// Prepare parameters
|
|
let mut parameters = HashMap::new();
|
|
parameters.insert("input_image".to_string(), json!(uploaded_filename));
|
|
parameters.insert("face_prompt".to_string(),
|
|
json!("beautiful woman, perfect skin, detailed facial features, professional photography"));
|
|
parameters.insert("face_denoise".to_string(), json!("0.25"));
|
|
|
|
let execution_options = ExecutionOptions {
|
|
timeout: Some(std::time::Duration::from_secs(180)), // 3 minutes timeout
|
|
priority: None,
|
|
};
|
|
|
|
let result = client.execute_template_with_callbacks(
|
|
template,
|
|
parameters,
|
|
execution_options,
|
|
callbacks,
|
|
).await?;
|
|
|
|
if result.success {
|
|
println!("\n🎉 AI Model Enhancement completed successfully!");
|
|
println!("📊 Total execution time: {}ms ({:.1}s)",
|
|
result.execution_time, result.execution_time as f64 / 1000.0);
|
|
println!("🆔 Prompt ID: {}", result.prompt_id);
|
|
|
|
if let Some(outputs) = &result.outputs {
|
|
println!("\n📁 Generated outputs:");
|
|
println!("{}", serde_json::to_string_pretty(outputs)?);
|
|
|
|
// Convert outputs to HTTP URLs
|
|
let image_urls = client.outputs_to_urls(outputs);
|
|
println!("\n🖼️ Enhanced Image URLs:");
|
|
for (index, url) in image_urls.iter().enumerate() {
|
|
println!(" {}. {}", index + 1, url);
|
|
}
|
|
|
|
println!("\n💡 How to use these URLs:");
|
|
println!(" - Copy the URL and paste in your browser to view");
|
|
println!(" - Right-click and \"Save As\" to download");
|
|
println!(" - Use in your application to display the enhanced image");
|
|
}
|
|
} else {
|
|
println!("\n❌ AI Model Enhancement failed!");
|
|
if let Some(error) = &result.error {
|
|
println!("Error details: {}", error.message);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Show troubleshooting tips based on error
|
|
fn show_troubleshooting_tips(error: &Box<dyn std::error::Error>) {
|
|
let error_msg = error.to_string();
|
|
|
|
if error_msg.contains("File not found") || error_msg.contains("No such file") {
|
|
println!("\n💡 Troubleshooting Tips:");
|
|
println!("1. 🔍 Check if the file path is correct");
|
|
println!("2. 📁 Make sure the file exists at the specified location");
|
|
println!("3. 🔐 Ensure you have read permissions for the file");
|
|
println!("4. 📝 Try using absolute path: /home/user/images/20250808-111737.png");
|
|
println!("5. 🖼️ Verify the file is a valid image format (PNG, JPG, etc.)");
|
|
} else if error_msg.contains("Failed to upload") || error_msg.contains("HTTP") {
|
|
println!("\n💡 Network/Server Issues:");
|
|
println!("1. 🌐 Check if ComfyUI server is running and accessible");
|
|
println!("2. 📡 Verify network connection to the server");
|
|
println!("3. 💾 Check if server has enough disk space");
|
|
println!("4. 🔒 Ensure server allows file uploads");
|
|
}
|
|
}
|
|
|
|
/// Alternative method using one-step upload and execute (conceptual)
|
|
async fn test_one_step_method() -> Result<(), Box<dyn std::error::Error>> {
|
|
println!("\n\n🚀 Testing One-Step Method (Upload + Execute)");
|
|
|
|
let mut client = ComfyUIClient::new(ComfyUIClientConfig {
|
|
base_url: "http://192.168.0.193:8188".to_string(),
|
|
..Default::default()
|
|
})?;
|
|
|
|
client.connect().await?;
|
|
client.templates().register_from_data(AI_MODEL_FACE_HAIR_FIX_TEMPLATE.clone())?;
|
|
let template = client.templates_ref()
|
|
.get_by_id(&AI_MODEL_FACE_HAIR_FIX_TEMPLATE.metadata.id)
|
|
.ok_or("Failed to register template")?;
|
|
|
|
let local_image_path = "20250808-111737.png";
|
|
|
|
println!("🔄 One-step upload and execute...");
|
|
|
|
// For now, we'll implement this as upload + execute since we don't have
|
|
// a dedicated one-step method yet
|
|
match upload_and_execute_one_step(&client, template, local_image_path).await {
|
|
Ok(_) => println!("🎉 One-step method completed successfully!"),
|
|
Err(e) => println!("⚠️ One-step method failed: {}", e),
|
|
}
|
|
|
|
client.disconnect().await?;
|
|
Ok(())
|
|
}
|
|
|
|
/// One-step upload and execute (simplified version)
|
|
async fn upload_and_execute_one_step(
|
|
client: &ComfyUIClient,
|
|
template: &comfyui_sdk::WorkflowTemplate,
|
|
image_path: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Upload image
|
|
let upload_response = client.upload_image(image_path, false).await?;
|
|
|
|
// Create simple callbacks
|
|
let callbacks = Arc::new(
|
|
SimpleCallbacks::new()
|
|
.with_progress(|progress| {
|
|
let percentage = (progress.progress as f64 / progress.max as f64 * 100.0) as u32;
|
|
println!("⏳ Progress: {}% - Node: {}", percentage, progress.node_id);
|
|
})
|
|
);
|
|
|
|
// Execute template
|
|
let mut parameters = HashMap::new();
|
|
parameters.insert("input_image".to_string(), json!(upload_response.name));
|
|
parameters.insert("face_prompt".to_string(),
|
|
json!("stunning model, flawless skin, professional photography, high quality"));
|
|
parameters.insert("face_denoise".to_string(), json!("0.3"));
|
|
|
|
let result = client.execute_template_with_callbacks(
|
|
template,
|
|
parameters,
|
|
ExecutionOptions {
|
|
timeout: Some(std::time::Duration::from_secs(180)),
|
|
priority: None,
|
|
},
|
|
callbacks,
|
|
).await?;
|
|
|
|
if result.success {
|
|
if let Some(outputs) = &result.outputs {
|
|
let image_urls = client.outputs_to_urls(outputs);
|
|
println!("🖼️ Result URLs: {:?}", image_urls);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Show usage examples
|
|
fn show_usage_examples() {
|
|
println!("\n📚 Complete Usage Guide for Local Images:");
|
|
println!("");
|
|
println!("🔧 Basic Setup:");
|
|
println!("```rust");
|
|
println!("use comfyui_sdk::{{ComfyUIClient, ComfyUIClientConfig, AI_MODEL_FACE_HAIR_FIX_TEMPLATE}};");
|
|
println!("");
|
|
println!("let mut client = ComfyUIClient::new(ComfyUIClientConfig {{");
|
|
println!(" base_url: \"http://your-comfyui-server:8188\".to_string(),");
|
|
println!(" ..Default::default()");
|
|
println!("}});");
|
|
println!("```");
|
|
println!("");
|
|
println!("📤 Method 1 - Manual Upload:");
|
|
println!("```rust");
|
|
println!("// Upload image first");
|
|
println!("let upload_response = client.upload_image(");
|
|
println!(" \"/path/to/your/image.png\", false");
|
|
println!(").await?;");
|
|
println!("");
|
|
println!("// Then execute template");
|
|
println!("let result = client.execute_template(template, parameters, options).await?;");
|
|
println!("```");
|
|
println!("");
|
|
println!("🚀 Method 2 - Combined Upload and Execute:");
|
|
println!("```rust");
|
|
println!("// Upload and execute in sequence");
|
|
println!("let upload_response = client.upload_image(image_path, false).await?;");
|
|
println!("let mut parameters = HashMap::new();");
|
|
println!("parameters.insert(\"input_image\".to_string(), json!(upload_response.name));");
|
|
println!("let result = client.execute_template_with_callbacks(");
|
|
println!(" template, parameters, options, callbacks");
|
|
println!(").await?;");
|
|
println!("```");
|
|
}
|
|
|
|
/// Run all tests
|
|
async fn run_all_tests() -> Result<(), Box<dyn std::error::Error>> {
|
|
show_usage_examples();
|
|
test_with_real_local_image().await?;
|
|
// Uncomment to test one-step method as well
|
|
// test_one_step_method().await?;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
run_all_tests().await
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn test_show_usage_examples() {
|
|
show_usage_examples();
|
|
// This test just ensures the function runs without panicking
|
|
}
|
|
}
|