7e88440ca9
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
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 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 4s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m25s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m11s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m40s
AI Code Review / AI Code Review (pull_request) Successful in 6m41s
CI/CD Pipeline / Integration Tests (push) Failing after 7m5s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 7m20s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Validate - Style (push) Successful in 8m25s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Failing after 13m44s
CI/CD Pipeline / Unit Tests (push) Successful in 14m12s
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
feat: #1970 片段级 AI 标签 + 叙事加权匹配 - atom_clip_tagger.py: MediaKit 抽帧 + 豆包视觉 API 识别 - narrative_match.py: AI 标签加权匹配 (2.0 vs 1.0) - Celery 链式触发 + 批量回填脚本 - migration 081 加 ai_tags 列 - 42 新测试,全量 15796 passed
110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
"""素材原子切片 Celery 任务 — #1970 智能剪辑流程重构 P1.
|
||
|
||
素材入库预处理完成(ingest 置 READY)后异步触发:
|
||
根据素材时长和已缓存的 scdet 切换点计算原子片段并落库。
|
||
失败不阻断素材入库主流程(atom_clips 未就绪时选片有内存兜底)。
|
||
|
||
P2 增强:切片完成后自动链式触发 AI 标签任务(每个 clip 一个 tag_atom_clip 任务)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from celery.utils.log import get_task_logger
|
||
from worker_app.celery_app import celery_app
|
||
from worker_app.db import SessionLocal
|
||
|
||
from packages.adapters.sqlalchemy_impl.asset_atom_clip_repository import (
|
||
SQLAlchemyAssetAtomClipRepository,
|
||
)
|
||
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
|
||
from packages.domain.atom_clip_service import compute_atom_clips
|
||
from packages.domain.plan_generator_utils import extract_scene_points_from_metadata
|
||
|
||
logger = get_task_logger(__name__)
|
||
|
||
|
||
@celery_app.task(name="worker.generate_atom_clips")
|
||
def generate_atom_clips(asset_id: str) -> dict:
|
||
"""为单条视频素材生成原子片段。
|
||
|
||
Returns:
|
||
任务结果 dict:status / asset_id / clips_count。
|
||
"""
|
||
db = SessionLocal()
|
||
try:
|
||
asset_repo = SQLAlchemyAssetRepository(db)
|
||
atom_repo = SQLAlchemyAssetAtomClipRepository(db)
|
||
|
||
asset = asset_repo.find_by_id(asset_id)
|
||
if asset is None:
|
||
return {"status": "skipped", "reason": "asset not found", "asset_id": asset_id}
|
||
|
||
# 仅视频素材切片
|
||
if asset.mime_type and not asset.mime_type.startswith("video/"):
|
||
return {"status": "skipped", "reason": "not a video", "asset_id": asset_id}
|
||
if not asset.duration or asset.duration <= 0:
|
||
return {"status": "skipped", "reason": "invalid duration", "asset_id": asset_id}
|
||
|
||
# 已生成过则幂等跳过(重新切片需先显式删除)
|
||
existing = atom_repo.count_by_asset(asset_id)
|
||
if existing > 0:
|
||
return {
|
||
"status": "skipped",
|
||
"reason": "already generated",
|
||
"asset_id": asset_id,
|
||
"clips_count": existing,
|
||
}
|
||
|
||
scene_points = extract_scene_points_from_metadata(asset.metadata)
|
||
# P1 阶段继承素材的标签 ID;片段级语义标签是 P2 功能
|
||
tags = list(getattr(asset, "tag_ids", []) or [])
|
||
|
||
clips = compute_atom_clips(
|
||
asset_id=asset_id,
|
||
duration=float(asset.duration),
|
||
scene_change_points=scene_points,
|
||
tags=tags,
|
||
)
|
||
if not clips:
|
||
return {"status": "skipped", "reason": "no clips computed", "asset_id": asset_id}
|
||
|
||
atom_repo.batch_create(clips)
|
||
logger.info(
|
||
"[atom_clips] asset_id=%s 生成 %d 个原子片段",
|
||
asset_id,
|
||
len(clips),
|
||
)
|
||
|
||
# P2 增强:链式触发 AI 标签任务(每个 clip 一个异步任务)
|
||
_dispatch_tagging_tasks(clips)
|
||
|
||
return {"status": "completed", "asset_id": asset_id, "clips_count": len(clips)}
|
||
except Exception as exc: # noqa: BLE001 - 后台任务兜底,失败不阻断主流程
|
||
db.rollback()
|
||
logger.exception("[atom_clips] asset_id=%s 生成失败: %s", asset_id, exc)
|
||
return {"status": "failed", "asset_id": asset_id, "error": str(exc)}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
def _dispatch_tagging_tasks(clips: list) -> None:
|
||
"""为每个新建片段发送 AI 标签异步任务.
|
||
|
||
失败不阻断(标签任务是锦上添花,不影响核心流程)。
|
||
"""
|
||
try:
|
||
for clip in clips:
|
||
celery_app.send_task(
|
||
"worker.tag_atom_clip",
|
||
args=[clip.id],
|
||
)
|
||
logger.info(
|
||
"[atom_clips] 已发送 %d 个 AI 标签任务",
|
||
len(clips),
|
||
)
|
||
except Exception as e:
|
||
logger.warning(
|
||
"[atom_clips] 发送 AI 标签任务失败(不影响切片结果): %s",
|
||
e,
|
||
)
|