scheme.py 5.3 KB

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