Files
xiaoxia-saas/scripts/backfill_generated_videos.py
xiaoxia 62a974a836
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 3m19s
CI/CD Pipeline / Frontend Lint (push) Successful in 3m45s
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging API Image (push) Successful in 6m1s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Failing after 3m43s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Successful in 7m39s
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Has been skipped
CI Build & Deploy Pipeline / Staging E2E Tests (push) Has been skipped
fix(P0): 修复一键生成视频成片库不显示 - project_id为空时跳过写表 (#541)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-07-18 23:01:36 +08:00

146 lines
4.8 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""补写 generated_videos 记录 — 修复一键生成场景下 project_id 为空导致未写表的问题.
背景:#535 之前的一键生成场景,由于 edit_plan.project_id 为空,
_finalize_render_success 中 `if generation_task_id and project_id:` 判断不通过,
导致渲染成功的视频没有写入 generated_videos 表,成片库看不到。
本脚本扫描所有 status=completed 的 generation_task
如果没有对应的 generated_videos 记录,则从 plan.config.rendered_url 补写。
用法:
PYTHONPATH="apps/worker:apps/api:packages" python scripts/backfill_generated_videos.py
安全说明:
- 只读事务扫描,补写前检查是否已存在,不会重复写入
- 失败不中断,继续处理下一个
"""
from __future__ import annotations
import logging
import sys
from datetime import datetime, timezone
from uuid import uuid4
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
logger = logging.getLogger(__name__)
def main() -> int:
from sqlalchemy import exists
from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.models import (
EditPlanModel,
GeneratedVideoModel,
GenerationTaskModel,
)
from packages.adapters.sqlalchemy_impl.session import get_db_session
db: Session = next(get_db_session())
try:
# 1. 查询所有 status=completed 的 generation_task
completed_tasks = (
db.query(GenerationTaskModel)
.filter(
GenerationTaskModel.status == "completed",
)
.all()
)
logger.info("找到 %d 个已完成的生成任务", len(completed_tasks))
fixed_count = 0
skipped_count = 0
failed_count = 0
for task in completed_tasks:
task_id = task.id
# 2. 检查是否已有 generated_videos 记录
exists_video = db.query(exists().where(GeneratedVideoModel.generation_task_id == task_id)).scalar()
if exists_video:
skipped_count += 1
continue
# 3. 从 source_edit_plan_id 找到对应的 edit_plan,取 rendered_url
if not task.source_edit_plan_id:
logger.warning("任务 %s 无 source_edit_plan_id,跳过", task_id)
skipped_count += 1
continue
plan = (
db.query(EditPlanModel)
.filter(
EditPlanModel.id == task.source_edit_plan_id,
)
.first()
)
if not plan:
logger.warning("任务 %s 对应的剪辑计划不存在,跳过", task_id)
skipped_count += 1
continue
# 从 config 中取 rendered_url
config = plan.config or {}
rendered_url = config.get("rendered_url", "")
rendered_storage_key = config.get("rendered_storage_key", "")
if not rendered_url:
logger.warning("任务 %s 的剪辑计划无 rendered_url,跳过", task_id)
skipped_count += 1
continue
# 4. 补写 generated_videos 记录
try:
video_id = uuid4().hex
video = GeneratedVideoModel(
id=video_id,
project_id=task.project_id or "",
generation_task_id=task_id,
name=f"generated-{task_id[:8]}.mp4",
file_url=rendered_url,
storage_key=rendered_storage_key,
file_size=0,
duration=0.0,
width=0,
height=0,
fps=0.0,
status="completed",
generation_params={"mode": "backfill", "plan_id": plan.id},
review_status="pending",
created_at=task.completed_at or datetime.now(timezone.utc),
updated_at=datetime.now(timezone.utc),
)
db.add(video)
db.commit()
fixed_count += 1
logger.info("已补写视频记录: task_id=%s video_id=%s url=%s", task_id, video_id, rendered_url[:80])
except Exception as e:
db.rollback()
failed_count += 1
logger.error("补写视频记录失败: task_id=%s error=%s", task_id, e)
logger.info(
"补写完成:共 %d 个已完成任务,补写 %d 条,跳过 %d 条,失败 %d 条",
len(completed_tasks),
fixed_count,
skipped_count,
failed_count,
)
return 0 if failed_count == 0 else 1
finally:
db.close()
if __name__ == "__main__":
sys.exit(main())