爆款开头复刻/拆镜复刻追加日志|拆镜复刻追加视频AI分析API

This commit is contained in:
2026-07-07 19:52:12 +08:00
parent 35ffa317e7
commit 2d419b171e
16 changed files with 1153 additions and 91 deletions
+159 -5
View File
@@ -12,6 +12,7 @@ from app.models.user import User
from app.enums.shot_replicate import (
ModuleCodeEnum,
ShotAnalysisStatusEnum,
ShotReplicateLogEventEnum,
ShotReplicateStepCodeEnum,
ShotSegmentAnalysisStatusEnum,
ShotSegmentReplicateStatusEnum,
@@ -27,6 +28,8 @@ from app.schemas.shot_replicate import (
ShotReplicateGenerateVideoPromptRequest,
ShotReplicateGenerateVideoRequest,
ShotReplicateImagePromptUpdateRequest,
ShotReanalyzeOut,
ShotReanalyzeRequest,
ShotReplicateMaterialUpdateRequest,
ShotReplicateSpecOut,
ShotReplicateTaskDetailOut,
@@ -65,6 +68,8 @@ from app.services.shot_replicate_taskset_service import (
get_segment_for_user,
list_segments,
list_task_sets,
prepare_reanalyze_segment,
prepare_reanalyze_task_set,
segment_detail,
task_set_detail,
)
@@ -152,7 +157,7 @@ def _log_api_exception_from_locals(exc: BaseException, local_values: dict, messa
req = local_values.get("req")
detail = {"api": local_values.get("__name__"), "request": req.model_dump() if hasattr(req, "model_dump") else str(req) if req is not None else None}
_log_api_error(
event_type="API_REQUEST_FAILED",
event_type=ShotReplicateLogEventEnum.API_REQUEST_FAILED.value,
current_user=current_user if isinstance(current_user, User) else None,
project_id=str(project_id) if project_id else None,
step_id=str(step_id) if step_id else None,
@@ -168,7 +173,7 @@ def _ensure_celery_enabled(*, current_user: User | None = None, project_id: str
return
message = "Celery未启用:请配置 REDIS_URL 或 CELERY_BROKER_URL 后启动 worker"
_log_api_error(
event_type="CELERY_DISABLED",
event_type=ShotReplicateLogEventEnum.CELERY_DISABLED.value,
current_user=current_user,
project_id=project_id,
step_id=step_id,
@@ -209,7 +214,7 @@ async def _mark_dispatch_failed_and_raise(
except Exception as exc:
await db.rollback()
_log_api_error(
event_type="CELERY_DISPATCH_MARK_FAILED",
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_MARK_FAILED.value,
current_user=current_user,
project_id=project_id,
step_id=step_id,
@@ -219,7 +224,7 @@ async def _mark_dispatch_failed_and_raise(
)
log_module_error(
module=MODULE,
event_type="CELERY_DISPATCH_FAILED",
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
project_id=project_id,
step_id=step_id,
user_id=_safe_user_id(current_user),
@@ -275,7 +280,7 @@ async def create_shot_task_set(
analyze_original_video.apply_async(args=[task_set_id], queue="gen_chatapi_create", countdown=0)
except Exception as exc:
_log_api_error(
event_type="CELERY_DISPATCH_FAILED",
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
current_user=current_user,
project_id=task_set_id,
message=f"拆镜分析任务投递失败: {exc}",
@@ -345,6 +350,79 @@ async def get_shot_task_set(
return await task_set_detail(db, current_user=_user_context(current_user), task_set_id=task_set_id)
@router.post(
"/task-sets/{task_set_id}/reanalyze",
response_model=ShotReanalyzeOut,
summary="重新投递原视频 AI 分析任务",
description="用于处理原视频分析失败或待处理的异常数据;重置分析状态后重新投递 analyze_original_video。",
)
async def reanalyze_task_set(
task_set_id: str = Path(..., description="拆镜总任务集ID,即 shot_replicate_task_sets.id"),
req: ShotReanalyzeRequest = Body(default_factory=ShotReanalyzeRequest, description="再次分析参数"),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=task_set_id)
try:
out = await prepare_reanalyze_task_set(
db,
current_user=current_user,
task_set_id=task_set_id,
force=req.force,
reason=req.reason,
)
await db.commit()
except HTTPException as exc:
await db.rollback()
log_module_event_file(
module=MODULE,
event_type=ShotReplicateLogEventEnum.TASK_SET_REANALYZE_REJECTED.value,
project_id=task_set_id,
user_id=_safe_user_id(current_user),
message="原视频再次分析请求被拒绝",
detail={"task_set_id": task_set_id, "request": req.model_dump(), "http_status": exc.status_code, "detail": exc.detail},
error=str(exc.detail),
)
raise
except Exception as exc:
await db.rollback()
_log_api_error(
event_type=ShotReplicateLogEventEnum.TASK_SET_REANALYZE_FAILED.value,
current_user=current_user,
project_id=task_set_id,
message=f"原视频再次分析状态重置失败: {exc}",
detail={"task_set_id": task_set_id, "request": req.model_dump()},
exc=exc,
)
raise HTTPException(status_code=500, detail=f"原视频再次分析状态重置失败: {exc}")
try:
from app.tasks.shot_replicate_tasks import analyze_original_video
await register_shot_task_set_analysis_task(task_set_id)
analyze_original_video.apply_async(args=[task_set_id], queue="gen_chatapi_create", countdown=0)
log_module_event_file(
module=MODULE,
event_type=ShotReplicateLogEventEnum.TASK_SET_REANALYZE_SUBMITTED.value,
project_id=task_set_id,
user_id=_safe_user_id(current_user),
message="原视频再次分析任务已投递",
detail={"task_set_id": task_set_id, "task": "analyze_original_video", "request": req.model_dump()},
)
except Exception as exc:
_log_api_error(
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
current_user=current_user,
project_id=task_set_id,
message=f"原视频再次分析任务投递失败: {exc}",
detail={"task_set_id": task_set_id, "task": "analyze_original_video"},
exc=exc,
)
raise HTTPException(status_code=503, detail=f"原视频再次分析任务投递失败: {exc}")
out.message = "原视频再次分析任务已提交"
return out
@router.post(
"/task-sets/{task_set_id}/split-by-ai",
response_model=ShotSplitByAIOut,
@@ -457,6 +535,82 @@ async def get_segment(
return await segment_detail(db, current_user=current_user, segment_id=segment_id)
@router.post(
"/segments/{segment_id}/reanalyze",
response_model=ShotReanalyzeOut,
summary="重新投递切片视频 AI 分析任务",
description="用于处理自定义切片视频分析失败或待处理的异常数据;重置分析状态后重新投递 analyze_custom_segment_video。",
)
async def reanalyze_segment(
segment_id: str = Path(..., description="拆镜片段ID,即 shot_replicate_segments.id"),
req: ShotReanalyzeRequest = Body(default_factory=ShotReanalyzeRequest, description="再次分析参数"),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, step_id=segment_id)
try:
out = await prepare_reanalyze_segment(
db,
current_user=current_user,
segment_id=segment_id,
force=req.force,
reason=req.reason,
)
task_set_id = out.task_set_id
await db.commit()
except HTTPException as exc:
await db.rollback()
log_module_event_file(
module=MODULE,
event_type=ShotReplicateLogEventEnum.SEGMENT_REANALYZE_REJECTED.value,
step_id=segment_id,
user_id=_safe_user_id(current_user),
message="切片视频再次分析请求被拒绝",
detail={"segment_id": segment_id, "request": req.model_dump(), "http_status": exc.status_code, "detail": exc.detail},
error=str(exc.detail),
)
raise
except Exception as exc:
await db.rollback()
_log_api_error(
event_type=ShotReplicateLogEventEnum.SEGMENT_REANALYZE_FAILED.value,
current_user=current_user,
step_id=segment_id,
message=f"切片视频再次分析状态重置失败: {exc}",
detail={"segment_id": segment_id, "request": req.model_dump()},
exc=exc,
)
raise HTTPException(status_code=500, detail=f"切片视频再次分析状态重置失败: {exc}")
try:
from app.tasks.shot_replicate_tasks import analyze_custom_segment_video
await register_shot_segment_analysis_task(segment_id, task_set_id=task_set_id)
analyze_custom_segment_video.apply_async(args=[segment_id], queue="gen_chatapi_create", countdown=0)
log_module_event_file(
module=MODULE,
event_type=ShotReplicateLogEventEnum.SEGMENT_REANALYZE_SUBMITTED.value,
project_id=task_set_id,
step_id=segment_id,
user_id=_safe_user_id(current_user),
message="切片视频再次分析任务已投递",
detail={"segment_id": segment_id, "task_set_id": task_set_id, "task": "analyze_custom_segment_video", "request": req.model_dump()},
)
except Exception as exc:
_log_api_error(
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
current_user=current_user,
project_id=task_set_id,
step_id=segment_id,
message=f"切片视频再次分析任务投递失败: {exc}",
detail={"segment_id": segment_id, "task_set_id": task_set_id, "task": "analyze_custom_segment_video"},
exc=exc,
)
raise HTTPException(status_code=503, detail=f"切片视频再次分析任务投递失败: {exc}")
out.message = "切片视频再次分析任务已提交"
return out
@router.delete(
"/segments/{segment_id}",
response_model=ShotSegmentDeleteOut,