/** * Workflow Templates Configuration | 工作流模板配置 * 预设工作流模板,支持一键添加到画布 */ import workflowCover1 from '@/assets/workflow01.jpeg' import workflowCover2 from '@/assets/workflow02.jpeg' import scene01 from '@/assets/scene01.jpeg' import shot01 from '@/assets/shot01.jpeg' // Multi-angle prompts | 多角度提示词模板 export const MULTI_ANGLE_PROMPTS = { front: { label: '正视', english: 'Front View', prompt: (character) => `使用提供的图片,生成四宫格分镜,每张四宫格包括人物正面对着镜头的4个景别(远景、中景、近景、和局部特写),保持场景、产品、人物特征的一致性,宫格里的每一张照片保持和提供图片相同的比例。并在图片下方用英文标注这个景别 角色参考: ${character}` }, side: { label: '侧视', english: 'Side View', prompt: (character) => `使用提供的图片,分别生成四宫格分镜,每张四宫格包括人物侧面角度的4个景别(远景、中景、近景、和局部特写),保持场景、产品、人物特征的一致性,宫格里的每一张照片保持和提供图片相同的比例。并在图片下方用英文标注这个景别 角色参考: ${character}` }, back: { label: '后视', english: 'Back View', prompt: (character) => `使用提供的图片,分别生成四宫格分镜,每张四宫格包括人物背影角度的4个景别(远景、中景、近景、和局部特写),保持场景、产品、人物特征的一致性,宫格里的每一张照片保持和提供图片相同的比例。并在图片下方用英文标注这个景别 角色参考: ${character}` }, top: { label: '俯视', english: 'Top/Bird\'s Eye View', prompt: (character) => `使用提供的图片,分别生成四宫格分镜,每张四宫格包括俯视角度的4个景别(远景、中景、近景、和局部特写),保持场景、产品、人物特征的一致性,宫格里的每一张照片保持和提供图片相同的比例。并在图片下方用英文标注这个景别 角色参考: ${character}` } } /** * Workflow Templates | 工作流模板 */ export const WORKFLOW_TEMPLATES = [ { id: 'multi-angle-storyboard', name: '多角度分镜', description: '生成角色的正视、侧视、后视、俯视四宫格分镜图', icon: 'GridOutline', category: 'storyboard', cover: workflowCover1, // 节点配置 createNodes: (startPosition) => { const nodeSpacing = 400 const rowSpacing = 280 const angles = ['front', 'side', 'back', 'top'] const nodes = [] const edges = [] let nodeIdCounter = 0 const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // 主角色图:提示词 + 文生图配置 const characterTextId = getNodeId() nodes.push({ id: characterTextId, type: 'text', position: { x: startPosition.x, y: startPosition.y + rowSpacing * 1.5 }, data: { content: '', label: '角色提示词' } }) const characterConfigId = getNodeId() nodes.push({ id: characterConfigId, type: 'imageConfig', position: { x: startPosition.x + nodeSpacing, y: startPosition.y + rowSpacing * 1.5 }, data: { label: '主角色图', model: 'auto', size: '1024x1536' } }) // 主角色图结果节点(空白图片节点) const characterImageId = getNodeId() nodes.push({ id: characterImageId, type: 'image', position: { x: startPosition.x + nodeSpacing * 2, y: startPosition.y + rowSpacing * 1.5 }, data: { url: '', label: '角色图结果' } }) // 连线:角色提示词 → 角色图配置 edges.push({ id: `edge_${characterTextId}_${characterConfigId}`, source: characterTextId, target: characterConfigId, sourceHandle: 'right', targetHandle: 'left' }) // 连线:角色图配置 → 角色图结果 edges.push({ id: `edge_${characterConfigId}_${characterImageId}`, source: characterConfigId, target: characterImageId, sourceHandle: 'right', targetHandle: 'left' }) // 创建4个角度的节点 const angleX = startPosition.x + nodeSpacing * 3 + 100 angles.forEach((angleKey, index) => { const angleConfig = MULTI_ANGLE_PROMPTS[angleKey] const angleY = startPosition.y + index * rowSpacing let currentX = angleX // 提示词节点(预填充默认提示词) const textNodeId = getNodeId() nodes.push({ id: textNodeId, type: 'text', position: { x: currentX, y: angleY }, data: { content: angleConfig.prompt(''), label: `${angleConfig.label}提示词` } }) currentX += nodeSpacing // 图片配置节点 const configNodeId = getNodeId() nodes.push({ id: configNodeId, type: 'imageConfig', position: { x: currentX, y: angleY }, data: { label: `${angleConfig.label} (${angleConfig.english})`, model: 'auto', size: '1024x1536' } }) // 连线:提示词 → 配置 edges.push({ id: `edge_${textNodeId}_${configNodeId}`, source: textNodeId, target: configNodeId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 连线:角色图结果 → 角度配置(参考图) edges.push({ id: `edge_${characterImageId}_${configNodeId}`, source: characterImageId, target: configNodeId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) }) return { nodes, edges } } }, { id: 'product-ecommerce-full-set', name: '通用产品全套电商图', description: '根据产品信息和图片,生成模特图、侧面展示图、俯瞰展示图', icon: 'ShoppingOutline', category: 'ecommerce', cover: workflowCover2, // 节点配置 createNodes: (startPosition) => { const colSpacing = 500 // 列间距 const rowSpacing = 350 // 行间距 const nodes = [] const edges = [] let nodeIdCounter = 0 const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // ========== 布局说明 ========== // 第一列: A(产品信息), B(产品图片) - 输入节点 // 第二列: C, D, E - 提示词节点 // 第三列: 生成模特图, 侧面展示图, 俯瞰展示图 - 输出节点 // ========== 第一列:输入节点 ========== // A: 产品信息文本节点 const nodeA_productInfoId = getNodeId() nodes.push({ id: nodeA_productInfoId, type: 'text', position: { x: startPosition.x, y: startPosition.y }, data: { content: 'Soundcore by Anker P20i真无线耳机,10mm驱动单元带来强劲低音,蓝牙5.3,30小时超长续航,防水,2个麦克风实现AI清晰通话,22种预设均衡器,可通过App定制 强劲低音:Soundcore P20i真无线耳机搭载超大10mm驱动单元,带来强劲音效和增强的低音,让您沉浸在喜爱的歌曲中。 个性化聆听体验:使用Soundcore App自定义控制选项,并从22种预设均衡器中进行选择。借助“Find My Earbuds”(查找我的耳机)功能,丢失的耳机可以发出声音,帮助您定位。 长续航,快速充电:单次充电可提供10小时电池续航,搭配充电盒则可延长至30小时。如果P20i真无线耳机电量不足,仅需10分钟快速充电即可提供2小时播放时间。 便携式设计:Soundcore P20i真无线耳机和充电盒小巧轻便,配有挂绳。其体积足够小,可轻松放入口袋,或挂在包或钥匙上,让您无需担心空间问题。 AI增强清晰通话:2个内置麦克风和AI算法协同工作,捕捉您的声音,让您无需在电话中大喊大叫。', label: '产品信息' } }) // B: 产品图片节点 const nodeB_productImageId = getNodeId() nodes.push({ id: nodeB_productImageId, type: 'image', position: { x: startPosition.x, y: startPosition.y + rowSpacing }, data: { url: 'https://ffile.chatfire.site/image/covers/product01.jpg', label: '产品图片' } }) // ========== 第二列:提示词节点 ========== // C: 模特图提示词 (与生成模特图对齐) const nodeC_modelPromptId = getNodeId() nodes.push({ id: nodeC_modelPromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y }, data: { content: '根据产品特性,生成一个适合展示该产品且时尚富有高级感的模特图,彩色人像,背景是白底,人物居中,欧美人优先', label: '模特图提示词' } }) // D: 侧面展示图提示词 (与侧面展示图对齐) const nodeD_sidePromptId = getNodeId() nodes.push({ id: nodeD_sidePromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y + rowSpacing }, data: { content: '根据产品图和产品信息,生成左侧侧面45度的展示图,高清展示侧面的产品形状和细节,保持产品不变形', label: '侧面展示图提示词' } }) // E: 俯瞰展示图提示词 (与俯瞰展示图对齐) const nodeE_topPromptId = getNodeId() nodes.push({ id: nodeE_topPromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y + rowSpacing * 2 }, data: { content: '根据产品图和产品信息,生成从上往下俯瞰的产品展示图,高清展示俯瞰角度的产品形状和细节,保持产品不变形', label: '俯瞰展示图提示词' } }) // F: 拆解图提示词 (与拆解图对齐) const nodeF_explodedPromptId = getNodeId() nodes.push({ id: nodeF_explodedPromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y + rowSpacing * 3 }, data: { content: '根据产品材质功能,生成一张产品核心部件的结构示意图,要展现出产品核心部件的内部构造,画面清晰呈现产品关键部件,背景为简洁的浅色调,同时包含核心卖点文案', label: '拆解图提示词' } }) // ========== 第三列:生成节点 ========== // B+C = 生成模特图 const modelConfigId = getNodeId() nodes.push({ id: modelConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y }, data: { label: '生成模特图', model: 'auto', size: '1024x1536' } }) // B+D = 生成侧面展示图 const sideConfigId = getNodeId() nodes.push({ id: sideConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y + rowSpacing }, data: { label: '侧面展示图', model: 'auto', size: '1024x1536' } }) // B+E = 生成俯瞰展示图 const topConfigId = getNodeId() nodes.push({ id: topConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y + rowSpacing * 2 }, data: { label: '俯瞰展示图', model: 'auto', size: '1024x1536' } }) // AB+F = 生成拆解图 const explodedConfigId = getNodeId() nodes.push({ id: explodedConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y + rowSpacing * 3 }, data: { label: '拆解图', model: 'auto', size: '1024x1536' } }) // ========== 连线 ========== // AB+C → 生成模特图 edges.push({ id: `edge_${nodeA_productInfoId}_${modelConfigId}`, source: nodeA_productInfoId, target: modelConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeB_productImageId}_${modelConfigId}`, source: nodeB_productImageId, target: modelConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeC_modelPromptId}_${modelConfigId}`, source: nodeC_modelPromptId, target: modelConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) // AB+D → 生成侧面展示图 edges.push({ id: `edge_${nodeA_productInfoId}_${sideConfigId}`, source: nodeA_productInfoId, target: sideConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeB_productImageId}_${sideConfigId}`, source: nodeB_productImageId, target: sideConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeD_sidePromptId}_${sideConfigId}`, source: nodeD_sidePromptId, target: sideConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) // AB+E → 生成俯瞰展示图 edges.push({ id: `edge_${nodeA_productInfoId}_${topConfigId}`, source: nodeA_productInfoId, target: topConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeB_productImageId}_${topConfigId}`, source: nodeB_productImageId, target: topConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeE_topPromptId}_${topConfigId}`, source: nodeE_topPromptId, target: topConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) // AB+F → 生成拆解图 edges.push({ id: `edge_${nodeA_productInfoId}_${explodedConfigId}`, source: nodeA_productInfoId, target: explodedConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeB_productImageId}_${explodedConfigId}`, source: nodeB_productImageId, target: explodedConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nodeF_explodedPromptId}_${explodedConfigId}`, source: nodeF_explodedPromptId, target: explodedConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) return { nodes, edges } } }, // ========== 短剧生图工作流 ========== { id: 'drama-character-design', name: '短剧角色设计', description: '根据角色描述生成一致性角色形象,后续多角度图依赖正面图保持一致性', icon: 'PersonOutline', category: 'drama', cover: shot01, createNodes: (startPosition) => { const colSpacing = 400 const rowSpacing = 280 const nodes = [] const edges = [] let nodeIdCounter = 0 const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // ========== 第一阶段:生成正面角色图 ========== // 角色描述 const characterDescId = getNodeId() nodes.push({ id: characterDescId, type: 'text', position: { x: startPosition.x, y: startPosition.y }, data: { content: '角色名称:林小雨\n性别:女\n年龄:22岁\n外貌特征:长发及腰,眼睛明亮有神,皮肤白皙,身材高挑\n服装风格:现代都市风,白色连衣裙\n性格特点:温柔善良,内心坚强', label: '角色描述' } }) // 风格参考图(可选) const styleRefId = getNodeId() nodes.push({ id: styleRefId, type: 'image', position: { x: startPosition.x, y: startPosition.y + rowSpacing }, data: { url: '', label: '风格参考图(可选)' } }) // 正面全身提示词 const frontPromptId = getNodeId() nodes.push({ id: frontPromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y }, data: { content: '根据角色描述,生成角色的正面全身照,人物居中,白色简洁背景,高清写实风格,电影级画质', label: '正面全身提示词' } }) // 正面全身生成配置 const frontConfigId = getNodeId() nodes.push({ id: frontConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y }, data: { label: '生成正面全身图', model: 'auto', size: '1024x1536' } }) // 正面全身图结果(作为后续生成的参考) const frontResultId = getNodeId() nodes.push({ id: frontResultId, type: 'image', position: { x: startPosition.x + colSpacing * 3, y: startPosition.y }, data: { url: '', label: '正面角色图(参考基准)' } }) // ========== 第二阶段:基于正面图生成多角度 ========== // 侧面半身提示词 const sidePromptId = getNodeId() nodes.push({ id: sidePromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing }, data: { content: '参考提供的角色正面图,保持人物外貌、服装完全一致,生成角色的侧面半身照,45度角侧脸,展示五官轮廓,白色简洁背景,高清写实风格', label: '侧面半身提示词' } }) // 表情特写提示词 const closeupPromptId = getNodeId() nodes.push({ id: closeupPromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing * 2 }, data: { content: '参考提供的角色正面图,保持人物五官、发型完全一致,生成角色的面部特写,展示多种表情(微笑、严肃、惊讶、悲伤),四宫格布局,高清写实风格', label: '表情特写提示词' } }) // 背面全身提示词 const backPromptId = getNodeId() nodes.push({ id: backPromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing * 3 }, data: { content: '参考提供的角色正面图,保持人物发型、服装、身材完全一致,生成角色的背面全身照,展示背影,白色简洁背景,高清写实风格', label: '背面全身提示词' } }) // 侧面生成配置 const sideConfigId = getNodeId() nodes.push({ id: sideConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing }, data: { label: '侧面半身图', model: 'auto', size: '1024x1536' } }) // 表情特写生成配置 const closeupConfigId = getNodeId() nodes.push({ id: closeupConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing * 2 }, data: { label: '表情特写图', model: 'auto', size: '1024x1536' } }) // 背面生成配置 const backConfigId = getNodeId() nodes.push({ id: backConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing * 3 }, data: { label: '背面全身图', model: 'auto', size: '1024x1536' } }) // ========== 连线:第一阶段 ========== // 角色描述 → 正面生成 edges.push({ id: `edge_${characterDescId}_${frontConfigId}`, source: characterDescId, target: frontConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 风格参考 → 正面生成 edges.push({ id: `edge_${styleRefId}_${frontConfigId}`, source: styleRefId, target: frontConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 正面提示词 → 正面生成 edges.push({ id: `edge_${frontPromptId}_${frontConfigId}`, source: frontPromptId, target: frontConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) // 正面生成 → 正面结果 edges.push({ id: `edge_${frontConfigId}_${frontResultId}`, source: frontConfigId, target: frontResultId, sourceHandle: 'right', targetHandle: 'left' }) // ========== 连线:第二阶段(依赖正面图) ========== // 正面结果 → 侧面生成(作为参考图) edges.push({ id: `edge_${frontResultId}_${sideConfigId}`, source: frontResultId, target: sideConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 正面结果 → 表情生成(作为参考图) edges.push({ id: `edge_${frontResultId}_${closeupConfigId}`, source: frontResultId, target: closeupConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 正面结果 → 背面生成(作为参考图) edges.push({ id: `edge_${frontResultId}_${backConfigId}`, source: frontResultId, target: backConfigId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 提示词 → 各生成节点 edges.push({ id: `edge_${sidePromptId}_${sideConfigId}`, source: sidePromptId, target: sideConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${closeupPromptId}_${closeupConfigId}`, source: closeupPromptId, target: closeupConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${backPromptId}_${backConfigId}`, source: backPromptId, target: backConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) return { nodes, edges } } }, { id: 'drama-scene-background', name: '多时段场景背景', description: '先生成基础场景,再基于基础场景生成多时段变体,保持场景一致性', icon: 'ImageOutline', category: 'drama', cover: scene01, createNodes: (startPosition) => { const colSpacing = 400 const rowSpacing = 260 const nodes = [] const edges = [] let nodeIdCounter = 0 const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // ========== 第一阶段:生成基础场景 ========== // 场景描述 const sceneDescId = getNodeId() nodes.push({ id: sceneDescId, type: 'text', position: { x: startPosition.x, y: startPosition.y }, data: { content: '场景名称:现代都市街道\n位置:繁华商业区主街道\n环境特征:高楼大厦林立,霓虹灯招牌,车水马龙\n氛围:都市繁华、现代感强\n特殊元素:咖啡店、书店、商场入口', label: '场景描述' } }) // 基础场景提示词 const basePromptId = getNodeId() nodes.push({ id: basePromptId, type: 'text', position: { x: startPosition.x + colSpacing, y: startPosition.y }, data: { content: '根据场景描述,生成白天正午时段的场景背景作为基准,阳光明媚,光线充足均匀,展示场景全貌和所有环境元素,纯背景无人物,电影级画质,宽屏构图', label: '基础场景提示词' } }) // 基础场景生成配置 const baseConfigId = getNodeId() nodes.push({ id: baseConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y }, data: { label: '生成基础场景', model: 'auto', size: '1536x1024' } }) // 基础场景结果(作为后续生成的参考) const baseResultId = getNodeId() nodes.push({ id: baseResultId, type: 'image', position: { x: startPosition.x + colSpacing * 3, y: startPosition.y }, data: { url: '', label: '基础场景图(参考基准)' } }) // ========== 第二阶段:基于基础场景生成多时段变体 ========== // 傍晚场景提示词 const eveningPromptId = getNodeId() nodes.push({ id: eveningPromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing }, data: { content: '参考提供的基础场景图,保持场景构图、建筑、环境元素完全一致,仅改变光照为傍晚时段:夕阳西下,天空呈橙红色渐变,光线柔和温暖,建筑投射长影', label: '傍晚场景提示词' } }) // 夜晚场景提示词 const nightPromptId = getNodeId() nodes.push({ id: nightPromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing * 2 }, data: { content: '参考提供的基础场景图,保持场景构图、建筑、环境元素完全一致,仅改变光照为夜晚时段:霓虹灯亮起,城市灯光璀璨,天空深蓝或黑色,窗户透出暖光', label: '夜晚场景提示词' } }) // 雨天场景提示词 const rainPromptId = getNodeId() nodes.push({ id: rainPromptId, type: 'text', position: { x: startPosition.x + colSpacing * 3 + 100, y: startPosition.y + rowSpacing * 3 }, data: { content: '参考提供的基础场景图,保持场景构图、建筑、环境元素完全一致,仅改变天气为雨天:细雨绵绵,地面湿润有倒影,天空阴沉灰暗,氛围忧郁', label: '雨天场景提示词' } }) // 傍晚生成配置 const eveningConfigId = getNodeId() nodes.push({ id: eveningConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing }, data: { label: '傍晚场景', model: 'auto', size: '1536x1024' } }) // 夜晚生成配置 const nightConfigId = getNodeId() nodes.push({ id: nightConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing * 2 }, data: { label: '夜晚场景', model: 'auto', size: '1536x1024' } }) // 雨天生成配置 const rainConfigId = getNodeId() nodes.push({ id: rainConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 4 + 100, y: startPosition.y + rowSpacing * 3 }, data: { label: '雨天场景', model: 'auto', size: '1536x1024' } }) // ========== 连线:第一阶段 ========== // 场景描述 → 基础场景生成 edges.push({ id: `edge_${sceneDescId}_${baseConfigId}`, source: sceneDescId, target: baseConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 基础提示词 → 基础场景生成 edges.push({ id: `edge_${basePromptId}_${baseConfigId}`, source: basePromptId, target: baseConfigId, type: 'promptOrder', data: { promptOrder: 2 }, sourceHandle: 'right', targetHandle: 'left' }) // 基础场景生成 → 基础场景结果 edges.push({ id: `edge_${baseConfigId}_${baseResultId}`, source: baseConfigId, target: baseResultId, sourceHandle: 'right', targetHandle: 'left' }) // ========== 连线:第二阶段(依赖基础场景图) ========== // 基础场景结果 → 各时段生成(作为参考图) const variantConfigs = [eveningConfigId, nightConfigId, rainConfigId] variantConfigs.forEach(configId => { edges.push({ id: `edge_${baseResultId}_${configId}`, source: baseResultId, target: configId, type: 'imageOrder', data: { imageOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) }) // 提示词 → 各生成节点 edges.push({ id: `edge_${eveningPromptId}_${eveningConfigId}`, source: eveningPromptId, target: eveningConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${nightPromptId}_${nightConfigId}`, source: nightPromptId, target: nightConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) edges.push({ id: `edge_${rainPromptId}_${rainConfigId}`, source: rainPromptId, target: rainConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) return { nodes, edges } } }, // { // id: 'drama-storyboard-shot', // name: '短剧分镜图', // description: '根据角色、场景和剧情描述生成分镜画面', // icon: 'FilmOutline', // category: 'drama', // cover: workflowCover1, // createNodes: (startPosition) => { // const colSpacing = 400 // const rowSpacing = 250 // const nodes = [] // const edges = [] // let nodeIdCounter = 0 // const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // // ========== 输入节点 ========== // // 角色参考图 // const characterRefId = getNodeId() // nodes.push({ // id: characterRefId, // type: 'image', // position: { x: startPosition.x, y: startPosition.y }, // data: { // url: '', // label: '角色参考图' // } // }) // // 场景背景图 // const sceneRefId = getNodeId() // nodes.push({ // id: sceneRefId, // type: 'image', // position: { x: startPosition.x, y: startPosition.y + rowSpacing }, // data: { // url: '', // label: '场景背景图' // } // }) // // 分镜描述 // const shotDescId = getNodeId() // nodes.push({ // id: shotDescId, // type: 'text', // position: { x: startPosition.x, y: startPosition.y + rowSpacing * 2 }, // data: { // content: '分镜编号:001\n景别:中景\n镜头角度:平视\n画面描述:女主角站在咖啡店门口,手持一杯咖啡,微微低头看着手机,若有所思\n人物动作:站立,单手持咖啡,另一手拿手机\n表情:略带忧郁,眉头微蹙\n光线:自然光,侧逆光', // label: '分镜描述' // } // }) // // ========== 生成提示词 ========== // const shotPromptId = getNodeId() // nodes.push({ // id: shotPromptId, // type: 'text', // position: { x: startPosition.x + colSpacing, y: startPosition.y + rowSpacing }, // data: { // content: '根据角色参考图、场景背景和分镜描述,生成电影级分镜画面,保持角色外貌一致,场景融合自然,光影效果符合描述,16:9宽屏比例,电影调色', // label: '分镜生成提示词' // } // }) // // ========== 生成节点 ========== // const shotConfigId = getNodeId() // nodes.push({ // id: shotConfigId, // type: 'imageConfig', // position: { x: startPosition.x + colSpacing * 2, y: startPosition.y + rowSpacing }, // data: { // label: '分镜画面', // model: 'auto', // size: '1536x1024' // } // }) // // ========== 连线 ========== // edges.push({ // id: `edge_${characterRefId}_${shotConfigId}`, // source: characterRefId, // target: shotConfigId, // sourceHandle: 'right', // targetHandle: 'left' // }) // edges.push({ // id: `edge_${sceneRefId}_${shotConfigId}`, // source: sceneRefId, // target: shotConfigId, // sourceHandle: 'right', // targetHandle: 'left' // }) // edges.push({ // id: `edge_${shotDescId}_${shotConfigId}`, // source: shotDescId, // target: shotConfigId, // type: 'promptOrder', // data: { promptOrder: 1 }, // sourceHandle: 'right', // targetHandle: 'left' // }) // edges.push({ // id: `edge_${shotPromptId}_${shotConfigId}`, // source: shotPromptId, // target: shotConfigId, // type: 'promptOrder', // data: { promptOrder: 2 }, // sourceHandle: 'right', // targetHandle: 'left' // }) // return { nodes, edges } // } // }, // ========== 儿童绘本工作流 ========== { id: 'picture-book-generator', name: '儿童绘本生成', description: '角色生成 → 剧情文字 → 绘本插画,支持角色一致性', icon: 'BookOutline', category: 'creative', cover: "https://ffile.chatfire.site/image/covers/workflow03.jpeg", createNodes: (startPosition) => { const colSpacing = 420 const rowSpacing = 280 const pageRowSpacing = 240 const nodes = [] const edges = [] let nodeIdCounter = 0 const getNodeId = () => `workflow_node_${Date.now()}_${nodeIdCounter++}` // ========== 第一阶段:故事输入 ========== const storyInputId = getNodeId() nodes.push({ id: storyInputId, type: 'text', position: { x: startPosition.x, y: startPosition.y }, data: { content: `【绘本名称】小兔子的冒险之旅 【故事主题】勇气与友谊 【主要角色】 1. 小白兔米米 - 主角,白色毛发,粉红色耳朵内侧,穿蓝色背带裤,性格勇敢好奇 2. 小狐狸橙橙 - 伙伴,橙色毛发,白色尾巴尖,戴绿色围巾,聪明机智 【故事梗概】 小白兔米米住在森林边的小木屋里,有一天她发现了一张神秘的藏宝图。在好朋友小狐狸橙橙的陪伴下,她们踏上了寻宝之旅。途中遇到各种挑战,最后发现真正的宝藏是友谊和勇气。 【画风要求】 温馨治愈的水彩绘本风格,色彩明亮柔和,适合3-6岁儿童阅读`, label: '故事大纲' } }) // ========== 第二阶段:LLM 角色设计 ========== const characterLLMId = getNodeId() nodes.push({ id: characterLLMId, type: 'llmConfig', position: { x: startPosition.x + colSpacing, y: startPosition.y - rowSpacing }, data: { label: '角色设计生成', systemPrompt: `你是专业的绘本角色设计师。根据故事大纲提取所有角色,为每个角色生成适合图像生成的详细提示词。 输出格式(用换行分隔每个角色): [角色名] [角色图像生成提示词] --- 输出要求: 1. 识别故事中的所有角色(主角、配角等) 2. 提示词包含:外貌特征、服装、表情、姿态、场景 3. 使用绘本水彩风格描述 4. 末尾加上"白色简洁背景,儿童绘本水彩风格,温馨治愈,色彩明亮柔和" 5. 直接输出,不要编号、标题或其他格式标记`, model: 'gpt-4o-mini', outputFormat: 'text' } }) // 故事大纲 → 角色设计LLM edges.push({ id: `edge_${storyInputId}_${characterLLMId}`, source: storyInputId, target: characterLLMId, sourceHandle: 'right', targetHandle: 'left' }) // 角色参考图配置 const characterConfigId = getNodeId() nodes.push({ id: characterConfigId, type: 'imageConfig', position: { x: startPosition.x + colSpacing * 2, y: startPosition.y - rowSpacing }, data: { label: '角色参考图', model: 'auto', size: '1024x1536' } }) // LLM → 角色图配置 edges.push({ id: `edge_${characterLLMId}_${characterConfigId}`, source: characterLLMId, target: characterConfigId, type: 'promptOrder', data: { promptOrder: 1 }, sourceHandle: 'right', targetHandle: 'left' }) // 角色参考图结果 const characterImageId = getNodeId() nodes.push({ id: characterImageId, type: 'image', position: { x: startPosition.x + colSpacing * 3, y: startPosition.y - rowSpacing }, data: { url: '', label: '角色参考图结果' } }) // 角色配置 → 角色图结果 edges.push({ id: `edge_${characterConfigId}_${characterImageId}`, source: characterConfigId, target: characterImageId, sourceHandle: 'right', targetHandle: 'left' }) // ========== 第三阶段:LLM 剧情拆分 ========== const storyLLMId = getNodeId() nodes.push({ id: storyLLMId, type: 'llmConfig', position: { x: startPosition.x + colSpacing, y: startPosition.y + rowSpacing * 0.5 }, data: { label: '剧情拆分', systemPrompt: `你是专业的绘本编剧。将故事拆分成绘本页面内容。 输出格式(严格按此格式,换行分割每页): 第1页:[故事配文] | [插画描述提示词] 第2页:[故事配文] | [插画描述提示词] ... 要求: 1. 根据故事复杂度拆分为4-8页 2. 故事配文简洁温馨,适合3-6岁儿童(每页不超过30字) 3. 插画描述要详细,包含角色外貌特征、动作、场景、色调 4. 每页插画描述末尾加上画风说明以保持一致 5. 故事节奏:开场→发展→高潮→温馨结局`, model: 'gpt-4o', outputFormat: 'text' } }) // 故事大纲 → 剧情拆分LLM edges.push({ id: `edge_${storyInputId}_${storyLLMId}`, source: storyInputId, target: storyLLMId, sourceHandle: 'right', targetHandle: 'left' }) // ========== 第四阶段:绘本页面(由 LLM 拆分动态生成) ========== // 操作提示节点 const hintId = getNodeId() nodes.push({ id: hintId, type: 'text', position: { x: startPosition.x + colSpacing * 2.5, y: startPosition.y + rowSpacing * 0.5 }, data: { content: `操作步骤: 1. 先点击「角色设计生成」的【执行生成】,等待生成所有角色参考图 2. 再点击「剧情拆分」的【执行生成】,等待 LLM 输出剧本 3. 在剧情拆分节点中点击【拆分为绘本页】按钮 4. 系统将自动创建每页的故事文字、插画描述和图片生成节点 5. 每页图片会自动关联角色参考图,保持角色一致性 6. 点击各页的【立即生成】按钮生成绘本插画`, label: '📖 操作指南' } }) return { nodes, edges } } } ] /** * Get workflow template by ID | 根据ID获取工作流模板 */ export const getWorkflowById = (id) => { return WORKFLOW_TEMPLATES.find(w => w.id === id) } /** * Get workflows by category | 根据分类获取工作流 */ export const getWorkflowsByCategory = (category) => { return WORKFLOW_TEMPLATES.filter(w => w.category === category) } export default WORKFLOW_TEMPLATES