//! ComfyUI V2 命令层 //! 基于新的 SDK 架构重写的 Tauri 命令 use anyhow::Result; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use tauri::State; use tracing::{info, warn, error, debug}; use crate::app_state::AppState; use crate::business::services::{ comfyui_v2_service::{ComfyUIV2Service, ComfyUIV2Config, ConnectionStatus, SystemInfo, QueueStatus}, template_engine::{TemplateEngine, CacheStats}, execution_engine::{ExecutionEngine, ExecutionResult, ExecutionConfig, ExecutionStats}, realtime_monitor_v2::{RealtimeMonitorV2, RealtimeEventV2, MonitorStats}, config_manager::{ConfigManager, ConfigStats, ConfigHealthStatus}, error_handler::{ComfyUIError, ErrorHandleResult, ErrorStats}, service_manager::ServiceManager, queue_manager::QueueManager, }; use crate::data::models::comfyui::{ WorkflowModel, TemplateModel, ExecutionModel, ExecutionStatus, ComfyUIConfig, ParameterValues, ValidationResult, }; use crate::data::repositories::comfyui_repository::ComfyUIRepository; use comfyui_sdk::types::{ComfyUIWorkflow, ComfyUINode}; use crate::business::services::comfyui_manager::ComfyUIManager; // ==================== 辅助函数 ==================== /// 将前端的 ComfyUIV2Config 转换为后端的 ComfyUIConfig fn convert_v2_config_to_config(v2_config: ComfyUIV2Config) -> ComfyUIConfig { // 处理超时时间:前端传递的是毫秒,后端需要秒 let timeout_seconds = match v2_config.timeout { Some(timeout_ms) => timeout_ms / 1000, None => 300, // 默认5分钟 }; // 处理重试延迟:从前端配置中提取或使用默认值 let retry_delay_ms = v2_config.retry_delay_ms.unwrap_or(1000); // 处理WebSocket启用状态 let enable_websocket = v2_config.enable_websocket.unwrap_or(true); // 处理自定义头部 let custom_headers = v2_config.custom_headers; ComfyUIConfig { base_url: v2_config.base_url, timeout_seconds, retry_attempts: v2_config.retry_attempts.unwrap_or(3), retry_delay_ms, enable_websocket, enable_cache: v2_config.enable_cache.unwrap_or(true), max_concurrency: v2_config.max_concurrency.unwrap_or(4), custom_headers, } } // ==================== 请求类型定义 ==================== /// 创建工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CreateWorkflowRequest { pub name: String, pub description: Option, pub workflow_json: serde_json::Value, pub tags: Option>, } /// 更新工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UpdateWorkflowRequest { pub id: String, pub name: Option, pub description: Option, pub workflow_json: Option, pub tags: Option>, } /// 批量删除工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BatchDeleteWorkflowsRequest { pub workflow_ids: Vec, } /// 导出工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExportWorkflowRequest { pub workflow_ids: Vec, pub include_metadata: Option, } /// 导入工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImportWorkflowRequest { pub workflow_data: serde_json::Value, pub overwrite_existing: Option, } /// 创建模板请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CreateTemplateRequest { pub name: String, pub description: Option, pub template_json: serde_json::Value, pub parameters: Option, pub tags: Option>, } /// 执行模板请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExecuteTemplateRequest { pub template_id: String, pub parameters: serde_json::Value, pub priority: Option, } // ==================== 响应类型定义 ==================== /// 连接状态响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConnectionStatusResponse { pub connected: bool, pub status: String, pub base_url: String, pub last_health_check: Option, pub timeout_seconds: u64, pub retry_attempts: u32, } /// 系统信息响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SystemInfoResponse { pub os: String, pub python_version: String, pub embedded_python: bool, pub devices: Vec, } /// 设备信息响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeviceInfoResponse { 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, } /// 队列状态响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct QueueStatusResponse { pub running_count: u32, pub pending_count: u32, pub running_tasks: Vec, pub pending_tasks: Vec, } /// 队列任务响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct QueueTaskResponse { pub prompt_id: String, pub number: u32, pub status: String, } /// 健康检查响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HealthCheckResponse { pub healthy: bool, pub connection_status: String, pub websocket_connected: bool, pub last_check_time: Option, pub error_message: Option, } // ==================== 基础连接管理命令 ==================== /// 连接到 ComfyUI 服务 /// 直接接收config参数,匹配前端传递的格式 #[tauri::command] pub async fn comfyui_v2_connect( config: ComfyUIV2Config, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_connect - 配置: {:?}", config); // 获取配置管理器 let config_manager = get_config_manager(&state).await?; // 转换前端配置为后端配置 let converted_config = convert_v2_config_to_config(config); info!("转换后的配置: base_url={}, timeout_seconds={}", converted_config.base_url, converted_config.timeout_seconds); // 先更新配置到配置管理器 config_manager.update_comfyui_config(converted_config.clone()).await .map_err(|e| { error!("更新配置失败: {}", e); format!("更新配置失败: {}", e) })?; // 获取或初始化服务管理器 let service_manager = state.get_comfyui_manager().await .map_err(|e| { error!("获取服务管理器失败: {}", e); format!("获取服务管理器失败: {}", e) })?; // 通过服务管理器重新配置并连接 service_manager.reconfigure(converted_config).await .map_err(|e| { error!("重新配置服务失败: {}", e); format!("重新配置服务失败: {}", e) })?; // 获取 ComfyUI 管理器并尝试连接 let comfyui_manager = service_manager.get_comfyui_manager().await .map_err(|e| { error!("获取ComfyUI管理器失败: {}", e); format!("获取ComfyUI管理器失败: {}", e) })?; // 尝试连接 match comfyui_manager.connect().await { Ok(_) => { let stats = comfyui_manager.get_connection_stats().await; info!("ComfyUI 连接成功"); Ok(ConnectionStatusResponse { connected: true, status: stats.status.to_string(), base_url: stats.base_url, last_health_check: stats.last_health_check.map(|t| format!("{:?}", t)), timeout_seconds: stats.timeout_seconds, retry_attempts: stats.retry_attempts, }) } Err(e) => { error!("ComfyUI 连接失败: {}", e); Err(format!("连接失败: {}", e)) } } } /// 断开 ComfyUI 连接 #[tauri::command] pub async fn comfyui_v2_disconnect( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_disconnect"); // 获取服务管理器 let service_manager = state.get_comfyui_manager().await .map_err(|e| { error!("获取服务管理器失败: {}", e); format!("获取服务管理器失败: {}", e) })?; // 获取 ComfyUI 管理器并断开连接 match service_manager.get_comfyui_manager().await { Ok(comfyui_manager) => { match comfyui_manager.disconnect().await { Ok(_) => { info!("ComfyUI 连接已断开"); Ok("连接已断开".to_string()) } Err(e) => { error!("断开连接失败: {}", e); Err(format!("断开连接失败: {}", e)) } } } Err(e) => { error!("获取ComfyUI管理器失败: {}", e); Err(format!("获取ComfyUI管理器失败: {}", e)) } } } /// 检查连接状态 #[tauri::command] pub async fn comfyui_v2_get_connection_status( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_connection_status"); // 获取服务管理器 let service_manager = match state.get_comfyui_manager().await { Ok(manager) => manager, Err(e) => { error!("获取服务管理器失败: {}", e); // 如果服务管理器未初始化,返回默认的未连接状态 return Ok(ConnectionStatusResponse { connected: false, status: "未初始化".to_string(), base_url: "http://localhost:8188".to_string(), last_health_check: None, timeout_seconds: 300, retry_attempts: 3, }); } }; // 获取 ComfyUI 管理器并检查连接状态 match service_manager.get_comfyui_manager().await { Ok(comfyui_manager) => { let stats = comfyui_manager.get_connection_stats().await; Ok(ConnectionStatusResponse { connected: comfyui_manager.is_connected().await, status: format!("{:?}", stats.status), base_url: stats.base_url, last_health_check: stats.last_health_check.map(|t| format!("{:?}", t)), timeout_seconds: stats.timeout_seconds, retry_attempts: stats.retry_attempts, }) } Err(e) => { error!("获取ComfyUI管理器失败: {}", e); Ok(ConnectionStatusResponse { connected: false, status: "管理器未初始化".to_string(), base_url: "http://localhost:8188".to_string(), last_health_check: None, timeout_seconds: 300, retry_attempts: 3, }) } } } /// 健康检查 #[tauri::command] pub async fn comfyui_v2_health_check( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_health_check"); // TODO: 实现健康检查逻辑 Ok(HealthCheckResponse { healthy: false, connection_status: "未连接".to_string(), websocket_connected: false, last_check_time: None, error_message: Some("服务未初始化".to_string()), }) } /// 获取系统信息 #[tauri::command] pub async fn comfyui_v2_get_system_info( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_system_info"); let service_manager = state.get_comfyui_manager().await .map_err(|e| format!("获取ComfyUI管理器失败: {}", e))?; let comfyui_manager = service_manager.get_comfyui_manager().await .map_err(|e| format!("获取ComfyUI管理器失败: {}", e))?; match comfyui_manager.get_system_info().await { Ok(stats) => Ok(convert_system_info(stats)), Err(e) => { error!("获取系统信息失败: {}", e); Err(format!("获取系统信息失败: {}", e)) } } } /// 获取队列基本状态 #[tauri::command] pub async fn comfyui_v2_get_queue_basic_status( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_queue_basic_status"); let service_manager = state.get_comfyui_manager().await .map_err(|e| format!("获取ComfyUI管理器失败: {}", e))?; let comfyui_manager = service_manager.get_comfyui_manager().await .map_err(|e| format!("获取ComfyUI管理器失败: {}", e))?; match comfyui_manager.get_queue_status().await { Ok(status) => Ok(QueueStatusResponse { running_count: status.queue_running.len() as u32, pending_count: status.queue_pending.len() as u32, running_tasks: Vec::new(), // TODO: 实现详细任务信息 pending_tasks: Vec::new(), // TODO: 实现详细任务信息 }), Err(e) => { error!("获取队列状态失败: {}", e); Err(format!("获取队列状态失败: {}", e)) } } } // 配置管理命令已移动到 comfyui_v2_config_commands.rs // ==================== 统计和监控命令 ==================== /// 获取配置统计信息 #[tauri::command] pub async fn comfyui_v2_get_config_stats( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_config_stats"); let config_manager = get_config_manager(&state).await?; let stats = config_manager.get_config_stats().await; Ok(stats) } /// 获取配置健康状态 #[tauri::command] pub async fn comfyui_v2_get_config_health( state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_config_health"); let config_manager = get_config_manager(&state).await?; match config_manager.health_check().await { Ok(status) => Ok(status.to_string()), Err(e) => Err(format!("健康检查失败: {}", e)), } } // ==================== 辅助函数 ==================== /// 获取配置管理器 async fn get_config_manager(state: &State<'_, AppState>) -> Result, String> { state.get_config_manager().await .map_err(|e| format!("获取配置管理器失败: {}", e)) } /// 获取服务管理器 async fn get_service_manager(state: &State<'_, AppState>) -> Result, String> { state.get_comfyui_manager().await .map_err(|e| format!("获取ComfyUI服务管理器失败: {}", e)) } /// 转换系统信息 fn convert_system_info(info: comfyui_sdk::types::SystemStats) -> SystemInfoResponse { SystemInfoResponse { os: info.system.os, python_version: info.system.python_version, embedded_python: info.system.embedded_python, devices: info.devices.into_iter().map(|device| DeviceInfoResponse { name: device.name, device_type: device.device_type, vram_total: device.vram_total, vram_free: device.vram_free, torch_vram_total: device.torch_vram_total, torch_vram_free: device.torch_vram_free, }).collect(), } } /// 转换队列状态 fn convert_queue_status(status: comfyui_sdk::types::QueueStatus) -> QueueStatusResponse { let running_items = status.get_running_items(); let pending_items = status.get_pending_items(); QueueStatusResponse { running_count: running_items.len() as u32, pending_count: pending_items.len() as u32, running_tasks: running_items.into_iter().map(|item| QueueTaskResponse { prompt_id: item.prompt_id, number: item.number, status: "running".to_string(), }).collect(), pending_tasks: pending_items.into_iter().map(|item| QueueTaskResponse { prompt_id: item.prompt_id, number: item.number, status: "pending".to_string(), }).collect(), } } // ==================== 工作流管理命令 ==================== /// 工作流响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WorkflowResponse { pub id: String, pub name: String, pub description: Option, pub workflow_data: HashMap, pub version: String, pub created_at: String, pub updated_at: String, pub enabled: bool, pub tags: Vec, pub category: Option, } /// 创建工作流 #[tauri::command] pub async fn comfyui_v2_create_workflow( request: CreateWorkflowRequest, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_create_workflow - {}", request.name); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 转换工作流数据 let workflow_data: ComfyUIWorkflow = serde_json::from_value(request.workflow_json.clone()) .map_err(|e| format!("解析工作流数据失败: {}", e))?; // 创建工作流模型 let mut workflow = WorkflowModel::new(request.name, workflow_data); // 设置可选字段 workflow.description = request.description; workflow.tags = request.tags.unwrap_or_default(); // 保存到数据库 repository.create_workflow(&workflow) .map_err(|e| format!("创建工作流失败: {}", e))?; Ok(convert_workflow_model(&workflow)) } /// 获取工作流列表(实际查询模板表,因为模板和工作流是同一概念) #[tauri::command] pub async fn comfyui_v2_list_workflows( enabled_only: Option, state: State<'_, AppState>, ) -> Result, String> { info!("Command: comfyui_v2_list_workflows"); let service_manager = get_service_manager(&state).await?; let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; // 查询模板列表(模板和工作流是同一概念) let templates = template_engine.list_templates(enabled_only.unwrap_or(true)).await .map_err(|e| format!("获取模板列表失败: {}", e))?; // 将模板转换为工作流响应格式 let responses = templates.iter().map(convert_template_to_workflow_response).collect(); Ok(responses) } /// 获取单个工作流(实际查询模板表,因为模板和工作流是同一概念) #[tauri::command] pub async fn comfyui_v2_get_workflow( workflow_id: String, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_get_workflow - {}", workflow_id); let service_manager = get_service_manager(&state).await?; let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; // 查询模板(模板和工作流是同一概念) match template_engine.load_template(&workflow_id).await { Ok(template) => Ok(convert_template_to_workflow_response(&template)), Err(e) => { if e.to_string().contains("模板不存在") { Err("工作流不存在".to_string()) } else { Err(format!("获取工作流失败: {}", e)) } } } } /// 更新工作流 #[tauri::command] pub async fn comfyui_v2_update_workflow( request: UpdateWorkflowRequest, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_update_workflow - {}", request.id); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 创建ComfyUI V2服务实例 let comfyui_service = { let realtime_monitor = Arc::new(crate::business::services::realtime_monitor_v2::RealtimeMonitorV2::new( Arc::new(crate::business::services::comfyui_manager::ComfyUIManager::new( crate::data::models::comfyui::ComfyUIConfig::default() ).map_err(|e| format!("创建ComfyUI管理器失败: {}", e))?), repository.clone(), None )); let queue_manager = Arc::new(crate::business::services::queue_manager::QueueManager::new( repository.clone(), None )); let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; crate::business::services::comfyui_v2_service::ComfyUIV2Service::new( repository.clone(), realtime_monitor, queue_manager, template_engine, ) }; // 调用服务层更新工作流 match comfyui_service.update_workflow(request.id.clone(), request).await { Ok(workflow) => { info!("工作流更新成功: {}", workflow.id); Ok(convert_workflow_model(&workflow)) } Err(e) => { error!("更新工作流失败: {}", e); Err(format!("更新工作流失败: {}", e)) } } } /// 删除工作流请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeleteWorkflowRequest { #[serde(rename = "workflowId")] pub workflow_id: String, } /// 删除工作流(实际删除模板,因为模板和工作流是同一概念) #[tauri::command] pub async fn comfyui_v2_delete_workflow( request: DeleteWorkflowRequest, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_delete_workflow - {}", request.workflow_id); let service_manager = get_service_manager(&state).await?; let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; // 删除模板(模板和工作流是同一概念) template_engine.delete_template(&request.workflow_id).await .map_err(|e| format!("删除工作流失败: {}", e))?; Ok("工作流删除成功".to_string()) } /// 调试:列出所有工作流 #[tauri::command] pub async fn comfyui_v2_debug_list_workflows( state: State<'_, AppState>, ) -> Result, String> { info!("Command: comfyui_v2_debug_list_workflows"); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 获取所有工作流(包括禁用的) let workflows = repository.list_workflows(false) .map_err(|e| format!("获取工作流列表失败: {}", e))?; let workflow_responses: Vec = workflows.into_iter() .map(|workflow| convert_workflow_model(&workflow)) .collect(); info!("找到 {} 个工作流", workflow_responses.len()); Ok(workflow_responses) } /// 批量删除工作流 #[tauri::command] pub async fn comfyui_v2_batch_delete_workflows( request: BatchDeleteWorkflowsRequest, state: State<'_, AppState>, ) -> Result, String> { info!("Command: comfyui_v2_batch_delete_workflows - {} 个工作流", request.workflow_ids.len()); let service_manager = get_service_manager(&state).await?; let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; let mut results = Vec::new(); let mut errors = Vec::new(); // 逐个删除工作流 for workflow_id in request.workflow_ids { match template_engine.delete_template(&workflow_id).await { Ok(_) => { results.push(format!("工作流删除成功: {}", workflow_id)); info!("工作流删除成功: {}", workflow_id); } Err(e) => { let error_msg = format!("删除工作流失败 {}: {}", workflow_id, e); errors.push(error_msg.clone()); error!("{}", error_msg); } } } // 如果有错误,返回错误信息 if !errors.is_empty() { return Err(format!("批量删除部分失败: {}", errors.join("; "))); } Ok(results) } /// 按分类获取工作流 #[tauri::command] pub async fn comfyui_v2_get_workflows_by_category( category: String, state: State<'_, AppState>, ) -> Result, String> { info!("Command: comfyui_v2_get_workflows_by_category - {}", category); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 直接使用仓库按分类获取工作流 match repository.get_workflows_by_category(&category) { Ok(workflows) => { info!("分类 {} 下有 {} 个工作流", category, workflows.len()); let responses = workflows.iter().map(convert_workflow_model).collect(); Ok(responses) } Err(e) => { error!("按分类获取工作流失败: {}", e); Err(format!("按分类获取工作流失败: {}", e)) } } } /// 搜索工作流 #[tauri::command] pub async fn comfyui_v2_search_workflows( query: String, state: State<'_, AppState>, ) -> Result, String> { info!("Command: comfyui_v2_search_workflows - {}", query); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 直接使用仓库搜索工作流 match repository.search_workflows(&query) { Ok(workflows) => { info!("搜索到 {} 个工作流", workflows.len()); let responses = workflows.iter().map(convert_workflow_model).collect(); Ok(responses) } Err(e) => { error!("搜索工作流失败: {}", e); Err(format!("搜索工作流失败: {}", e)) } } } /// 导出工作流 #[tauri::command] pub async fn comfyui_v2_export_workflows( request: ExportWorkflowRequest, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_export_workflows - {} 个工作流", request.workflow_ids.len()); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); let mut exported_workflows = Vec::new(); let mut errors = Vec::new(); // 逐个获取工作流数据 for workflow_id in request.workflow_ids { match repository.get_workflow(&workflow_id) { Ok(Some(workflow)) => { let mut export_data = serde_json::json!({ "id": workflow.id, "name": workflow.name, "description": workflow.description, "workflow_data": workflow.workflow_data, "version": workflow.version, "tags": workflow.tags, "category": workflow.category, }); // 如果包含元数据,添加时间戳等信息 if request.include_metadata.unwrap_or(true) { export_data["created_at"] = serde_json::Value::String(workflow.created_at.to_rfc3339()); export_data["updated_at"] = serde_json::Value::String(workflow.updated_at.to_rfc3339()); export_data["enabled"] = serde_json::Value::Bool(workflow.enabled); } exported_workflows.push(export_data); } Ok(None) => { errors.push(format!("工作流不存在: {}", workflow_id)); } Err(e) => { errors.push(format!("获取工作流失败 {}: {}", workflow_id, e)); } } } let result = serde_json::json!({ "workflows": exported_workflows, "export_time": chrono::Utc::now().to_rfc3339(), "total_count": exported_workflows.len(), "errors": errors }); info!("成功导出 {} 个工作流", exported_workflows.len()); Ok(result) } /// 导入工作流 #[tauri::command] pub async fn comfyui_v2_import_workflows( request: ImportWorkflowRequest, state: State<'_, AppState>, ) -> Result { info!("Command: comfyui_v2_import_workflows"); let service_manager = get_service_manager(&state).await?; let repository = service_manager.get_repository(); // 解析导入数据 let import_data = request.workflow_data; let workflows_array = import_data.get("workflows") .and_then(|v| v.as_array()) .ok_or_else(|| "导入数据格式错误:缺少workflows数组".to_string())?; let mut imported_count = 0; let mut skipped_count = 0; let mut errors = Vec::new(); for workflow_data in workflows_array { // 解析工作流数据 let name = workflow_data.get("name") .and_then(|v| v.as_str()) .ok_or_else(|| "工作流缺少name字段".to_string())?; let description = workflow_data.get("description") .and_then(|v| v.as_str()) .map(|s| s.to_string()); let workflow_json = workflow_data.get("workflow_data") .ok_or_else(|| "工作流缺少workflow_data字段".to_string())? .clone(); let tags = workflow_data.get("tags") .and_then(|v| v.as_array()) .map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()); // 检查是否已存在同名工作流 let existing_workflows = repository.list_workflows(false) .map_err(|e| format!("检查现有工作流失败: {}", e))?; let name_exists = existing_workflows.iter().any(|w| w.name == name); if name_exists && !request.overwrite_existing.unwrap_or(false) { skipped_count += 1; continue; } // 创建工作流请求 let create_request = CreateWorkflowRequest { name: name.to_string(), description, workflow_json, tags, }; // 创建ComfyUI V2服务实例并创建工作流 let comfyui_service = { let realtime_monitor = Arc::new(crate::business::services::realtime_monitor_v2::RealtimeMonitorV2::new( Arc::new(crate::business::services::comfyui_manager::ComfyUIManager::new( crate::data::models::comfyui::ComfyUIConfig::default() ).map_err(|e| format!("创建ComfyUI管理器失败: {}", e))?), repository.clone(), None )); let queue_manager = Arc::new(crate::business::services::queue_manager::QueueManager::new( repository.clone(), None )); let template_engine = service_manager.get_template_engine().await .map_err(|e| format!("获取模板引擎失败: {}", e))?; crate::business::services::comfyui_v2_service::ComfyUIV2Service::new( repository.clone(), realtime_monitor, queue_manager, template_engine, ) }; match comfyui_service.create_workflow(create_request).await { Ok(_) => { imported_count += 1; info!("成功导入工作流: {}", name); } Err(e) => { errors.push(format!("导入工作流失败 {}: {}", name, e)); error!("导入工作流失败 {}: {}", name, e); } } } let result = serde_json::json!({ "imported_count": imported_count, "skipped_count": skipped_count, "total_count": workflows_array.len(), "errors": errors, "import_time": chrono::Utc::now().to_rfc3339() }); info!("导入完成:成功 {} 个,跳过 {} 个", imported_count, skipped_count); Ok(result) } /// 转换工作流模型为响应 fn convert_workflow_model(workflow: &WorkflowModel) -> WorkflowResponse { WorkflowResponse { id: workflow.id.clone(), name: workflow.name.clone(), description: workflow.description.clone(), workflow_data: workflow.workflow_data.iter() .map(|(k, v)| (k.clone(), serde_json::to_value(v).unwrap_or(serde_json::Value::Null))) .collect(), version: workflow.version.clone(), created_at: workflow.created_at.to_rfc3339(), updated_at: workflow.updated_at.to_rfc3339(), enabled: workflow.enabled, tags: workflow.tags.clone(), category: workflow.category.clone(), } } /// 转换模板模型为工作流响应(因为模板和工作流是同一概念) fn convert_template_to_workflow_response(template: &crate::data::models::comfyui::TemplateModel) -> WorkflowResponse { WorkflowResponse { id: template.id.clone(), name: template.name.clone(), description: template.description.clone(), workflow_data: template.template_data.workflow.iter() .map(|(k, v)| (k.clone(), serde_json::to_value(v).unwrap_or(serde_json::Value::Null))) .collect(), version: template.version.clone(), created_at: template.created_at.to_rfc3339(), updated_at: template.updated_at.to_rfc3339(), enabled: template.enabled, tags: template.tags.clone(), category: template.category.clone(), } }