This commit is contained in:
2026-07-09 09:10:49 +08:00
parent 2882d37112
commit fec47bf47a
54 changed files with 5985 additions and 992 deletions
@@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime
from types import SimpleNamespace
from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query
from fastapi import APIRouter, Body, Depends, File, HTTPException, Path, Query, UploadFile
from sqlalchemy import inspect as sa_inspect
from sqlalchemy.ext.asyncio import AsyncSession
@@ -48,6 +48,9 @@ from app.services.module_async_recovery_service import (
register_module_step_task,
)
from app.tasks.celery_app import celery_app
from app.enums.upload_resource import UploadResourceEventEnum, UploadResourceModuleEnum, UploadResourceSourceModelEnum, UploadResourceTypeEnum
from app.services.upload_resource import upload_reference_file, bind_upload_resources, cleanup_upload_resource_files_after_commit
from app.services.upload_resource.log_service import log_upload_resource_exception, safe_rollback_with_log
MODULE = ModuleCodeEnum.HOT_OPENING_REPLICATE.value
@@ -203,6 +206,66 @@ async def get_spec():
return HotOpeningSpecOut()
@router.post(
"/upload-image",
summary="上传爆款开头复刻图片素材",
description="上传后先记录为 pending UploadResource;创建项目成功后绑定 ModuleGenerationProject。",
)
async def upload_hot_opening_image(
file: UploadFile = File(...),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
result = await upload_reference_file(
db,
file=file,
current_user=current_user,
module=UploadResourceModuleEnum.HOT_OPENING_REPLICATE.value,
resource_type=UploadResourceTypeEnum.IMAGE.value,
gen_type="video",
)
await db.commit()
return {
"url": result.url,
"filename": result.filename,
"type": "image",
"module": result.module,
"resource_id": result.resource_id,
"file_size_bytes": result.file_size_bytes,
}
@router.post(
"/upload-video",
summary="上传爆款开头复刻视频素材",
description="上传后先记录为 pending UploadResource;创建项目成功后绑定 ModuleGenerationProject。",
)
async def upload_hot_opening_video(
file: UploadFile = File(...),
duration_seconds: float | None = Query(None, description="前端识别的视频时长秒数,可选"),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
result = await upload_reference_file(
db,
file=file,
current_user=current_user,
module=UploadResourceModuleEnum.HOT_OPENING_REPLICATE.value,
resource_type=UploadResourceTypeEnum.VIDEO.value,
duration_seconds=duration_seconds,
)
await db.commit()
return {
"url": result.url,
"filename": result.filename,
"type": "video",
"module": result.module,
"resource_id": result.resource_id,
"file_size_bytes": result.file_size_bytes,
"duration_seconds": result.duration_seconds,
}
@router.post(
"/tasks",
response_model=HotOpeningTaskDetailOut,
@@ -222,6 +285,16 @@ async def create_task(
try:
project = await create_hot_opening_project(db, current_user, req)
project_id_value = str(project.id)
await bind_upload_resources(
db,
user_id=current_user.id,
module=UploadResourceModuleEnum.HOT_OPENING_REPLICATE.value,
source_model=UploadResourceSourceModelEnum.MODULE_GENERATION_PROJECT.value,
source_id=project_id_value,
resource_ids=[req.material_video_resource_id, req.material_image_resource_id],
urls=[req.material_video_url, req.material_image_url],
allow_common_migrate=True,
)
await db.commit()
except HTTPException:
await db.rollback()
@@ -703,13 +776,72 @@ async def delete_task(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
user_id = _safe_user_id(current_user)
pending_ids: list[str] = []
try:
result = await delete_hot_opening_project(db, current_user=current_user, project_id=project_id)
pending_ids = list(result.pending_delete_resource_ids or [])
await db.commit()
return result
except HTTPException:
await db.rollback()
except HTTPException as exc:
await safe_rollback_with_log(
db,
event_type=UploadResourceEventEnum.HOT_OPENING_DELETE_PROJECT_ROLLBACK_FAILED.value,
message="删除爆款开头复刻项目 HTTPException 回滚失败",
user_id=user_id,
module=MODULE,
detail={"project_id": project_id},
original_exc=exc,
)
raise
except Exception as exc:
await db.rollback()
except Exception as exc: # noqa: BLE001
await safe_rollback_with_log(
db,
event_type=UploadResourceEventEnum.HOT_OPENING_DELETE_PROJECT_ROLLBACK_FAILED.value,
message="删除爆款开头复刻项目主事务回滚失败",
user_id=user_id,
module=MODULE,
detail={"project_id": project_id},
original_exc=exc,
)
_log_api_error(
event_type=HotOpeningLogEventEnum.API_REQUEST_FAILED.value,
current_user=current_user,
project_id=project_id,
message=f"删除爆款开头复刻项目失败: {exc}",
detail={"project_id": project_id},
exc=exc,
)
log_upload_resource_exception(
event_type=UploadResourceEventEnum.HOT_OPENING_DELETE_PROJECT_FAILED.value,
message=f"删除爆款开头复刻项目失败: {exc}",
user_id=user_id,
module=MODULE,
detail={"project_id": project_id},
exc=exc,
)
raise HTTPException(status_code=500, detail=f"删除爆款开头复刻项目失败: {exc}")
if pending_ids:
try:
await cleanup_upload_resource_files_after_commit(db, resource_ids=pending_ids)
await db.commit()
except Exception as exc: # noqa: BLE001
await safe_rollback_with_log(
db,
event_type=UploadResourceEventEnum.HOT_OPENING_DELETE_PROJECT_ROLLBACK_FAILED.value,
message="删除爆款开头复刻项目 cleanup 事务回滚失败",
user_id=user_id,
module=MODULE,
detail={"project_id": project_id, "pending_ids": pending_ids},
original_exc=exc,
)
log_upload_resource_exception(
event_type=UploadResourceEventEnum.HOT_OPENING_DELETE_PROJECT_CLEANUP_FAILED.value,
message=f"删除爆款开头复刻项目后清理真实文件失败: {exc}",
user_id=user_id,
resource_ids=pending_ids,
module=MODULE,
detail={"project_id": project_id},
exc=exc,
)
return result