fix: 电商测试清单一轮 bug 修复(视频项目角色/场景 + 图片工作台 + 视频收口)

视频项目(ZWQ):
- 演员工作台保存后「我的演员」仍 0 个:保存时加入资产库(in_library=True)
- 资产详情「应用当前角色」自动送审(不再要手动点灰盾)
- 「我的演员」卡 + 待生成 seed 卡补删除入口(垃圾桶,两步确认)
- 新增场景未生成就刷新会丢:sceneDrafts 按项目持久化 localStorage
- 场景 AI 生成强制叠加「无真人」约束,避免出真人致视频被火山拒
- 进入项目默认落到当前阶段(不再恒显第 1 阶段)
- 视频已出但进度卡 3/4:submit/poll/adopt 幂等补推 current_stage→VIDEO,
  否则 settle_video_completion 因阶段守卫直接返回、永不收口 completed

图片工作台(PMC):
- 生图走 action 全局单飞锁致并发重跑/多平台套图被拒成「失败/少出图」:
  action 加 concurrent 选项,生图不占单飞锁
- 切模块再切回状态丢/数量少:每批各自落盘 pendingIds(onSubmitted 回传),
  切回时全部批次各自续轮询

附:含一处早前未提交的图片创作改动(选火山+传参考图强制切 gpt-image-2 + gen 气泡溢出 CSS)。
新增/通过测试:AttachOfficialModel、商品图删除、视频卡阶段收口、参考图强切模型。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-27 15:11:29 +08:00
co-authored by Claude Opus 4.8
parent ce7eaefe1d
commit 8f32ad69d3
9 changed files with 253 additions and 97 deletions
+18 -2
View File
@@ -160,6 +160,16 @@ def promote_base_asset_stage_if_ready(project: Project) -> bool:
VIDEO_IS_FINAL_STAGE = True
def _ensure_video_stage(project: Project) -> None:
"""幂等地把项目推进到「视频」阶段(生成视频片段时调用)。current_stage 没到 VIDEO 时,
settle_video_completion 会直接返回 → 全段出片也不收口、卡在故事板格(ZWQ#15)。"""
if project.current_stage != ProjectStage.Stage.VIDEO:
project.current_stage = ProjectStage.Stage.VIDEO
if project.status != Project.Status.COMPLETED:
project.status = Project.Status.VIDEOING
project.save(update_fields=["current_stage", "status", "updated_at"])
def settle_video_completion(project: Project) -> bool:
"""视频阶段收口(幂等):
· 全部片段已出片(SUCCEEDED + 有采用版)→ 项目 COMPLETED、VIDEO 阶段标成功;
@@ -745,7 +755,8 @@ class ProjectViewSet(TeamScopedViewSetMixin, ModelViewSet):
timeline.clips.filter(asset_id__in=segment_asset_ids).exclude(asset_id=version.asset_id).update(
asset_id=version.asset_id, trim_start_ms=0, trim_end_ms=None
)
# 采用历史版后该段为已出片 → 若全部段就绪,收口项目为 completed
# 采用历史版后该段为已出片 → 先确保在视频阶段,再收口项目为 completed(否则卡 3/4,ZWQ#15)
_ensure_video_stage(project)
settle_video_completion(project)
return Response(ProjectSerializer(project).data)
@@ -856,6 +867,10 @@ class ProjectViewSet(TeamScopedViewSetMixin, ModelViewSet):
poll_video_segment_task.apply_async(args=[str(segment.id)], countdown=30)
except Exception: # noqa: BLE001
logger.error("poll_video_segment_task enqueue failed; relying on client polling", exc_info=True)
# 生成视频即代表已进入视频阶段:某些路径(跳过故事板/异常)可能没把 current_stage 推到 VIDEO,
# 而 settle_video_completion 只在 current_stage==VIDEO 时收口 → 不补推的话,全段出片后项目会永远停在
# 「3/4 故事板」、永不 completed(ZWQ#15)。这里幂等补推。
_ensure_video_stage(project)
# 重跑某段 → 该段回到在制;若项目此前已 completed,退回 videoing
settle_video_completion(project)
return Response(ProjectSerializer(project).data, status=status.HTTP_202_ACCEPTED)
@@ -867,7 +882,8 @@ class ProjectViewSet(TeamScopedViewSetMixin, ModelViewSet):
version = poll_video_segment(video_segment=segment, user=request.user)
if version is None:
return Response({"status": segment.status}, status=status.HTTP_202_ACCEPTED)
# 这一段刚出片 → 若是最后一段,收口整个项目为 completed(视频是末阶段)
# 这一段刚出片 → 先确保已在视频阶段(否则 settle 不收口,卡 3/4),再收口整个项目为 completed
_ensure_video_stage(project)
settle_video_completion(project)
return Response(VideoSegmentVersionSerializer(version).data)