UI编辑器节点改为单组件模型
修改 Node、Binding DTO、识别与分离链路为 component 单字段 为识别和绑定 LLM 工具引入 PureNode/WithComponent 显式载荷 移除前端组件索引、排序和组件栈操作 同步生成 ts-rs TypeScript 类型、状态校验、测试与专题文档
This commit is contained in:
@@ -8,13 +8,21 @@
|
||||
|
||||
## 识别结果
|
||||
|
||||
- `recognize` 返回完整 `Node.components` 草稿,不再要求用户先导入独立素材。
|
||||
- `components` 为空表示纯节点。
|
||||
- `recognize` 返回完整 `Node.component` 草稿,不再要求用户先导入独立素材。
|
||||
- `component = null` 表示纯节点。
|
||||
- `ImageComponent.target_graphic = None` 表示图片组件等待分离结果回填;它不是“明确没有图片”。
|
||||
- 当前约束:需要分离的节点最多包含一个 `ImageComponent`,回填暂使用该节点的第一个图片组件。
|
||||
- 组件容器“一种组件类型最多一个”的正式重构列为 TODO;当前 `Vec<Component>` 仅按上述约束使用。
|
||||
- 一个 Node 最多承载一个 `Component`;需要多个视觉层时使用多个 Node 表达。
|
||||
- 组件草稿直接保存在正式 UI Node 中;临时 separation tree 不复制组件。
|
||||
|
||||
### LLM 工具中的组件载荷
|
||||
|
||||
正式 `Node` 使用 `component: Option<Component>`,因为 Rust/前端状态需要直接表达“纯结构节点”或唯一组件;但识别和绑定 LLM 工具不使用可空字段。部分模型在严格工具 schema 下不会稳定地产生 `null`,因此工具返回显式外部枚举:
|
||||
|
||||
- `"PureNode"` 表示纯结构节点;
|
||||
- `{ "WithComponent": <完整 Component> }` 表示该节点拥有一个组件。
|
||||
|
||||
Rust 在接收并校验工具结果后,才把这两个枚举变体映射为正式 Node 的 `None` / `Some(Component)`。`PureNode + NeedReview/Blocked` 是非法组合;`PureNode + NoProblem` 合法,带组件节点可以处于 `NoProblem`、`NeedReview` 或 `Blocked`。该枚举只解决工具调用的可判别性,不引入旧 `null` 格式兼容或迁移。
|
||||
|
||||
## Separation tree
|
||||
|
||||
- recognition 完成后由 UI tree 构造临时 separation tree;每棵树保留原 UI tree 的 `src_ui_design` 与真实 `root`,不生成 synthetic root。
|
||||
@@ -70,7 +78,7 @@
|
||||
- problematic 记录原始 NodeId、问题描述和 `rework_count`;原始 UI Node 保留不变。
|
||||
- `SeparationDTO` 不返回计数字段,只返回 `bound_nodes` 与 `problematic_nodes`。
|
||||
- separation Rust 流程不自动登记项目级 SpriteAsset。
|
||||
- 前端调用方消费 `SeparationDTO.bound_nodes`,复制/登记 cut 图片为项目级 SpriteAsset,再回填对应 Node 的第一个 Image component。
|
||||
- 前端调用方消费 `SeparationDTO.bound_nodes`,复制/登记 cut 图片为项目级 SpriteAsset,再回填对应 Node 的唯一 Image component。
|
||||
- 每次重做产生新的 SpriteAssetId,不假设 NodeId 到 SpriteAssetId 的稳定映射。
|
||||
- sidecar 中的图片保留,正式 SpriteAsset 的最终清理策略列 TODO。
|
||||
|
||||
@@ -80,10 +88,10 @@
|
||||
- 如果 sidecar 已存在未完成的 `state.json`,点击入口时先打开独立弹窗,由用户选择“继续上次分离”或“开始新的分离”。继续复用 sidecar 的 pending tree;重新开始只替换当前 `state.json`,不删除 sidecar 图片。
|
||||
- `BoundNode.cut_image_path` 必须是项目根相对路径。前端使用现有 `import_local_project_image_assets` 登记 cut 图片;由于该通用命令单次最多 100 个路径,前端可以在资源登记阶段按 100 条分组调用,但这不属于 separation batch,也不向用户展示。
|
||||
- 现有本地资源导入按清洗后的文件名 stem 与内容摘要生成目标路径;相同目标路径直接复用已有 manifest asset ID,内容不同则拒绝覆盖或生成不同摘要路径。前端不自行猜测 SpriteAsset 是否存在,也不从 NodeId 派生 SpriteAssetId。
|
||||
- 全部可登记图片完成导入后,前端在一个 `runWithStateLocked` 中复用 `addSpriteAssets` 的内部 State 变换逻辑,加入返回的 SpriteAsset 并回填仍匹配 Node 的第一个未绑定 Image component,最后一次性提交 State。公开 `addSpriteAssets` 的普通 mutation guard 不放宽。
|
||||
- 全部可登记图片完成导入后,前端在一个 `runWithStateLocked` 中复用 `addSpriteAssets` 的内部 State 变换逻辑,加入返回的 SpriteAsset 并回填仍匹配 Node 的唯一未绑定 Image component,最后一次性提交 State。公开 `addSpriteAssets` 的普通 mutation guard 不放宽。
|
||||
- UI tree 在 separation 期间发生变化时,已登记的 cut 图片和可匹配节点的回填保留;找不到 Node 或没有未绑定 Image 的结果产生明确问题提示,不回滚已登记资源,不静默跳过。
|
||||
- State 保存成功后才调用 `finalize_separation` 删除 sidecar `state.json`;登记、回填或保存失败时保留 sidecar,允许下次选择继续。sidecar 图片按当前 debug 策略保留。
|
||||
- 本次只替换 UI 编辑器独立页面的 `bindComponents` 前端入口。`binding.rs`、`bind_components` Tauri 命令及 Runtime `workflow.rs` 的旧 binding 链路暂列后续退役/迁移事项。
|
||||
- UI 编辑器独立页面的 `bindComponents` 前端入口、`binding.rs`、`bind_components` Tauri 命令及 Runtime `workflow.rs` 统一使用当前单组件模型;LLM 工具载荷使用 `NodeComponent`,正式 Node 仍使用 `Option<Component>`。
|
||||
|
||||
## 重启与 Raw GPT Image 2
|
||||
|
||||
@@ -95,8 +103,6 @@
|
||||
|
||||
## TODO
|
||||
|
||||
- `Vec<Component>` 重构为一种组件类型最多一个的容器。
|
||||
- 当前第一个 Image component 回填规则的正式替代方案。
|
||||
- 正在执行 batch 的持久化和恢复。
|
||||
- 前端自动分离接入已实现;仍需补齐真实 Tauri/前端联调回归测试与失败注入测试。
|
||||
- 临时图片清理/归档策略。
|
||||
|
||||
Reference in New Issue
Block a user