Files
xiaoxia-saas/scripts/backfill_generated_videos.py
T
xiaoxia 4244c558a5
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 47s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m13s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m26s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m5s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Unit 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 Merge on CI Green + Approved (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 26h39m38s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 26h39m44s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 26h39m53s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 26h39m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 26h39m6s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 26h39m6s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 26h39m8s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 26h39m13s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 26h39m15s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 26h39m13s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 26h39m13s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 26h39m0s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 26h39m3s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 26h39m16s
fix(#1834): 批量修复 UP 系列静态分析警告
- UP007: Optional[X] -> X | None
- UP006: List/Dict/Tuple/Set/Type -> list/dict/tuple/set/type
- UP017: timezone.utc -> datetime.UTC
- UP035: 移除 typing 模块已弃用的导入

共修复 224 个文件,971 处问题
B006/B909/B904/B023 在 develop 上已全部通过
B008 已在 ruff 配置中忽略(FastAPI Depends 模式)

Closes #1834
2026-09-15 12:43:31 +08:00

146 lines
4.8 KiB
Python
Executable File
Raw 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, UTC
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(UTC),
updated_at=datetime.now(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())