上传素材管控-历史素材success

This commit is contained in:
2026-07-08 16:25:03 +08:00
parent 657505e63b
commit d085a6d2ec
47 changed files with 5424 additions and 447 deletions
@@ -36,12 +36,15 @@ from app.schemas.shot_replicate import (
ShotSplitCustomOut,
ShotSplitCustomRequest,
ShotTaskSetCreate,
ShotTaskSetDeleteOut,
ShotTaskSetDetailOut,
ShotTaskSetListOut,
ShotTaskSetOut,
)
from app.services.module_generation_log_service import log_module_event_file
from app.services.resource_accounting_service import SOURCE_MODEL_SHOT_SEGMENT, soft_delete_resources_by_source
from app.enums.upload_resource import UploadResourceModuleEnum, UploadResourceSourceModelEnum
from app.services.upload_resource import release_upload_resources_by_source
from app.services.upload_video_asset_service import (
build_time_node,
validate_split_range,
@@ -667,6 +670,15 @@ async def delete_segment(
source_ids=[segment.id],
deleted_at=deleted_at,
)
upload_release = await release_upload_resources_by_source(
db,
source_model=UploadResourceSourceModelEnum.SHOT_REPLICATE_SEGMENT.value,
source_ids=[segment.id],
module=UploadResourceModuleEnum.SHOT_REPLICATE.value,
)
pending_delete_resource_ids: list[str] = list(upload_release.get("released_resource_ids") or [])
released_size_bytes += int(upload_release.get("released_size_bytes") or 0)
upload_resource_released = int(upload_release.get("released") or 0)
deleted_module_project_id: str | None = None
if module_project_id:
@@ -680,6 +692,8 @@ async def delete_segment(
)
deleted_module_project_id = project_delete_out.project_id
released_size_bytes += int(project_delete_out.released_size_bytes or 0)
upload_resource_released += int(project_delete_out.upload_resource_released or 0)
pending_delete_resource_ids.extend(project_delete_out.pending_delete_resource_ids or [])
segment.deleted_at = deleted_at
segment.replicate_status = (
@@ -704,7 +718,9 @@ async def delete_segment(
"module_project_id": module_project_id,
"deleted_module_project_id": deleted_module_project_id,
"released_size_bytes": released_size_bytes,
"physical_file_deleted": False,
"upload_resource_release": {k: v for k, v in upload_release.items() if k != "released_resource_ids"},
"pending_delete_resource_count": len(pending_delete_resource_ids),
"physical_file_delete": "after_commit",
"refund": False,
},
)
@@ -716,9 +732,127 @@ async def delete_segment(
deleted=True,
deleted_module_project_id=deleted_module_project_id,
released_size_bytes=int(released_size_bytes or 0),
upload_resource_released=upload_resource_released,
pending_delete_resource_ids=pending_delete_resource_ids,
)
async def delete_task_set(
db: AsyncSession,
*,
current_user: User,
task_set_id: str,
) -> ShotTaskSetDeleteOut:
"""软删除整个拆镜任务集。
对外删除入口以 ShotReplicateTaskSet 为边界;内部 ModuleGenerationProject
只作为片段复刻链路被联动软删。这里不 commit、不 rollback、不删除真实文件。
"""
task_set = await get_task_set_for_user(db, task_set_id=task_set_id, user=current_user, for_update=True)
task_set_id_snapshot = task_set.id
user_id_snapshot = task_set.user_id
if task_set.analysis_status == ShotAnalysisStatusEnum.PROCESSING.value:
raise HTTPException(status_code=400, detail="原视频分析正在处理中,暂不能删除任务集")
if task_set.split_status == ShotSplitStatusEnum.PROCESSING.value:
raise HTTPException(status_code=400, detail="拆镜切片正在处理中,暂不能删除任务集")
segments_result = await db.execute(
select(ShotReplicateSegment)
.where(
ShotReplicateSegment.task_set_id == task_set_id_snapshot,
ShotReplicateSegment.deleted_at.is_(None),
)
.with_for_update()
)
segments = list(segments_result.scalars().all())
for segment in segments:
if segment.split_status == ShotSplitStatusEnum.PROCESSING.value:
raise HTTPException(status_code=400, detail=f"片段{segment.segment_index}正在切割处理中,暂不能删除任务集")
if segment.analysis_status == ShotSegmentAnalysisStatusEnum.PROCESSING.value:
raise HTTPException(status_code=400, detail=f"片段{segment.segment_index}正在分析处理中,暂不能删除任务集")
if segment.replicate_status == ShotSegmentReplicateStatusEnum.PROCESSING.value:
raise HTTPException(status_code=400, detail=f"片段{segment.segment_index}关联复刻流程正在处理中,暂不能删除任务集")
segment_ids = [segment.id for segment in segments]
module_project_ids = [segment.module_project_id for segment in segments if segment.module_project_id]
deleted_at = _now()
released_size_bytes = 0
upload_resource_released = 0
pending_delete_resource_ids: list[str] = []
task_upload_release = await release_upload_resources_by_source(
db,
source_model=UploadResourceSourceModelEnum.SHOT_REPLICATE_TASK_SET.value,
source_ids=[task_set_id_snapshot],
module=UploadResourceModuleEnum.SHOT_REPLICATE.value,
)
released_size_bytes += int(task_upload_release.get("released_size_bytes") or 0)
upload_resource_released += int(task_upload_release.get("released") or 0)
pending_delete_resource_ids.extend(task_upload_release.get("released_resource_ids") or [])
segment_upload_release = await release_upload_resources_by_source(
db,
source_model=UploadResourceSourceModelEnum.SHOT_REPLICATE_SEGMENT.value,
source_ids=segment_ids,
module=UploadResourceModuleEnum.SHOT_REPLICATE.value,
)
released_size_bytes += int(segment_upload_release.get("released_size_bytes") or 0)
upload_resource_released += int(segment_upload_release.get("released") or 0)
pending_delete_resource_ids.extend(segment_upload_release.get("released_resource_ids") or [])
from app.services.shot_replicate_flow_service import delete_shot_replicate_project
deleted_module_project_count = 0
for module_project_id in dict.fromkeys(module_project_ids):
project_delete_out = await delete_shot_replicate_project(
db,
current_user=current_user,
project_id=module_project_id,
refund_unfinished=False,
)
deleted_module_project_count += 1
released_size_bytes += int(project_delete_out.released_size_bytes or 0)
upload_resource_released += int(project_delete_out.upload_resource_released or 0)
pending_delete_resource_ids.extend(project_delete_out.pending_delete_resource_ids or [])
task_set.deleted_at = deleted_at
task_set.status = ShotTaskSetStatusEnum.DELETED.value
for segment in segments:
segment.deleted_at = deleted_at
segment.replicate_status = ShotSegmentReplicateStatusEnum.FAILED.value if segment.module_project_id else segment.replicate_status
await db.flush()
log_module_event_file(
module=MODULE,
event_type="SHOT_TASK_SET_DELETED",
project_id=task_set_id_snapshot,
user_id=user_id_snapshot,
message="软删除拆镜任务集并标记上传资源待物理删除",
detail={
"task_set_id": task_set_id_snapshot,
"segment_count": len(segment_ids),
"module_project_count": deleted_module_project_count,
"released_size_bytes": released_size_bytes,
"upload_resource_released": upload_resource_released,
"pending_delete_resource_count": len(pending_delete_resource_ids),
"task_upload_release": {k: v for k, v in task_upload_release.items() if k != "released_resource_ids"},
"segment_upload_release": {k: v for k, v in segment_upload_release.items() if k != "released_resource_ids"},
"physical_file_delete": "after_commit",
"refund": False,
},
)
return ShotTaskSetDeleteOut(
message="拆镜任务集已删除",
task_set_id=task_set_id_snapshot,
deleted=True,
deleted_segment_count=len(segment_ids),
deleted_module_project_count=deleted_module_project_count,
released_size_bytes=int(released_size_bytes or 0),
upload_resource_released=upload_resource_released,
pending_delete_resource_ids=pending_delete_resource_ids,
)
async def prepare_reanalyze_task_set(
db: AsyncSession,