Add concat by target two-port UI design spec

This commit is contained in:
Gin3601
2026-05-26 11:32:46 +08:00
parent 9d95ac58b1
commit 6926861bc3
@@ -0,0 +1,243 @@
# LLS Concat By Target Two-Port UI Design
## Context
`LLS Concat By Target` 当前已经支持自动识别 `IMAGE` 和 `MASK` 输入,并且运行时可以只靠两路数据完成拼接逻辑。
当前问题不在运行逻辑,而在 ComfyUI 节点 UI:
- 后端把两个输入声明成 `IMAGE,MASK`
- ComfyUI 前端会把这种联合类型拆成 4 个可见输入口
- 用户实际看到的是 4 个端口,而不是预期的 2 个端口
用户要的最终效果很明确:
- 节点左侧只保留 2 个可见输入口
- 这两个输入口显示为 `image/mask_A` 和 `image/mask_B`
- 两个口都继续支持 `IMAGE` 和 `MASK`
- 运行时继续自动判断实际输入类型
## Goals
- 把 `LLS Concat By Target` 的 UI 从 4 个可见输入口收敛成 2 个
- 保持两个输入都能接 `IMAGE` 或 `MASK`
- 保持现有自动识别逻辑和混接报错逻辑
- 让节点界面显示名使用 `image/mask_A` 和 `image/mask_B`
- 保持现有输出和拼接行为不变
## Non-Goals
本次不做以下事情:
- 不新增独立的 `image_A` / `image_B` / `mask_A` / `mask_B` 四路 schema
- 不修改拼接算法、尺寸匹配、gap、batch broadcast 等运行时行为
- 不引入额外 widget 来切换输入模式
- 不尝试修改 ComfyUI 核心联合类型渲染逻辑
## Chosen Approach
采用“后端 2 个通配输入 + 前端改显示标签”的组合方案。
### Backend
- 把 `LLSConcatByTarget.INPUT_TYPES()` 的可选输入从:
- `image/mask_A: IMAGE,MASK`
- `image/mask_B: IMAGE,MASK`
- 调整为:
- `a: *`
- `b: *`
这里的 `*` 沿用项目里已经用过的 `AnyType("*")` 模式,使 ComfyUI 在节点 UI 中只生成 2 个可见输入口,而不是按联合类型拆成 4 个。
运行时继续保留现有自动识别逻辑:
- `a` 和 `b` 都是图像张量时,走 `IMAGE` 拼接
- `a` 和 `b` 都是遮罩张量时,走 `MASK` 拼接
- 一边图像一边遮罩时,抛出清晰错误
### Frontend
- 新增一个很小的前端扩展文件,例如 `web/js/lls_concat_by_target.js`
- 在 `beforeRegisterNodeDef` 中挂接 `LLSConcatByTarget`
- 在节点创建后查找输入名为 `a` 和 `b` 的两个输入
- 只修改它们的显示标签:
- `a -> image/mask_A`
- `b -> image/mask_B`
这个扩展只负责 UI 呈现,不改变连接和运行逻辑。内部 schema 名仍然是 `a` / `b`,所以不会依赖 ComfyUI 对带斜杠名字的输入做特殊处理。
## Why This Approach
### Option A: 直接使用 `IMAGE,MASK` 联合类型并把输入名写成 `image/mask_A` / `image/mask_B`
不采用。
原因:
- 这正是当前 4 个可见输入口的来源
- 即使名字符合预期,UI 结构仍然不符合用户目标
### Option B: 后端使用 `a` / `b` 通配输入,但不加前端重命名
不采用。
原因:
- 可以得到 2 个可见输入口
- 但界面显示会是 `a` 和 `b`,不符合用户要求
### Option C: 后端通配输入 + 前端改标签
采用。
原因:
- 可以稳定得到 2 个可见输入口
- 可以把显示名改成用户想要的 `image/mask_A` / `image/mask_B`
- 不需要修改现有拼接逻辑
- 风险和改动范围最小
## File Changes
本次会修改或新增以下文件:
- Modify: `utils/concat_by_target.py`
- Create: `web/js/lls_concat_by_target.js`
- Modify: `tests/test_concat_by_target_registration.py`
- Modify: `tests/test_concat_by_target_node.py`
- Create: `tests/test_concat_by_target_frontend.py`
如有需要,也可以补一条节点文档说明到 `LLS-Nodes-Reference.md`,但这不是本次行为变更的阻塞项。
## Backend Contract
### Node Identity
- class key: `LLSConcatByTarget`
- display name: `LLS Concat By Target`
- category: `LLS/Utils`
- function: `concat`
### Inputs
Required inputs 保持不变:
- `data_type`
- `target`
- `position`
- `match_target_size`
- `resize_mode`
- `align`
- `gap`
- `background_color`
- `background_value`
- `multiple_of`
- `allow_batch_broadcast`
Optional inputs 调整为:
- `a: *`
- `b: *`
### UI Labels
节点界面中:
- `a` 显示为 `image/mask_A`
- `b` 显示为 `image/mask_B`
这里的“显示为”仅指前端 label,不改变后端实际字段名。
### Outputs
保持不变:
- `image: IMAGE`
- `mask: MASK`
- `width: INT`
- `height: INT`
## Runtime Behavior
运行时行为保持现状:
1. 从 `a` / `b` 读取输入
2. 根据张量形状自动推断是 `IMAGE` 还是 `MASK`
3. 两边同类型时继续对应拼接流程
4. 两边类型不一致时抛出明确错误
5. `data_type` 仅在无法从输入推断时作为回退值
这意味着本次改动是 UI/schema 形态调整,不是算法行为调整。
## Error Handling
保留或继续强化以下报错语义:
- `IMAGE` 路径缺少 `a` 或 `b` 时,报缺少两个输入
- `MASK` 路径缺少 `a` 或 `b` 时,报缺少两个输入
- `a` / `b` 混接 `IMAGE` 和 `MASK` 时,报两边类型不一致
- 输入 shape 非法时,继续沿用现有 shape 校验错误
错误消息可以在文案中提及 `image/mask_A` / `image/mask_B`,但内部实现仍可使用 `a` / `b` 来接收参数。
## Testing
### Registration Tests
更新注册测试,验证:
- `optional["a"]` 和 `optional["b"]` 存在
- 可选输入不再是 `image/mask_A` / `image/mask_B`
- 节点元数据和输出保持不变
### Runtime Tests
保留现有节点运行测试,确保:
- 图像输入仍然可以拼接
- 遮罩输入仍然可以拼接
- 自动识别逻辑不变
- 混接仍然报错
这些测试大多只需要继续走 `a` / `b` 输入,不需要覆盖 UI 标签。
### Frontend Tests
新增前端资产测试,验证:
- `web/js/lls_concat_by_target.js` 存在
- 文件注册了 ComfyUI 扩展
- 目标节点是 `LLSConcatByTarget` / `LLS Concat By Target`
- 文件中包含 `image/mask_A` 和 `image/mask_B`
- 文件中包含对 `a` 和 `b` 的标签重写逻辑
## Compatibility
### New Nodes
新建节点时,用户会看到 2 个输入口,符合目标 UI。
### Existing Workflows
这是本次唯一需要注意的兼容点。
如果历史工作流已经把 schema 输入名保存成 `image/mask_A` / `image/mask_B`,单纯把后端改回 `a` / `b` 可能导致旧工作流无法自动连回对应输入。
因此实现阶段需要一并确认其中一种处理方式:
- 优先方案:在前端节点创建/图配置完成时,把旧工作流中的这两个历史输入名映射到当前节点的 `a` / `b`
- 如果 ComfyUI 当前序列化结构不便做安全映射,则至少要在实现中验证:
- 新建节点满足目标
- 并明确记录旧工作流是否需要手动重连
如果兼容映射实现足够简单且可靠,应当一并纳入本次修改;如果映射风险偏高,则优先保证新节点 UI 和运行正确,不在本次扩展更大范围的工作流迁移逻辑。
## Acceptance Criteria
- `LLS Concat By Target` 在 ComfyUI 界面中只显示 2 个输入口
- 两个输入口显示名分别为 `image/mask_A` 和 `image/mask_B`
- 两个输入口都能连接 `IMAGE` 或 `MASK`
- 连接两路 `IMAGE` 时,图像拼接行为保持正确
- 连接两路 `MASK` 时,遮罩拼接行为保持正确
- 混接 `IMAGE` 与 `MASK` 时,继续报错
- 自动化测试覆盖后端注册、运行逻辑和前端扩展存在性