admin_schema.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. """
  2. 后台管理系统数据传输对象定义
  3. 定义管理员认证、用户管理、模型管理相关API请求和响应的数据结构
  4. """
  5. from datetime import datetime, date
  6. from decimal import Decimal
  7. from typing import Optional, List
  8. from pydantic import BaseModel, ConfigDict, Field
  9. # ==================== 认证相关 Schema ====================
  10. class AdminLoginRequest(BaseModel):
  11. """管理员登录请求"""
  12. username: str = Field(..., min_length=1, max_length=50, description="用户名")
  13. password: str = Field(..., min_length=1, max_length=100, description="密码")
  14. class AdminLoginResponse(BaseModel):
  15. """管理员登录响应"""
  16. token: str = Field(..., description="JWT Token")
  17. admin_id: int = Field(..., description="管理员ID")
  18. username: str = Field(..., description="用户名")
  19. nickname: str = Field(..., description="昵称")
  20. expires_at: datetime = Field(..., description="Token过期时间")
  21. class AdminInfo(BaseModel):
  22. """管理员信息"""
  23. id: int
  24. username: str
  25. nickname: str
  26. status: str
  27. created_at: datetime
  28. model_config = ConfigDict(from_attributes=True)
  29. # ==================== 用户管理相关 Schema ====================
  30. class UserListParams(BaseModel):
  31. """用户列表查询参数"""
  32. keyword: Optional[str] = Field(None, description="搜索关键词(用户ID/用户名/手机号/邮箱)")
  33. status: Optional[str] = Field(None, description="账户状态:active/disabled")
  34. register_start: Optional[date] = Field(None, description="注册开始日期")
  35. register_end: Optional[date] = Field(None, description="注册结束日期")
  36. sort_by: Optional[str] = Field("created_at", description="排序字段:created_at")
  37. sort_order: Optional[str] = Field("desc", description="排序方向:asc/desc")
  38. page: int = Field(1, ge=1, description="页码")
  39. size: int = Field(20, ge=1, le=100, description="每页数量")
  40. class UserListItem(BaseModel):
  41. """用户列表项"""
  42. id: str
  43. username: Optional[str] = None
  44. nickname: str
  45. phone: Optional[str] = None
  46. registration_date: Optional[date] = None
  47. status: str = "active"
  48. is_verified: Optional[str] = None
  49. real_name: Optional[str] = None
  50. model_config = ConfigDict(from_attributes=True)
  51. class UserDetailResponse(BaseModel):
  52. """用户详情响应"""
  53. id: str
  54. username: Optional[str] = None
  55. nickname: str
  56. phone: Optional[str] = None
  57. email: Optional[str] = None
  58. avatar: Optional[str] = None
  59. registration_date: Optional[date] = None
  60. status: str = "active"
  61. model_config = ConfigDict(from_attributes=True)
  62. class UserUsageStats(BaseModel):
  63. """用户使用统计"""
  64. conversation_count: int = 0
  65. token_consumed: int = 0
  66. image_count: int = 0
  67. audio_count: int = 0
  68. audio_duration: int = 0
  69. video_count: int = 0
  70. api_call_count: int = 0
  71. api_input_tokens: int = 0
  72. api_output_tokens: int = 0
  73. class UserStatusRequest(BaseModel):
  74. """用户状态变更请求"""
  75. status: str = Field(..., pattern="^(active|disabled)$", description="目标状态:active/disabled")
  76. class ResetPasswordResponse(BaseModel):
  77. """密码重置响应"""
  78. user_id: str
  79. new_password: str
  80. # ==================== 模型管理相关 Schema ====================
  81. class ModelListParams(BaseModel):
  82. """模型列表查询参数"""
  83. keyword: Optional[str] = Field(None, description="搜索关键词(模型标识/显示名称/供应商)")
  84. category: Optional[int] = Field(None, description="模型分类")
  85. supplier: Optional[str] = Field(None, description="供应商")
  86. is_show_enabled: Optional[bool] = Field(None, description="是否展示")
  87. is_api_enabled: Optional[bool] = Field(None, description="是否启用API")
  88. page: int = Field(1, ge=1, description="页码")
  89. size: int = Field(20, ge=1, le=100, description="每页数量")
  90. class ModelListItem(BaseModel):
  91. """模型列表项"""
  92. id: int
  93. model_code: str
  94. display_name: Optional[str] = None
  95. img: str = ""
  96. category: int
  97. categories: List[int] = []
  98. supplier: str
  99. description: Optional[str] = None # 描述摘要(前80字)
  100. # 价格摘要:取第一条 is_active 价格记录
  101. price_label: Optional[str] = None # 如 "input<=32k"
  102. input_price_original: Optional[Decimal] = None
  103. output_price_original: Optional[Decimal] = None
  104. input_price_discounted: Optional[Decimal] = None
  105. output_price_discounted: Optional[Decimal] = None
  106. discount_rate: Optional[Decimal] = None
  107. discount_label: Optional[str] = None
  108. price_unit: Optional[str] = None
  109. is_show_enabled: bool = True
  110. is_api_enabled: bool = False
  111. is_featured: bool = False
  112. is_search: bool = False
  113. is_thinking: bool = False
  114. model_config = ConfigDict(from_attributes=True)
  115. class PriceTierItem(BaseModel):
  116. """价格阶梯项"""
  117. tier_min: int
  118. tier_max: Optional[int] = None
  119. input_price: Decimal
  120. output_price: Decimal
  121. class ModelPriceDetail(BaseModel):
  122. """模型价格详情"""
  123. id: Optional[int] = None
  124. pricing_mode: str = "simple"
  125. input_price: Optional[Decimal] = None
  126. output_price: Optional[Decimal] = None
  127. unit: str = "tokens"
  128. currency: str = "CNY"
  129. tiers: Optional[List[PriceTierItem]] = None
  130. class ModelDetailResponse(BaseModel):
  131. """模型详情响应"""
  132. id: int
  133. model_code: str
  134. display_name: Optional[str] = None
  135. img: Optional[str] = None
  136. category: int
  137. supplier: str
  138. description: Optional[str] = None
  139. custom_description: Optional[str] = None
  140. tag1: Optional[str] = None
  141. tag2: Optional[str] = None
  142. keywords: Optional[str] = None
  143. is_featured: bool = False
  144. is_search: bool = False
  145. is_thinking: bool = False
  146. is_show_enabled: bool = True
  147. is_api_enabled: bool = False
  148. source_keys: Optional[List[str]] = None
  149. normalized_keys: Optional[List[str]] = None
  150. created_at: datetime
  151. updated_at: datetime
  152. model_config = ConfigDict(from_attributes=True)
  153. class ModelCreateRequest(BaseModel):
  154. """模型创建请求"""
  155. model_code: str = Field(..., min_length=1, max_length=200, description="模型唯一标识")
  156. display_name: Optional[str] = Field(None, max_length=255, description="显示名称")
  157. img: Optional[str] = Field(None, description="图标URL")
  158. category: int = Field(0, ge=0, le=8, description="模型分类")
  159. supplier: str = Field("Qwen", min_length=1, max_length=100, description="供应商")
  160. description: Optional[str] = Field(None, description="模型描述")
  161. custom_description: Optional[str] = Field(None, description="管理员自定义描述")
  162. tag1: Optional[str] = Field(None, max_length=100, description="主标签")
  163. tag2: Optional[str] = Field(None, max_length=100, description="次要标签")
  164. keywords: Optional[str] = Field(None, description="关键词")
  165. is_featured: bool = Field(False, description="是否精选")
  166. is_search: bool = Field(False, description="是否支持搜索")
  167. is_thinking: bool = Field(False, description="是否支持思考")
  168. is_show_enabled: bool = Field(True, description="是否展示")
  169. is_api_enabled: bool = Field(False, description="是否启用API")
  170. class ModelUpdateRequest(BaseModel):
  171. """模型更新请求"""
  172. display_name: Optional[str] = Field(None, max_length=255, description="显示名称")
  173. img: Optional[str] = Field(None, description="图标URL")
  174. category: Optional[int] = Field(None, ge=0, le=8, description="模型分类")
  175. supplier: Optional[str] = Field(None, min_length=1, max_length=100, description="供应商")
  176. description: Optional[str] = Field(None, description="模型描述")
  177. custom_description: Optional[str] = Field(None, description="管理员自定义描述")
  178. tag1: Optional[str] = Field(None, max_length=100, description="主标签")
  179. tag2: Optional[str] = Field(None, max_length=100, description="次要标签")
  180. keywords: Optional[str] = Field(None, description="关键词")
  181. is_featured: Optional[bool] = Field(None, description="是否精选")
  182. is_search: Optional[bool] = Field(None, description="是否支持搜索")
  183. is_thinking: Optional[bool] = Field(None, description="是否支持思考")
  184. class ModelPriceRequest(BaseModel):
  185. """模型价格设置请求"""
  186. label: str = Field("default", description="价格标签,如 input<=128k / 视频生成(720P)")
  187. tier_min: Optional[Decimal] = Field(None, description="阶梯下限")
  188. tier_max: Optional[Decimal] = Field(None, description="阶梯上限")
  189. tier_unit: Optional[str] = Field(None, description="阶梯单位:tokens/seconds/images")
  190. input_price: Optional[Decimal] = Field(None, description="输入原价")
  191. output_price: Optional[Decimal] = Field(None, description="输出原价")
  192. discount_rate: Optional[Decimal] = Field(Decimal("100"), description="折扣率 0-100,100=无折扣")
  193. unit: str = Field("元/每百万tokens", description="显示单位")
  194. display_multiplier: int = Field(1000000, description="展示倍数")
  195. currency: str = Field("CNY", description="货币单位")
  196. class ModelStatusRequest(BaseModel):
  197. """模型状态变更请求"""
  198. field: str = Field(..., pattern="^(is_show_enabled|is_api_enabled|is_featured)$", description="状态字段")
  199. value: bool = Field(..., description="目标值")
  200. # ==================== 本地模型管理相关 Schema ====================
  201. class LocalModelListParams(BaseModel):
  202. """本地模型列表查询参数"""
  203. keyword: Optional[str] = Field(None, description="搜索关键词")
  204. user_id: Optional[str] = Field(None, description="用户ID筛选")
  205. visibility: Optional[str] = Field(None, description="可见性筛选: user/global")
  206. page: int = Field(1, ge=1, description="页码")
  207. size: int = Field(20, ge=1, le=100, description="每页数量")
  208. class LocalModelListItem(BaseModel):
  209. """本地模型列表项"""
  210. id: int
  211. title: str
  212. name: str
  213. supplier: Optional[str] = "Custom"
  214. user_id: str
  215. username: Optional[str] = None
  216. base_url: str
  217. visibility: str = "user"
  218. category: int = 0
  219. created_at: datetime
  220. updated_at: datetime
  221. model_config = ConfigDict(from_attributes=True)
  222. class LocalModelVisibilityRequest(BaseModel):
  223. """本地模型可见性变更请求"""
  224. visibility: str = Field(..., pattern="^(user|global)$", description="可见性: user/global")