refactor: 清理未使用IPC命令、修正point_service注释与扣费逻辑、修复camelToSnake正则、优化vidu import
- 删除8个未使用IPC命令,保留validate_media_path - file.rs返回类型优化为ApiResponse<()> - point_service.consume()注释与签名一致 - VideoGeneration改为拼接成功后扣费 - 添加漏扣费风险注释 - 删除过时测试文件 - 修复camelToSnake连续大写字母问题 - vidu.py import移至模块顶层 Refs: P1-1~P1-6 技术债务清理
This commit is contained in:
@@ -10,12 +10,10 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from app.core.platform_config import get_platform_config_loader
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.scheduler.handlers.base import AsyncHandler
|
||||
from app.scheduler.models import StateChange
|
||||
from app.scheduler.registry import TaskRegistry
|
||||
from app.scheduler.slot_manager import SlotManager
|
||||
from app.services import point_service as ps
|
||||
from app.services.vidu_service import ViduService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -52,44 +50,6 @@ class VideoHandler(AsyncHandler):
|
||||
)
|
||||
return self.service
|
||||
|
||||
async def _deduct_video_points(self, task: Any, params: dict[str, Any]) -> None:
|
||||
"""视频生成后置扣费:按总规划时长一次性扣费,批次幂等。"""
|
||||
batch_id = params.get("batch_id")
|
||||
total_planned_duration = float(params.get("total_planned_duration", 0) or 0)
|
||||
|
||||
if not batch_id or total_planned_duration <= 0:
|
||||
return
|
||||
|
||||
async with AsyncSessionLocal() as db:
|
||||
from sqlalchemy import select
|
||||
from app.models.point_transaction import PointTransaction
|
||||
|
||||
# 幂等:该批次是否已扣过
|
||||
result = await db.execute(
|
||||
select(PointTransaction).where(
|
||||
PointTransaction.user_id == task.user_id,
|
||||
PointTransaction.source_type == "video",
|
||||
PointTransaction.source_id == batch_id,
|
||||
)
|
||||
)
|
||||
if result.scalar_one_or_none():
|
||||
return
|
||||
|
||||
try:
|
||||
points = ps._calculate_cost("video", {"seconds": total_planned_duration})
|
||||
await ps.consume(
|
||||
db,
|
||||
user_id=task.user_id,
|
||||
points=points,
|
||||
source_type="video",
|
||||
source_id=batch_id,
|
||||
description="【视频生成】",
|
||||
duration=total_planned_duration,
|
||||
)
|
||||
await db.commit()
|
||||
except Exception as e:
|
||||
logger.error(f"[Video {task.task_id}] 扣费失败: {e}")
|
||||
|
||||
async def tick(
|
||||
self, tasks: list[Any], registry: TaskRegistry, slots: SlotManager
|
||||
) -> list[StateChange]:
|
||||
@@ -104,7 +64,7 @@ class VideoHandler(AsyncHandler):
|
||||
result_data = task.result or {}
|
||||
if result_data.get("video_url") or result_data.get("state") == "success":
|
||||
# callback 已到达,结果已写入 TaskRegistry
|
||||
await self._deduct_video_points(task, params)
|
||||
await registry.remove_running(task.task_id)
|
||||
|
||||
changes.append(
|
||||
StateChange(
|
||||
@@ -145,8 +105,6 @@ class VideoHandler(AsyncHandler):
|
||||
video_url = creations[0].get("url") if creations else None
|
||||
|
||||
if vidu_state == "success" and video_url:
|
||||
await self._deduct_video_points(task, params)
|
||||
|
||||
changes.append(
|
||||
StateChange(
|
||||
task_id=task.task_id,
|
||||
@@ -229,31 +187,6 @@ class VideoHandler(AsyncHandler):
|
||||
)
|
||||
continue # ← 已提交,不再重复提交
|
||||
|
||||
# 积分预检:余额不足直接失败,不提交 Vidu 任务
|
||||
planned_duration = float(params.get("planned_duration", 0) or 0)
|
||||
if planned_duration > 0:
|
||||
try:
|
||||
async with AsyncSessionLocal() as db:
|
||||
from sqlalchemy import select
|
||||
from app.models.user_point import UserPoint
|
||||
|
||||
points = ps._calculate_cost("video", {"seconds": planned_duration})
|
||||
result = await db.execute(select(UserPoint).where(UserPoint.user_id == task.user_id))
|
||||
up = result.scalar_one_or_none()
|
||||
if not up or up.balance < points:
|
||||
message = f"积分不足,需要 {points} 积分,当前余额 {up.balance if up else 0}"
|
||||
await registry.update(
|
||||
task.task_id,
|
||||
status="failed",
|
||||
progress=0,
|
||||
message=message,
|
||||
)
|
||||
changes.append(StateChange(task_id=task.task_id, field_path="status", value="failed"))
|
||||
changes.append(StateChange(task_id=task.task_id, field_path="message", value=message))
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"[Video {task.task_id}] 积分预检失败: {e}")
|
||||
|
||||
# 提交阶段:占用 slot,提交成功后自动释放
|
||||
async with slots.acquire_ctx(
|
||||
SLOT_KEY, task.task_id, self.max_slots
|
||||
|
||||
Reference in New Issue
Block a user