WIP: UI编辑器自动分图层切图标 #304

Draft
k88936 wants to merge 100 commits from feat/ui-editor-auto-seperation into master
Showing only changes of commit b2d4690f94 - Show all commits
@@ -0,0 +1,75 @@
# UI 编辑器自动分离工作流
更新时间:`2026-09-08`
## 目标
将 UI 编辑器现有“用户先提供独立图片/图标,再执行组件绑定”的入口替换为自动分离:结构识别阶段直接返回可渲染组件草稿,分离阶段按整页叶节点批次调用图片编辑模型,再由视觉模型确认处理图中的区域与目标节点。
## 识别结果
- `recognize` 返回完整 `Node.components` 草稿,不再要求用户先导入独立素材。
- `components` 为空表示纯节点。
- `ImageComponent.target_graphic = None` 表示图片组件等待分离结果回填;它不是“明确没有图片”。
- 当前约束:需要分离的节点最多包含一个 `ImageComponent`,回填暂使用该节点的第一个图片组件。
- 组件容器“一种组件类型最多一个”的正式重构列为 TODO;当前 `Vec<Component>` 仅按上述约束使用。
- 组件草稿直接保存在正式 UI Node 中;临时 separation tree 不复制组件。
## Separation tree
- recognition 完成后由 UI tree 构造临时 separation tree。
- 纯节点、纯 Text 节点和不需要切图的节点在构造时过滤;被过滤节点的可处理 children 向上透传。
- separation tree 只保留真实待处理节点。
- 一个 batch 是整页当前所有互不重叠叶节点。
- 一个 batch 的最小处理单元是:一次 image-edit + 一次 visual binding。
- batch 成功后从 pending tree 移除对应叶节点,并把结果放入 bound 容器;失败节点移入 problematic 容器,流程继续消费剩余树。
- 不额外维护节点状态枚举;节点是否仍在 pending tree、`rework_count` 和 problematic 容器共同表达状态。
## 图片编辑与视觉绑定
- image-edit 使用源 UI design 图片及由 Rust 生成的绿色标记/紫色重建输入。
- 请求尺寸始终使用源 UI design 尺寸;Raw GPT Image 2 API 保证返回相同尺寸,客户端不额外做尺寸拒绝检查。
- 视觉 binding 输入源图与处理图,必须为当前 batch 每个节点恰好返回一次 `Ok``NeedRework`
- `Ok` 返回 `NodeId + BindingArea`Rust 仅校验 NodeId、区域边界和非零尺寸,不检查与原节点框的偏差,也不要求区域不重叠。
- `NeedRework` 携带短问题描述。结构化工具调用失败时使用可复用 repair harness,把错误反馈给模型并额外请求一次;image-edit 不使用该 harness。
- 达到模块级重做常量后,节点移入 problematic;不中断整条工作流,最终统一通知用户。
- 父节点背景重建由 image-edit 模型完成,不由 Rust 硬编码重建算法完成。
## 临时 sidecar
- separation 状态不写入 UI JSON,也不进入 manifest。
- sidecar 目录按 UI manifest `asset_id` 生成,复用 `generated_file_stem(asset_id)` 的安全字符替换和 SHA-256 摘要规则,位于项目 `ui/` 下。
- 目录只保存一份当前 separation state,而不是每 batch 一个状态文件。
- state 文件只保留 `schema_version`、pending tree、bound 结果和 problematic 节点,不重复保存 `projectId / assetId / uiStateRevision`
- sidecar 只在 separation 未完成期间存在;完成后删除 state JSON。
- 当前只持久化已经完成的 batch;正在执行 batch 的恢复语义列 TODO。
- 临时图片可跨重启保留。raw image-edit 返回图、绿色/紫色标记图、处理图和 cut 图片当前都保留用于 debug;理论上只应在内存中,清理/归档策略列 TODO。
## bound 与 problematic
- bound 结果仅保存 `NodeId + cut_image_path`,不保存 `BindingArea` 或 component kind。
- problematic 记录原始 NodeId、问题描述和 `rework_count`;原始 UI Node 保留不变。
- `SeparationDTO` 不返回计数字段,只返回 `bound_nodes``problematic_nodes`
- separation Rust 流程不自动登记项目级 SpriteAsset。
- 前端调用方消费 `SeparationDTO.bound_nodes`,复制/登记 cut 图片为项目级 SpriteAsset,再回填对应 Node 的第一个 Image component。
- 每次重做产生新的 SpriteAssetId,不假设 NodeId 到 SpriteAssetId 的稳定映射。
- sidecar 中的图片保留,正式 SpriteAsset 的最终清理策略列 TODO。
## 重启与 Raw GPT Image 2
- 已保存的 separation state 是跨重启继续工作的最小单位;重启后从上一个已保存 batch 的状态继续。
- 当前执行中的 batch 是否持久化、以及如何避免 image-edit 成功后在 patch 前崩溃导致重复调用,列为 TODO。
- Raw endpoint 每次 HTTP 调用都是一次新操作;客户端不保存或复用 raw operation ID,不实现第二套本地幂等账本。
- 后端 raw operation 的持久状态与扣费后崩溃恢复窗口,遵循 Raw GPT Image 2 方案中的独立 TODO。
## TODO
- `Vec<Component>` 重构为一种组件类型最多一个的容器。
- 当前第一个 Image component 回填规则的正式替代方案。
- 正在执行 batch 的持久化和恢复。
- 前端复制、登记 SpriteAsset、回填 State 的精确 IPC/提交合同。
- 临时图片清理/归档策略。
- 手动抠图能力。
- problematic 对更高层 workflow 完成门禁的最终定义。
- separation workflow 与 manifest/stage 的接入。
- Raw GPT Image 2 后端 raw operation 持久状态及恢复 worker。