拆镜复刻、爆款开头复刻容灾优化

This commit is contained in:
2026-06-15 14:41:14 +08:00
parent 9e98c9c981
commit b6b4039f65
12 changed files with 987 additions and 70 deletions
+75 -35
View File
@@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.dependencies import get_current_user, get_db
from app.models.user import User
from app.enums.shot_replicate import ModuleCodeEnum
from app.enums.shot_replicate import ModuleCodeEnum, ShotReplicateStepCodeEnum
from app.schemas.shot_replicate import (
ShotReplicateActionOut,
ShotReplicateDeleteOut,
@@ -57,6 +57,14 @@ from app.services.shot_replicate_taskset_service import (
task_set_detail,
)
from app.services.module_generation_log_service import log_module_error, log_module_event_file
from app.services.module_async_recovery_service import (
TASK_SHOT_IMAGE_PROMPT,
TASK_SHOT_VIDEO_PROMPT,
register_module_step_task,
register_shot_segment_analysis_task,
register_shot_split_task,
register_shot_task_set_analysis_task,
)
from app.tasks.celery_app import celery_app
MODULE = ModuleCodeEnum.SHOT_REPLICATE.value
@@ -141,6 +149,22 @@ def _log_api_exception_from_locals(exc: BaseException, local_values: dict, messa
exc=exc,
)
def _ensure_celery_enabled(*, current_user: User | None = None, project_id: str | None = None, step_id: str | None = None) -> None:
if celery_app is not None:
return
message = "Celery未启用:请配置 REDIS_URL 或 CELERY_BROKER_URL 后启动 worker"
_log_api_error(
event_type="CELERY_DISABLED",
current_user=current_user,
project_id=project_id,
step_id=step_id,
message=message,
detail={"api": "shot_replicate"},
)
raise HTTPException(status_code=503, detail=message)
async def _reload_project_detail(db: AsyncSession, current_user: User, project_id: str) -> ShotReplicateTaskDetailOut:
project = await _get_project_for_user(
db,
@@ -213,6 +237,7 @@ async def create_shot_task_set(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
task_set = await create_task_set(db, current_user=current_user, req=req)
task_set_id = task_set.id
@@ -225,22 +250,21 @@ async def create_shot_task_set(
_log_api_exception_from_locals(exc, locals(), f"创建拆镜总任务集失败: {exc}")
raise HTTPException(status_code=500, detail=f"创建拆镜总任务集失败: {exc}")
if celery_app:
try:
from app.tasks.shot_replicate_tasks import analyze_original_video
try:
from app.tasks.shot_replicate_tasks import analyze_original_video
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",
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}")
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)
except Exception as exc:
_log_api_error(
event_type="CELERY_DISPATCH_FAILED",
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}")
return await task_set_detail(db, current_user=_user_context(current_user), task_set_id=task_set_id)
@@ -296,6 +320,7 @@ async def split_by_ai(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
out = await create_segments_by_ai(db, current_user=current_user, task_set_id=task_set_id, req=req)
segment_ids = [item.id for item in out.segments]
@@ -308,11 +333,11 @@ async def split_by_ai(
_log_api_exception_from_locals(exc, locals(), f"按 AI 建议拆镜失败: {exc}")
raise HTTPException(status_code=500, detail=f"按 AI 建议拆镜失败: {exc}")
if celery_app:
from app.tasks.shot_replicate_tasks import split_one_segment
from app.tasks.shot_replicate_tasks import split_one_segment
for segment_id in segment_ids:
split_one_segment.apply_async(args=[segment_id], queue="gen_result_download", countdown=0)
for segment_id in segment_ids:
await register_shot_split_task(segment_id, task_set_id=task_set_id)
split_one_segment.apply_async(args=[segment_id], queue="gen_result_download", countdown=0)
return out
@@ -327,6 +352,7 @@ async def split_custom(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
out = await create_custom_segment(db, current_user=current_user, task_set_id=task_set_id, req=req)
segment_id = out.segment.id
@@ -339,10 +365,10 @@ async def split_custom(
_log_api_exception_from_locals(exc, locals(), f"自定义拆镜失败: {exc}")
raise HTTPException(status_code=500, detail=f"自定义拆镜失败: {exc}")
if celery_app:
from app.tasks.shot_replicate_tasks import split_one_segment
from app.tasks.shot_replicate_tasks import split_one_segment
split_one_segment.apply_async(args=[segment_id], queue="gen_result_download", countdown=0)
await register_shot_split_task(segment_id, task_set_id=task_set_id)
split_one_segment.apply_async(args=[segment_id], queue="gen_result_download", countdown=0)
return out
@@ -520,6 +546,7 @@ async def generate_image_prompt(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
project, step = await submit_image_prompt_optimize(db, current_user=current_user, project_id=project_id, req=req)
project_id_value, step_id_value = project.id, step.id
@@ -533,10 +560,16 @@ async def generate_image_prompt(
raise HTTPException(status_code=500, detail=f"提交图片 AI 提词失败: {exc}")
try:
if celery_app:
from app.tasks.shot_replicate_flow_tasks import start_image_prompt_optimize
from app.tasks.shot_replicate_flow_tasks import start_image_prompt_optimize
start_image_prompt_optimize.apply_async(args=[project_id_value, step_id_value], queue="gen_chatapi_create", countdown=0)
await register_module_step_task(
module=MODULE,
project_id=project_id_value,
step_id=step_id_value,
step_code=ShotReplicateStepCodeEnum.IMAGE_PROMPT_OPTIMIZE.value,
task_name=TASK_SHOT_IMAGE_PROMPT,
)
start_image_prompt_optimize.apply_async(args=[project_id_value, step_id_value], queue="gen_chatapi_create", countdown=0)
except Exception as exc:
await _mark_dispatch_failed_and_raise(db, current_user=current_user, project_id=project_id_value, step_id=step_id_value, message=f"图片 AI 提词任务投递失败: {exc}")
@@ -554,6 +587,7 @@ async def generate_image(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
project, step, chat_task = await generate_image_from_prompt(db, current_user=current_user, project_id=project_id, req=req)
project_id_value, step_id_value, chat_task_id_value = project.id, step.id, chat_task.id
@@ -567,10 +601,9 @@ async def generate_image(
raise HTTPException(status_code=500, detail=f"提交图片生成失败: {exc}")
try:
if celery_app:
from app.tasks.generation_create_tasks import chatapi_create_generation_task
from app.tasks.generation_create_tasks import chatapi_create_generation_task
chatapi_create_generation_task.apply_async(args=[chat_task_id_value], queue="gen_chatapi_create", countdown=0)
chatapi_create_generation_task.apply_async(args=[chat_task_id_value], queue="gen_chatapi_create", countdown=0)
except Exception as exc:
await _mark_dispatch_failed_and_raise(db, current_user=current_user, project_id=project_id_value, step_id=step_id_value, message=f"图片生成任务投递失败: {exc}")
@@ -588,6 +621,7 @@ async def generate_video_prompt(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
project, step = await submit_video_prompt_optimize(db, current_user=current_user, project_id=project_id, req=req)
project_id_value, step_id_value = project.id, step.id
@@ -601,10 +635,16 @@ async def generate_video_prompt(
raise HTTPException(status_code=500, detail=f"提交视频 AI 提词失败: {exc}")
try:
if celery_app:
from app.tasks.shot_replicate_flow_tasks import start_video_prompt_optimize
from app.tasks.shot_replicate_flow_tasks import start_video_prompt_optimize
start_video_prompt_optimize.apply_async(args=[project_id_value, step_id_value], queue="gen_chatapi_create", countdown=0)
await register_module_step_task(
module=MODULE,
project_id=project_id_value,
step_id=step_id_value,
step_code=ShotReplicateStepCodeEnum.VIDEO_PROMPT_OPTIMIZE.value,
task_name=TASK_SHOT_VIDEO_PROMPT,
)
start_video_prompt_optimize.apply_async(args=[project_id_value, step_id_value], queue="gen_chatapi_create", countdown=0)
except Exception as exc:
await _mark_dispatch_failed_and_raise(db, current_user=current_user, project_id=project_id_value, step_id=step_id_value, message=f"视频 AI 提词任务投递失败: {exc}")
@@ -622,6 +662,7 @@ async def generate_video(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
_ensure_celery_enabled(current_user=current_user, project_id=locals().get("project_id") or locals().get("task_set_id"))
try:
project, step, chat_task = await generate_video_from_prompt(db, current_user=current_user, project_id=project_id, req=req)
project_id_value, step_id_value, chat_task_id_value = project.id, step.id, chat_task.id
@@ -635,10 +676,9 @@ async def generate_video(
raise HTTPException(status_code=500, detail=f"提交视频生成失败: {exc}")
try:
if celery_app:
from app.tasks.generation_create_tasks import chatapi_create_generation_task
from app.tasks.generation_create_tasks import chatapi_create_generation_task
chatapi_create_generation_task.apply_async(args=[chat_task_id_value], queue="gen_chatapi_create", countdown=0)
chatapi_create_generation_task.apply_async(args=[chat_task_id_value], queue="gen_chatapi_create", countdown=0)
except Exception as exc:
await _mark_dispatch_failed_and_raise(db, current_user=current_user, project_id=project_id_value, step_id=step_id_value, message=f"视频生成任务投递失败: {exc}")