Files
20260512-skg-tk/web/canvas-app/src/config/workflows.js

1237 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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.330小时超长续航防水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