|
@@ -1,5 +1,3 @@
|
|
|
-# --- START OF FILE app/api/formate_xy.py ---
|
|
|
|
|
-
|
|
|
|
|
import requests
|
|
import requests
|
|
|
import json
|
|
import json
|
|
|
|
|
|
|
@@ -23,31 +21,18 @@ router = APIRouter()
|
|
|
db_dependency = Depends(get_db_connection)
|
|
db_dependency = Depends(get_db_connection)
|
|
|
|
|
|
|
|
|
|
|
|
|
-@router.get("/query", response_model=CardDetailResponse, summary="获取指定卡牌的详细信息(格式化xy)")
|
|
|
|
|
-def get_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
|
|
+def _process_images_to_xy_format(card_data: dict):
|
|
|
"""
|
|
"""
|
|
|
- 获取卡牌元数据以及所有与之关联的图片信息。
|
|
|
|
|
- 【特殊处理】:会将 json 中的 points 坐标转换为 [{"id":..., "x":..., "y":...}] 格式,
|
|
|
|
|
- 并在 defects 列表中每项添加 id。
|
|
|
|
|
|
|
+ 内部辅助函数:遍历卡牌数据中的图片,将 JSON 格式转换为前端需要的 XY 格式。
|
|
|
|
|
+ 直接修改传入的 card_data 字典。
|
|
|
"""
|
|
"""
|
|
|
- # 1. 获取原始数据 (Dict 格式)
|
|
|
|
|
- # 注意:这里直接获取 Dict,而不是让 Pydantic 马上校验,因为我们需要先修改数据结构
|
|
|
|
|
- card_data = crud_card.get_card_with_details(db_conn, card_id)
|
|
|
|
|
-
|
|
|
|
|
- if not card_data:
|
|
|
|
|
- raise HTTPException(status_code=404, detail=f"ID为 {card_id} 的卡牌未找到。")
|
|
|
|
|
-
|
|
|
|
|
- # 2. 遍历图片,转换格式
|
|
|
|
|
- # crud_card 返回的 card_data["images"] 是一个 list of dict
|
|
|
|
|
if "images" in card_data and card_data["images"]:
|
|
if "images" in card_data and card_data["images"]:
|
|
|
for img in card_data["images"]:
|
|
for img in card_data["images"]:
|
|
|
# 处理 detection_json
|
|
# 处理 detection_json
|
|
|
if img.detection_json:
|
|
if img.detection_json:
|
|
|
- # 如果数据库取出的是字符串,先转 dict (通常 cursor dictionary=True 且 JSON 列会自动转,但在某些驱动下可能是 str)
|
|
|
|
|
d_json = img.detection_json
|
|
d_json = img.detection_json
|
|
|
if isinstance(d_json, str):
|
|
if isinstance(d_json, str):
|
|
|
d_json = json.loads(d_json)
|
|
d_json = json.loads(d_json)
|
|
|
-
|
|
|
|
|
# *** 转换逻辑 ***
|
|
# *** 转换逻辑 ***
|
|
|
img.detection_json = convert_internal_to_xy_format(d_json)
|
|
img.detection_json = convert_internal_to_xy_format(d_json)
|
|
|
|
|
|
|
@@ -56,16 +41,105 @@ def get_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependenc
|
|
|
m_json = img.modified_json
|
|
m_json = img.modified_json
|
|
|
if isinstance(m_json, str):
|
|
if isinstance(m_json, str):
|
|
|
m_json = json.loads(m_json)
|
|
m_json = json.loads(m_json)
|
|
|
-
|
|
|
|
|
# *** 转换逻辑 ***
|
|
# *** 转换逻辑 ***
|
|
|
img.modified_json = convert_internal_to_xy_format(m_json)
|
|
img.modified_json = convert_internal_to_xy_format(m_json)
|
|
|
|
|
+ return card_data
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@router.get("/query", response_model=CardDetailResponse, summary="获取指定卡牌的详细信息(格式化xy)")
|
|
|
|
|
+def get_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
+ """
|
|
|
|
|
+ 获取卡牌元数据以及所有与之关联的图片信息。
|
|
|
|
|
+ 【特殊处理】:会将 json 中的 points 坐标转换为 [{"id":..., "x":..., "y":...}] 格式。
|
|
|
|
|
+ """
|
|
|
|
|
+ # 1. 获取原始数据
|
|
|
|
|
+ card_data = crud_card.get_card_with_details(db_conn, card_id)
|
|
|
|
|
+
|
|
|
|
|
+ if not card_data:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"ID为 {card_id} 的卡牌未找到。")
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 转换格式 (提取为公共函数)
|
|
|
|
|
+ _process_images_to_xy_format(card_data)
|
|
|
|
|
|
|
|
# 3. 验证并返回
|
|
# 3. 验证并返回
|
|
|
- # 因为 CardDetailResponse 定义中 detection_json 是 Dict[str, Any],
|
|
|
|
|
- # 所以无论里面是 [[x,y]] 还是 [{"x":x...}] 都可以通过校验
|
|
|
|
|
return CardDetailResponse.model_validate(card_data)
|
|
return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+@router.get("/query_next", response_model=CardDetailResponse, summary="获取下一个卡牌的详细信息(格式化xy)")
|
|
|
|
|
+def get_next_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
+ """
|
|
|
|
|
+ 获取指定ID的下一张卡牌的信息,并格式化为xy坐标结构。
|
|
|
|
|
+ """
|
|
|
|
|
+ try:
|
|
|
|
|
+ with db_conn.cursor(dictionary=True) as cursor:
|
|
|
|
|
+ # 1. 查询下一个ID (ID > current ORDER BY ID ASC)
|
|
|
|
|
+ query_next = (
|
|
|
|
|
+ f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
+ f"WHERE id > %s ORDER BY id ASC LIMIT 1"
|
|
|
|
|
+ )
|
|
|
|
|
+ cursor.execute(query_next, (card_id,))
|
|
|
|
|
+ row = cursor.fetchone()
|
|
|
|
|
+
|
|
|
|
|
+ if not row:
|
|
|
|
|
+ # 保持与 cards.py 一致的行为,没有下一张时返回 200 或 404 视业务需求定,这里参考 cards.py 逻辑
|
|
|
|
|
+ raise HTTPException(status_code=200, detail=f"没有下一张")
|
|
|
|
|
+
|
|
|
|
|
+ next_card_id = row['id']
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 获取数据
|
|
|
|
|
+ card_data = crud_card.get_card_with_details(db_conn, next_card_id)
|
|
|
|
|
+ if not card_data:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"下一个卡牌ID {next_card_id} 数据异常。")
|
|
|
|
|
+
|
|
|
|
|
+ # 3. 转换格式
|
|
|
|
|
+ _process_images_to_xy_format(card_data)
|
|
|
|
|
+
|
|
|
|
|
+ return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
+
|
|
|
|
|
+ except HTTPException:
|
|
|
|
|
+ raise
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"查询下一个卡牌(xy)失败 (基准ID: {card_id}): {e}")
|
|
|
|
|
+ raise HTTPException(status_code=500, detail="查询失败")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@router.get("/query_prev", response_model=CardDetailResponse, summary="获取上一个卡牌的详细信息(格式化xy)")
|
|
|
|
|
+def get_prev_card_details(card_id: int, db_conn: PooledMySQLConnection = db_dependency):
|
|
|
|
|
+ """
|
|
|
|
|
+ 获取指定ID的上一张卡牌的信息,并格式化为xy坐标结构。
|
|
|
|
|
+ """
|
|
|
|
|
+ try:
|
|
|
|
|
+ with db_conn.cursor(dictionary=True) as cursor:
|
|
|
|
|
+ # 1. 查询上一个ID (ID < current ORDER BY ID DESC)
|
|
|
|
|
+ query_prev = (
|
|
|
|
|
+ f"SELECT id FROM {settings.DB_CARD_TABLE_NAME} "
|
|
|
|
|
+ f"WHERE id < %s ORDER BY id DESC LIMIT 1"
|
|
|
|
|
+ )
|
|
|
|
|
+ cursor.execute(query_prev, (card_id,))
|
|
|
|
|
+ row = cursor.fetchone()
|
|
|
|
|
+
|
|
|
|
|
+ if not row:
|
|
|
|
|
+ raise HTTPException(status_code=200, detail=f"没有上一张")
|
|
|
|
|
+
|
|
|
|
|
+ prev_card_id = row['id']
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 获取数据
|
|
|
|
|
+ card_data = crud_card.get_card_with_details(db_conn, prev_card_id)
|
|
|
|
|
+ if not card_data:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"上一个卡牌ID {prev_card_id} 数据异常。")
|
|
|
|
|
+
|
|
|
|
|
+ # 3. 转换格式
|
|
|
|
|
+ _process_images_to_xy_format(card_data)
|
|
|
|
|
+
|
|
|
|
|
+ return CardDetailResponse.model_validate(card_data)
|
|
|
|
|
+
|
|
|
|
|
+ except HTTPException:
|
|
|
|
|
+ raise
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"查询上一个卡牌(xy)失败 (基准ID: {card_id}): {e}")
|
|
|
|
|
+ raise HTTPException(status_code=500, detail="查询失败")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
@router.put("/update/json/{id}", status_code=200, summary="接收xy格式, 还原后重计算分数并保存")
|
|
@router.put("/update/json/{id}", status_code=200, summary="接收xy格式, 还原后重计算分数并保存")
|
|
|
async def update_image_modified_json(
|
|
async def update_image_modified_json(
|
|
|
id: int,
|
|
id: int,
|
|
@@ -144,7 +218,7 @@ async def update_image_modified_json(
|
|
|
logger.error(f"更新卡牌 {card_id_to_update} 分数失败: {score_update_e}")
|
|
logger.error(f"更新卡牌 {card_id_to_update} 分数失败: {score_update_e}")
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- "message": f"成功更新图片ID {id} 的JSON数据",
|
|
|
|
|
|
|
+ "detail": f"成功更新图片ID {id} 的JSON数据",
|
|
|
"image_type": image_type,
|
|
"image_type": image_type,
|
|
|
"score_type": score_type
|
|
"score_type": score_type
|
|
|
}
|
|
}
|
|
@@ -158,4 +232,4 @@ async def update_image_modified_json(
|
|
|
raise HTTPException(status_code=500, detail=f"更新JSON数据失败: {e}")
|
|
raise HTTPException(status_code=500, detail=f"更新JSON数据失败: {e}")
|
|
|
finally:
|
|
finally:
|
|
|
if cursor:
|
|
if cursor:
|
|
|
- cursor.close()
|
|
|
|
|
|
|
+ cursor.close()
|