edca0dcfa7
P1-1 统一扣费回调: - 新增 POST /api/compute/internal/deduct(COMPUTE_ADMIN_TOKEN鉴权,engine_log_id幂等) - compute 扣费后异步回调,按引擎实际费用(微元)扣平台来源账本 - 删除 relay.py 中 _bill_usage/_bill_usage_anthropic 调用(改由compute回调记账) - ComputeUsageRecord 加 engine_log_id 字段,alembic 0079 迁移 P1-2 请求前预检: - _user_engine_pat 中查 compute 余额(5s缓存),余额<=0直接403 - 避免无余额请求仍转发到引擎 P2-1 对账接口: - GET /admin/compute/reconcile 对比引擎used_quota vs 平台累计扣费 - 支持分页、only_mismatch过滤 P2-2 折扣统一: - 用户级折扣设置/删除时异步同步等效系数到引擎users.discount - compute /api/user/manage 支持 username 定位用户 - compute_client 新增 set_user_discount_by_username
62 lines
2.3 KiB
Python
62 lines
2.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""compute 引擎 → server-core 内部回调接口。
|
|
|
|
compute 扣费完成后异步回调此接口,按引擎实际费用(微元)扣平台来源账本。
|
|
鉴权:Authorization: Bearer <COMPUTE_ADMIN_TOKEN>(与引擎侧 PINEAGENTS_INTERNAL_TOKEN 一致)。
|
|
幂等:engine_log_id 去重,防网络重试重复扣费。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Depends, Header, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from ... import config
|
|
from ...infrastructure.repositories import Database
|
|
from ..dependencies import get_db
|
|
from ...services.compute_pricing_service import deduct_by_engine_cost
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/compute/internal", tags=["compute-internal"])
|
|
|
|
|
|
class EngineDeductRequest(BaseModel):
|
|
username: str
|
|
actual_cost_micro: int
|
|
engine_log_id: int
|
|
model_name: str = ""
|
|
token_count: int = 0
|
|
|
|
|
|
def _verify_internal_token(authorization: str = Header(default="")) -> None:
|
|
"""校验 compute 引擎内部回调令牌。"""
|
|
token = authorization[7:].strip() if authorization.lower().startswith("bearer ") else authorization.strip()
|
|
expected = config.COMPUTE_ADMIN_TOKEN or ""
|
|
if not expected or token != expected:
|
|
raise HTTPException(status_code=401, detail="invalid internal token")
|
|
|
|
|
|
@router.post("/deduct", summary="compute 引擎扣费回调(按实际费用扣平台账本)")
|
|
async def engine_deduct(
|
|
req: EngineDeductRequest,
|
|
db: Database = Depends(get_db),
|
|
_auth: None = Depends(_verify_internal_token),
|
|
):
|
|
"""compute 扣费后回调:actual_cost_micro(微元)→ 扣企业分配/个人余额,engine_log_id 幂等。"""
|
|
try:
|
|
result = await deduct_by_engine_cost(
|
|
db,
|
|
username=req.username,
|
|
actual_cost_micro=req.actual_cost_micro,
|
|
engine_log_id=req.engine_log_id,
|
|
model_name=req.model_name,
|
|
token_count=req.token_count,
|
|
)
|
|
return {"ok": result.get("ok", True), **result}
|
|
except Exception as exc: # noqa: BLE001
|
|
logger.warning("[compute-internal] deduct callback failed username=%s engine_log_id=%s err=%s",
|
|
req.username, req.engine_log_id, exc)
|
|
raise HTTPException(status_code=500, detail=str(exc)) from exc
|