mixvideo-v2/apps/desktop/src/services/comfyuiV2Service.ts

690 lines
19 KiB
TypeScript

/**
* ComfyUI V2 API 服务层
* 基于新的后端 V2 API 的现代化前端服务接口
*/
import { invoke } from '@tauri-apps/api/core';
import { listen, UnlistenFn } from '@tauri-apps/api/event';
// ==================== 基础类型定义 ====================
export interface ComfyUIV2Config {
base_url: string;
timeout?: number;
retry_attempts?: number;
enable_cache?: boolean;
max_concurrency?: number;
websocket_url?: string;
}
export interface ConnectionStatus {
connected: boolean;
last_connected_at?: string;
last_disconnected_at?: string;
reconnect_attempts: number;
total_connections: number;
error_message?: string;
}
export interface SystemInfo {
version: string;
python_version: string;
platform: string;
gpu_info?: string;
memory_info?: string;
disk_info?: string;
}
export interface QueueStatus {
running_count: number;
pending_count: number;
history_count: number;
}
// ==================== 工作流类型 ====================
export interface WorkflowV2 {
id: string;
name: string;
description?: string;
category?: string;
workflow_data: any;
input_schema?: any;
output_schema?: any;
created_at: string;
updated_at: string;
version: number;
is_active: boolean;
tags: string[];
}
export interface CreateWorkflowRequest {
name: string;
description?: string;
workflow_json: any;
tags?: string[];
}
export interface UpdateWorkflowRequest {
name?: string;
description?: string;
category?: string;
workflow_data?: any;
input_schema?: any;
output_schema?: any;
tags?: string[];
is_active?: boolean;
}
// ==================== 模板类型 ====================
export interface TemplateV2 {
id: string;
name: string;
description?: string;
category?: string;
workflow_id: string;
parameter_definitions: any;
default_values?: any;
created_at: string;
updated_at: string;
version: number;
is_active: boolean;
tags: string[];
}
export interface CreateTemplateRequest {
name: string;
description?: string;
category?: string;
workflow_id: string;
parameter_definitions: any;
default_values?: any;
tags?: string[];
}
// ==================== 执行类型 ====================
export interface ExecutionV2 {
id: string;
workflow_id?: string;
template_id?: string;
prompt_id: string;
parameters: any;
status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
progress?: number;
results?: any;
output_urls?: string[];
error_message?: string;
execution_time?: number;
created_at: string;
updated_at: string;
}
export interface ExecuteWorkflowRequest {
workflow_id: string;
parameters?: any;
}
export interface ExecuteTemplateRequest {
template_id: string;
parameters: any;
}
// ==================== 实时事件类型 ====================
export interface RealtimeEvent {
event_type: string;
data: any;
timestamp: string;
}
export interface ExecutionProgressEvent {
prompt_id: string;
execution_id?: string;
node_id: string;
progress: number;
max_progress: number;
percentage: number;
timestamp: string;
}
export interface ExecutionCompletedEvent {
prompt_id: string;
execution_id?: string;
outputs: Record<string, any>;
output_urls: string[];
execution_time: number;
timestamp: string;
}
// ==================== ComfyUI V2 服务类 ====================
export class ComfyUIV2Service {
private static eventListeners: Map<string, UnlistenFn> = new Map();
// ==================== 连接管理 ====================
/**
* 连接到 ComfyUI 服务
*/
static async connect(config: ComfyUIV2Config): Promise<string> {
try {
const result = await invoke<{connected: boolean, status: string, base_url: string}>('comfyui_v2_connect', { config });
return result.connected ? '连接成功' : '连接失败';
} catch (error) {
console.error('Failed to connect to ComfyUI:', error);
throw new Error(`连接 ComfyUI 失败: ${error}`);
}
}
/**
* 断开 ComfyUI 连接
*/
static async disconnect(): Promise<string> {
try {
return await invoke<string>('comfyui_v2_disconnect');
} catch (error) {
console.error('Failed to disconnect from ComfyUI:', error);
throw new Error(`断开 ComfyUI 连接失败: ${error}`);
}
}
/**
* 获取连接状态
*/
static async getConnectionStatus(): Promise<ConnectionStatus> {
try {
return await invoke<ConnectionStatus>('comfyui_v2_get_connection_status');
} catch (error) {
console.error('Failed to get connection status:', error);
throw new Error(`获取连接状态失败: ${error}`);
}
}
/**
* 健康检查
*/
static async healthCheck(): Promise<boolean> {
try {
const result = await invoke<string>('comfyui_v2_health_check');
return result === 'healthy';
} catch (error) {
console.error('Health check failed:', error);
return false;
}
}
/**
* 获取系统信息
*/
static async getSystemInfo(): Promise<SystemInfo> {
try {
return await invoke<SystemInfo>('comfyui_v2_get_system_info');
} catch (error) {
console.error('Failed to get system info:', error);
throw new Error(`获取系统信息失败: ${error}`);
}
}
/**
* 获取队列状态
*/
static async getQueueStatus(): Promise<QueueStatus> {
try {
return await invoke<QueueStatus>('comfyui_v2_get_queue_status');
} catch (error) {
console.error('Failed to get queue status:', error);
throw new Error(`获取队列状态失败: ${error}`);
}
}
// ==================== 配置管理 ====================
/**
* 获取配置
*/
static async getConfig(): Promise<ComfyUIV2Config> {
try {
return await invoke<ComfyUIV2Config>('comfyui_v2_get_config');
} catch (error) {
console.error('Failed to get config:', error);
throw new Error(`获取配置失败: ${error}`);
}
}
/**
* 更新配置
*/
static async updateConfig(config: Partial<ComfyUIV2Config>): Promise<string> {
try {
// 获取当前配置,然后合并新配置
let currentConfig: ComfyUIV2Config;
try {
currentConfig = await this.getConfig();
} catch {
// 如果获取失败,使用默认配置
currentConfig = {
base_url: 'http://192.168.0.193:8188',
timeout: 30000,
retry_attempts: 3,
enable_cache: true,
max_concurrency: 4,
websocket_url: 'ws://192.168.0.193:8188/ws',
};
}
// 合并配置
const fullConfig: ComfyUIV2Config = {
...currentConfig,
...config,
};
return await invoke<string>('comfyui_v2_update_config', { configRequest: fullConfig });
} catch (error) {
console.error('Failed to update config:', error);
throw new Error(`更新配置失败: ${error}`);
}
}
/**
* 验证配置
*/
static async validateConfig(config: ComfyUIV2Config): Promise<boolean> {
try {
const result = await invoke<string>('comfyui_v2_validate_config', { configRequest: config });
return result === 'valid';
} catch (error) {
console.error('Failed to validate config:', error);
return false;
}
}
// ==================== 工作流管理 ====================
/**
* 创建工作流
*/
static async createWorkflow(request: CreateWorkflowRequest): Promise<WorkflowV2> {
try {
return await invoke<WorkflowV2>('comfyui_v2_create_workflow', { request });
} catch (error) {
console.error('Failed to create workflow:', error);
throw new Error(`创建工作流失败: ${error}`);
}
}
/**
* 获取工作流列表
*/
static async listWorkflows(category?: string, tags?: string[]): Promise<WorkflowV2[]> {
try {
return await invoke<WorkflowV2[]>('comfyui_v2_list_workflows', { category, tags });
} catch (error) {
console.error('Failed to list workflows:', error);
throw new Error(`获取工作流列表失败: ${error}`);
}
}
/**
* 获取单个工作流
*/
static async getWorkflow(id: string): Promise<WorkflowV2> {
try {
return await invoke<WorkflowV2>('comfyui_v2_get_workflow', { id });
} catch (error) {
console.error('Failed to get workflow:', error);
throw new Error(`获取工作流失败: ${error}`);
}
}
/**
* 更新工作流
*/
static async updateWorkflow(id: string, request: UpdateWorkflowRequest): Promise<WorkflowV2> {
try {
return await invoke<WorkflowV2>('comfyui_v2_update_workflow', { id, request });
} catch (error) {
console.error('Failed to update workflow:', error);
throw new Error(`更新工作流失败: ${error}`);
}
}
/**
* 删除工作流
*/
static async deleteWorkflow(id: string): Promise<string> {
try {
return await invoke<string>('comfyui_v2_delete_workflow', { id });
} catch (error) {
console.error('Failed to delete workflow:', error);
throw new Error(`删除工作流失败: ${error}`);
}
}
/**
* 搜索工作流
*/
static async searchWorkflows(query: string, category?: string): Promise<WorkflowV2[]> {
try {
return await invoke<WorkflowV2[]>('comfyui_v2_search_workflows', { query, category });
} catch (error) {
console.error('Failed to search workflows:', error);
throw new Error(`搜索工作流失败: ${error}`);
}
}
// ==================== 模板管理 ====================
/**
* 创建模板
*/
static async createTemplate(request: CreateTemplateRequest): Promise<TemplateV2> {
try {
return await invoke<TemplateV2>('comfyui_v2_create_template', { request });
} catch (error) {
console.error('Failed to create template:', error);
throw new Error(`创建模板失败: ${error}`);
}
}
/**
* 获取模板列表
*/
static async listTemplates(category?: string, tags?: string[]): Promise<TemplateV2[]> {
try {
return await invoke<TemplateV2[]>('comfyui_v2_list_templates', { category, tags });
} catch (error) {
console.error('Failed to list templates:', error);
throw new Error(`获取模板列表失败: ${error}`);
}
}
/**
* 获取单个模板
*/
static async getTemplate(id: string): Promise<TemplateV2> {
try {
return await invoke<TemplateV2>('comfyui_v2_get_template', { id });
} catch (error) {
console.error('Failed to get template:', error);
throw new Error(`获取模板失败: ${error}`);
}
}
/**
* 删除模板
*/
static async deleteTemplate(id: string): Promise<string> {
try {
return await invoke<string>('comfyui_v2_delete_template', { id });
} catch (error) {
console.error('Failed to delete template:', error);
throw new Error(`删除模板失败: ${error}`);
}
}
/**
* 预览模板实例
*/
static async previewTemplateInstance(templateId: string, parameters: any): Promise<any> {
try {
return await invoke<any>('comfyui_v2_preview_template_instance', { templateId, parameters });
} catch (error) {
console.error('Failed to preview template instance:', error);
throw new Error(`预览模板实例失败: ${error}`);
}
}
/**
* 验证模板参数
*/
static async validateTemplateParameters(templateId: string, parameters: any): Promise<boolean> {
try {
const result = await invoke<string>('comfyui_v2_validate_template_parameters', { templateId, parameters });
return result === 'valid';
} catch (error) {
console.error('Failed to validate template parameters:', error);
return false;
}
}
// ==================== 执行管理 ====================
/**
* 执行工作流
*/
static async executeWorkflow(request: ExecuteWorkflowRequest): Promise<ExecutionV2> {
try {
return await invoke<ExecutionV2>('comfyui_v2_execute_workflow', { request });
} catch (error) {
console.error('Failed to execute workflow:', error);
throw new Error(`执行工作流失败: ${error}`);
}
}
/**
* 执行模板
*/
static async executeTemplate(request: ExecuteTemplateRequest): Promise<ExecutionV2> {
try {
return await invoke<ExecutionV2>('comfyui_v2_execute_template', { request });
} catch (error) {
console.error('Failed to execute template:', error);
throw new Error(`执行模板失败: ${error}`);
}
}
/**
* 取消执行
*/
static async cancelExecution(executionId: string): Promise<string> {
try {
return await invoke<string>('comfyui_v2_cancel_execution', { executionId });
} catch (error) {
console.error('Failed to cancel execution:', error);
throw new Error(`取消执行失败: ${error}`);
}
}
/**
* 获取执行状态
*/
static async getExecutionStatus(executionId: string): Promise<ExecutionV2> {
try {
return await invoke<ExecutionV2>('comfyui_v2_get_execution_status', { executionId });
} catch (error) {
console.error('Failed to get execution status:', error);
throw new Error(`获取执行状态失败: ${error}`);
}
}
/**
* 获取执行历史
*/
static async getExecutionHistory(limit?: number, status?: string): Promise<ExecutionV2[]> {
try {
return await invoke<ExecutionV2[]>('comfyui_v2_get_execution_history', { limit, status });
} catch (error) {
console.error('Failed to get execution history:', error);
throw new Error(`获取执行历史失败: ${error}`);
}
}
// ==================== 实时通信 ====================
/**
* 启动实时监控
*/
static async startRealtimeMonitor(config?: any): Promise<string> {
try {
return await invoke<string>('comfyui_v2_start_realtime_monitor_enhanced', { config });
} catch (error) {
console.error('Failed to start realtime monitor:', error);
throw new Error(`启动实时监控失败: ${error}`);
}
}
/**
* 停止实时监控
*/
static async stopRealtimeMonitor(): Promise<string> {
try {
return await invoke<string>('comfyui_v2_stop_realtime_monitor_enhanced');
} catch (error) {
console.error('Failed to stop realtime monitor:', error);
throw new Error(`停止实时监控失败: ${error}`);
}
}
/**
* 订阅实时事件
*/
static async subscribeRealtimeEvents(
eventTypes?: string[],
callback?: (event: RealtimeEvent) => void
): Promise<string> {
try {
// 订阅后端事件
const subscriptionId = await invoke<string>('comfyui_v2_subscribe_realtime_events_enhanced', { eventTypes });
// 如果提供了回调,设置事件监听
if (callback) {
// 监听连接状态变化
const connectionUnlisten = await listen('comfyui://connection-changed', (event) => {
callback({
event_type: 'connection_changed',
data: event.payload,
timestamp: new Date().toISOString(),
});
});
// 监听执行进度
const progressUnlisten = await listen('comfyui://execution-progress', (event) => {
callback({
event_type: 'execution_progress',
data: event.payload,
timestamp: new Date().toISOString(),
});
});
// 监听执行完成
const completedUnlisten = await listen('comfyui://execution-completed', (event) => {
callback({
event_type: 'execution_completed',
data: event.payload,
timestamp: new Date().toISOString(),
});
});
// 监听执行失败
const failedUnlisten = await listen('comfyui://execution-failed', (event) => {
callback({
event_type: 'execution_failed',
data: event.payload,
timestamp: new Date().toISOString(),
});
});
// 保存监听器以便后续清理
this.eventListeners.set(`${subscriptionId}_connection`, connectionUnlisten);
this.eventListeners.set(`${subscriptionId}_progress`, progressUnlisten);
this.eventListeners.set(`${subscriptionId}_completed`, completedUnlisten);
this.eventListeners.set(`${subscriptionId}_failed`, failedUnlisten);
}
return subscriptionId;
} catch (error) {
console.error('Failed to subscribe to realtime events:', error);
throw new Error(`订阅实时事件失败: ${error}`);
}
}
/**
* 取消订阅实时事件
*/
static async unsubscribeRealtimeEvents(subscriptionId: string): Promise<string> {
try {
// 清理事件监听器
const listenersToRemove = Array.from(this.eventListeners.keys())
.filter(key => key.startsWith(subscriptionId));
for (const key of listenersToRemove) {
const unlisten = this.eventListeners.get(key);
if (unlisten) {
unlisten();
this.eventListeners.delete(key);
}
}
// 取消后端订阅
return await invoke<string>('comfyui_v2_unsubscribe_realtime_events', { subscriptionId });
} catch (error) {
console.error('Failed to unsubscribe from realtime events:', error);
throw new Error(`取消订阅实时事件失败: ${error}`);
}
}
/**
* 注册执行映射
*/
static async registerExecutionMapping(promptId: string, executionId: string): Promise<string> {
try {
return await invoke<string>('comfyui_v2_register_execution_mapping', { promptId, executionId });
} catch (error) {
console.error('Failed to register execution mapping:', error);
throw new Error(`注册执行映射失败: ${error}`);
}
}
// ==================== 批量操作 ====================
/**
* 批量执行工作流
*/
static async batchExecuteWorkflows(requests: ExecuteWorkflowRequest[]): Promise<ExecutionV2[]> {
try {
return await invoke<ExecutionV2[]>('comfyui_v2_batch_execute_workflows', { requests });
} catch (error) {
console.error('Failed to batch execute workflows:', error);
throw new Error(`批量执行工作流失败: ${error}`);
}
}
/**
* 批量执行模板
*/
static async batchExecuteTemplates(requests: ExecuteTemplateRequest[]): Promise<ExecutionV2[]> {
try {
return await invoke<ExecutionV2[]>('comfyui_v2_batch_execute_templates', { requests });
} catch (error) {
console.error('Failed to batch execute templates:', error);
throw new Error(`批量执行模板失败: ${error}`);
}
}
/**
* 批量取消执行
*/
static async batchCancelExecutions(executionIds: string[]): Promise<string[]> {
try {
return await invoke<string[]>('comfyui_v2_batch_cancel_executions', { executionIds });
} catch (error) {
console.error('Failed to batch cancel executions:', error);
throw new Error(`批量取消执行失败: ${error}`);
}
}
// ==================== 工具方法 ====================
/**
* 清理所有事件监听器
*/
static cleanup(): void {
for (const [key, unlisten] of this.eventListeners) {
unlisten();
}
this.eventListeners.clear();
}
}