From 3c247b2d3bb3c090c02b7f903e7a2ce471a19f1d Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 8 Aug 2025 13:52:49 +0800 Subject: [PATCH] fix: sdk --- .../services/comfyui_integration_service.rs | 328 ++++++++++++++++++ .../src-tauri/src/business/services/mod.rs | 2 + apps/desktop/src-tauri/src/config.rs | 51 +++ 3 files changed, 381 insertions(+) create mode 100644 apps/desktop/src-tauri/src/business/services/comfyui_integration_service.rs diff --git a/apps/desktop/src-tauri/src/business/services/comfyui_integration_service.rs b/apps/desktop/src-tauri/src/business/services/comfyui_integration_service.rs new file mode 100644 index 0000000..448e259 --- /dev/null +++ b/apps/desktop/src-tauri/src/business/services/comfyui_integration_service.rs @@ -0,0 +1,328 @@ +use anyhow::{Result, anyhow}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Duration; +use tracing::{info, warn, error, debug}; + +use crate::config::ComfyUISettings; +use crate::business::services::comfyui_service::ComfyUIService; +use crate::business::services::comfyui_sdk_service::{ComfyUISDKService, WorkflowExecutionResult, SDKExecutionConfig}; +use crate::data::models::outfit_photo_generation::{WorkflowProgress, WorkflowNodeReplacement}; + +/// ComfyUI 集成服务 +/// 提供统一的接口,可以选择使用原生实现或 SDK 实现 +pub struct ComfyUIIntegrationService { + legacy_service: Arc, + sdk_service: Option>, + use_sdk: bool, + settings: ComfyUISettings, +} + +/// 集成服务配置 +#[derive(Debug, Clone)] +pub struct IntegrationConfig { + pub prefer_sdk: bool, + pub fallback_to_legacy: bool, + pub timeout: Duration, + pub retry_attempts: u32, +} + +impl Default for IntegrationConfig { + fn default() -> Self { + Self { + prefer_sdk: true, + fallback_to_legacy: true, + timeout: Duration::from_secs(300), + retry_attempts: 3, + } + } +} + +/// 统一的工作流执行结果 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UnifiedWorkflowResult { + pub prompt_id: String, + pub outputs: HashMap>, + pub execution_time: Duration, + pub node_outputs: HashMap, + pub used_sdk: bool, +} + +impl ComfyUIIntegrationService { + /// 创建新的集成服务实例 + pub async fn new(settings: ComfyUISettings, config: IntegrationConfig) -> Result { + // 创建传统服务 + let legacy_service = Arc::new(ComfyUIService::new(settings.clone()).await?); + + // 尝试创建 SDK 服务 + let sdk_service = if config.prefer_sdk { + match ComfyUISDKService::new(settings.clone()) { + Ok(service) => { + info!("ComfyUI SDK 服务初始化成功"); + Some(Arc::new(service)) + } + Err(e) => { + warn!("ComfyUI SDK 服务初始化失败: {}, 将使用传统服务", e); + None + } + } + } else { + None + }; + + let use_sdk = sdk_service.is_some() && config.prefer_sdk; + + Ok(Self { + legacy_service, + sdk_service, + use_sdk, + settings, + }) + } + + /// 检查服务健康状态 + pub async fn check_health(&self) -> Result { + if self.use_sdk { + if let Some(sdk_service) = &self.sdk_service { + match sdk_service.check_health().await { + Ok(healthy) => return Ok(healthy), + Err(e) => { + warn!("SDK 健康检查失败,尝试传统服务: {}", e); + } + } + } + } + + // 回退到传统服务 + self.legacy_service.check_health().await + } + + /// 执行工作流(统一接口) + pub async fn execute_workflow( + &self, + workflow: Value, + replacements: Vec, + config: IntegrationConfig, + ) -> Result { + // 应用节点替换 + let processed_workflow = self.apply_replacements(workflow, replacements)?; + + // 优先使用 SDK + if self.use_sdk { + if let Some(sdk_service) = &self.sdk_service { + match self.execute_with_sdk(sdk_service.clone(), processed_workflow.clone(), &config).await { + Ok(result) => { + info!("使用 SDK 成功执行工作流"); + return Ok(UnifiedWorkflowResult { + prompt_id: result.prompt_id, + outputs: result.outputs, + execution_time: result.execution_time, + node_outputs: result.node_outputs, + used_sdk: true, + }); + } + Err(e) => { + warn!("SDK 执行失败: {}", e); + if !config.fallback_to_legacy { + return Err(e); + } + } + } + } + } + + // 回退到传统服务 + info!("使用传统服务执行工作流"); + let result = self.execute_with_legacy(processed_workflow, &config).await?; + + Ok(UnifiedWorkflowResult { + prompt_id: result.prompt_id, + outputs: result.outputs, + execution_time: result.execution_time, + node_outputs: result.node_outputs, + used_sdk: false, + }) + } + + /// 使用 SDK 执行工作流 + async fn execute_with_sdk( + &self, + sdk_service: Arc, + workflow: Value, + config: &IntegrationConfig, + ) -> Result { + let sdk_config = SDKExecutionConfig { + timeout: config.timeout, + retry_attempts: config.retry_attempts, + progress_callback: None, // 可以根据需要添加进度回调 + }; + + sdk_service.execute_workflow(workflow, sdk_config).await + } + + /// 使用传统服务执行工作流 + async fn execute_with_legacy( + &self, + workflow: Value, + config: &IntegrationConfig, + ) -> Result { + // 这里需要调用传统服务的执行方法 + // 由于原始的 ComfyUIService 可能没有统一的执行接口,我们需要适配 + + let start_time = std::time::Instant::now(); + + // 提交工作流 + let prompt_id = self.legacy_service.submit_workflow(workflow).await?; + + // 等待完成(这里需要根据实际的传统服务接口来实现) + let outputs = self.legacy_service.wait_for_completion(&prompt_id, config.timeout).await?; + + let execution_time = start_time.elapsed(); + + Ok(LegacyWorkflowResult { + prompt_id, + outputs, + execution_time, + node_outputs: HashMap::new(), // 传统服务可能不提供详细的节点输出 + }) + } + + /// 应用节点替换 + fn apply_replacements( + &self, + mut workflow: Value, + replacements: Vec, + ) -> Result { + for replacement in replacements { + if let Some(node) = workflow.get_mut(&replacement.node_id) { + if let Some(inputs) = node.get_mut("inputs") { + if let Some(inputs_obj) = inputs.as_object_mut() { + inputs_obj.insert(replacement.field_name, replacement.new_value); + } + } + } + } + Ok(workflow) + } + + /// 获取队列状态 + pub async fn get_queue_status(&self) -> Result { + if self.use_sdk { + if let Some(sdk_service) = &self.sdk_service { + match sdk_service.get_queue_status().await { + Ok(status) => { + return Ok(QueueStatusInfo { + running: status.running, + pending: status.pending, + from_sdk: true, + }); + } + Err(e) => { + warn!("SDK 获取队列状态失败: {}", e); + } + } + } + } + + // 回退到传统服务 + let status = self.legacy_service.get_queue_status().await?; + Ok(QueueStatusInfo { + running: status.running, + pending: status.pending, + from_sdk: false, + }) + } + + /// 取消工作流执行 + pub async fn cancel_workflow(&self, prompt_id: &str) -> Result<()> { + if self.use_sdk { + if let Some(sdk_service) = &self.sdk_service { + if let Ok(_) = sdk_service.cancel_workflow(prompt_id).await { + return Ok(()); + } + } + } + + // 回退到传统服务 + self.legacy_service.cancel_workflow(prompt_id).await + } + + /// 切换到 SDK 模式 + pub async fn switch_to_sdk(&mut self) -> Result<()> { + if self.sdk_service.is_none() { + let sdk_service = ComfyUISDKService::new(self.settings.clone())?; + self.sdk_service = Some(Arc::new(sdk_service)); + } + self.use_sdk = true; + info!("已切换到 SDK 模式"); + Ok(()) + } + + /// 切换到传统模式 + pub fn switch_to_legacy(&mut self) { + self.use_sdk = false; + info!("已切换到传统模式"); + } + + /// 获取当前使用的服务类型 + pub fn get_current_service_type(&self) -> &'static str { + if self.use_sdk && self.sdk_service.is_some() { + "SDK" + } else { + "Legacy" + } + } +} + +/// 传统服务工作流结果 +#[derive(Debug)] +struct LegacyWorkflowResult { + prompt_id: String, + outputs: HashMap>, + execution_time: Duration, + node_outputs: HashMap, +} + +/// 队列状态信息 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct QueueStatusInfo { + pub running: usize, + pub pending: usize, + pub from_sdk: bool, +} + +// 为了编译通过,我们需要为传统服务添加一些方法的扩展 +// 这些方法需要在实际的 ComfyUIService 中实现 +impl ComfyUIService { + /// 提交工作流(需要在实际服务中实现) + pub async fn submit_workflow(&self, _workflow: Value) -> Result { + // 这里需要调用实际的提交方法 + todo!("需要在 ComfyUIService 中实现 submit_workflow 方法") + } + + /// 等待完成(需要在实际服务中实现) + pub async fn wait_for_completion(&self, _prompt_id: &str, _timeout: Duration) -> Result>> { + // 这里需要调用实际的等待方法 + todo!("需要在 ComfyUIService 中实现 wait_for_completion 方法") + } + + /// 获取队列状态(需要在实际服务中实现) + pub async fn get_queue_status(&self) -> Result { + // 这里需要调用实际的队列状态方法 + todo!("需要在 ComfyUIService 中实现 get_queue_status 方法") + } + + /// 取消工作流(需要在实际服务中实现) + pub async fn cancel_workflow(&self, _prompt_id: &str) -> Result<()> { + // 这里需要调用实际的取消方法 + todo!("需要在 ComfyUIService 中实现 cancel_workflow 方法") + } + + /// 检查健康状态(需要在实际服务中实现) + pub async fn check_health(&self) -> Result { + // 这里需要调用实际的健康检查方法 + todo!("需要在 ComfyUIService 中实现 check_health 方法") + } +} diff --git a/apps/desktop/src-tauri/src/business/services/mod.rs b/apps/desktop/src-tauri/src/business/services/mod.rs index 0b811fc..c3b6b42 100644 --- a/apps/desktop/src-tauri/src/business/services/mod.rs +++ b/apps/desktop/src-tauri/src/business/services/mod.rs @@ -36,6 +36,8 @@ pub mod jianying_export; pub mod template_segment_weight_service; pub mod directory_settings_service; pub mod comfyui_service; +pub mod comfyui_sdk_service; +pub mod comfyui_integration_service; pub mod outfit_photo_generation_service; pub mod workflow_management_service; pub mod error_handling_service; diff --git a/apps/desktop/src-tauri/src/config.rs b/apps/desktop/src-tauri/src/config.rs index 7998d9f..65c4402 100644 --- a/apps/desktop/src-tauri/src/config.rs +++ b/apps/desktop/src-tauri/src/config.rs @@ -51,6 +51,26 @@ pub struct ComfyUISettings { pub workflow_directory: Option, /// 输出文件存储目录 pub output_directory: Option, + /// SDK 配置 + pub sdk_config: ComfyUISDKConfig, +} + +/// ComfyUI SDK 配置 +/// 控制 SDK 的使用和行为 +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ComfyUISDKConfig { + /// 是否优先使用 SDK + pub prefer_sdk: bool, + /// 当 SDK 失败时是否回退到传统实现 + pub fallback_to_legacy: bool, + /// SDK 执行超时时间(秒) + pub sdk_timeout_seconds: u64, + /// SDK 重试次数 + pub sdk_retry_attempts: u32, + /// 是否启用详细日志 + pub enable_verbose_logging: bool, + /// 是否启用进度回调 + pub enable_progress_callback: bool, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -72,6 +92,19 @@ impl Default for DirectorySettings { } } +impl Default for ComfyUISDKConfig { + fn default() -> Self { + ComfyUISDKConfig { + prefer_sdk: true, + fallback_to_legacy: true, + sdk_timeout_seconds: 300, + sdk_retry_attempts: 3, + enable_verbose_logging: false, + enable_progress_callback: true, + } + } +} + impl Default for ComfyUISettings { fn default() -> Self { ComfyUISettings { @@ -82,10 +115,28 @@ impl Default for ComfyUISettings { enabled: false, workflow_directory: None, output_directory: None, + sdk_config: ComfyUISDKConfig::default(), } } } +impl ComfyUISettings { + /// 获取完整的 ComfyUI 服务 URL + pub fn base_url(&self) -> String { + format!("http://{}:{}", self.server_address, self.server_port) + } + + /// 检查是否启用了 SDK + pub fn is_sdk_enabled(&self) -> bool { + self.enabled && self.sdk_config.prefer_sdk + } + + /// 获取 SDK 超时时间 + pub fn get_sdk_timeout(&self) -> std::time::Duration { + std::time::Duration::from_secs(self.sdk_config.sdk_timeout_seconds) + } +} + impl Default for AppConfig { fn default() -> Self { AppConfig {