fix(ai): 图片创作重跑三连修——丢参考图/裂新批次/提示词矛盾

① 重跑丢参考图:「重跑这张/重跑整批」原来不带 refs → 后端收不到
reference_image_ids 落到纯文生图,出图与上传素材无关。现 GenBatch.refs
存 assetId(上传后回写;恢复批次由 tasks 接口新带的 id 还原),重跑原样带回。

② 重跑裂新聊天记录:enqueue 每次新铸 batch_id,后端没有「补进原批次」
概念,刷新/切对话后重跑图裂成新卡、原卡失败格还挂着。现生成接口收/回
batch_id(UUID 校验,非法兜底新铸),重跑沿用原批次并打 batch_append 标记;
前端批次卡存 backendBatchId(提交回调即落,整批全失败也不丢),重跑带回。
恢复分组时 rerun 任务不计入「应出张数」→ 补图成功后失败格自然收掉;
批次状态改按「有任务在跑」判定,已有好图+补图在途也能接续轮询。

③ 同批换装一半不换:带参考图模板「严格保留款式/不要换款」与用户要求
(如"生成现代服装的穿着")直接矛盾,模型每张随机听一边。改为只锁主体身份
(人物五官/发型/体型,商品品类/外形/Logo),用户明确要求改变的以用户要求
为最高优先级,未提及的才默认与参考图一致。

测试:apps 全量 214 过(需 --settings=airshelf.settings.test);
新增 test_rerun_with_batch_id_reuses_batch_and_marks_append。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-07-02 13:40:52 +08:00
co-authored by Claude Fable 5
parent dcc5d7fe50
commit a048c32527
7 changed files with 148 additions and 43 deletions
+7 -6
View File
@@ -538,24 +538,25 @@ export function App() {
if (res) setUser(res);
}
function generateImages(payload: { prompt: string; mode?: "image" | "model" | "cover"; count?: number; product_id?: string; reference_product?: boolean; model_id?: string; ratio?: string; image_model?: string; platform_id?: string; conversation_id?: string; reference_image_ids?: string[]; onSubmitted?: (taskIds: string[]) => void }) {
function generateImages(payload: { prompt: string; mode?: "image" | "model" | "cover"; count?: number; product_id?: string; reference_product?: boolean; model_id?: string; ratio?: string; image_model?: string; platform_id?: string; conversation_id?: string; reference_image_ids?: string[]; batch_id?: string; onSubmitted?: (taskIds: string[], batchId?: string) => void }) {
// 异步生图:提交后立刻拿到任务列表,前端轮询直到出图。慢的 ARK 出图在 Celery worker 里跑——
// Web 层不被 ~30s 请求占住 → 健康探针不饿死 → 根治"几张图整站 502";且提交成功后浏览器关掉/断网,
// worker 仍会把图生成并落库(扣费/退费在 worker 内闭环),重开素材库即可见。
const { onSubmitted, ...apiPayload } = payload; // onSubmitted 是本地回调,不发后端
return action(async () => {
const { tasks, conversation_id } = await api.submitGenerateImage(apiPayload);
const { tasks, conversation_id, batch_id } = await api.submitGenerateImage(apiPayload);
const ids = tasks.map((t) => t.id);
if (ids.length === 0) throw new Error("未能提交生成任务");
// 把刚提交的任务 id 回传给工作台,让它按「批」各自落盘 pending → 切走再回来每一批都能恢复并续轮询(PMC#5/#10)
onSubmitted?.(ids);
// 把刚提交的任务 id + 后端 batch_id 回传给工作台:pending 按批落盘续轮询(PMC#5/#10);
// batch_id 必须在提交时就落(不能等出图)——整批全失败时轮询会抛错,等不到结果,重跑就丢了归属
onSubmitted?.(ids, batch_id);
// 提交成功即落盘:刷新页面也能恢复"生成中"并继续轮询(任务在 worker 里跑,关掉浏览器也不丢)
// 记下本批所属商品(id+名),恢复在途批次时用它当导航头,而不是用「当前选中商品」(切走再回会显示错名)
const batchProduct = products.find((p) => p.id === payload.product_id);
saveImgwb(payload.mode, { pending: ids, results: [], count: payload.count, productId: payload.product_id, productTitle: batchProduct?.title });
const res = await pollImageTasks(payload.mode, ids);
// 回传后端归属/新建的对话 id,供工作室把它登记进左栏会话列表并设为 active
return { ...res, conversation_id };
// 回传后端归属/新建的对话 id + 本批 batch_id(重跑时带回原批次用),供工作台登记
return { ...res, conversation_id, batch_id };
// successText 留空:工作台的批次卡已就地显示出图结果(生成中→已完成),全局右下角「图片已生成」toast 多余,
// 且会在「生成中删掉该批次」后才弹出来,让人以为删了又生成(PMC#23)。靠批次卡反馈即可。
// concurrent:生图支持多批并行,不占全局单飞锁(否则并发重跑被拒成 null→标失败,PMC#8)