scheme.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import json
  2. from datetime import datetime
  3. from pathlib import Path
  4. from typing import Optional, Dict, Any, List
  5. from pydantic import BaseModel, field_validator, Field, field_serializer
  6. from enum import Enum
  7. class ImageType(str, Enum):
  8. front_coaxial = "front_coaxial"
  9. back_coaxial = "back_coaxial"
  10. front_ring = "front_ring"
  11. back_ring = "back_ring"
  12. # 灰度图类型
  13. front_gray = "front_gray"
  14. back_gray = "back_gray"
  15. # 融合图类型
  16. front_fusion = "front_fusion"
  17. back_fusion = "back_fusion"
  18. class CardType(str, Enum):
  19. pokemon = "pokemon"
  20. basketball = "basketball"
  21. football = "football"
  22. class ResultImagePathType(str, Enum):
  23. detection = "detection"
  24. modified = "modified"
  25. class SortBy(str, Enum):
  26. card_name = "card_name"
  27. created_at = "created_at"
  28. updated_at = "updated_at"
  29. detection_score = "detection_score"
  30. modified_score = "modified_score"
  31. class SortOrder(str, Enum):
  32. asc = "ASC"
  33. desc = "DESC"
  34. class CardNoList(BaseModel):
  35. cardNoList: List[str]
  36. # "图片类型和计算分数分数类型映射表"
  37. # [CHANGED] 更新映射关系以匹配 score_service.py
  38. IMAGE_TYPE_TO_SCORE_TYPE = {
  39. "front_coaxial": "front_coaxial",
  40. "back_coaxial": "back_coaxial",
  41. "front_ring": "front_ring",
  42. "back_ring": "back_ring",
  43. "front_gray": None,
  44. "back_gray": None,
  45. "front_fusion": None,
  46. "back_fusion": None
  47. }
  48. # --- Pydantic 数据模型 ---
  49. class CardImageResponse(BaseModel):
  50. """用于API响应的图片数据模型 (主键为 id)"""
  51. id: int
  52. card_id: int
  53. image_type: str
  54. image_name: Optional[str] = None
  55. image_path: str
  56. # Gray images need these fields to be Optional/None
  57. detection_image_path: Optional[str] = None
  58. modified_image_path: Optional[str] = None
  59. detection_json: Dict[str, Any]
  60. modified_json: Optional[Dict[str, Any]] = None
  61. is_edited: bool = False
  62. created_at: datetime
  63. updated_at: datetime
  64. class Config:
  65. from_attributes = True
  66. @field_validator('detection_json', 'modified_json', mode='before')
  67. @classmethod
  68. def parse_json_string(cls, v):
  69. if v is None:
  70. return None
  71. if isinstance(v, str):
  72. try:
  73. return json.loads(v)
  74. except json.JSONDecodeError:
  75. raise ValueError("Invalid JSON string in database")
  76. return v
  77. # 拦截序列化,格式化掉中间的 "T"
  78. @field_serializer('created_at', 'updated_at', check_fields=False)
  79. def serialize_datetime(self, dt: datetime, _info):
  80. if dt is not None:
  81. return dt.strftime('%Y-%m-%d %H:%M:%S')
  82. return dt
  83. class CardDetailResponse(BaseModel):
  84. """用于响应单个卡牌详细信息的模型 (主键为 id)"""
  85. id: int
  86. id_prev: Optional[int] = None
  87. id_next: Optional[int] = None
  88. card_name: Optional[str] = None
  89. cardNo: Optional[str] = None
  90. created_at: datetime
  91. updated_at: datetime
  92. card_type: str
  93. is_edited: bool
  94. review_state: int = 1
  95. detection_score: Optional[float] = None
  96. modified_score: Optional[float] = None
  97. detection_score_detail: Optional[Dict[str, Any]] = None
  98. modified_score_detail: Optional[Dict[str, Any]] = None
  99. images: List[CardImageResponse] = []
  100. class Config:
  101. from_attributes = True
  102. # 拦截序列化,格式化掉中间的 "T"
  103. @field_serializer('created_at', 'updated_at', check_fields=False)
  104. def serialize_datetime(self, dt: datetime, _info):
  105. if dt is not None:
  106. return dt.strftime('%Y-%m-%d %H:%M:%S')
  107. return dt
  108. class ImageJsonPairResponse(BaseModel):
  109. id: int
  110. detection_json: Dict[str, Any]
  111. modified_json: Optional[Dict[str, Any]] = None
  112. class Config:
  113. from_attributes = True
  114. @field_validator('detection_json', 'modified_json', mode='before')
  115. @classmethod
  116. def parse_json_string(cls, v):
  117. if v is None:
  118. return None
  119. if isinstance(v, str):
  120. try:
  121. return json.loads(v)
  122. except json.JSONDecodeError:
  123. raise ValueError("Invalid JSON string in database")
  124. return v
  125. class CardImageInListResponse(BaseModel):
  126. id: int
  127. image_type: str
  128. image_path: str
  129. detection_image_path: Optional[str] = None
  130. modified_image_path: Optional[str] = None
  131. class Config:
  132. from_attributes = True
  133. class CardListDetailResponse(BaseModel):
  134. id: int
  135. card_name: Optional[str] = None
  136. cardNo: Optional[str] = None
  137. card_type: str
  138. detection_score: Optional[float] = None
  139. modified_score: Optional[float] = None
  140. is_edited: bool
  141. review_state: int = 1
  142. created_at: datetime
  143. updated_at: datetime
  144. image_path_list: Dict[str, Optional[str]] = {}
  145. detection_image_path_list: Dict[str, Optional[str]] = {}
  146. modified_image_path_list: Dict[str, Optional[str]] = {}
  147. is_bound: bool = False
  148. class Config:
  149. from_attributes = True
  150. # 拦截序列化,格式化掉中间的 "T"
  151. @field_serializer('created_at', 'updated_at', check_fields=False)
  152. def serialize_datetime(self, dt: datetime, _info):
  153. if dt is not None:
  154. return dt.strftime('%Y-%m-%d %H:%M:%S')
  155. return dt
  156. class CardListWithTotal(BaseModel):
  157. total: int
  158. list: List[CardListDetailResponse]
  159. class CardListResponseWrapper(BaseModel):
  160. data: CardListWithTotal
  161. class ReviewUpdate(BaseModel):
  162. review_state: int = Field(..., ge=1, le=4, description="审核状态 (1待复检, 2已复检, 3审核未通过, 4审核通过)")
  163. class CardTable(BaseModel):
  164. id: int
  165. card_name: Optional[str] = None
  166. cardNo: Optional[str] = None
  167. card_type: str = "pokemon"
  168. detection_score: Optional[float] = None
  169. modified_score: Optional[float] = None
  170. is_edited: bool = False
  171. created_at: datetime
  172. updated_at: datetime
  173. review_state: int = 1
  174. class Config:
  175. from_attributes = True
  176. @field_serializer("created_at", "updated_at", check_fields=False)
  177. def serialize_datetime(self, dt: datetime, _info):
  178. if dt is not None:
  179. return dt.strftime("%Y-%m-%d %H:%M:%S")
  180. return dt
  181. class CardImageTable(BaseModel):
  182. id: int
  183. card_id: int
  184. image_type: str
  185. image_name: Optional[str] = None
  186. image_path: str
  187. detection_image_path: Optional[str] = None
  188. modified_image_path: Optional[str] = None
  189. detection_json: Dict[str, Any]
  190. modified_json: Optional[Dict[str, Any]] = None
  191. is_edited: bool = False
  192. created_at: datetime
  193. updated_at: datetime
  194. class Config:
  195. from_attributes = True
  196. @field_validator("detection_json", "modified_json", mode="before")
  197. @classmethod
  198. def parse_json_string(cls, v):
  199. if v is None:
  200. return None
  201. if isinstance(v, str):
  202. try:
  203. return json.loads(v)
  204. except json.JSONDecodeError:
  205. raise ValueError("Invalid JSON string in database")
  206. return v
  207. @field_serializer("created_at", "updated_at", check_fields=False)
  208. def serialize_datetime(self, dt: datetime, _info):
  209. if dt is not None:
  210. return dt.strftime("%Y-%m-%d %H:%M:%S")
  211. return dt
  212. class CardGrayImageTable(BaseModel):
  213. id: int
  214. card_id: int
  215. image_type: str
  216. image_path: str
  217. created_at: datetime
  218. updated_at: datetime
  219. class Config:
  220. from_attributes = True
  221. @field_serializer("created_at", "updated_at", check_fields=False)
  222. def serialize_datetime(self, dt: datetime, _info):
  223. if dt is not None:
  224. return dt.strftime("%Y-%m-%d %H:%M:%S")
  225. return dt