积分冻结释放
This commit is contained in:
@@ -15,12 +15,15 @@ from app.schemas.module_generation_v2 import (
|
||||
)
|
||||
from app.services.generation.pipeline.enqueue_service import enqueue_generation_create
|
||||
from app.services.hot_opening_replicate_service import project_to_detail_out
|
||||
from app.services.llm_billing import LlmBillingContext, log_celery_dispatch_compensated
|
||||
from app.services.module_async_recovery_service import OBJECT_MODULE_STEP, has_live_object_lock
|
||||
from app.services.module_generation_v2.config import HOT_OPENING_V2
|
||||
from app.services.module_generation_v2.dispatch_service import (
|
||||
dispatch_video_prompt_v2,
|
||||
ensure_v2_celery_enabled,
|
||||
)
|
||||
from app.services.module_generation_v2.flow_service import (
|
||||
build_v2_video_prompt_billing_context,
|
||||
create_hot_opening_project_v2,
|
||||
delete_project_v2,
|
||||
generate_video_from_prompt_v2,
|
||||
@@ -35,6 +38,19 @@ from app.services.upload_resource import cleanup_upload_resource_files_after_com
|
||||
router = APIRouter(prefix="/hot-opening-replications", tags=["hot-opening-replications-v2"])
|
||||
|
||||
|
||||
def _dispatch_context(*, user_id: str, project_id: str, step_id: str, step_version: int) -> LlmBillingContext:
|
||||
context = build_v2_video_prompt_billing_context(
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
step_id=step_id,
|
||||
step_version=step_version,
|
||||
module=HOT_OPENING_V2.module,
|
||||
display_name=HOT_OPENING_V2.display_name,
|
||||
)
|
||||
context.celery_task_id = f"module-v2-video-prompt:{step_id}"
|
||||
return context
|
||||
|
||||
|
||||
async def _detail(db: AsyncSession, current_user: User, project_id: str) -> HotOpeningTaskDetailOut:
|
||||
project = await get_v2_project_for_user(
|
||||
db,
|
||||
@@ -50,14 +66,19 @@ async def _dispatch_or_mark_failed(
|
||||
*,
|
||||
project_id: str,
|
||||
step_id: str,
|
||||
billing_context: LlmBillingContext,
|
||||
) -> None:
|
||||
dispatch = await dispatch_video_prompt_v2(
|
||||
config=HOT_OPENING_V2,
|
||||
project_id=project_id,
|
||||
step_id=step_id,
|
||||
billing_context=billing_context,
|
||||
)
|
||||
if dispatch.recoverable:
|
||||
return
|
||||
if await has_live_object_lock(object_type=OBJECT_MODULE_STEP, object_id=step_id):
|
||||
# apply_async 可能已送达但客户端收到异常;worker 已领取时不能释放冻结。
|
||||
return
|
||||
error_message = "视频提词任务的 Redis 注册和 Celery 投递均失败,请重新执行步骤2"
|
||||
await mark_video_prompt_dispatch_failed_v2(
|
||||
db,
|
||||
@@ -66,6 +87,7 @@ async def _dispatch_or_mark_failed(
|
||||
step_id=step_id,
|
||||
error_message=error_message,
|
||||
)
|
||||
log_celery_dispatch_compensated(billing_context, error=error_message)
|
||||
raise HTTPException(status_code=503, detail=error_message)
|
||||
|
||||
|
||||
@@ -81,6 +103,12 @@ async def create_task_v2(
|
||||
project_id = str(result.project.id)
|
||||
step_id = str(result.prompt_step.id)
|
||||
created_new = bool(result.created_new)
|
||||
billing_context = _dispatch_context(
|
||||
user_id=str(result.project.user_id),
|
||||
project_id=project_id,
|
||||
step_id=step_id,
|
||||
step_version=int(result.prompt_step.version or 1),
|
||||
)
|
||||
await db.commit()
|
||||
except IntegrityError as exc:
|
||||
await db.rollback()
|
||||
@@ -91,6 +119,12 @@ async def create_task_v2(
|
||||
project_id = str(result.project.id)
|
||||
step_id = str(result.prompt_step.id)
|
||||
created_new = bool(result.created_new)
|
||||
billing_context = _dispatch_context(
|
||||
user_id=str(result.project.user_id),
|
||||
project_id=project_id,
|
||||
step_id=step_id,
|
||||
step_version=int(result.prompt_step.version or 1),
|
||||
)
|
||||
await db.commit()
|
||||
except HTTPException:
|
||||
await db.rollback()
|
||||
@@ -100,7 +134,9 @@ async def create_task_v2(
|
||||
raise HTTPException(status_code=500, detail="创建爆款复刻 V2 项目失败") from exc
|
||||
|
||||
if created_new:
|
||||
await _dispatch_or_mark_failed(db, project_id=project_id, step_id=step_id)
|
||||
await _dispatch_or_mark_failed(
|
||||
db, project_id=project_id, step_id=step_id, billing_context=billing_context
|
||||
)
|
||||
return await _detail(db, current_user, project_id)
|
||||
|
||||
|
||||
@@ -136,11 +172,22 @@ async def retry_video_prompt_v2(
|
||||
)
|
||||
project_id_value = str(project.id)
|
||||
step_id_value = str(new_step.id)
|
||||
billing_context = _dispatch_context(
|
||||
user_id=str(project.user_id),
|
||||
project_id=project_id_value,
|
||||
step_id=step_id_value,
|
||||
step_version=int(new_step.version or 1),
|
||||
)
|
||||
await db.commit()
|
||||
except HTTPException:
|
||||
await db.rollback()
|
||||
raise
|
||||
await _dispatch_or_mark_failed(db, project_id=project_id_value, step_id=step_id_value)
|
||||
await _dispatch_or_mark_failed(
|
||||
db,
|
||||
project_id=project_id_value,
|
||||
step_id=step_id_value,
|
||||
billing_context=billing_context,
|
||||
)
|
||||
return HotOpeningActionOut(
|
||||
message="视频提词已重新提交",
|
||||
project_id=project_id_value,
|
||||
|
||||
Reference in New Issue
Block a user