| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- import json
- from datetime import datetime
- from pathlib import Path
- from typing import Optional, Dict, Any, List
- from pydantic import BaseModel, field_validator
- from enum import Enum
- class ImageType(str, Enum):
- front_coaxial = "front_coaxial"
- back_coaxial = "back_coaxial"
- front_ring = "front_ring"
- back_ring = "back_ring"
- # 灰度图类型
- front_gray = "front_gray"
- back_gray = "back_gray"
- class CardType(str, Enum):
- pokemon = "pokemon"
- basketball = "basketball"
- baseball = "baseball"
- class ResultImagePathType(str, Enum):
- detection = "detection"
- modified = "modified"
- class SortBy(str, Enum):
- card_name = "card_name"
- created_at = "created_at"
- updated_at = "updated_at"
- detection_score = "detection_score"
- modified_score = "modified_score"
- class SortOrder(str, Enum):
- asc = "ASC"
- desc = "DESC"
- # "图片类型和计算分数分数类型映射表"
- # [CHANGED] 更新映射关系以匹配 score_service.py
- IMAGE_TYPE_TO_SCORE_TYPE = {
- "front_coaxial": "front_coaxial",
- "back_coaxial": "back_coaxial",
- "front_ring": "front_ring",
- "back_ring": "back_ring",
- "front_gray": None,
- "back_gray": None
- }
- # --- Pydantic 数据模型 ---
- class CardImageResponse(BaseModel):
- """用于API响应的图片数据模型 (主键为 id)"""
- id: int
- card_id: int
- image_type: str
- image_name: Optional[str] = None
- image_path: str
- # Gray images need these fields to be Optional/None
- detection_image_path: Optional[str] = None
- modified_image_path: Optional[str] = None
- detection_json: Dict[str, Any]
- modified_json: Optional[Dict[str, Any]] = None
- is_edited: bool = False
- created_at: datetime
- updated_at: datetime
- class Config:
- from_attributes = True
- @field_validator('detection_json', 'modified_json', mode='before')
- @classmethod
- def parse_json_string(cls, v):
- if v is None:
- return None
- if isinstance(v, str):
- try:
- return json.loads(v)
- except json.JSONDecodeError:
- raise ValueError("Invalid JSON string in database")
- return v
- class CardDetailResponse(BaseModel):
- """用于响应单个卡牌详细信息的模型 (主键为 id)"""
- id: int
- id_prev: Optional[int] = None
- id_next: Optional[int] = None
- card_name: Optional[str] = None
- created_at: datetime
- updated_at: datetime
- card_type: str
- is_edited: bool
- detection_score: Optional[float] = None
- modified_score: Optional[float] = None
- detection_score_detail: Optional[Dict[str, Any]] = None
- modified_score_detail: Optional[Dict[str, Any]] = None
- images: List[CardImageResponse] = []
- class Config:
- from_attributes = True
- class ImageJsonPairResponse(BaseModel):
- id: int
- detection_json: Dict[str, Any]
- modified_json: Optional[Dict[str, Any]] = None
- class Config:
- from_attributes = True
- @field_validator('detection_json', 'modified_json', mode='before')
- @classmethod
- def parse_json_string(cls, v):
- if v is None:
- return None
- if isinstance(v, str):
- try:
- return json.loads(v)
- except json.JSONDecodeError:
- raise ValueError("Invalid JSON string in database")
- return v
- class CardImageInListResponse(BaseModel):
- id: int
- image_type: str
- image_path: str
- detection_image_path: Optional[str] = None
- modified_image_path: Optional[str] = None
- class Config:
- from_attributes = True
- class CardListDetailResponse(BaseModel):
- id: int
- card_name: Optional[str] = None
- card_type: str
- detection_score: Optional[float] = None
- modified_score: Optional[float] = None
- is_edited: bool
- created_at: datetime
- updated_at: datetime
- image_path_list: Dict[str, Optional[str]] = {}
- detection_image_path_list: Dict[str, Optional[str]] = {}
- modified_image_path_list: Dict[str, Optional[str]] = {}
- class Config:
- from_attributes = True
- class CardListWithTotal(BaseModel):
- total: int
- list: List[CardListDetailResponse]
- class CardListResponseWrapper(BaseModel):
- data: CardListWithTotal
|