13 KiB
13 KiB
图片生成无法删除失败图片 BUG TODO
状态:Step 2 方案已确认,待进入实施 页面:图片生成入口
/asset-factory所进入的模特上身图、平台套图、图片创作 协作规则:一次只执行一个 Step;在确认问题表现前,不排查、不修改代码。
1. 待确认的问题表现
用户提供的三个入口截图显示:
- 模特上身图、平台套图与图片创作都可在失败/生成批次的“更多”菜单中看到“删除当前批次”;
- 失败批次没有实际图片资产,页面只显示“这张生成失败”的占位格;
- 点击删除的目标是整个失败批次,而非某一张已生成的图片;预期应当让该失败批次不再显示,且刷新、切换商品或重新进入页面后也不应恢复。
2. 初步目标
让失败批次能够被可靠删除:删除后立即从当前页面消失,且后端不会再将该失败任务回放到工作台;正常成图删除、生成中任务、重跑与积分结算不受影响。
3. 后续步骤(待现象确认后执行)
Step 1:只读定位删除链路
- 定位图片生成页面中失败图片的删除入口、可见条件和请求;
- 定位后端删除接口及其对失败任务、资产和批次状态的处理;
- 先给出根因假设与最小修复范围,不修改代码。
状态:已完成,未改业务代码。
排查结论:这是“删除资产”被错误地当作“删除批次/任务”的问题,失败批次没有资产,因此没有任何后端记录被删除。
- 三个图片生成入口共用
core/frontend/src/routes/ai-tools.tsx的ImageWorkbenchPage;失败格由“批次数量大于成功资产数”在前端补出,并不对应一张Asset。 - 当前确认删除逻辑只收集
batch.results.map(a => a.id)后调用DELETE /api/assets/<asset-id>/。纯失败批次的results为空,所以请求列表为空,点击确认不会发送任何删除请求;前端只是暂时把卡片从内存中移除。 - 模特上身图/平台套图在挂载、切换商品时会请求
GET /api/ai/tasks/workbench/。该接口会继续返回失败的AITask,前端将其还原为failed批次,因此删除后的失败卡会在刷新、切换商品或重新进入页面时恢复。 - 图片创作使用对话任务恢复,但失败任务同样没有资产;当前删除路径同样不具备删除任务的能力。
关键位置:
| 环节 | 位置 | 证据 |
|---|---|---|
| 失败格生成 | core/frontend/src/routes/ai-tools.tsx renderBatchGrid |
无成图且批次已终态时,渲染“这张生成失败”占位 |
| 当前删除动作 | 同文件 doConfirmedDelete |
只调用 api.deleteAsset();失败批次 results=[],不会请求接口 |
| 工作台恢复 | 同文件 batchesFromWorkbenchTasks 与恢复 effect |
失败任务被还原成失败批次 |
| 后端回放 | core/backend/apps/ai/views.py AITaskViewSet.workbench |
查询未排除已删除任务,且当前不存在工作台任务/批次删除接口 |
本 Step 的结论不涉及模型、生成请求、积分或视觉样式;尚未实施修复。
Step 2:确认修复方案
- 明确要修复的状态与边界;
- 确认删除后页面、任务记录与批次卡应如何呈现;
- 经确认后再实施。
状态:已完成,已确认“失败/异常批次整批可恢复;全成功批次维持现状”,待实施。
2.1 确认的行为边界
| 场景 | 修复后行为 |
|---|---|
| 纯失败批次(无成图资产) | 整批进入垃圾桶的“图片异常批次”分区;卡片立即消失,刷新/切换/重新进入后不恢复;可整批恢复 |
| 全部成功批次(有成图且无失败) | 保持当前行为:每张成图进入既有“资产”分区,按图片恢复;不创建批次垃圾桶记录 |
| 同一批含失败、成功或补图/重跑任务 | 视为异常批次:以真实 batch_id 为范围整体删除和整体恢复,不留下孤立失败格或补图;已成功图片不单独出现在“资产”分区 |
| 生成中、排队中、后处理中 | 不提供批次删除;不尝试取消供应商请求、不改任务状态、不触发额外退款逻辑 |
| 图片创作中的某一批 | 只删除该批任务,保留同一对话的其它批次与对话本身 |
| 单张成功图片删除 | 沿用现有资产删除与垃圾桶恢复逻辑;本次不改变 |
compensating 在前端当前被视为终态,但文案为“回滚中”;本次按安全边界把它与其它在途状态一样禁止删除,待积分回滚完成并转为 failed 或 cancelled 后,用户才可删除。
2.2 确认的最小实现方案
- 在
AITaskViewSet增加仅用于异常图片批次的“删除当前批次 / 批次垃圾桶 / 恢复批次 / 彻底删除批次”接口。前端只提交批次中的一个锚点任务 ID;后端从该任务自行确认团队、图片模式、是否属于独立工作台,并以其真实batch_id查出同批任务。旧数据没有batch_id时只处理该锚点任务。 - 接口仅接受
succeeded、failed、cancelled三种已结束状态;任何在途任务返回可见的拒绝结果,且不修改数据。 - 后端先判断整批任务是否含
failed或cancelled:没有失败的全成功批次继续走现有逐张资产软删;含失败的异常批次才进入新的批次软删流程。这样全成功批次的现有删除与资产垃圾桶行为不变。 - 异常批次的删除、恢复和彻底删除均在同一数据库事务中处理该批全部
AITask与其已生成Asset:删除标记is_deleted=True,恢复统一复原,彻底删除再写入purged_at。失败任务没有资产时,仍作为可恢复的批次记录存在。 - 在现有全局垃圾桶新增“图片异常批次”分区,复用已有列表行、恢复、彻底删除、清空和全部恢复交互;不新建垃圾桶页面或视觉组件。批次行显示原提示词、模式、张数、删除时间;缩略图优先使用该批次所属商品的商品图(模特上身图、平台套图及关联商品的图片创作均适用),商品不存在或无可用商品图时回退现有“无图”占位。商品图只作展示引用,不复制、不删除、不影响商品本身。
- 为避免异常批次出现两个恢复入口:该批任务处于删除状态时,其成功图片不单独列入“资产”分区;只有全成功批次、资产库删除或单图删除,才继续出现在“资产”分区。异常批次恢复会恢复该批的图片和任务记录;单图恢复维持现有语义。
GET /api/ai/tasks/workbench/与图片创作对话的tasks读取接口均过滤is_deleted=False、purged_at is null,防止删除的异常任务再次被回放。- 前端批次数据补存完整任务 ID 列表(当前恢复批次只保留卡片 ID,无法稳定定位后端锚点);点击“删除当前批次”后先等待接口成功,再从本地列表移除。请求失败时保留卡片,并复用应用既有通知提示失败原因。
- “更多 → 删除当前批次”只在批次已结束时显示;现有确认弹窗文字改为“删除后可在垃圾桶恢复”。不新增弹窗、颜色、按钮或样式。
2.3 用户操作变化
生成页面的主流程不变:仍是“更多 → 删除当前批次 → 确认删除”。用户只会在需要反悔时,多一个恢复路径:
全局侧栏「垃圾桶」
→ 「图片异常批次」分区
→ 恢复(整批任务与图片回到原图片生成入口)
“全部恢复”和“清空垃圾桶”会包含这个异常批次分区,行为与商品、资产等现有分区一致;全成功批次则继续由“资产”分区按图片恢复。
2.4 明确不在本次范围
- 不取消或中断供应商正在执行的图片生成;
- 不改变已预扣/已结算/失败补偿的积分逻辑;
- 不新增失败图片的单格删除按钮(失败格无可删除资产,删除语义仍是“删除当前批次”);
- 不删除图片创作的整条对话,也不改变对话垃圾桶;
- 不修改模型路由、提示词、生成结果、页面视觉或共享 CSS。
2.5 实施验收与回归
- 纯失败的模特上身图、平台套图、图片创作批次均可删除;刷新、切换商品/对话及重新进入页面后不再显示。
- 一批中含成功图与失败图时,删除后整批不回显,并仅出现在“图片异常批次”分区;恢复后任务和全部图片一并恢复。
- 含“重跑/补图”的同一
batch_id会整体删除,不留下孤立失败格或历史补图。 - 生成中、排队中、后处理中与回滚中的批次没有删除入口;任务继续按既有流程完成或失败。
- 非当前团队、项目内任务、非图片生成任务不可通过新接口删除。
- “全部恢复 / 清空垃圾桶”正确包含图片异常批次;异常批次删除的图片不会与资产分区重复出现;全成功批次仍仅出现在资产分区。
- 图片异常批次优先展示所属商品图;未关联商品、商品已不可用或无商品图时稳定回退“无图”占位,不影响恢复和彻底删除。
- 后端定向测试覆盖上述状态、团队隔离、删除→垃圾桶→恢复→工作台回放、彻底删除与重复隐藏;前端执行 TypeScript/生产构建检查。测试全部使用模拟任务,不发起真实模型调用或积分消耗。
Step 3:实施与验证
- 按已确认方案完成最小改动;
- 验证失败图片可删除,正常图片与其他生成流程不受影响。
状态:已完成。
实施结果:
- 图片工作台的“删除当前批次”现在提交批次锚点任务给后端统一判断。全成功批次继续按原有逻辑将成图逐张移入“资产”垃圾桶;含
failed或cancelled任务的批次会作为一个可恢复的异常批次删除。 - 新增“图片异常批次”的删除、恢复、彻底删除与垃圾桶读取接口。异常批次恢复时,任务记录、成功成图和失败卡会一起恢复;同一
batch_id的补图/重跑任务也一起处理。删除的异常任务已从工作台和图片创作对话的历史读取中排除,刷新后不会复活。 - 全局垃圾桶新增“图片异常批次”分区,复用现有列表行、恢复、彻底删除、全部恢复和清空垃圾桶交互;优先显示所属商品图,无法取得时沿用“无图”占位。异常批次中的成功图不会在“资产”分区重复显示;全成功批次保持原有资产分区行为。
- 生成中、排队中、处理中或回滚中的批次由后端拒绝删除;前端只为已结束批次展示“删除当前批次”。单张图片删除、整条图片创作对话删除、模型调用、积分扣除与补偿逻辑未改动。
- 页面未新增 CSS、颜色、圆角或组件;继续使用既有垃圾桶行、缩略图、按钮、Toast 与确认弹窗。确认弹窗文案已明确说明“删除后可在垃圾桶恢复”。
验证:
- 图片批次定向回归
9 / 9通过:纯/部分失败批次删除、恢复、彻底删除、商品图缩略、全成功批次原行为、图片创作对话回放、在途拒删与团队隔离; - AI 模块完整回归
58 / 58通过; - 前端 TypeScript 与生产构建通过;
git diff --check通过;- 所有测试使用 SQLite 和模拟模型,不产生真实模型调用或积分消耗。
Step 4:页面回归与交付检查
状态:已完成(自动化回归)。
- 已复查删除入口仅在批次结束后显示;
回滚中现与生成、排队、处理中一样视为在途状态,不显示删除入口,待最终转为failed或cancelled后才可删除。 - 已复查垃圾桶沿用既有列表行:异常批次使用商品图缩略图,无法取得时使用现有无图占位;不新增页面、Tab、组件或 CSS。
- 前端生产构建再次通过,
git diff --check通过。 - 未创建真实失败生成任务,未消耗积分;浏览器连接在本机运行时初始化时受限,实际页面点击验收留待开发环境中已有失败批次时按 Step 2.5 的清单执行。
真实页面验收(2026-07-15)
状态:通过。
- 模特上身图中的 1 张失败批次可通过「更多 → 删除当前批次」进入删除流程;
- 删除后,垃圾桶出现「图片异常批次 · 1」分区。该行展示关联商品图缩略图、原提示词、
模特上身图 · 1 张与删除时间; - 点击恢复后,失败批次重新出现在原商品的模特上身图工作台,仍显示失败格;
- 本次未点击彻底删除或清空垃圾桶,保留数据的可恢复性。