feat: add uni-comfyui-sdk - Rust SDK for ComfyUI API
- Complete Rust SDK implementation based on OpenAPI specification - All 23 endpoints implemented with type-safe interfaces - Comprehensive error handling and async support - Full documentation and examples included - Client renamed to UniComfyUIClient for clear identification
This commit is contained in:
20
cargos/uni-comfyui-sdk/.gitignore
vendored
Normal file
20
cargos/uni-comfyui-sdk/.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Rust
|
||||||
|
/target/
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
23
cargos/uni-comfyui-sdk/Cargo.toml
Normal file
23
cargos/uni-comfyui-sdk/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "uni-comfyui-sdk"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "Rust SDK for ComfyUI Workflow Service & Management API"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/your-repo/uni-comfyui-sdk"
|
||||||
|
keywords = ["comfyui", "api", "sdk", "workflow"]
|
||||||
|
categories = ["api-bindings", "web-programming::http-client"]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
|
thiserror = "1.0"
|
||||||
|
url = "2.4"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio-test = "0.4"
|
||||||
124
cargos/uni-comfyui-sdk/README.md
Normal file
124
cargos/uni-comfyui-sdk/README.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# uni-comfyui-sdk
|
||||||
|
|
||||||
|
A Rust SDK for ComfyUI Workflow Service & Management API.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Status Management**: Get metrics, server status, and file listings
|
||||||
|
- **Workflow Management**: Create, retrieve, and delete workflows
|
||||||
|
- **Workflow Execution**: Run workflows and monitor their status
|
||||||
|
- **Server Management**: Register, unregister, and manage ComfyUI servers
|
||||||
|
- **Monitoring**: Health checks, system stats, and task monitoring
|
||||||
|
- **Type Safety**: Strongly typed API with comprehensive error handling
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add this to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
uni-comfyui-sdk = "0.1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use uni_comfyui_sdk::{UniComfyUIClient, Result};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
// Create a client
|
||||||
|
let client = UniComfyUIClient::new("http://localhost:8000")?;
|
||||||
|
|
||||||
|
// Get system metrics
|
||||||
|
let metrics = client.get_metrics().await?;
|
||||||
|
println!("Metrics: {:#?}", metrics);
|
||||||
|
|
||||||
|
// Get all workflows
|
||||||
|
let workflows = client.get_all_workflows().await?;
|
||||||
|
println!("Found {} workflows", workflows.len());
|
||||||
|
|
||||||
|
// Run a workflow
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
data.insert("input".to_string(), serde_json::json!("test input"));
|
||||||
|
let result = client.run_workflow("my_workflow", None, data).await?;
|
||||||
|
println!("Workflow result: {:#?}", result);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Coverage
|
||||||
|
|
||||||
|
### Status Endpoints
|
||||||
|
- `get_metrics()` - Get queue status overview
|
||||||
|
- `get_servers_status()` - Get all configured ComfyUI servers status
|
||||||
|
- `list_server_files(server_index)` - List files in server input/output folders
|
||||||
|
|
||||||
|
### Workflow Endpoints
|
||||||
|
- `get_all_workflows()` - Get all workflows
|
||||||
|
- `publish_workflow(data)` - Publish a new workflow
|
||||||
|
- `delete_workflow(workflow_name)` - Delete a workflow
|
||||||
|
- `get_one_workflow(base_name, version)` - Get workflow specification
|
||||||
|
|
||||||
|
### Run Endpoints
|
||||||
|
- `run_workflow(name, version, data)` - Execute workflow asynchronously
|
||||||
|
- `get_run_status(workflow_run_id)` - Get workflow execution status
|
||||||
|
|
||||||
|
### RunX Endpoints
|
||||||
|
- `model_with_multi_dress(version, data)` - Model with multiple dresses workflow
|
||||||
|
- `model_with_multi_dress_json_schema()` - Get workflow definition
|
||||||
|
|
||||||
|
### Monitor Endpoints
|
||||||
|
- `monitor_dashboard()` - Get monitoring dashboard HTML
|
||||||
|
- `get_system_stats()` - Get system statistics
|
||||||
|
- `get_task_stats()` - Get task statistics
|
||||||
|
- `get_monitor_server_status()` - Get server status information
|
||||||
|
- `get_recent_tasks(limit)` - Get recent tasks list
|
||||||
|
- `health_check()` - Health check endpoint
|
||||||
|
|
||||||
|
### ComfyUI Server Management Endpoints
|
||||||
|
- `register_server(request)` - Register ComfyUI server
|
||||||
|
- `update_heartbeat(request)` - Update server heartbeat
|
||||||
|
- `unregister_server(request)` - Unregister ComfyUI server
|
||||||
|
- `get_server_status(server_name)` - Get specific server status
|
||||||
|
- `list_all_servers()` - Get all servers list
|
||||||
|
- `get_system_health()` - Get system overall health status
|
||||||
|
- `force_health_check()` - Force health check execution
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The SDK provides comprehensive error handling through the `ComfyUIError` enum:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use uni_comfyui_sdk::{UniComfyUIClient, ComfyUIError};
|
||||||
|
|
||||||
|
match client.get_metrics().await {
|
||||||
|
Ok(metrics) => println!("Success: {:#?}", metrics),
|
||||||
|
Err(ComfyUIError::Http(e)) => println!("HTTP error: {}", e),
|
||||||
|
Err(ComfyUIError::Api { status, message }) => {
|
||||||
|
println!("API error {}: {}", status, message)
|
||||||
|
}
|
||||||
|
Err(e) => println!("Other error: {}", e),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Models
|
||||||
|
|
||||||
|
The SDK includes strongly typed models for all API requests and responses:
|
||||||
|
|
||||||
|
- `ServerRegistrationRequest` - Server registration data
|
||||||
|
- `ServerHeartbeatRequest` - Server heartbeat data
|
||||||
|
- `ServerStatusResponse` - Server status information
|
||||||
|
- `ServerFiles` - Server file listings
|
||||||
|
- `FileDetails` - Individual file information
|
||||||
|
- And more...
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
See the `examples/` directory for more usage examples.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
172
cargos/uni-comfyui-sdk/examples/advanced_usage.rs
Normal file
172
cargos/uni-comfyui-sdk/examples/advanced_usage.rs
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
use uni_comfyui_sdk::{
|
||||||
|
UniComfyUIClient, ComfyUIError, Result, ServerHeartbeatRequest, ServerRegistrationRequest,
|
||||||
|
ServerUnregisterRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
|
||||||
|
// Demonstrate comprehensive server management
|
||||||
|
println!("=== Server Management Demo ===");
|
||||||
|
|
||||||
|
// Register a new server
|
||||||
|
let server_name = "demo-server";
|
||||||
|
let registration = ServerRegistrationRequest {
|
||||||
|
name: server_name.to_string(),
|
||||||
|
http_url: "http://192.168.0.148:8188".to_string(),
|
||||||
|
ws_url: "ws://192.168.0.148:8188".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.register_server(registration).await {
|
||||||
|
Ok(response) => println!("✓ Server registered: {:?}", response),
|
||||||
|
Err(ComfyUIError::Api { status: 409, .. }) => {
|
||||||
|
println!("ℹ Server already exists (409 conflict)")
|
||||||
|
}
|
||||||
|
Err(e) => println!("✗ Failed to register server: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send heartbeat
|
||||||
|
let heartbeat = ServerHeartbeatRequest {
|
||||||
|
name: server_name.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.update_heartbeat(heartbeat).await {
|
||||||
|
Ok(response) => println!("✓ Heartbeat sent: {:?}", response),
|
||||||
|
Err(e) => println!("✗ Failed to send heartbeat: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all servers
|
||||||
|
match client.list_all_servers().await {
|
||||||
|
Ok(servers) => {
|
||||||
|
println!("✓ Found {} servers:", servers.len());
|
||||||
|
for server in servers {
|
||||||
|
println!(" - {}: {} ({})", server.name, server.http_url, server.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => println!("✗ Failed to list servers: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate workflow management
|
||||||
|
println!("\n=== Workflow Management Demo ===");
|
||||||
|
|
||||||
|
// Get all workflows
|
||||||
|
match client.get_all_workflows().await {
|
||||||
|
Ok(workflows) => println!("✓ Found {} workflows", workflows.len()),
|
||||||
|
Err(e) => println!("✗ Failed to get workflows: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish a sample workflow
|
||||||
|
let mut sample_workflow = HashMap::new();
|
||||||
|
sample_workflow.insert("name".to_string(), serde_json::json!("demo_workflow"));
|
||||||
|
sample_workflow.insert("version".to_string(), serde_json::json!("1.0.0"));
|
||||||
|
sample_workflow.insert(
|
||||||
|
"description".to_string(),
|
||||||
|
serde_json::json!("A demo workflow for testing"),
|
||||||
|
);
|
||||||
|
|
||||||
|
match client.publish_workflow(sample_workflow).await {
|
||||||
|
Ok(_) => println!("✓ Workflow published successfully"),
|
||||||
|
Err(e) => println!("✗ Failed to publish workflow: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate workflow execution
|
||||||
|
println!("\n=== Workflow Execution Demo ===");
|
||||||
|
|
||||||
|
let mut execution_data = HashMap::new();
|
||||||
|
execution_data.insert("input_text".to_string(), serde_json::json!("Hello, ComfyUI!"));
|
||||||
|
execution_data.insert("steps".to_string(), serde_json::json!(20));
|
||||||
|
execution_data.insert("seed".to_string(), serde_json::json!(42));
|
||||||
|
|
||||||
|
match client
|
||||||
|
.run_workflow("demo_workflow", Some("1.0.0"), execution_data)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
println!("✓ Workflow execution started");
|
||||||
|
|
||||||
|
// Try to extract run ID from response for status checking
|
||||||
|
if let Some(run_id) = response.get("run_id").and_then(|v| v.as_str()) {
|
||||||
|
println!(" Run ID: {}", run_id);
|
||||||
|
|
||||||
|
// Poll for status (demo - in real usage you'd want better polling logic)
|
||||||
|
for i in 1..=3 {
|
||||||
|
sleep(Duration::from_secs(2)).await;
|
||||||
|
match client.get_run_status(run_id).await {
|
||||||
|
Ok(status) => {
|
||||||
|
println!(" Status check {}: {:?}", i, status);
|
||||||
|
}
|
||||||
|
Err(e) => println!(" Status check {} failed: {}", i, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => println!("✗ Failed to start workflow: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate monitoring
|
||||||
|
println!("\n=== Monitoring Demo ===");
|
||||||
|
|
||||||
|
// System health
|
||||||
|
match client.get_system_health().await {
|
||||||
|
Ok(health) => println!("✓ System health: {:?}", health),
|
||||||
|
Err(e) => println!("✗ Failed to get system health: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// System stats
|
||||||
|
match client.get_system_stats().await {
|
||||||
|
Ok(stats) => println!("✓ System stats retrieved"),
|
||||||
|
Err(e) => println!("✗ Failed to get system stats: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recent tasks
|
||||||
|
match client.get_recent_tasks(Some(5)).await {
|
||||||
|
Ok(tasks) => println!("✓ Found {} recent tasks", tasks.len()),
|
||||||
|
Err(e) => println!("✗ Failed to get recent tasks: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force health check
|
||||||
|
match client.force_health_check().await {
|
||||||
|
Ok(response) => println!("✓ Health check forced: {:?}", response),
|
||||||
|
Err(e) => println!("✗ Failed to force health check: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate RunX endpoints
|
||||||
|
println!("\n=== RunX Demo ===");
|
||||||
|
|
||||||
|
// Get schema for model_with_multi_dress
|
||||||
|
match client.model_with_multi_dress_json_schema().await {
|
||||||
|
Ok(schema) => println!("✓ Got model_with_multi_dress schema"),
|
||||||
|
Err(e) => println!("✗ Failed to get schema: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to run model_with_multi_dress workflow
|
||||||
|
let mut dress_data = HashMap::new();
|
||||||
|
dress_data.insert("model_image".to_string(), serde_json::json!("base64_image_data"));
|
||||||
|
dress_data.insert("dress_images".to_string(), serde_json::json!(["dress1.jpg", "dress2.jpg"]));
|
||||||
|
|
||||||
|
match client
|
||||||
|
.model_with_multi_dress(None, dress_data)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => println!("✓ Model with multi dress executed: {:?}", response),
|
||||||
|
Err(e) => println!("✗ Failed to execute model with multi dress: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup: Unregister the demo server
|
||||||
|
println!("\n=== Cleanup ===");
|
||||||
|
let unregister = ServerUnregisterRequest {
|
||||||
|
name: server_name.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.unregister_server(unregister).await {
|
||||||
|
Ok(response) => println!("✓ Server unregistered: {:?}", response),
|
||||||
|
Err(e) => println!("✗ Failed to unregister server: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("\n=== Demo Complete ===");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
56
cargos/uni-comfyui-sdk/examples/basic_usage.rs
Normal file
56
cargos/uni-comfyui-sdk/examples/basic_usage.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use uni_comfyui_sdk::{UniComfyUIClient, Result, ServerRegistrationRequest};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
// Create a new client
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
|
||||||
|
// Get system metrics
|
||||||
|
println!("Getting system metrics...");
|
||||||
|
let metrics = client.get_metrics().await?;
|
||||||
|
println!("Metrics: {:#?}", metrics);
|
||||||
|
|
||||||
|
// Get all workflows
|
||||||
|
println!("\nGetting all workflows...");
|
||||||
|
let workflows = client.get_all_workflows().await?;
|
||||||
|
println!("Found {} workflows", workflows.len());
|
||||||
|
|
||||||
|
// Get servers status
|
||||||
|
println!("\nGetting servers status...");
|
||||||
|
let servers = client.get_servers_status().await?;
|
||||||
|
println!("Found {} servers", servers.len());
|
||||||
|
|
||||||
|
// Health check
|
||||||
|
println!("\nPerforming health check...");
|
||||||
|
let health = client.health_check().await?;
|
||||||
|
println!("Health status: {:#?}", health);
|
||||||
|
|
||||||
|
// Example: Register a new server
|
||||||
|
println!("\nRegistering a new server...");
|
||||||
|
let registration_request = ServerRegistrationRequest {
|
||||||
|
name: "test-server".to_string(),
|
||||||
|
http_url: "http://192.168.0.148:8188".to_string(),
|
||||||
|
ws_url: "ws://192.168.0.148:8188".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.register_server(registration_request).await {
|
||||||
|
Ok(response) => println!("Server registered: {:#?}", response),
|
||||||
|
Err(e) => println!("Failed to register server: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: Run a workflow
|
||||||
|
println!("\nRunning a workflow...");
|
||||||
|
let mut workflow_data = HashMap::new();
|
||||||
|
workflow_data.insert("input".to_string(), serde_json::json!("test input"));
|
||||||
|
|
||||||
|
match client
|
||||||
|
.run_workflow("test_workflow", None, workflow_data)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => println!("Workflow started: {:#?}", response),
|
||||||
|
Err(e) => println!("Failed to start workflow: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
291
cargos/uni-comfyui-sdk/src/client.rs
Normal file
291
cargos/uni-comfyui-sdk/src/client.rs
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
use crate::error::{ComfyUIError, Result};
|
||||||
|
use crate::models::*;
|
||||||
|
use crate::types::*;
|
||||||
|
use reqwest::{Client, Response};
|
||||||
|
use serde_json::Value;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
/// UniComfyUI API client
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct UniComfyUIClient {
|
||||||
|
client: Client,
|
||||||
|
base_url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UniComfyUIClient {
|
||||||
|
/// Create a new UniComfyUI client
|
||||||
|
pub fn new(base_url: &str) -> Result<Self> {
|
||||||
|
let base_url = Url::parse(base_url)?;
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
Ok(Self { client, base_url })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new UniComfyUI client with custom reqwest client
|
||||||
|
pub fn with_client(base_url: &str, client: Client) -> Result<Self> {
|
||||||
|
let base_url = Url::parse(base_url)?;
|
||||||
|
|
||||||
|
Ok(Self { client, base_url })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build URL for an endpoint
|
||||||
|
fn build_url(&self, path: &str) -> Result<Url> {
|
||||||
|
Ok(self.base_url.join(path)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle HTTP response and convert to appropriate result
|
||||||
|
async fn handle_response<T>(&self, response: Response) -> Result<T>
|
||||||
|
where
|
||||||
|
T: serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
let status = response.status();
|
||||||
|
|
||||||
|
if status.is_success() {
|
||||||
|
let text = response.text().await?;
|
||||||
|
if text.is_empty() {
|
||||||
|
// Handle empty responses for some endpoints
|
||||||
|
return Ok(serde_json::from_value(Value::Null)?);
|
||||||
|
}
|
||||||
|
Ok(serde_json::from_str(&text)?)
|
||||||
|
} else {
|
||||||
|
let error_text = response.text().await.unwrap_or_default();
|
||||||
|
Err(ComfyUIError::Api {
|
||||||
|
status: status.as_u16(),
|
||||||
|
message: error_text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status endpoints
|
||||||
|
|
||||||
|
/// Get metrics - 获取队列状态概览
|
||||||
|
pub async fn get_metrics(&self) -> Result<GenericResponse> {
|
||||||
|
let url = self.build_url("/api/service/metrics")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get servers status - 获取所有已配置的ComfyUI服务器的配置信息和实时状态
|
||||||
|
pub async fn get_servers_status(&self) -> Result<Vec<ServerStatus>> {
|
||||||
|
let url = self.build_url("/api/service/servers_status")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List server files - 获取指定ComfyUI服务器的输入和输出文件夹中的文件列表
|
||||||
|
pub async fn list_server_files(&self, server_index: u32) -> Result<ServerFiles> {
|
||||||
|
let url = self.build_url(&format!("/api/service/servers/{}/files", server_index))?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workflow endpoints
|
||||||
|
|
||||||
|
/// Get all workflows - 获取所有工作流
|
||||||
|
pub async fn get_all_workflows(&self) -> Result<ObjectArrayResponse> {
|
||||||
|
let url = self.build_url("/api/workflow")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Publish workflow - 发布工作流
|
||||||
|
pub async fn publish_workflow(&self, data: JsonObject) -> Result<GenericResponse> {
|
||||||
|
let url = self.build_url("/api/workflow")?;
|
||||||
|
let response = self.client.post(url).json(&data).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete workflow - 删除工作流
|
||||||
|
pub async fn delete_workflow(&self, workflow_name: &str) -> Result<GenericResponse> {
|
||||||
|
let url = self.build_url(&format!("/api/workflow/{}", workflow_name))?;
|
||||||
|
let response = self.client.delete(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get one workflow - 获取工作流规范
|
||||||
|
pub async fn get_one_workflow(
|
||||||
|
&self,
|
||||||
|
base_name: &str,
|
||||||
|
version: Option<&str>,
|
||||||
|
) -> Result<GenericResponse> {
|
||||||
|
let mut url = self.build_url(&format!("/api/workflow/{}", base_name))?;
|
||||||
|
|
||||||
|
if let Some(version) = version {
|
||||||
|
url.query_pairs_mut().append_pair("version", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run endpoints
|
||||||
|
|
||||||
|
/// Run workflow - 异步执行工作流
|
||||||
|
pub async fn run_workflow(
|
||||||
|
&self,
|
||||||
|
workflow_name: &str,
|
||||||
|
workflow_version: Option<&str>,
|
||||||
|
data: JsonObject,
|
||||||
|
) -> Result<GenericResponse> {
|
||||||
|
let mut url = self.build_url("/api/run")?;
|
||||||
|
url.query_pairs_mut().append_pair("workflow_name", workflow_name);
|
||||||
|
|
||||||
|
if let Some(version) = workflow_version {
|
||||||
|
url.query_pairs_mut().append_pair("workflow_version", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = self.client.post(url).json(&data).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get run status - 获取工作流执行状态
|
||||||
|
pub async fn get_run_status(&self, workflow_run_id: &str) -> Result<GenericResponse> {
|
||||||
|
let url = self.build_url(&format!("/api/run/{}", workflow_run_id))?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunX endpoints
|
||||||
|
|
||||||
|
/// Model with multi dress - 一个模特,穿多件不同的衣服
|
||||||
|
pub async fn model_with_multi_dress(
|
||||||
|
&self,
|
||||||
|
workflow_version: Option<&str>,
|
||||||
|
data: JsonObject,
|
||||||
|
) -> Result<GenericResponse> {
|
||||||
|
let mut url = self.build_url("/api/runx/model_with_multi_dress")?;
|
||||||
|
|
||||||
|
if let Some(version) = workflow_version {
|
||||||
|
url.query_pairs_mut().append_pair("workflow_version", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = self.client.post(url).json(&data).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get model with multi dress JSON schema - 获取工作流定义
|
||||||
|
pub async fn model_with_multi_dress_json_schema(&self) -> Result<GenericResponse> {
|
||||||
|
let url = self.build_url("/api/runx/model_with_multi_dress/json_schema")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monitor endpoints
|
||||||
|
|
||||||
|
/// Monitor dashboard - 监控仪表板页面
|
||||||
|
pub async fn monitor_dashboard(&self) -> Result<String> {
|
||||||
|
let url = self.build_url("/monitor/")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
|
||||||
|
let status = response.status();
|
||||||
|
if status.is_success() {
|
||||||
|
Ok(response.text().await?)
|
||||||
|
} else {
|
||||||
|
let error_text = response.text().await.unwrap_or_default();
|
||||||
|
Err(ComfyUIError::Api {
|
||||||
|
status: status.as_u16(),
|
||||||
|
message: error_text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get system stats - 获取系统统计信息
|
||||||
|
pub async fn get_system_stats(&self) -> Result<AdditionalPropertiesResponse> {
|
||||||
|
let url = self.build_url("/monitor/system-stats")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get task stats - 获取任务统计信息
|
||||||
|
pub async fn get_task_stats(&self) -> Result<AdditionalPropertiesResponse> {
|
||||||
|
let url = self.build_url("/monitor/task-stats")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get server status (monitor) - 获取服务器状态信息
|
||||||
|
pub async fn get_monitor_server_status(&self) -> Result<ObjectArrayResponse> {
|
||||||
|
let url = self.build_url("/monitor/server-status")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get recent tasks - 获取最近的任务列表
|
||||||
|
pub async fn get_recent_tasks(&self, limit: Option<i32>) -> Result<ObjectArrayResponse> {
|
||||||
|
let mut url = self.build_url("/monitor/recent-tasks")?;
|
||||||
|
|
||||||
|
if let Some(limit) = limit {
|
||||||
|
url.query_pairs_mut().append_pair("limit", &limit.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Health check - 健康检查端点
|
||||||
|
pub async fn health_check(&self) -> Result<AdditionalPropertiesResponse> {
|
||||||
|
let url = self.build_url("/monitor/health")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComfyUI Server Management endpoints
|
||||||
|
|
||||||
|
/// Register server - 注册ComfyUI服务器
|
||||||
|
pub async fn register_server(
|
||||||
|
&self,
|
||||||
|
request: ServerRegistrationRequest,
|
||||||
|
) -> Result<StringDictResponse> {
|
||||||
|
let url = self.build_url("/api/comfy/register")?;
|
||||||
|
let response = self.client.post(url).json(&request).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update heartbeat - 更新服务器心跳
|
||||||
|
pub async fn update_heartbeat(
|
||||||
|
&self,
|
||||||
|
request: ServerHeartbeatRequest,
|
||||||
|
) -> Result<StringDictResponse> {
|
||||||
|
let url = self.build_url("/api/comfy/heartbeat")?;
|
||||||
|
let response = self.client.post(url).json(&request).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unregister server - 注销ComfyUI服务器
|
||||||
|
pub async fn unregister_server(
|
||||||
|
&self,
|
||||||
|
request: ServerUnregisterRequest,
|
||||||
|
) -> Result<StringDictResponse> {
|
||||||
|
let url = self.build_url("/api/comfy/unregister")?;
|
||||||
|
let response = self.client.post(url).json(&request).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get server status - 获取指定服务器状态
|
||||||
|
pub async fn get_server_status(&self, server_name: &str) -> Result<ServerStatusResponse> {
|
||||||
|
let url = self.build_url(&format!("/api/comfy/status/{}", server_name))?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List all servers - 获取所有服务器列表
|
||||||
|
pub async fn list_all_servers(&self) -> Result<Vec<ServerStatusResponse>> {
|
||||||
|
let url = self.build_url("/api/comfy/list")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get system health - 获取系统整体健康状态
|
||||||
|
pub async fn get_system_health(&self) -> Result<AdditionalPropertiesResponse> {
|
||||||
|
let url = self.build_url("/api/comfy/health")?;
|
||||||
|
let response = self.client.get(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Force health check - 强制执行健康检查
|
||||||
|
pub async fn force_health_check(&self) -> Result<StringDictResponse> {
|
||||||
|
let url = self.build_url("/api/comfy/force_health_check")?;
|
||||||
|
let response = self.client.post(url).send().await?;
|
||||||
|
self.handle_response(response).await
|
||||||
|
}
|
||||||
|
}
|
||||||
40
cargos/uni-comfyui-sdk/src/error.rs
Normal file
40
cargos/uni-comfyui-sdk/src/error.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Result type alias for ComfyUI SDK operations
|
||||||
|
pub type Result<T> = std::result::Result<T, ComfyUIError>;
|
||||||
|
|
||||||
|
/// Error types for ComfyUI SDK operations
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ComfyUIError {
|
||||||
|
/// HTTP request error
|
||||||
|
#[error("HTTP request failed: {0}")]
|
||||||
|
Http(#[from] reqwest::Error),
|
||||||
|
|
||||||
|
/// JSON serialization/deserialization error
|
||||||
|
#[error("JSON error: {0}")]
|
||||||
|
Json(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
/// URL parsing error
|
||||||
|
#[error("URL parsing error: {0}")]
|
||||||
|
Url(#[from] url::ParseError),
|
||||||
|
|
||||||
|
/// API error response
|
||||||
|
#[error("API error: {status} - {message}")]
|
||||||
|
Api { status: u16, message: String },
|
||||||
|
|
||||||
|
/// Validation error
|
||||||
|
#[error("Validation error: {0}")]
|
||||||
|
Validation(String),
|
||||||
|
|
||||||
|
/// Server not found error
|
||||||
|
#[error("Server not found: {0}")]
|
||||||
|
ServerNotFound(String),
|
||||||
|
|
||||||
|
/// Workflow not found error
|
||||||
|
#[error("Workflow not found: {0}")]
|
||||||
|
WorkflowNotFound(String),
|
||||||
|
|
||||||
|
/// Generic error
|
||||||
|
#[error("Error: {0}")]
|
||||||
|
Generic(String),
|
||||||
|
}
|
||||||
58
cargos/uni-comfyui-sdk/src/lib.rs
Normal file
58
cargos/uni-comfyui-sdk/src/lib.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//! # uni-comfyui-sdk
|
||||||
|
//!
|
||||||
|
//! Rust SDK for ComfyUI Workflow Service & Management API
|
||||||
|
//!
|
||||||
|
//! This SDK provides a type-safe interface to interact with the ComfyUI API,
|
||||||
|
//! including workflow management, execution, monitoring, and server management.
|
||||||
|
//!
|
||||||
|
//! ## Features
|
||||||
|
//!
|
||||||
|
//! - **Status Management**: Get metrics, server status, and file listings
|
||||||
|
//! - **Workflow Management**: Create, retrieve, and delete workflows
|
||||||
|
//! - **Workflow Execution**: Run workflows and monitor their status
|
||||||
|
//! - **Server Management**: Register, unregister, and manage ComfyUI servers
|
||||||
|
//! - **Monitoring**: Health checks, system stats, and task monitoring
|
||||||
|
//! - **Type Safety**: Strongly typed API with comprehensive error handling
|
||||||
|
//!
|
||||||
|
//! ## Quick Start
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! use uni_comfyui_sdk::{UniComfyUIClient, Result};
|
||||||
|
//! use std::collections::HashMap;
|
||||||
|
//!
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() -> Result<()> {
|
||||||
|
//! // Create a client
|
||||||
|
//! let client = UniComfyUIClient::new("http://localhost:8000")?;
|
||||||
|
//!
|
||||||
|
//! // Get system metrics
|
||||||
|
//! let metrics = client.get_metrics().await?;
|
||||||
|
//! println!("Metrics: {:#?}", metrics);
|
||||||
|
//!
|
||||||
|
//! // Run a workflow
|
||||||
|
//! let mut data = HashMap::new();
|
||||||
|
//! data.insert("input".to_string(), serde_json::json!("test"));
|
||||||
|
//! let result = client.run_workflow("my_workflow", None, data).await?;
|
||||||
|
//! println!("Workflow result: {:#?}", result);
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
pub mod client;
|
||||||
|
pub mod error;
|
||||||
|
pub mod models;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
pub use client::UniComfyUIClient;
|
||||||
|
pub use error::{ComfyUIError, Result};
|
||||||
|
pub use models::*;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
|
/// Re-export commonly used types
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::client::UniComfyUIClient;
|
||||||
|
pub use crate::error::{ComfyUIError, Result};
|
||||||
|
pub use crate::models::*;
|
||||||
|
pub use crate::types::*;
|
||||||
|
}
|
||||||
130
cargos/uni-comfyui-sdk/src/models.rs
Normal file
130
cargos/uni-comfyui-sdk/src/models.rs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// File details information
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct FileDetails {
|
||||||
|
/// File name
|
||||||
|
pub name: String,
|
||||||
|
/// File size in KB
|
||||||
|
pub size_kb: f64,
|
||||||
|
/// Last modified timestamp
|
||||||
|
pub modified_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HTTP validation error details
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct HTTPValidationError {
|
||||||
|
/// List of validation errors
|
||||||
|
pub detail: Vec<ValidationError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Individual validation error
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ValidationError {
|
||||||
|
/// Error location path
|
||||||
|
pub loc: Vec<ValidationErrorLocation>,
|
||||||
|
/// Error message
|
||||||
|
pub msg: String,
|
||||||
|
/// Error type
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub error_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validation error location (can be string or integer)
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum ValidationErrorLocation {
|
||||||
|
String(String),
|
||||||
|
Integer(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server files information
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerFiles {
|
||||||
|
/// Server index in configuration list
|
||||||
|
pub server_index: i32,
|
||||||
|
/// HTTP URL of the server
|
||||||
|
pub http_url: String,
|
||||||
|
/// List of input files
|
||||||
|
pub input_files: Vec<FileDetails>,
|
||||||
|
/// List of output files
|
||||||
|
pub output_files: Vec<FileDetails>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server heartbeat request
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerHeartbeatRequest {
|
||||||
|
/// Server name
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server queue details
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerQueueDetails {
|
||||||
|
/// Number of running tasks
|
||||||
|
pub running_count: i32,
|
||||||
|
/// Number of pending tasks
|
||||||
|
pub pending_count: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server registration request
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerRegistrationRequest {
|
||||||
|
/// Server name
|
||||||
|
pub name: String,
|
||||||
|
/// HTTP URL of the server
|
||||||
|
pub http_url: String,
|
||||||
|
/// WebSocket URL of the server
|
||||||
|
pub ws_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server status information
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerStatus {
|
||||||
|
/// Server index in configuration list
|
||||||
|
pub server_index: i32,
|
||||||
|
/// HTTP URL of the server
|
||||||
|
pub http_url: String,
|
||||||
|
/// WebSocket URL of the server
|
||||||
|
pub ws_url: String,
|
||||||
|
/// Whether the server is reachable
|
||||||
|
pub is_reachable: bool,
|
||||||
|
/// Whether the server is free
|
||||||
|
pub is_free: bool,
|
||||||
|
/// Queue details
|
||||||
|
pub queue_details: ServerQueueDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server status response
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerStatusResponse {
|
||||||
|
/// Server name
|
||||||
|
pub name: String,
|
||||||
|
/// HTTP URL of the server
|
||||||
|
pub http_url: String,
|
||||||
|
/// WebSocket URL of the server
|
||||||
|
pub ws_url: String,
|
||||||
|
/// Server status
|
||||||
|
pub status: String,
|
||||||
|
/// Last heartbeat timestamp
|
||||||
|
pub last_heartbeat: Option<String>,
|
||||||
|
/// Last health check timestamp
|
||||||
|
pub last_health_check: Option<String>,
|
||||||
|
/// Current number of tasks
|
||||||
|
pub current_tasks: i32,
|
||||||
|
/// Maximum concurrent tasks
|
||||||
|
pub max_concurrent_tasks: i32,
|
||||||
|
/// Server capabilities
|
||||||
|
pub capabilities: HashMap<String, serde_json::Value>,
|
||||||
|
/// Server metadata
|
||||||
|
pub metadata: HashMap<String, serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server unregister request
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ServerUnregisterRequest {
|
||||||
|
/// Server name
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
16
cargos/uni-comfyui-sdk/src/types.rs
Normal file
16
cargos/uni-comfyui-sdk/src/types.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Generic JSON object type
|
||||||
|
pub type JsonObject = HashMap<String, serde_json::Value>;
|
||||||
|
|
||||||
|
/// Generic response type for endpoints that return arbitrary JSON
|
||||||
|
pub type GenericResponse = serde_json::Value;
|
||||||
|
|
||||||
|
/// Response type for endpoints that return a dictionary of strings
|
||||||
|
pub type StringDictResponse = HashMap<String, String>;
|
||||||
|
|
||||||
|
/// Response type for endpoints that return an array of objects
|
||||||
|
pub type ObjectArrayResponse = Vec<JsonObject>;
|
||||||
|
|
||||||
|
/// Response type for endpoints that return an object with additional properties
|
||||||
|
pub type AdditionalPropertiesResponse = JsonObject;
|
||||||
90
cargos/uni-comfyui-sdk/tests/integration_tests.rs
Normal file
90
cargos/uni-comfyui-sdk/tests/integration_tests.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use uni_comfyui_sdk::{UniComfyUIClient, Result, ServerRegistrationRequest};
|
||||||
|
|
||||||
|
// Note: These tests require a running ComfyUI service
|
||||||
|
// They are disabled by default and should be run manually when needed
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_client_creation() -> Result<()> {
|
||||||
|
let _client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
assert!(true); // Just test that client creation doesn't panic
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_get_metrics() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
let _metrics = client.get_metrics().await?;
|
||||||
|
// Just test that the call doesn't fail
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_get_all_workflows() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
let workflows = client.get_all_workflows().await?;
|
||||||
|
assert!(workflows.is_empty() || !workflows.is_empty()); // Just test the call
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_health_check() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
let _health = client.health_check().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_server_registration() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
|
||||||
|
let registration_request = ServerRegistrationRequest {
|
||||||
|
name: "test-server".to_string(),
|
||||||
|
http_url: "http://192.168.0.148:8188".to_string(),
|
||||||
|
ws_url: "ws://192.168.0.148:8188".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This might fail if server already exists, which is fine for testing
|
||||||
|
let _result = client.register_server(registration_request).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_workflow_execution() -> Result<()> {
|
||||||
|
let client = UniComfyUIClient::new("http://192.168.0.148:18000")?;
|
||||||
|
|
||||||
|
let mut workflow_data = HashMap::new();
|
||||||
|
workflow_data.insert("test_input".to_string(), serde_json::json!("test_value"));
|
||||||
|
|
||||||
|
// This will likely fail without a real workflow, but tests the API call
|
||||||
|
let _result = client
|
||||||
|
.run_workflow("test_workflow", None, workflow_data)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_url_building() {
|
||||||
|
let _client = UniComfyUIClient::new("http://192.168.0.148:18000").unwrap();
|
||||||
|
// Test that URL building works correctly
|
||||||
|
assert!(true); // Basic test that client creation works
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_types() {
|
||||||
|
use uni_comfyui_sdk::ComfyUIError;
|
||||||
|
|
||||||
|
// Test that error types can be created
|
||||||
|
let _error = ComfyUIError::Validation("test error".to_string());
|
||||||
|
let _error = ComfyUIError::ServerNotFound("test server".to_string());
|
||||||
|
let _error = ComfyUIError::WorkflowNotFound("test workflow".to_string());
|
||||||
|
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
1173
cargos/uni-comfyui-sdk/unicomfy.json
Normal file
1173
cargos/uni-comfyui-sdk/unicomfy.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user