feat: add comfyui sdk

This commit is contained in:
imeepos
2025-08-08 13:48:38 +08:00
parent 763b4a975c
commit 5f6a302dfd
27 changed files with 4713 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
//! API types for ComfyUI SDK
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Queue status response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueueStatus {
pub queue_running: Vec<QueueItem>,
pub queue_pending: Vec<QueueItem>,
}
/// Queue item
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueueItem {
pub prompt_id: String,
pub number: u32,
pub outputs: HashMap<String, serde_json::Value>,
}
/// Prompt request
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptRequest {
pub prompt: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extra_data: Option<HashMap<String, serde_json::Value>>,
}
/// Prompt response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptResponse {
pub prompt_id: String,
pub number: u32,
pub node_errors: HashMap<String, serde_json::Value>,
}
/// History item
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryItem {
pub prompt: Vec<serde_json::Value>,
pub outputs: HashMap<String, HashMap<String, Vec<HistoryOutput>>>,
pub status: HistoryStatus,
}
/// History output
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryOutput {
pub filename: String,
pub subfolder: String,
#[serde(rename = "type")]
pub output_type: String,
}
/// History status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryStatus {
pub status_str: String,
pub completed: bool,
pub messages: Vec<Vec<serde_json::Value>>,
}
/// System stats
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemStats {
pub system: SystemInfo,
pub devices: Vec<DeviceInfo>,
}
/// System information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemInfo {
pub os: String,
pub python_version: String,
pub embedded_python: bool,
}
/// Device information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceInfo {
pub name: String,
pub device_type: String,
pub vram_total: u64,
pub vram_free: u64,
pub torch_vram_total: u64,
pub torch_vram_free: u64,
}
/// Object info response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObjectInfo {
#[serde(flatten)]
pub nodes: HashMap<String, NodeInfo>,
}
/// Node information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeInfo {
pub input: NodeInputInfo,
pub output: Vec<String>,
pub output_is_list: Vec<bool>,
pub output_name: Vec<String>,
pub name: String,
pub display_name: String,
pub description: String,
pub category: String,
pub python_module: String,
}
/// Node input information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeInputInfo {
pub required: HashMap<String, Vec<serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub optional: Option<HashMap<String, Vec<serde_json::Value>>>,
}
/// Upload image response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadImageResponse {
pub name: String,
pub subfolder: String,
#[serde(rename = "type")]
pub image_type: String,
}
/// View metadata response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ViewMetadata {
#[serde(flatten)]
pub metadata: HashMap<String, serde_json::Value>,
}

View File

@@ -0,0 +1,160 @@
//! Event types for ComfyUI SDK
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use std::collections::HashMap;
/// Execution progress information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionProgress {
pub node_id: String,
pub progress: u32,
pub max: u32,
pub timestamp: DateTime<Utc>,
}
/// Execution result information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionResult {
pub prompt_id: String,
pub outputs: HashMap<String, serde_json::Value>,
pub execution_time: u64,
pub timestamp: DateTime<Utc>,
}
/// Execution error information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionError {
pub node_id: Option<String>,
pub message: String,
pub details: Option<serde_json::Value>,
pub timestamp: DateTime<Utc>,
}
/// Callback trait for execution events
pub trait ExecutionCallbacks: Send + Sync {
/// Called when progress is updated
fn on_progress(&self, _progress: ExecutionProgress) {}
/// Called when a node starts executing
fn on_executing(&self, _node_id: String) {}
/// Called when execution completes successfully
fn on_executed(&self, _result: ExecutionResult) {}
/// Called when an error occurs
fn on_error(&self, _error: ExecutionError) {}
}
/// WebSocket message types
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WSMessage {
#[serde(rename = "progress")]
Progress {
data: WSProgressData,
},
#[serde(rename = "executing")]
Executing {
data: WSExecutingData,
},
#[serde(rename = "executed")]
Executed {
data: WSExecutedData,
},
#[serde(rename = "execution_error")]
ExecutionError {
data: WSErrorData,
},
#[serde(other)]
Unknown,
}
/// WebSocket progress message data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WSProgressData {
pub value: u32,
pub max: u32,
pub node: Option<String>,
}
/// WebSocket executing message data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WSExecutingData {
pub node: Option<String>,
pub prompt_id: String,
}
/// WebSocket executed message data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WSExecutedData {
pub node: String,
pub output: HashMap<String, serde_json::Value>,
pub prompt_id: String,
}
/// WebSocket error message data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WSErrorData {
pub node_id: Option<String>,
pub message: String,
pub details: Option<serde_json::Value>,
}
/// Execution options
#[derive(Debug, Clone)]
pub struct ExecutionOptions {
pub timeout: Option<std::time::Duration>,
pub priority: Option<i32>,
}
impl Default for ExecutionOptions {
fn default() -> Self {
Self {
timeout: Some(std::time::Duration::from_secs(300)), // 5 minutes default
priority: None,
}
}
}
/// Template execution result
#[derive(Debug, Clone)]
pub struct TemplateExecutionResult {
pub prompt_id: String,
pub success: bool,
pub outputs: Option<HashMap<String, serde_json::Value>>,
pub error: Option<ExecutionError>,
pub execution_time: u64,
}
impl TemplateExecutionResult {
/// Create a successful execution result
pub fn success(
prompt_id: String,
outputs: HashMap<String, serde_json::Value>,
execution_time: u64,
) -> Self {
Self {
prompt_id,
success: true,
outputs: Some(outputs),
error: None,
execution_time,
}
}
/// Create a failed execution result
pub fn failure(
prompt_id: String,
error: ExecutionError,
execution_time: u64,
) -> Self {
Self {
prompt_id,
success: false,
outputs: None,
error: Some(error),
execution_time,
}
}
}

View File

@@ -0,0 +1,192 @@
//! Core types for ComfyUI SDK
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
pub mod api;
pub mod events;
// Re-export all types
pub use api::*;
pub use events::*;
/// Base ComfyUI node definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComfyUINode {
pub class_type: String,
pub inputs: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<NodeMeta>,
}
/// Node metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMeta {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
/// ComfyUI workflow definition
pub type ComfyUIWorkflow = HashMap<String, ComfyUINode>;
/// Parameter schema types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ParameterType {
String,
Number,
Boolean,
Array,
Object,
}
/// Parameter schema definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterSchema {
#[serde(rename = "type")]
pub param_type: ParameterType,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#enum: Option<Vec<serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pattern: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Box<ParameterSchema>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<HashMap<String, ParameterSchema>>,
}
/// Template metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateMetadata {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<DateTime<Utc>>,
}
/// Workflow template data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowTemplateData {
pub metadata: TemplateMetadata,
pub workflow: ComfyUIWorkflow,
pub parameters: HashMap<String, ParameterSchema>,
}
/// Client configuration
#[derive(Debug, Clone)]
pub struct ComfyUIClientConfig {
pub base_url: String,
pub timeout: Option<std::time::Duration>,
pub retry_attempts: Option<u32>,
pub retry_delay: Option<std::time::Duration>,
pub headers: Option<HashMap<String, String>>,
}
impl Default for ComfyUIClientConfig {
fn default() -> Self {
Self {
base_url: "http://localhost:8188".to_string(),
timeout: Some(std::time::Duration::from_secs(30)),
retry_attempts: Some(3),
retry_delay: Some(std::time::Duration::from_millis(1000)),
headers: None,
}
}
}
/// Parameter values type
pub type ParameterValues = HashMap<String, serde_json::Value>;
/// Variable syntax options
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableSyntax {
DoubleBrace, // {{}}
DollarBrace, // ${}
AtBrace, // @{}
}
/// Template validation result
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub valid: bool,
pub errors: Vec<ValidationError>,
}
/// Validation error
#[derive(Debug, Clone)]
pub struct ValidationError {
pub path: String,
pub message: String,
pub value: Option<serde_json::Value>,
}
impl ValidationResult {
/// Create a successful validation result
pub fn success() -> Self {
Self {
valid: true,
errors: Vec::new(),
}
}
/// Create a failed validation result with errors
pub fn failure(errors: Vec<ValidationError>) -> Self {
Self {
valid: false,
errors,
}
}
/// Add an error to the validation result
pub fn add_error(&mut self, error: ValidationError) {
self.valid = false;
self.errors.push(error);
}
}
impl ValidationError {
/// Create a new validation error
pub fn new(path: impl Into<String>, message: impl Into<String>) -> Self {
Self {
path: path.into(),
message: message.into(),
value: None,
}
}
/// Create a new validation error with value
pub fn with_value(
path: impl Into<String>,
message: impl Into<String>,
value: serde_json::Value,
) -> Self {
Self {
path: path.into(),
message: message.into(),
value: Some(value),
}
}
}