(null);
+ const [connectionStatus, setConnectionStatus] = useState<'unknown' | 'connected' | 'failed'>('unknown');
+
+ // 加载模特信息
+ const loadModel = useCallback(async () => {
+ if (!modelId) {
+ setError('未指定模特ID');
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ setError(null);
+
+ const modelData = await modelService.getModelById(modelId);
+ setModel(modelData);
+ } catch (err) {
+ console.error('加载模特信息失败:', err);
+ setError(err instanceof Error ? err.message : '加载模特信息失败');
+ } finally {
+ setLoading(false);
+ }
+ }, [modelId]);
+
+ // 加载 ComfyUI 设置
+ const loadComfyUISettings = useCallback(async () => {
+ try {
+ const settings = await OutfitPhotoGenerationService.getComfyUISettings();
+ setComfyUISettings(settings);
+
+ // 如果启用了 ComfyUI,测试连接
+ if (settings.enabled) {
+ const connected = await OutfitPhotoGenerationService.testComfyUIConnection();
+ setConnectionStatus(connected ? 'connected' : 'failed');
+ }
+ } catch (err) {
+ console.error('加载 ComfyUI 设置失败:', err);
+ }
+ }, []);
+
+ // 初始加载
+ useEffect(() => {
+ loadModel();
+ loadComfyUISettings();
+ }, [loadModel, loadComfyUISettings]);
+
+ // 处理生成完成
+ const handleGenerationComplete = useCallback((response: OutfitPhotoGenerationResponse) => {
+ console.log('生成完成:', response);
+ // 切换到历史记录标签页查看结果
+ setActiveTab('history');
+ }, []);
+
+ // 处理重试生成
+ const handleRetryGeneration = useCallback((generationId: string) => {
+ console.log('重试生成:', generationId);
+ // 可以在这里添加重试逻辑或通知
+ }, []);
+
+ // 处理设置变更
+ const handleSettingsChange = useCallback((settings: ComfyUISettings) => {
+ setComfyUISettings(settings);
+ // 重新测试连接
+ if (settings.enabled) {
+ OutfitPhotoGenerationService.testComfyUIConnection().then(connected => {
+ setConnectionStatus(connected ? 'connected' : 'failed');
+ });
+ } else {
+ setConnectionStatus('unknown');
+ }
+ }, []);
+
+ // 返回上一页
+ const handleGoBack = useCallback(() => {
+ if (projectId) {
+ navigate(`/projects/${projectId}`);
+ } else if (modelId) {
+ navigate(`/models/${modelId}`);
+ } else {
+ navigate('/models');
+ }
+ }, [navigate, projectId, modelId]);
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
+
加载失败
+
{error}
+
+
+
+ );
+ }
+
+ if (!model) {
+ return (
+
+
+
+
模特不存在
+
未找到指定的模特信息
+
+
+
+ );
+ }
+
+ return (
+
+ {/* 头部导航 */}
+
+
+
+
+
+
+
+
+
+ 穿搭照片生成
+
+
+ 模特: {model.name}
+ {projectId && ` • 项目: ${projectId}`}
+
+
+
+
+ {/* 连接状态指示器 */}
+
+ {comfyUISettings?.enabled && (
+
+ {connectionStatus === 'connected' ? (
+ <>
+
+ ComfyUI 已连接
+ >
+ ) : connectionStatus === 'failed' ? (
+ <>
+
+ ComfyUI 连接失败
+ >
+ ) : (
+ <>
+
+ ComfyUI 状态未知
+ >
+ )}
+
+ )}
+
+ {!comfyUISettings?.enabled && (
+
+ )}
+
+
+
+
+
+ {/* 主要内容 */}
+
+ {/* 标签页导航 */}
+
+
+
+
+ {/* 标签页内容 */}
+
+ {activeTab === 'generator' && (
+
+ {!comfyUISettings?.enabled ? (
+
+
+
ComfyUI 未启用
+
+ 请先在设置页面启用并配置 ComfyUI 服务器连接
+
+
+
+ ) : connectionStatus === 'failed' ? (
+
+
+
ComfyUI 连接失败
+
+ 无法连接到 ComfyUI 服务器,请检查服务器状态和网络连接
+
+
+
+ ) : (
+
+ )}
+
+ )}
+
+ {activeTab === 'history' && (
+
+ )}
+
+ {activeTab === 'settings' && (
+
+ )}
+
+
+
+ );
+};
diff --git a/apps/desktop/src/pages/Settings.tsx b/apps/desktop/src/pages/Settings.tsx
index b105af2..2949fe9 100644
--- a/apps/desktop/src/pages/Settings.tsx
+++ b/apps/desktop/src/pages/Settings.tsx
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { ScreenAdaptationSettings } from '../components/ScreenAdaptationSettings';
+import { ComfyUISettingsPanel } from '../components/outfit/ComfyUISettingsPanel';
/**
* 设置页面
@@ -68,6 +69,17 @@ const Settings: React.FC = () => {
+ {/* ComfyUI 设置 */}
+
+
+
穿搭照片生成
+
配置 ComfyUI 服务器连接和生成参数
+
+
+
+
+
+
{/* 通知设置 */}
通知设置
diff --git a/apps/desktop/src/services/outfitPhotoGenerationService.ts b/apps/desktop/src/services/outfitPhotoGenerationService.ts
new file mode 100644
index 0000000..1c030d8
--- /dev/null
+++ b/apps/desktop/src/services/outfitPhotoGenerationService.ts
@@ -0,0 +1,274 @@
+/**
+ * 穿搭照片生成服务
+ * 基于 ComfyUI 工作流的穿搭照片生成功能
+ */
+
+import { invoke } from '@tauri-apps/api/core';
+import { listen } from '@tauri-apps/api/event';
+import type {
+ OutfitPhotoGenerationRequest,
+ OutfitPhotoGenerationResponse,
+ GenerationHistoryQuery,
+ GenerationHistoryResponse,
+ ComfyUISettings,
+ CloudUploadStatistics,
+ WorkflowProgress,
+ BatchGenerationProgress,
+ WorkflowTemplate,
+ GenerationPreset
+} from '../types/outfitPhotoGeneration';
+
+export class OutfitPhotoGenerationService {
+ /**
+ * 创建穿搭照片生成任务
+ */
+ static async createGenerationTask(request: OutfitPhotoGenerationRequest): Promise {
+ try {
+ const taskId = await invoke('create_outfit_photo_generation_task', { request });
+ return taskId;
+ } catch (error) {
+ console.error('创建穿搭照片生成任务失败:', error);
+ throw new Error(`创建生成任务失败: ${error}`);
+ }
+ }
+
+ /**
+ * 执行穿搭照片生成
+ */
+ static async executeGeneration(
+ generationId: string,
+ onProgress?: (progress: WorkflowProgress) => void
+ ): Promise {
+ try {
+ // 监听进度事件
+ let progressUnlisten: (() => void) | null = null;
+ if (onProgress) {
+ progressUnlisten = await listen('outfit_generation_progress', (event) => {
+ if (event.payload) {
+ onProgress(event.payload);
+ }
+ });
+ }
+
+ const response = await invoke('execute_outfit_photo_generation', {
+ generationId
+ });
+
+ // 清理进度监听器
+ if (progressUnlisten) {
+ progressUnlisten();
+ }
+
+ return response;
+ } catch (error) {
+ console.error('执行穿搭照片生成失败:', error);
+ throw new Error(`生成失败: ${error}`);
+ }
+ }
+
+ /**
+ * 批量执行穿搭照片生成
+ */
+ static async executeBatchGeneration(
+ requests: OutfitPhotoGenerationRequest[],
+ onProgress?: (progress: BatchGenerationProgress) => void
+ ): Promise {
+ try {
+ // 监听批量进度事件
+ let progressUnlisten: (() => void) | null = null;
+ if (onProgress) {
+ progressUnlisten = await listen('outfit_generation_batch_progress', (event) => {
+ if (event.payload) {
+ onProgress(event.payload);
+ }
+ });
+ }
+
+ const responses = await invoke('execute_outfit_photo_generation_batch', {
+ requests
+ });
+
+ // 清理进度监听器
+ if (progressUnlisten) {
+ progressUnlisten();
+ }
+
+ return responses;
+ } catch (error) {
+ console.error('批量执行穿搭照片生成失败:', error);
+ throw new Error(`批量生成失败: ${error}`);
+ }
+ }
+
+ /**
+ * 重试失败的穿搭照片生成
+ */
+ static async retryGeneration(generationId: string): Promise {
+ try {
+ const response = await invoke('retry_outfit_photo_generation', {
+ generationId
+ });
+ return response;
+ } catch (error) {
+ console.error('重试穿搭照片生成失败:', error);
+ throw new Error(`重试失败: ${error}`);
+ }
+ }
+
+ /**
+ * 获取生成历史记录
+ */
+ static async getGenerationHistory(query: GenerationHistoryQuery): Promise {
+ try {
+ const response = await invoke('get_outfit_photo_generation_history', {
+ query
+ });
+ return response;
+ } catch (error) {
+ console.error('获取生成历史记录失败:', error);
+ throw new Error(`获取历史记录失败: ${error}`);
+ }
+ }
+
+ /**
+ * 删除生成记录
+ */
+ static async deleteGeneration(generationId: string): Promise {
+ try {
+ await invoke('delete_outfit_photo_generation', { generationId });
+ } catch (error) {
+ console.error('删除生成记录失败:', error);
+ throw new Error(`删除记录失败: ${error}`);
+ }
+ }
+
+ /**
+ * 清理失败的生成记录
+ */
+ static async cleanupFailedGenerations(maxAgeHours: number): Promise {
+ try {
+ const cleanedCount = await invoke('cleanup_failed_outfit_generations', {
+ maxAgeHours
+ });
+ return cleanedCount;
+ } catch (error) {
+ console.error('清理失败记录失败:', error);
+ throw new Error(`清理失败: ${error}`);
+ }
+ }
+
+ /**
+ * 获取 ComfyUI 设置
+ */
+ static async getComfyUISettings(): Promise {
+ try {
+ const settings = await invoke('get_comfyui_settings');
+ return settings;
+ } catch (error) {
+ console.error('获取 ComfyUI 设置失败:', error);
+ throw new Error(`获取设置失败: ${error}`);
+ }
+ }
+
+ /**
+ * 更新 ComfyUI 设置
+ */
+ static async updateComfyUISettings(settings: ComfyUISettings): Promise {
+ try {
+ await invoke('update_comfyui_settings', { settings });
+ } catch (error) {
+ console.error('更新 ComfyUI 设置失败:', error);
+ throw new Error(`更新设置失败: ${error}`);
+ }
+ }
+
+ /**
+ * 测试 ComfyUI 连接
+ */
+ static async testComfyUIConnection(): Promise {
+ try {
+ const connected = await invoke('test_comfyui_connection');
+ return connected;
+ } catch (error) {
+ console.error('测试 ComfyUI 连接失败:', error);
+ return false;
+ }
+ }
+
+ /**
+ * 获取云端上传统计
+ */
+ static async getCloudUploadStatistics(): Promise {
+ try {
+ const statistics = await invoke('get_cloud_upload_statistics');
+ return statistics;
+ } catch (error) {
+ console.error('获取云端上传统计失败:', error);
+ throw new Error(`获取统计失败: ${error}`);
+ }
+ }
+
+ /**
+ * 测试云端上传连接
+ */
+ static async testCloudUploadConnection(): Promise {
+ try {
+ const connected = await invoke('test_cloud_upload_connection');
+ return connected;
+ } catch (error) {
+ console.error('测试云端上传连接失败:', error);
+ return false;
+ }
+ }
+
+ /**
+ * 获取可用的工作流模板
+ */
+ static async getWorkflowTemplates(): Promise {
+ try {
+ const templates = await invoke('get_workflow_templates');
+ return templates;
+ } catch (error) {
+ console.error('获取工作流模板失败:', error);
+ throw new Error(`获取模板失败: ${error}`);
+ }
+ }
+
+ /**
+ * 获取生成预设
+ */
+ static async getGenerationPresets(): Promise {
+ try {
+ const presets = await invoke('get_generation_presets');
+ return presets;
+ } catch (error) {
+ console.error('获取生成预设失败:', error);
+ throw new Error(`获取预设失败: ${error}`);
+ }
+ }
+
+ /**
+ * 保存生成预设
+ */
+ static async saveGenerationPreset(preset: Omit): Promise {
+ try {
+ const presetId = await invoke('save_generation_preset', { preset });
+ return presetId;
+ } catch (error) {
+ console.error('保存生成预设失败:', error);
+ throw new Error(`保存预设失败: ${error}`);
+ }
+ }
+
+ /**
+ * 删除生成预设
+ */
+ static async deleteGenerationPreset(presetId: string): Promise {
+ try {
+ await invoke('delete_generation_preset', { presetId });
+ } catch (error) {
+ console.error('删除生成预设失败:', error);
+ throw new Error(`删除预设失败: ${error}`);
+ }
+ }
+}
diff --git a/apps/desktop/src/types/outfitPhotoGeneration.ts b/apps/desktop/src/types/outfitPhotoGeneration.ts
new file mode 100644
index 0000000..9047f0c
--- /dev/null
+++ b/apps/desktop/src/types/outfitPhotoGeneration.ts
@@ -0,0 +1,196 @@
+/**
+ * 穿搭照片生成相关类型定义
+ * 基于 ComfyUI 工作流的穿搭照片生成功能
+ */
+
+// 生成状态枚举
+export enum GenerationStatus {
+ Pending = "Pending",
+ Processing = "Processing",
+ Completed = "Completed",
+ Failed = "Failed"
+}
+
+// 工作流进度信息
+export interface WorkflowProgress {
+ stage: string;
+ progress: number;
+ message?: string;
+ current_step?: number;
+ total_steps?: number;
+}
+
+// 工作流配置
+export interface WorkflowConfig {
+ workflow_file_path: string;
+ steps?: number;
+ cfg_scale?: number;
+ seed?: number;
+ sampler?: string;
+ scheduler?: string;
+ denoise?: number;
+}
+
+// 穿搭照片生成请求
+export interface OutfitPhotoGenerationRequest {
+ project_id: string;
+ model_id: string;
+ product_image_path: string;
+ prompt: string;
+ negative_prompt?: string;
+ workflow_config?: WorkflowConfig;
+}
+
+// 穿搭照片生成响应
+export interface OutfitPhotoGenerationResponse {
+ id: string;
+ status: GenerationStatus;
+ result_image_urls: string[];
+ error_message?: string;
+ generation_time_ms?: number;
+}
+
+// 穿搭照片生成记录(完整数据)
+export interface OutfitPhotoGeneration {
+ id: string;
+ project_id: string;
+ model_id: string;
+ product_image_path: string;
+ product_image_url?: string;
+ prompt: string;
+ negative_prompt?: string;
+ status: GenerationStatus;
+ workflow_id?: string;
+ comfyui_prompt_id?: string;
+ result_image_paths: string[];
+ result_image_urls: string[];
+ error_message?: string;
+ started_at: string;
+ completed_at?: string;
+ generation_time_ms?: number;
+ created_at: string;
+ updated_at: string;
+}
+
+// 批量生成进度信息
+export interface BatchGenerationProgress {
+ current_index: number;
+ total_count: number;
+ current_progress: WorkflowProgress;
+ completed_count: number;
+ failed_count: number;
+}
+
+// ComfyUI 设置
+export interface ComfyUISettings {
+ server_address: string;
+ server_port: number;
+ is_local: boolean;
+ timeout_seconds: number;
+ enabled: boolean;
+ workflow_directory?: string;
+ output_directory?: string;
+}
+
+// 云端上传统计
+export interface CloudUploadStatistics {
+ total_uploads: number;
+ successful_uploads: number;
+ failed_uploads: number;
+ pending_uploads: number;
+ total_size_bytes: number;
+ average_upload_time_ms: number;
+ last_upload_time?: string;
+}
+
+// 生成历史记录查询参数
+export interface GenerationHistoryQuery {
+ project_id?: string;
+ model_id?: string;
+ status?: GenerationStatus;
+ start_date?: string;
+ end_date?: string;
+ page?: number;
+ page_size?: number;
+}
+
+// 生成历史记录响应
+export interface GenerationHistoryResponse {
+ records: OutfitPhotoGeneration[];
+ total_count: number;
+ page: number;
+ page_size: number;
+ has_more: boolean;
+}
+
+// 工作流模板信息
+export interface WorkflowTemplate {
+ id: string;
+ name: string;
+ description?: string;
+ file_path: string;
+ preview_image?: string;
+ default_config: WorkflowConfig;
+ supported_features: string[];
+ created_at: string;
+ updated_at: string;
+}
+
+// 生成预设
+export interface GenerationPreset {
+ id: string;
+ name: string;
+ description?: string;
+ workflow_config: WorkflowConfig;
+ default_prompt: string;
+ default_negative_prompt?: string;
+ tags: string[];
+ is_favorite: boolean;
+ created_at: string;
+ updated_at: string;
+}
+
+// 模特图片选择项
+export interface ModelImageOption {
+ id: string;
+ model_id: string;
+ image_path: string;
+ image_url?: string;
+ thumbnail_url?: string;
+ description?: string;
+ photo_type: string;
+ is_primary: boolean;
+}
+
+// 商品图片信息
+export interface ProductImageInfo {
+ id: string;
+ file_path: string;
+ file_name: string;
+ file_size: number;
+ mime_type: string;
+ upload_url?: string;
+ thumbnail_url?: string;
+ description?: string;
+ created_at: string;
+}
+
+// 生成任务队列项
+export interface GenerationQueueItem {
+ id: string;
+ request: OutfitPhotoGenerationRequest;
+ priority: number;
+ created_at: string;
+ estimated_duration_ms?: number;
+ dependencies?: string[];
+}
+
+// 生成任务队列状态
+export interface GenerationQueueStatus {
+ total_items: number;
+ pending_items: number;
+ processing_items: number;
+ completed_items: number;
+ failed_items: number;
+ estimated_wait_time_ms?: number;
+}