Files
yingqing/docs/bug_todo/图片生成-无法删除失败图片-bug-todo.md
T

13 KiB
Raw Blame History

图片生成无法删除失败图片 BUG TODO

状态:Step 2 方案已确认,待进入实施 页面:图片生成入口 /asset-factory 所进入的模特上身图、平台套图、图片创作 协作规则:一次只执行一个 Step;在确认问题表现前,不排查、不修改代码。

1. 待确认的问题表现

用户提供的三个入口截图显示:

  • 模特上身图、平台套图与图片创作都可在失败/生成批次的“更多”菜单中看到“删除当前批次”;
  • 失败批次没有实际图片资产,页面只显示“这张生成失败”的占位格;
  • 点击删除的目标是整个失败批次,而非某一张已生成的图片;预期应当让该失败批次不再显示,且刷新、切换商品或重新进入页面后也不应恢复。

2. 初步目标

让失败批次能够被可靠删除:删除后立即从当前页面消失,且后端不会再将该失败任务回放到工作台;正常成图删除、生成中任务、重跑与积分结算不受影响。

3. 后续步骤(待现象确认后执行)

Step 1:只读定位删除链路

  • 定位图片生成页面中失败图片的删除入口、可见条件和请求;
  • 定位后端删除接口及其对失败任务、资产和批次状态的处理;
  • 先给出根因假设与最小修复范围,不修改代码。

状态:已完成,未改业务代码。

排查结论:这是“删除资产”被错误地当作“删除批次/任务”的问题,失败批次没有资产,因此没有任何后端记录被删除。

  1. 三个图片生成入口共用 core/frontend/src/routes/ai-tools.tsxImageWorkbenchPage;失败格由“批次数量大于成功资产数”在前端补出,并不对应一张 Asset
  2. 当前确认删除逻辑只收集 batch.results.map(a => a.id) 后调用 DELETE /api/assets/<asset-id>/。纯失败批次的 results 为空,所以请求列表为空,点击确认不会发送任何删除请求;前端只是暂时把卡片从内存中移除。
  3. 模特上身图/平台套图在挂载、切换商品时会请求 GET /api/ai/tasks/workbench/。该接口会继续返回失败的 AITask,前端将其还原为 failed 批次,因此删除后的失败卡会在刷新、切换商品或重新进入页面时恢复。
  4. 图片创作使用对话任务恢复,但失败任务同样没有资产;当前删除路径同样不具备删除任务的能力。

关键位置:

环节 位置 证据
失败格生成 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 在前端当前被视为终态,但文案为“回滚中”;本次按安全边界把它与其它在途状态一样禁止删除,待积分回滚完成并转为 failedcancelled 后,用户才可删除。

2.2 确认的最小实现方案

  1. AITaskViewSet 增加仅用于异常图片批次的“删除当前批次 / 批次垃圾桶 / 恢复批次 / 彻底删除批次”接口。前端只提交批次中的一个锚点任务 ID;后端从该任务自行确认团队、图片模式、是否属于独立工作台,并以其真实 batch_id 查出同批任务。旧数据没有 batch_id 时只处理该锚点任务。
  2. 接口仅接受 succeededfailedcancelled 三种已结束状态;任何在途任务返回可见的拒绝结果,且不修改数据。
  3. 后端先判断整批任务是否含 failedcancelled:没有失败的全成功批次继续走现有逐张资产软删;含失败的异常批次才进入新的批次软删流程。这样全成功批次的现有删除与资产垃圾桶行为不变。
  4. 异常批次的删除、恢复和彻底删除均在同一数据库事务中处理该批全部 AITask 与其已生成 Asset:删除标记 is_deleted=True,恢复统一复原,彻底删除再写入 purged_at。失败任务没有资产时,仍作为可恢复的批次记录存在。
  5. 在现有全局垃圾桶新增“图片异常批次”分区,复用已有列表行、恢复、彻底删除、清空和全部恢复交互;不新建垃圾桶页面或视觉组件。批次行显示原提示词、模式、张数、删除时间;缩略图优先使用该批次所属商品的商品图(模特上身图、平台套图及关联商品的图片创作均适用),商品不存在或无可用商品图时回退现有“无图”占位。商品图只作展示引用,不复制、不删除、不影响商品本身。
  6. 为避免异常批次出现两个恢复入口:该批任务处于删除状态时,其成功图片不单独列入“资产”分区;只有全成功批次、资产库删除或单图删除,才继续出现在“资产”分区。异常批次恢复会恢复该批的图片和任务记录;单图恢复维持现有语义。
  7. GET /api/ai/tasks/workbench/ 与图片创作对话的 tasks 读取接口均过滤 is_deleted=Falsepurged_at is null,防止删除的异常任务再次被回放。
  8. 前端批次数据补存完整任务 ID 列表(当前恢复批次只保留卡片 ID,无法稳定定位后端锚点);点击“删除当前批次”后先等待接口成功,再从本地列表移除。请求失败时保留卡片,并复用应用既有通知提示失败原因。
  9. “更多 → 删除当前批次”只在批次已结束时显示;现有确认弹窗文字改为“删除后可在垃圾桶恢复”。不新增弹窗、颜色、按钮或样式。

2.3 用户操作变化

生成页面的主流程不变:仍是“更多 → 删除当前批次 → 确认删除”。用户只会在需要反悔时,多一个恢复路径:

全局侧栏「垃圾桶」
  → 「图片异常批次」分区
    → 恢复(整批任务与图片回到原图片生成入口)

“全部恢复”和“清空垃圾桶”会包含这个异常批次分区,行为与商品、资产等现有分区一致;全成功批次则继续由“资产”分区按图片恢复。

2.4 明确不在本次范围

  • 不取消或中断供应商正在执行的图片生成;
  • 不改变已预扣/已结算/失败补偿的积分逻辑;
  • 不新增失败图片的单格删除按钮(失败格无可删除资产,删除语义仍是“删除当前批次”);
  • 不删除图片创作的整条对话,也不改变对话垃圾桶;
  • 不修改模型路由、提示词、生成结果、页面视觉或共享 CSS。

2.5 实施验收与回归

  1. 纯失败的模特上身图、平台套图、图片创作批次均可删除;刷新、切换商品/对话及重新进入页面后不再显示。
  2. 一批中含成功图与失败图时,删除后整批不回显,并仅出现在“图片异常批次”分区;恢复后任务和全部图片一并恢复。
  3. 含“重跑/补图”的同一 batch_id 会整体删除,不留下孤立失败格或历史补图。
  4. 生成中、排队中、后处理中与回滚中的批次没有删除入口;任务继续按既有流程完成或失败。
  5. 非当前团队、项目内任务、非图片生成任务不可通过新接口删除。
  6. “全部恢复 / 清空垃圾桶”正确包含图片异常批次;异常批次删除的图片不会与资产分区重复出现;全成功批次仍仅出现在资产分区。
  7. 图片异常批次优先展示所属商品图;未关联商品、商品已不可用或无商品图时稳定回退“无图”占位,不影响恢复和彻底删除。
  8. 后端定向测试覆盖上述状态、团队隔离、删除→垃圾桶→恢复→工作台回放、彻底删除与重复隐藏;前端执行 TypeScript/生产构建检查。测试全部使用模拟任务,不发起真实模型调用或积分消耗。

Step 3:实施与验证

  • 按已确认方案完成最小改动;
  • 验证失败图片可删除,正常图片与其他生成流程不受影响。

状态:已完成。

实施结果:

  1. 图片工作台的“删除当前批次”现在提交批次锚点任务给后端统一判断。全成功批次继续按原有逻辑将成图逐张移入“资产”垃圾桶;含 failedcancelled 任务的批次会作为一个可恢复的异常批次删除。
  2. 新增“图片异常批次”的删除、恢复、彻底删除与垃圾桶读取接口。异常批次恢复时,任务记录、成功成图和失败卡会一起恢复;同一 batch_id 的补图/重跑任务也一起处理。删除的异常任务已从工作台和图片创作对话的历史读取中排除,刷新后不会复活。
  3. 全局垃圾桶新增“图片异常批次”分区,复用现有列表行、恢复、彻底删除、全部恢复和清空垃圾桶交互;优先显示所属商品图,无法取得时沿用“无图”占位。异常批次中的成功图不会在“资产”分区重复显示;全成功批次保持原有资产分区行为。
  4. 生成中、排队中、处理中或回滚中的批次由后端拒绝删除;前端只为已结束批次展示“删除当前批次”。单张图片删除、整条图片创作对话删除、模型调用、积分扣除与补偿逻辑未改动。
  5. 页面未新增 CSS、颜色、圆角或组件;继续使用既有垃圾桶行、缩略图、按钮、Toast 与确认弹窗。确认弹窗文案已明确说明“删除后可在垃圾桶恢复”。

验证:

  • 图片批次定向回归 9 / 9 通过:纯/部分失败批次删除、恢复、彻底删除、商品图缩略、全成功批次原行为、图片创作对话回放、在途拒删与团队隔离;
  • AI 模块完整回归 58 / 58 通过;
  • 前端 TypeScript 与生产构建通过;
  • git diff --check 通过;
  • 所有测试使用 SQLite 和模拟模型,不产生真实模型调用或积分消耗。

Step 4:页面回归与交付检查

状态:已完成(自动化回归)。

  • 已复查删除入口仅在批次结束后显示;回滚中 现与生成、排队、处理中一样视为在途状态,不显示删除入口,待最终转为 failedcancelled 后才可删除。
  • 已复查垃圾桶沿用既有列表行:异常批次使用商品图缩略图,无法取得时使用现有无图占位;不新增页面、Tab、组件或 CSS。
  • 前端生产构建再次通过,git diff --check 通过。
  • 未创建真实失败生成任务,未消耗积分;浏览器连接在本机运行时初始化时受限,实际页面点击验收留待开发环境中已有失败批次时按 Step 2.5 的清单执行。

真实页面验收(2026-07-15

状态:通过。

  1. 模特上身图中的 1 张失败批次可通过「更多 → 删除当前批次」进入删除流程;
  2. 删除后,垃圾桶出现「图片异常批次 · 1」分区。该行展示关联商品图缩略图、原提示词、模特上身图 · 1 张 与删除时间;
  3. 点击恢复后,失败批次重新出现在原商品的模特上身图工作台,仍显示失败格;
  4. 本次未点击彻底删除或清空垃圾桶,保留数据的可恢复性。