//! WorkflowTemplate implementation for managing parameterized ComfyUI workflows use std::collections::HashMap; use crate::types::{ WorkflowTemplateData, TemplateMetadata, ComfyUIWorkflow, ParameterSchema, ParameterValues, ValidationResult, ParameterType }; use crate::error::{ComfyUIError, Result}; use crate::templates::WorkflowInstance; use crate::utils::validation::validate_parameters; /// Represents a parameterized workflow template #[derive(Debug, Clone)] pub struct WorkflowTemplate { metadata: TemplateMetadata, workflow: ComfyUIWorkflow, parameters: HashMap, } impl WorkflowTemplate { /// Creates a new WorkflowTemplate instance pub fn new(data: WorkflowTemplateData) -> Result { let template = Self { metadata: data.metadata, workflow: data.workflow, parameters: data.parameters, }; // Validate template structure template.validate_template()?; Ok(template) } /// Gets the template metadata pub fn metadata(&self) -> &TemplateMetadata { &self.metadata } /// Gets the workflow definition pub fn workflow(&self) -> &ComfyUIWorkflow { &self.workflow } /// Gets the parameter schemas pub fn parameters(&self) -> &HashMap { &self.parameters } /// Gets the template ID pub fn id(&self) -> &str { &self.metadata.id } /// Gets the template name pub fn name(&self) -> &str { &self.metadata.name } /// Gets the template description pub fn description(&self) -> Option<&str> { self.metadata.description.as_deref() } /// Gets the template category pub fn category(&self) -> Option<&str> { self.metadata.category.as_deref() } /// Gets the template tags pub fn tags(&self) -> &[String] { self.metadata.tags.as_deref().unwrap_or(&[]) } /// Validates the provided parameters against the template schema pub fn validate(&self, parameters: &ParameterValues) -> ValidationResult { validate_parameters(parameters, &self.parameters) } /// Creates a workflow instance with the provided parameters pub fn create_instance(&self, parameters: ParameterValues) -> Result { let validation = self.validate(¶meters); if !validation.valid { let error_messages: Vec = validation.errors .iter() .map(|e| format!("{}: {}", e.path, e.message)) .collect(); return Err(ComfyUIError::parameter_validation( format!("Invalid parameters: {}", error_messages.join(", ")) )); } WorkflowInstance::new(self.clone(), parameters) } /// Gets the parameter schema for a specific parameter pub fn get_parameter_schema(&self, parameter_name: &str) -> Option<&ParameterSchema> { self.parameters.get(parameter_name) } /// Gets all required parameter names pub fn get_required_parameters(&self) -> Vec<&str> { self.parameters .iter() .filter(|(_, schema)| schema.required.unwrap_or(false)) .map(|(name, _)| name.as_str()) .collect() } /// Gets all optional parameter names pub fn get_optional_parameters(&self) -> Vec<&str> { self.parameters .iter() .filter(|(_, schema)| !schema.required.unwrap_or(false)) .map(|(name, _)| name.as_str()) .collect() } /// Checks if the template has a specific parameter pub fn has_parameter(&self, parameter_name: &str) -> bool { self.parameters.contains_key(parameter_name) } /// Gets default values for all parameters that have defaults pub fn get_default_values(&self) -> ParameterValues { let mut defaults = HashMap::new(); for (name, schema) in &self.parameters { if let Some(default_value) = &schema.default { defaults.insert(name.clone(), default_value.clone()); } } defaults } /// Creates a copy of the template with updated metadata pub fn with_metadata(&self, metadata: TemplateMetadata) -> Self { Self { metadata, workflow: self.workflow.clone(), parameters: self.parameters.clone(), } } /// Converts the template to a JSON-serializable object pub fn to_data(&self) -> WorkflowTemplateData { WorkflowTemplateData { metadata: self.metadata.clone(), workflow: self.workflow.clone(), parameters: self.parameters.clone(), } } /// Creates a WorkflowTemplate from template data pub fn from_data(data: WorkflowTemplateData) -> Result { Self::new(data) } /// Validates the template structure fn validate_template(&self) -> Result<()> { // Validate metadata if self.metadata.id.is_empty() { return Err(ComfyUIError::template_validation( "Template metadata must have a valid id" )); } if self.metadata.name.is_empty() { return Err(ComfyUIError::template_validation( "Template metadata must have a valid name" )); } // Validate workflow if self.workflow.is_empty() { return Err(ComfyUIError::template_validation( "Template must have a valid workflow object" )); } // Validate parameter schemas for (name, schema) in &self.parameters { if !matches!( schema.param_type, ParameterType::String | ParameterType::Number | ParameterType::Boolean | ParameterType::Array | ParameterType::Object ) { return Err(ComfyUIError::template_validation( format!("Parameter '{}' has invalid type: {:?}", name, schema.param_type) )); } } Ok(()) } }