1
0

scheme.py 7.5 KB

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