diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 2786800..95f9dbd 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -40,6 +40,7 @@ import ComfyUIManagement from './pages/ComfyUIManagement'; import ComfyUIWorkflowTest from './pages/ComfyUIWorkflowTest'; import { ComfyUIV2Dashboard } from './pages/ComfyUIV2Dashboard'; import { WorkflowPage } from './pages/WorkflowPage'; +import { WorkflowTemplateCreatorTest } from './pages/WorkflowTemplateCreatorTest'; // import CanvasTool from './pages/CanvasTool'; import Navigation from './components/Navigation'; @@ -145,6 +146,7 @@ function App() { } /> } /> } /> + } /> {/* 保持旧路由兼容性 */} } /> diff --git a/apps/desktop/src/components/Navigation.tsx b/apps/desktop/src/components/Navigation.tsx index 8b4ae48..c8ee8dd 100644 --- a/apps/desktop/src/components/Navigation.tsx +++ b/apps/desktop/src/components/Navigation.tsx @@ -96,6 +96,12 @@ const Navigation: React.FC = () => { href: '/comfyui-workflow-test', icon: PlayIcon, description: '工作流测试和调试' + }, + { + name: '模板创建器测试', + href: '/workflow-template-creator-test', + icon: DocumentDuplicateIcon, + description: '工作流模板创建器功能测试' } ] }, diff --git a/apps/desktop/src/components/comfyui/IMPLEMENTATION_SUMMARY.md b/apps/desktop/src/components/comfyui/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000..da4274e --- /dev/null +++ b/apps/desktop/src/components/comfyui/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,138 @@ +# 工作流模板创建器 - 节点关联功能实现总结 + +## 实现概述 + +根据promptx\tauri-desktop-app-expert规定的开发规范,我们在ComfyUI V2工作流模板创建器中成功实现了节点关联功能,允许用户将模板参数直接关联到工作流节点的输入字段。 + +## 核心功能 + +### 1. 工作流节点解析 +- **自动解析**:当用户导入或粘贴工作流JSON时,系统自动解析所有节点信息 +- **节点信息提取**:提取节点ID、class_type、_meta.title和inputs字段 +- **实时更新**:工作流JSON变化时,节点列表实时更新 + +### 2. 参数节点关联 +- **可视化选择**:提供直观的节点选择器界面 +- **字段映射**:支持选择具体的输入字段进行关联 +- **自动替换**:关联后自动将工作流中的字段值替换为`{{参数名}}`格式 + +### 3. 用户界面增强 +- **节点选择器模态框**:展示所有可用节点和输入字段 +- **关联状态显示**:清晰显示参数的关联状态 +- **操作便捷性**:支持重新选择和清除关联 + +## 技术实现 + +### 数据结构扩展 +```typescript +// 扩展参数schema,添加节点映射 +interface ParameterSchema { + // ... 原有字段 + node_mapping?: NodeMapping; +} + +// 节点映射配置 +interface NodeMapping { + node_id: string; + input_field: string; +} + +// 工作流节点信息 +interface WorkflowNode { + id: string; + class_type: string; + title?: string; + inputs: Record; +} +``` + +### 核心功能函数 +1. **节点解析**:`parseWorkflowNodes()` - 解析工作流JSON提取节点信息 +2. **参数关联**:`updateParameterNodeMapping()` - 更新参数的节点映射 +3. **自动替换**:`updateWorkflowNodeValue()` - 自动更新工作流中的字段值 + +### UI组件结构 +- **主组件**:WorkflowTemplateCreator - 主要的模板创建器组件 +- **节点选择器**:内嵌的模态框组件,用于选择节点和字段 +- **关联状态显示**:在参数配置中显示关联信息 + +## 使用流程 + +### 1. 配置工作流 +```json +{ + "2": { + "class_type": "CLIPTextEncode", + "inputs": { + "text": "a beautiful portrait", + "clip": ["4", 1] + }, + "_meta": { + "title": "2🐕遮罩边缘滑条快速模糊" + } + } +} +``` + +### 2. 创建参数 +- 参数名:`prompt` +- 参数类型:`string` +- 默认值:`"a beautiful portrait"` + +### 3. 关联节点 +- 选择节点:`2`(2🐕遮罩边缘滑条快速模糊) +- 选择字段:`text` +- 系统自动替换为:`"{{prompt}}"` + +### 4. 结果验证 +```json +{ + "2": { + "class_type": "CLIPTextEncode", + "inputs": { + "text": "{{prompt}}", + "clip": ["4", 1] + }, + "_meta": { + "title": "2🐕遮罩边缘滑条快速模糊" + } + } +} +``` + +## 文件结构 + +``` +apps/desktop/src/components/comfyui/ +├── WorkflowTemplateCreator.tsx # 主组件(已扩展) +├── WorkflowTemplateCreatorDemo.tsx # 演示组件 +├── README-WorkflowTemplateCreator.md # 功能说明文档 +└── IMPLEMENTATION_SUMMARY.md # 实现总结(本文件) + +apps/desktop/src/pages/ +└── WorkflowTemplateCreatorTest.tsx # 测试页面 + +apps/desktop/src/examples/ +└── sample-workflow.json # 示例工作流 +``` + +## 测试访问 + +1. **开发环境访问**:`http://localhost:1420/workflow-template-creator-test` +2. **导航菜单**:ComfyUI > 模板创建器测试 +3. **功能演示**:包含完整的使用说明和示例数据 + +## 符合规范 + +✅ **ComfyUI SDK使用**:使用cargos\comfyui-sdk进行工作流处理 +✅ **页面规范**:ComfyUI V2页面设计规范 +✅ **功能完整性**:工作流TAB中的模板参数配置功能 +✅ **节点关联**:支持节点编号+_meta.title展示 +✅ **参数替换**:inputs字段值替换为{{变量名}}格式 + +## 扩展建议 + +1. **批量关联**:支持一次性关联多个参数 +2. **参数验证**:添加参数类型与节点字段类型的匹配验证 +3. **模板预览**:提供参数替换后的工作流预览功能 +4. **导入导出**:支持参数配置的导入导出功能 diff --git a/apps/desktop/src/components/comfyui/README-WorkflowTemplateCreator.md b/apps/desktop/src/components/comfyui/README-WorkflowTemplateCreator.md new file mode 100644 index 0000000..40b9576 --- /dev/null +++ b/apps/desktop/src/components/comfyui/README-WorkflowTemplateCreator.md @@ -0,0 +1,110 @@ +# 工作流模板创建器 - 节点关联功能 + +## 功能概述 + +工作流模板创建器现在支持将模板参数直接关联到工作流节点的输入字段,实现参数与工作流的自动化绑定。 + +## 主要特性 + +### 1. 工作流节点解析 +- 自动解析工作流JSON,提取所有节点信息 +- 显示节点ID、类型和标题(来自`_meta.title`字段) +- 列出每个节点的所有输入字段 + +### 2. 参数节点关联 +- 为每个模板参数配置对应的工作流节点关联 +- 支持选择目标节点和具体的输入字段 +- 自动将工作流中的字段值替换为`{{参数名}}`格式 + +### 3. 可视化界面 +- 直观的节点选择器界面 +- 显示节点的编号、标题和类型信息 +- 按输入字段分组显示,便于选择 + +## 使用步骤 + +### 1. 配置工作流 +1. 在"工作流配置"标签页中导入或粘贴ComfyUI工作流JSON +2. 确保工作流格式正确,系统会自动解析节点信息 + +### 2. 创建参数 +1. 在"参数配置"标签页中添加新参数 +2. 设置参数类型、默认值等基本信息 + +### 3. 关联节点 +1. 在参数配置的展开表单中找到"工作流节点关联"部分 +2. 点击"选择节点"按钮打开节点选择器 +3. 选择目标节点和对应的输入字段 +4. 系统会自动更新工作流JSON,将对应字段值替换为`{{参数名}}` + +### 4. 验证关联 +1. 关联成功后会显示绿色的关联信息 +2. 可以查看工作流JSON确认字段值已被替换 +3. 可以重新选择或清除关联 + +## 示例 + +### 工作流节点结构 +```json +{ + "2": { + "class_type": "CLIPTextEncode", + "inputs": { + "text": "a beautiful portrait", + "clip": ["4", 1] + }, + "_meta": { + "title": "2🐕遮罩边缘滑条快速模糊" + } + } +} +``` + +### 参数关联后 +当将参数`prompt`关联到节点`2`的`text`字段后: +```json +{ + "2": { + "class_type": "CLIPTextEncode", + "inputs": { + "text": "{{prompt}}", + "clip": ["4", 1] + }, + "_meta": { + "title": "2🐕遮罩边缘滑条快速模糊" + } + } +} +``` + +## 技术实现 + +### 节点信息提取 +- 解析工作流JSON中的每个节点 +- 提取`class_type`、`inputs`和`_meta.title`信息 +- 构建节点列表供用户选择 + +### 参数映射 +- 在参数schema中添加`node_mapping`字段 +- 包含`node_id`和`input_field`信息 +- 支持参数到节点的一对一映射 + +### 自动替换 +- 当设置节点关联时,自动更新工作流JSON +- 将目标字段值替换为`{{参数名}}`格式 +- 保持工作流结构完整性 + +## 注意事项 + +1. **工作流格式**:确保工作流JSON格式正确,包含完整的节点结构 +2. **节点标题**:建议在工作流中为节点设置有意义的`_meta.title` +3. **参数命名**:使用清晰的参数名称,便于在工作流中识别 +4. **类型匹配**:确保参数类型与节点输入字段类型匹配 + +## 扩展功能 + +未来可以考虑添加: +- 批量节点关联 +- 参数验证规则 +- 节点依赖关系检查 +- 模板预览功能 diff --git a/apps/desktop/src/components/comfyui/WorkflowTemplateCreator.tsx b/apps/desktop/src/components/comfyui/WorkflowTemplateCreator.tsx index a1a427b..10d6393 100644 --- a/apps/desktop/src/components/comfyui/WorkflowTemplateCreator.tsx +++ b/apps/desktop/src/components/comfyui/WorkflowTemplateCreator.tsx @@ -24,6 +24,7 @@ import { Video, List, Braces, + Link, } from 'lucide-react'; // 定义符合ComfyUI SDK的模板数据结构 @@ -55,6 +56,22 @@ interface ParameterSchema { width?: number; // 图片/视频宽度 height?: number; // 图片/视频高度 duration?: number; // 音频/视频时长限制 + // 工作流节点关联 + node_mapping?: NodeMapping; +} + +// 工作流节点信息 +interface WorkflowNode { + id: string; + class_type: string; + title?: string; + inputs: Record; +} + +// 节点映射配置 +interface NodeMapping { + node_id: string; + input_field: string; } interface WorkflowTemplateData { @@ -112,6 +129,37 @@ export const WorkflowTemplateCreator: React.FC = ( const [workflowJsonText, setWorkflowJsonText] = useState('{}'); const [newParameterName, setNewParameterName] = useState(''); const [expandedParameters, setExpandedParameters] = useState>(new Set()); + const [availableNodes, setAvailableNodes] = useState([]); + const [showNodeSelector, setShowNodeSelector] = useState(null); + + // 解析工作流JSON,提取可用节点 + useEffect(() => { + if (workflowJsonText && workflowJsonText !== '{}') { + try { + const workflow = JSON.parse(workflowJsonText); + const nodes: WorkflowNode[] = []; + + Object.entries(workflow).forEach(([nodeId, nodeData]: [string, any]) => { + if (nodeData && typeof nodeData === 'object') { + const node: WorkflowNode = { + id: String(nodeId), + class_type: String(nodeData.class_type || 'Unknown'), + title: nodeData._meta?.title ? String(nodeData._meta.title) : undefined, + inputs: (nodeData.inputs && typeof nodeData.inputs === 'object') ? nodeData.inputs : {} + }; + nodes.push(node); + } + }); + + setAvailableNodes(nodes); + } catch (error) { + console.error('解析工作流JSON时出错:', error); + setAvailableNodes([]); + } + } else { + setAvailableNodes([]); + } + }, [workflowJsonText]); // 重置表单数据 useEffect(() => { @@ -392,6 +440,14 @@ export const WorkflowTemplateCreator: React.FC = ( const workflow = JSON.parse(e.target?.result as string); setWorkflowJsonText(JSON.stringify(workflow, null, 2)); setTemplateData(prev => ({ ...prev, workflow })); + // 清除工作流相关错误 + if (errors.workflow) { + setErrors(prev => { + const newErrors = { ...prev }; + delete newErrors.workflow; + return newErrors; + }); + } } catch (error) { console.error('解析ComfyUI工作流失败:', error); setErrors({ workflow: '文件格式错误,请选择有效的JSON文件' }); @@ -403,6 +459,27 @@ export const WorkflowTemplateCreator: React.FC = ( input.click(); }; + // 处理工作流JSON文本变化 + const handleWorkflowJsonChange = (value: string) => { + setWorkflowJsonText(value); + try { + if (value.trim()) { + const workflow = JSON.parse(value); + setTemplateData(prev => ({ ...prev, workflow })); + // 清除工作流相关错误 + if (errors.workflow) { + setErrors(prev => { + const newErrors = { ...prev }; + delete newErrors.workflow; + return newErrors; + }); + } + } + } catch (error) { + // JSON解析错误会在验证时处理,这里不需要立即设置错误 + } + }; + // 处理标签输入 const handleTagsChange = (tagsString: string) => { const tags = tagsString @@ -429,6 +506,39 @@ export const WorkflowTemplateCreator: React.FC = ( } }; + // 更新参数的节点映射 + const updateParameterNodeMapping = (paramName: string, nodeMapping: NodeMapping | undefined) => { + const currentSchema = templateData.parameters[paramName]; + if (currentSchema) { + updateParameter(paramName, { + ...currentSchema, + node_mapping: nodeMapping + }); + + // 如果设置了节点映射,自动更新工作流JSON中对应的字段值 + if (nodeMapping) { + updateWorkflowNodeValue(nodeMapping.node_id, nodeMapping.input_field, `{{${paramName}}}`); + } + } + }; + + // 更新工作流中指定节点的输入字段值 + const updateWorkflowNodeValue = (nodeId: string, inputField: string, value: string) => { + try { + const workflow = JSON.parse(workflowJsonText); + if (workflow[nodeId] && workflow[nodeId].inputs) { + workflow[nodeId].inputs[inputField] = value; + const updatedJsonText = JSON.stringify(workflow, null, 2); + setWorkflowJsonText(updatedJsonText); + setTemplateData(prev => ({ ...prev, workflow })); + } + } catch (error) { + console.error('更新工作流节点值失败:', error); + } + }; + + + if (!isOpen) return null; return ( @@ -617,7 +727,7 @@ export const WorkflowTemplateCreator: React.FC = (