scheme.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. class CardType(str, Enum):
  16. pokemon = "pokemon"
  17. basketball = "basketball"
  18. football = "football"
  19. class ResultImagePathType(str, Enum):
  20. detection = "detection"
  21. modified = "modified"
  22. class SortBy(str, Enum):
  23. card_name = "card_name"
  24. created_at = "created_at"
  25. updated_at = "updated_at"
  26. detection_score = "detection_score"
  27. modified_score = "modified_score"
  28. class SortOrder(str, Enum):
  29. asc = "ASC"
  30. desc = "DESC"
  31. class CardNoList(BaseModel):
  32. cardNoList: List[str]
  33. # "图片类型和计算分数分数类型映射表"
  34. # [CHANGED] 更新映射关系以匹配 score_service.py
  35. IMAGE_TYPE_TO_SCORE_TYPE = {
  36. "front_coaxial": "front_coaxial",
  37. "back_coaxial": "back_coaxial",
  38. "front_ring": "front_ring",
  39. "back_ring": "back_ring",
  40. "front_gray": None,
  41. "back_gray": None
  42. }
  43. # --- Pydantic 数据模型 ---
  44. class CardImageResponse(BaseModel):
  45. """用于API响应的图片数据模型 (主键为 id)"""
  46. id: int
  47. card_id: int
  48. image_type: str
  49. image_name: Optional[str] = None
  50. image_path: str
  51. # Gray images need these fields to be Optional/None
  52. detection_image_path: Optional[str] = None
  53. modified_image_path: Optional[str] = None
  54. detection_json: Dict[str, Any]
  55. modified_json: Optional[Dict[str, Any]] = None
  56. is_edited: bool = False
  57. created_at: datetime
  58. updated_at: datetime
  59. class Config:
  60. from_attributes = True
  61. @field_validator('detection_json', 'modified_json', mode='before')
  62. @classmethod
  63. def parse_json_string(cls, v):
  64. if v is None:
  65. return None
  66. if isinstance(v, str):
  67. try:
  68. return json.loads(v)
  69. except json.JSONDecodeError:
  70. raise ValueError("Invalid JSON string in database")
  71. return v
  72. # 拦截序列化,格式化掉中间的 "T"
  73. @field_serializer('created_at', 'updated_at', check_fields=False)
  74. def serialize_datetime(self, dt: datetime, _info):
  75. if dt is not None:
  76. return dt.strftime('%Y-%m-%d %H:%M:%S')
  77. return dt
  78. class CardDetailResponse(BaseModel):
  79. """用于响应单个卡牌详细信息的模型 (主键为 id)"""
  80. id: int
  81. id_prev: Optional[int] = None
  82. id_next: Optional[int] = None
  83. card_name: Optional[str] = None
  84. cardNo: Optional[str] = None
  85. created_at: datetime
  86. updated_at: datetime
  87. card_type: str
  88. is_edited: bool
  89. review_state: int = 1
  90. detection_score: Optional[float] = None
  91. modified_score: Optional[float] = None
  92. detection_score_detail: Optional[Dict[str, Any]] = None
  93. modified_score_detail: Optional[Dict[str, Any]] = None
  94. images: List[CardImageResponse] = []
  95. class Config:
  96. from_attributes = True
  97. # 拦截序列化,格式化掉中间的 "T"
  98. @field_serializer('created_at', 'updated_at', check_fields=False)
  99. def serialize_datetime(self, dt: datetime, _info):
  100. if dt is not None:
  101. return dt.strftime('%Y-%m-%d %H:%M:%S')
  102. return dt
  103. class ImageJsonPairResponse(BaseModel):
  104. id: int
  105. detection_json: Dict[str, Any]
  106. modified_json: Optional[Dict[str, Any]] = None
  107. class Config:
  108. from_attributes = True
  109. @field_validator('detection_json', 'modified_json', mode='before')
  110. @classmethod
  111. def parse_json_string(cls, v):
  112. if v is None:
  113. return None
  114. if isinstance(v, str):
  115. try:
  116. return json.loads(v)
  117. except json.JSONDecodeError:
  118. raise ValueError("Invalid JSON string in database")
  119. return v
  120. class CardImageInListResponse(BaseModel):
  121. id: int
  122. image_type: str
  123. image_path: str
  124. detection_image_path: Optional[str] = None
  125. modified_image_path: Optional[str] = None
  126. class Config:
  127. from_attributes = True
  128. class CardListDetailResponse(BaseModel):
  129. id: int
  130. card_name: Optional[str] = None
  131. cardNo: Optional[str] = None
  132. card_type: str
  133. detection_score: Optional[float] = None
  134. modified_score: Optional[float] = None
  135. is_edited: bool
  136. review_state: int = 1
  137. created_at: datetime
  138. updated_at: datetime
  139. image_path_list: Dict[str, Optional[str]] = {}
  140. detection_image_path_list: Dict[str, Optional[str]] = {}
  141. modified_image_path_list: Dict[str, Optional[str]] = {}
  142. class Config:
  143. from_attributes = True
  144. # 拦截序列化,格式化掉中间的 "T"
  145. @field_serializer('created_at', 'updated_at', check_fields=False)
  146. def serialize_datetime(self, dt: datetime, _info):
  147. if dt is not None:
  148. return dt.strftime('%Y-%m-%d %H:%M:%S')
  149. return dt
  150. class CardListWithTotal(BaseModel):
  151. total: int
  152. list: List[CardListDetailResponse]
  153. class CardListResponseWrapper(BaseModel):
  154. data: CardListWithTotal
  155. class ReviewUpdate(BaseModel):
  156. review_state: int = Field(..., ge=1, le=4, description="审核状态 (1待复检, 2已复检, 3审核未通过, 4审核通过)")