Files
meida_backend/apps/api/schemas.py
T
xsl 2009aa938c fix(billing): make quota seed and column names match the product SSOT
The product plan is the only source for quota numbers, but the 0001 seed
used a second set (agent_chat 20/50, tryon hard 10) and omitted hairstyle,
hd_export and report regen. Migration 0003 replaces the seed and renames
points_reserved → quota_reserved and bonus_value → bonus_granted so the
docs and the schema stop contradicting each other.

Effective limit now clips at hard_cap. CI runs the integration slice
against the Postgres/Redis services it already starts.
2026-08-14 11:28:35 +08:00

99 lines
2.2 KiB
Python
Executable File

"""Request/response schemas.
NFR-MAINT-01 契约先行: schema 先定义,客户端类型由 OpenAPI 生成。
Wire responses are wrapped by the unified envelope (架构文档 §9.2); these models
describe the ``data`` payload only.
"""
from __future__ import annotations
from datetime import datetime
from pydantic import BaseModel, Field
class DevTokenRequest(BaseModel):
device_key: str = Field(
default="local-dev",
min_length=1,
max_length=64,
description="任意稳定字符串;同一 device_key 复用同一测试用户",
)
class DevTokenResponse(BaseModel):
access_token: str
token_type: str = "Bearer"
expires_in: int
user_id: str = Field(description="雪花 ID 以字符串返回,避免 JS 精度丢失")
class ChatRequest(BaseModel):
message: str = Field(min_length=1, max_length=2000)
request_key: str | None = Field(
default=None,
max_length=128,
description="幂等键;相同键不会重复扣配额 (架构文档 §9.1)",
)
class ChatUsage(BaseModel):
tokens_in: int
tokens_out: int
tokens_cached: int
latency_ms: int
cost_cents: str
class ChatResponse(BaseModel):
reply: str
provider: str
model: str
prompt_id: str | None
prompt_version: str | None
call_id: str
usage: ChatUsage
quota_remaining: int
class QuotaResponse(BaseModel):
quota_key: str
period_key: str
used: int
limit_value: int
bonus_granted: int
remaining: int
reset_at: datetime | None
class LedgerEntry(BaseModel):
tx_id: str
delta: int
tx_type: str
status: str
reason: str | None
quota_key: str | None
period_key: str | None
balance_after: int
created_at: datetime
class TaskSubmitRequest(BaseModel):
echo: str = Field(default="ping", max_length=200)
idempotency_key: str | None = Field(default=None, max_length=128)
class TaskResponse(BaseModel):
task_id: str
task_type: str
status: str
progress: int
stage_text: str | None
result: dict[str, object] | None
error_code: int | None
error_message: str | None
retry_count: int
submitted_at: datetime
started_at: datetime | None
finished_at: datetime | None