fix: 统一封面管道增加cover_url多步fallback查找,修复500错误
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 45s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m15s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m17s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m20s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m41s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 1m58s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 771h54m46s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 771h54m48s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 771h55m30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 771h55m32s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 771h55m34s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 771h55m34s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 771h55m34s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 772h28m18s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 772h29m1s

根因:统一封面管道只通过 generation_task_id 查找 cover_url,
但 generation_task_id 为空时(如 plan 创建时未关联),
直接 fall through 到 run_generate_cover → RuntimeError → 500。

修复:
- 统一封面管道 section 增加与视频URL查找一致的 3 步 fallback:
  A: generation_task_id 直接查找
  B: source_edit_plan_id 查找
  C: user+template 兜底查找
- 所有步骤都找不到 cover_url 时返回 400 而非 500,
  提示用户重新生成预览视频以触发封面自动提取
- 新增 3 个单元测试覆盖新 fallback 路径
This commit is contained in:
xiaoxia
2026-08-15 11:30:52 +08:00
parent 206d517a91
commit 8b1be55f9d
2 changed files with 225 additions and 60 deletions
+78 -16
View File
@@ -209,39 +209,101 @@ def generate_cover(
) from e
# 统一封面管道:优先从 GenerationTask.cover_url 读取渲染后视频抽帧的封面
# 多步查找 cover_url,和查找视频 URL 一样的 fallback 逻辑
if body.cover_type in ("ai_frame", "ai_regenerate"):
# 尝试从 GenerationTask 读取已持久化的封面 URL
cover_url_from_task = None
gen_task_repo = SQLAlchemyGenerationTaskRepository(db)
# 步骤 A:通过 generation_task_id 直接查找
generation_task_id = (plan.config or {}).get("generation_task_id", "")
if generation_task_id:
try:
gen_task_repo = SQLAlchemyGenerationTaskRepository(db)
task = gen_task_repo.get(generation_task_id)
if task and getattr(task, "cover_url", ""):
cover_data = {
"type": "ai_frame",
"image_url": task.cover_url,
"frame_time": 0.0,
"confidence": 0.95,
}
cover_url_from_task = task.cover_url
logger.info(
"[封面生成] 使用统一管道封面: plan_id=%s task_id=%s url=%s",
"[封面生成] 统一管道封面(步骤A-direct): plan_id=%s task_id=%s url=%s",
plan_id,
generation_task_id,
task.cover_url[:80],
cover_url_from_task[:80],
)
current_config = dict(plan.config) if plan.config else {}
current_config["cover"] = cover_data
normalized = normalize_plan_config(current_config)
plan_svc.update_plan_config(plan_id, {"cover": normalized["cover"]})
return GenerateCoverResponse(plan_id=plan_id, cover=cover_data)
except Exception:
logger.warning(
"[封面生成] 读取 GenerationTask.cover_url 失败: plan_id=%s task_id=%s",
"[封面生成] 步骤A读取 cover_url 失败: plan_id=%s task_id=%s",
plan_id,
generation_task_id,
exc_info=True,
)
# 步骤 B:通过 source_edit_plan_id 查找关联预览任务的 cover_url
if not cover_url_from_task:
try:
preview_tasks = gen_task_repo.list_by_source_edit_plan(plan_id)
for pt in preview_tasks:
if getattr(pt, "status", "") == "completed" and getattr(pt, "cover_url", ""):
cover_url_from_task = pt.cover_url
logger.info(
"[封面生成] 统一管道封面(步骤B-source_plan): plan_id=%s task_id=%s url=%s",
plan_id,
pt.id,
cover_url_from_task[:80],
)
break
except Exception:
logger.warning(
"[封面生成] 步骤B查找 cover_url 失败: plan_id=%s",
plan_id,
exc_info=True,
)
# 步骤 C:通过 user+template 查找最近的已完成预览任务的 cover_url
if not cover_url_from_task:
try:
preview_tasks = gen_task_repo.list_latest_completed_preview(
user_id=str(current_user.user.id),
template_id=template_id,
)
for pt in preview_tasks:
if getattr(pt, "cover_url", ""):
cover_url_from_task = pt.cover_url
logger.info(
"[封面生成] 统一管道封面(步骤C-user+template): plan_id=%s task_id=%s url=%s",
plan_id,
pt.id,
cover_url_from_task[:80],
)
break
except Exception:
logger.warning(
"[封面生成] 步骤C查找 cover_url 失败: plan_id=%s template_id=%s",
plan_id,
template_id,
exc_info=True,
)
if cover_url_from_task:
cover_data = {
"type": "ai_frame",
"image_url": cover_url_from_task,
"frame_time": 0.0,
"confidence": 0.95,
}
current_config = dict(plan.config) if plan.config else {}
current_config["cover"] = cover_data
normalized = normalize_plan_config(current_config)
plan_svc.update_plan_config(plan_id, {"cover": normalized["cover"]})
return GenerateCoverResponse(plan_id=plan_id, cover=cover_data)
logger.warning(
"[封面生成] 统一管道未找到 cover_url: plan_id=%s",
plan_id,
)
# ai_frame/ai_regenerate 类型必须从渲染管道获取,不再回退到 AI 服务
raise HTTPException(
status_code=400,
detail="封面尚未生成,请先重新生成预览视频以触发封面自动提取",
)
from packages.shared.ai_service import run_generate_cover
try: