Appearance
Feature: 节点间数据流
一句话目标
用户在下游节点触发 AI 生成时,系统自动收集所有上游节点的输出内容,按数据类型注入到生成请求的对应参数中。三个生成接口均支持文本、图片、视频三种输入类型,具体哪些输入生效由模型能力决定。
与画布系统的关系
连线的一切(创建、删除、渲染、持久化、验证、连接角色规则)均属于画布系统。数据流不管理连线,只通过 flowStore 的 edges 读取"谁连着谁",基于此收集上游节点数据。
行为约束
约束 1:数据收集时机
前置条件: 用户在下游节点点击生成 行为: 系统通过 flowStore.edges 找到所有以该节点为 target 的连线,读取对应 source 节点的输出 后置条件: 上游数据在生成请求发出前收集完毕,作为参数注入
约束 2:输出内容提取规则
| 上游类型 | 提取字段 | 说明 |
|---|---|---|
| text | result(优先)或 content(回退) | result 是 AI 生成结果,content 是用户编辑内容(HTML,需剥离标签);两者都是节点的"产出" |
| image | imageUrl | 当前展示的主图 URL |
| video | videoUrl | 当前视频 URL |
不提取
prompt(那是生成指令,不是产出内容)
约束 3:上游输出注入下游参数的规则
收集到上游输出后,按数据类型注入到下游生成请求的对应参数:
- 文本类输出 → 拼接到下游
prompt前面(上游文本在前,用户 prompt 在后,空行分隔) - 图片类输出 → 注入下游
images[]参数 - 视频类输出 → 注入下游
videos[]参数
三个生成接口(文本、图片、视频)均接受这三种输入参数。哪些输入实际生效由模型能力决定,数据流层只负责收集和注入,不判断兼容性。模型不支持的输入类型由后端忽略或返回错误。
约束 4:多上游合并策略
前置条件: 下游节点有多条入边 行为: 按连线创建时间顺序收集;同类型上游输出合并(文本拼接,图片追加到 images[],视频追加到 videos[]) 后置条件: 合并后的参数传递给 AI Service
约束 5:上游无输出时静默跳过
前置条件: 上游节点 status 为 idle 或输出字段为空 行为: 跳过该上游,不报错、不阻塞 后置条件: 下游正常生成,仅携带有输出的上游数据
约束 6:全量注入,不判断兼容性
前置条件: 上游输出已收集 行为: 全量注入到请求参数中,不判断模型是否支持该输入类型 后置条件: 由后端根据模型能力决定如何处理不支持的输入(忽略或报错)
兼容性的前置提示属于 model-capabilities 和 edge-system AC-11 的职责。
约束 7:上游数据为只读快照
前置条件: 收集上游数据时 行为: 读取上游节点当前时刻的输出值,不建立响应式绑定 后置条件: 上游后续变更不影响已发出的生成请求
约束 8:prompt 拼接规则
前置条件: 存在上游文本输出且用户有自身 prompt 行为: 上游文本在前,用户 prompt 在后,以空行分隔 后置条件: 拼接后的完整文本作为 prompt 参数发送
格式:
{上游文本1}
{上游文本2}
{用户prompt}仅上游文本或仅用户 prompt 时不拼接,直接使用有值的部分。
约束 9:自身媒体与上游媒体合并
前置条件: 下游节点自身有媒体(如 ImageNode 已上传图片、VideoNode 已截帧) 行为: 自身媒体与上游同类型媒体合并(去重),自身在前、上游在后 后置条件: 合并后的列表作为 images[] 或 videos[] 参数发送
Acceptance Criteria
收集层(约束 1、2)
- [x] AC-01:下游节点生成时,自动通过 edges 收集所有上游节点的输出内容
- [x] AC-02:文本节点输出提取
result(优先)或content(回退),HTML 标签剥离为纯文本 - [x] AC-03:图片节点输出提取
imageUrl - [x] AC-04:视频节点输出提取
videoUrl
注入层 — 文本类(约束 3、8)
- [x] AC-05:上游文本拼接到下游
prompt前面,空行分隔用户 prompt - [x] AC-06:仅有上游文本无用户 prompt 时,prompt 为上游文本本身
- [x] AC-07:仅有用户 prompt 无上游文本时,prompt 不变
注入层 — 图片类(约束 3、9)
- [x] AC-08:上游图片注入 TextNode 的
images[]参数 - [x] AC-09:上游图片注入 ImageNode 的
images[]参数,与自身图片合并去重 - [x] AC-10:上游图片注入 VideoNode 的
images[]参数
注入层 — 视频类(约束 3)
- [x] AC-11:上游视频注入 TextNode 的
videos[]参数 - [x] AC-12:上游视频注入 ImageNode 的
videos[]参数 - [x] AC-13:上游视频注入 VideoNode 的
videos[]参数
合并与边界(约束 4、5、7)
- [x] AC-14:多上游节点的输出按连线创建顺序合并
- [x] AC-15:上游节点无输出时静默跳过,不阻塞下游
- [x] AC-16:收集的上游数据为只读快照,不建立响应式绑定
BDD Scenarios
gherkin
Feature: 节点间数据流
# AC-01, AC-02, AC-05
Scenario: 文本节点输出拼接到下游 prompt
Given 文本节点 A 已生成内容 "一只可爱的猫"
And A 连线到图片节点 B
And B 的用户 prompt 为 "添加翅膀"
When 用户在 B 中点击生成
Then B 的生成请求 prompt 为 "一只可爱的猫\n\n添加翅膀"
# AC-02 回退路径
Scenario: 文本节点无 result 时回退到 content(HTML 剥离)
Given 文本节点 A 未触发过生成
And A 的编辑器内容为 "<p>手动输入的描述</p>"
And A 连线到图片节点 B
When 用户在 B 中点击生成
Then B 的 prompt 中包含纯文本 "手动输入的描述"
# AC-06
Scenario: 仅有上游文本无用户 prompt
Given 文本节点 A 已生成 "赛博朋克城市"
And A 连线到图片节点 B
And B 的用户 prompt 为空
When 用户在 B 中点击生成
Then B 的生成请求 prompt 为 "赛博朋克城市"
# AC-07
Scenario: 无上游文本仅有用户 prompt
Given 图片节点 A 已生成图片(无文本输出)
And A 连线到图片节点 B
And B 的用户 prompt 为 "变成油画风格"
When 用户在 B 中点击生成
Then B 的 prompt 为 "变成油画风格"(不拼接)
# AC-08
Scenario: 图片节点输出注入文本节点
Given 图片节点 A 已生成图片
And A 连线到文本节点 B
When 用户在 B 中点击生成
Then B 的生成请求 images 参数包含 A 的 imageUrl
# AC-09
Scenario: 图片节点输出注入图片节点(合并去重)
Given 图片节点 A 已生成图片 url-1
And 图片节点 B 自身已上传图片 url-1
And A 连线到 B
When 用户在 B 中点击生成
Then B 的 images 参数为 ["url-1"](去重后)
# AC-10
Scenario: 图片节点输出注入视频节点
Given 图片节点 A 已生成图片
And A 连线到视频节点 B
When 用户在 B 中点击生成
Then B 的生成请求 images 参数包含 A 的 imageUrl
# AC-11
Scenario: 视频节点输出注入文本节点
Given 视频节点 A 已生成视频
And A 连线到文本节点 B
When 用户在 B 中点击生成
Then B 的生成请求 videos 参数包含 A 的 videoUrl
# AC-14
Scenario: 多上游按连线顺序合并
Given 文本节点 A 已生成 "一只猫"
And 文本节点 C 已生成 "在花园里"
And A 先连线到图片节点 B,C 后连线到 B
When 用户在 B 中点击生成
Then B 的 prompt 中 "一只猫" 在 "在花园里" 之前
# AC-05, AC-09 组合
Scenario: 混合类型上游分别注入对应参数
Given 文本节点 A 已生成 "赛博朋克风格"
And 图片节点 C 已生成图片
And A 和 C 均连线到图片节点 B
And B 的用户 prompt 为 "添加霓虹灯"
When 用户在 B 中点击生成
Then B 的 prompt 为 "赛博朋克风格\n\n添加霓虹灯"
And B 的 images 参数包含 C 的 imageUrl
# AC-15
Scenario: 上游无输出时静默跳过
Given 文本节点 A 处于 idle 状态(无 result 且 content 为空)
And A 连线到图片节点 B
When 用户在 B 中输入 prompt 并点击生成
Then B 正常发起生成请求,prompt 仅为用户输入TDD 单元测试要点
收集层(collectUpstreamOutputs,测试文件 test/unit/collectUpstream.test.ts):
- [x] 给定 edges 和 nodes,正确找到指定节点的所有上游节点
- [x] 文本节点:result 有值时提取 result,为空时回退到 content
- [x] 文本节点:HTML 内容剥离标签,空 HTML 视为无输出
- [x] 图片节点:提取 imageUrl
- [x] 视频节点:提取 videoUrl
- [x] 上游无输出时返回空,不报错
- [x] 多上游按 edge 创建顺序排列
prompt 拼接函数(buildPrompt,测试文件 test/unit/collectUpstream.test.ts):
- [x] 有上游文本 + 有用户 prompt → 上游在前、空行分隔、用户 prompt 在后
- [x] 有上游文本 + 无用户 prompt → 仅上游文本
- [x] 无上游文本 + 有用户 prompt → 仅用户 prompt
- [x] 多段上游文本按顺序换行拼接
注入层(各节点 onGenerate):
- [x] TextNode 注入
images[]和videos[] - [x] ImageNode 注入
images[](自身+上游去重)和videos[] - [x] VideoNode 注入
images[]和videos[] - [x] 三种节点都执行 prompt 拼接
- [x] 无有效上游时参数不受影响
Out of Scope
- 实时数据流(上游变更自动触发下游重新生成)
- 条件分支(根据上游内容决定下游行为)
- 上游输出的版本选择(多 variations 时选择哪一个 — 当前取主图/主结果)
- 模型能力查询与兼容性判断 — 属于 model-capabilities
- 连线兼容性警告 UI — 属于 edge-system AC-11/AC-12
- 输入数量截断(images/videos 超出模型 maxCount 时的处理)— 属于模型能力层职责
context独立字段方案 — 当前采用 prompt 拼接,待后端支持后可切换