会员积分改版V1
This commit is contained in:
@@ -16,7 +16,6 @@ from app.enums.credit_record import (
|
||||
CreditRecordSourceModule,
|
||||
CreditRecordSourceStepCode,
|
||||
)
|
||||
from app.enums.llm_billing import LlmBillingConfigKey
|
||||
from sqlalchemy import String, case, cast, func, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -56,8 +55,8 @@ from app.schemas.shot_replicate import (
|
||||
from app.services.module_generation_log_service import log_module_event_file
|
||||
from app.services.llm_billing import (
|
||||
LlmBillingContext,
|
||||
release_on_failure,
|
||||
start_hold,
|
||||
refund_on_final_failure,
|
||||
pre_deduct,
|
||||
validate_retryable_previous_attempt,
|
||||
)
|
||||
from app.services.resource_accounting_service import SOURCE_MODEL_SHOT_SEGMENT, soft_delete_resources_by_source
|
||||
@@ -94,8 +93,7 @@ def build_task_set_analysis_billing_context(task_set: ShotReplicateTaskSet) -> L
|
||||
source_step_id=str(task_set.id),
|
||||
source_step_code=CreditRecordSourceStepCode.VIDEO_ANALYSIS.value,
|
||||
related_id=str(task_set.id),
|
||||
hold_config_key=LlmBillingConfigKey.HOLD_SHOT_VIDEO_ANALYSIS.value,
|
||||
description_prefix="拆镜复刻原视频AI分析",
|
||||
description_prefix="拆镜复刻原视频AI分析",
|
||||
trace_id=f"shot-task-set-analysis:{task_set.id}:attempt:{int(task_set.analysis_attempt_no or 1)}",
|
||||
)
|
||||
|
||||
@@ -113,8 +111,7 @@ def build_segment_analysis_billing_context(segment: ShotReplicateSegment) -> Llm
|
||||
source_step_id=str(segment.id),
|
||||
source_step_code=CreditRecordSourceStepCode.VIDEO_ANALYSIS.value,
|
||||
related_id=str(segment.id),
|
||||
hold_config_key=LlmBillingConfigKey.HOLD_SHOT_VIDEO_ANALYSIS.value,
|
||||
description_prefix="拆镜复刻片段视频AI分析",
|
||||
description_prefix="拆镜复刻片段视频AI分析",
|
||||
trace_id=f"shot-segment-analysis:{segment.id}:attempt:{int(segment.analysis_attempt_no or 1)}",
|
||||
)
|
||||
|
||||
@@ -268,7 +265,7 @@ async def create_task_set(
|
||||
)
|
||||
db.add(task_set)
|
||||
await db.flush()
|
||||
await start_hold(db, build_task_set_analysis_billing_context(task_set))
|
||||
await pre_deduct(db, build_task_set_analysis_billing_context(task_set))
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type="SHOT_TASK_SET_CREATED",
|
||||
@@ -751,7 +748,7 @@ async def create_custom_segment(
|
||||
task_set.status = ShotTaskSetStatusEnum.SPLITTING.value
|
||||
task_set.split_status = ShotSplitStatusEnum.PROCESSING.value
|
||||
await db.flush()
|
||||
await start_hold(db, build_segment_analysis_billing_context(segment))
|
||||
await pre_deduct(db, build_segment_analysis_billing_context(segment))
|
||||
await refresh_task_set_split_summary(db, task_set.id)
|
||||
await db.flush()
|
||||
log_module_event_file(
|
||||
@@ -920,7 +917,7 @@ async def delete_segment(
|
||||
raise HTTPException(status_code=409, detail="当前拆镜片段关联的复刻流程正在处理中,暂不能删除")
|
||||
|
||||
if segment.source_mode == ShotSegmentSourceModeEnum.CUSTOM.value:
|
||||
await release_on_failure(
|
||||
await refund_on_final_failure(
|
||||
db,
|
||||
build_segment_analysis_billing_context(segment),
|
||||
error="用户删除自定义拆镜片段,释放未结算的片段分析预扣",
|
||||
@@ -982,7 +979,7 @@ async def delete_segment(
|
||||
"pending_delete_resource_count": len(pending_delete_resource_ids),
|
||||
"physical_file_delete": "after_commit",
|
||||
"media_refund": False,
|
||||
"llm_hold_release_on_cancel": segment.source_mode == ShotSegmentSourceModeEnum.CUSTOM.value,
|
||||
"llm_pre_deduct_refund_on_cancel": segment.source_mode == ShotSegmentSourceModeEnum.CUSTOM.value,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1037,14 +1034,14 @@ async def delete_task_set(
|
||||
|
||||
# 删除是对未执行/失败任务的最终取消动作;处理中的任务已在上方拦截。
|
||||
# 这里仅做账务补偿,不改变现有逐项目删除流程。
|
||||
await release_on_failure(
|
||||
await refund_on_final_failure(
|
||||
db,
|
||||
build_task_set_analysis_billing_context(task_set),
|
||||
error="用户删除拆镜任务集,释放未结算的原视频分析预扣",
|
||||
)
|
||||
for segment in segments:
|
||||
if segment.source_mode == ShotSegmentSourceModeEnum.CUSTOM.value:
|
||||
await release_on_failure(
|
||||
await refund_on_final_failure(
|
||||
db,
|
||||
build_segment_analysis_billing_context(segment),
|
||||
error="用户删除拆镜任务集,释放未结算的片段分析预扣",
|
||||
@@ -1113,7 +1110,7 @@ async def delete_task_set(
|
||||
"segment_upload_release": {k: v for k, v in segment_upload_release.items() if k != "released_resource_ids"},
|
||||
"physical_file_delete": "after_commit",
|
||||
"media_refund": False,
|
||||
"llm_hold_release_on_cancel": True,
|
||||
"llm_pre_deduct_refund_on_cancel": True,
|
||||
},
|
||||
)
|
||||
return ShotTaskSetDeleteOut(
|
||||
@@ -1198,7 +1195,7 @@ async def prepare_reanalyze_task_set(
|
||||
task_set.analysis_raw_json = None
|
||||
task_set.analysis_result_json = None
|
||||
await db.flush()
|
||||
await start_hold(db, build_task_set_analysis_billing_context(task_set))
|
||||
await pre_deduct(db, build_task_set_analysis_billing_context(task_set))
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type=ShotReplicateLogEventEnum.TASK_SET_REANALYZE_RECEIVED.value,
|
||||
@@ -1304,7 +1301,7 @@ async def prepare_reanalyze_segment(
|
||||
segment.segment_category = None
|
||||
segment.segment_audience = None
|
||||
await db.flush()
|
||||
await start_hold(db, build_segment_analysis_billing_context(segment))
|
||||
await pre_deduct(db, build_segment_analysis_billing_context(segment))
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type=ShotReplicateLogEventEnum.SEGMENT_REANALYZE_RECEIVED.value,
|
||||
@@ -1357,7 +1354,7 @@ async def mark_task_set_analysis_dispatch_failed(
|
||||
task_set.analysis_claim_token = None
|
||||
task_set.analysis_lease_until = None
|
||||
task_set.analysis_error_message = error_message
|
||||
await release_on_failure(db, build_task_set_analysis_billing_context(task_set), error=error_message)
|
||||
await refund_on_final_failure(db, build_task_set_analysis_billing_context(task_set), error=error_message)
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
|
||||
@@ -1394,7 +1391,7 @@ async def mark_segment_analysis_dispatch_failed(
|
||||
segment.analysis_claim_token = None
|
||||
segment.analysis_lease_until = None
|
||||
segment.analysis_error_message = error_message
|
||||
await release_on_failure(db, build_segment_analysis_billing_context(segment), error=error_message)
|
||||
await refund_on_final_failure(db, build_segment_analysis_billing_context(segment), error=error_message)
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
|
||||
@@ -1423,7 +1420,7 @@ async def mark_custom_segment_split_dispatch_failed(
|
||||
segment.split_next_retry_at = None
|
||||
segment.split_last_error = error_message
|
||||
# 切片投递失败不改变 LLM attempt 的冻结状态。用户重试切片时继续沿用
|
||||
# 原 active HOLD;只有片段分析最终失败或用户删除片段时才释放。
|
||||
# 原固定预扣;只有片段分析最终失败或用户删除片段时才按原来源退款。
|
||||
log_module_event_file(
|
||||
module=MODULE,
|
||||
event_type=ShotReplicateLogEventEnum.CELERY_DISPATCH_FAILED.value,
|
||||
|
||||
Reference in New Issue
Block a user