|
@@ -11,10 +11,9 @@ from app.core.config import settings
|
|
|
from app.core.logger import get_logger
|
|
from app.core.logger import get_logger
|
|
|
from app.core.database_loader import get_db_connection
|
|
from app.core.database_loader import get_db_connection
|
|
|
from app.utils.scheme import (
|
|
from app.utils.scheme import (
|
|
|
- CardDetailResponse, IMAGE_TYPE_TO_SCORE_TYPE
|
|
|
|
|
|
|
+ CardDetailResponse, IMAGE_TYPE_TO_SCORE_TYPE, ImageType
|
|
|
)
|
|
)
|
|
|
from app.crud import crud_card
|
|
from app.crud import crud_card
|
|
|
-# 导入新写的工具函数
|
|
|
|
|
from app.utils.xy_process import convert_internal_to_xy_format, convert_xy_to_internal_format
|
|
from app.utils.xy_process import convert_internal_to_xy_format, convert_xy_to_internal_format
|
|
|
|
|
|
|
|
logger = get_logger(__name__)
|
|
logger = get_logger(__name__)
|
|
@@ -221,4 +220,157 @@ 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()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+# 处理灰度如
|
|
|
|
|
+@router.put("/update/json_gray/{id}", status_code=200, summary="[灰度] 接收xy格式, 合并至Ring图重计算并保存")
|
|
|
|
|
+async def update_gray_image_json(
|
|
|
|
|
+ id: int,
|
|
|
|
|
+ new_json_data: dict = Body(..., description="前端传来的灰度图编辑后的JSON(xy格式)"),
|
|
|
|
|
+ db_conn: PooledMySQLConnection = db_dependency
|
|
|
|
|
+):
|
|
|
|
|
+ """
|
|
|
|
|
+ 针对灰度图 (front_gray/back_gray) 的保存逻辑。
|
|
|
|
|
+ """
|
|
|
|
|
+ cursor = None
|
|
|
|
|
+
|
|
|
|
|
+ # 1. 格式还原
|
|
|
|
|
+ internal_gray_json = convert_xy_to_internal_format(new_json_data)
|
|
|
|
|
+ gray_defects = internal_gray_json.get("result", {}).get("defect_result", {}).get("defects", [])
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ cursor = db_conn.cursor(dictionary=True)
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 获取灰度图信息
|
|
|
|
|
+ # 注意:灰度图存在 card_gray_images 表中
|
|
|
|
|
+ cursor.execute(f"SELECT card_id, image_type FROM {settings.DB_GRAY_IMAGE_TABLE_NAME} WHERE id = %s", (id,))
|
|
|
|
|
+ gray_row = cursor.fetchone()
|
|
|
|
|
+
|
|
|
|
|
+ if not gray_row:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"ID为 {id} 的灰度图未找到。")
|
|
|
|
|
+
|
|
|
|
|
+ card_id = gray_row['card_id']
|
|
|
|
|
+ gray_image_type = gray_row['image_type']
|
|
|
|
|
+
|
|
|
|
|
+ # 3. 确定目标 Ring 图类型
|
|
|
|
|
+ target_ring_type = None
|
|
|
|
|
+ if gray_image_type == ImageType.front_gray.value:
|
|
|
|
|
+ target_ring_type = ImageType.front_ring.value
|
|
|
|
|
+ elif gray_image_type == ImageType.back_gray.value:
|
|
|
|
|
+ target_ring_type = ImageType.back_ring.value
|
|
|
|
|
+ else:
|
|
|
|
|
+ raise HTTPException(status_code=400, detail=f"不支持的灰度图类型: {gray_image_type}")
|
|
|
|
|
+
|
|
|
|
|
+ # 4. 获取目标 Ring 图数据 (Card Images 表)
|
|
|
|
|
+ cursor.execute(
|
|
|
|
|
+ f"SELECT id, detection_json, modified_json FROM {settings.DB_IMAGE_TABLE_NAME} "
|
|
|
|
|
+ f"WHERE card_id = %s AND image_type = %s",
|
|
|
|
|
+ (card_id, target_ring_type)
|
|
|
|
|
+ )
|
|
|
|
|
+ ring_row = cursor.fetchone()
|
|
|
|
|
+
|
|
|
|
|
+ if not ring_row:
|
|
|
|
|
+ raise HTTPException(status_code=404, detail=f"未找到对应的 Ring 图 ({target_ring_type}),无法应用修改。")
|
|
|
|
|
+
|
|
|
|
|
+ ring_image_id = ring_row['id']
|
|
|
|
|
+ # 优先使用 modified_json,如果没有则使用 detection_json
|
|
|
|
|
+ source_json_str = ring_row['modified_json'] if ring_row['modified_json'] else ring_row['detection_json']
|
|
|
|
|
+
|
|
|
|
|
+ if isinstance(source_json_str, str):
|
|
|
|
|
+ ring_json_data = json.loads(source_json_str)
|
|
|
|
|
+ else:
|
|
|
|
|
+ ring_json_data = source_json_str
|
|
|
|
|
+
|
|
|
|
|
+ # 5. 合并逻辑 (Merge Logic)
|
|
|
|
|
+ # 确保路径存在
|
|
|
|
|
+ if "result" not in ring_json_data: ring_json_data["result"] = {}
|
|
|
|
|
+ if "defect_result" not in ring_json_data["result"]: ring_json_data["result"]["defect_result"] = {}
|
|
|
|
|
+ if "defects" not in ring_json_data["result"]["defect_result"]: ring_json_data["result"]["defect_result"][
|
|
|
|
|
+ "defects"] = []
|
|
|
|
|
+
|
|
|
|
|
+ ring_defects = ring_json_data["result"]["defect_result"]["defects"]
|
|
|
|
|
+
|
|
|
|
|
+ # 遍历灰度图传来的新缺陷列表
|
|
|
|
|
+ for new_defect in gray_defects:
|
|
|
|
|
+ gray_id = new_defect.get("gray_id")
|
|
|
|
|
+
|
|
|
|
|
+ # 只有带有 gray_id 的才进行特殊合并处理 (理论上前端编辑的都应该有,或者新生成的)
|
|
|
|
|
+ # 如果没有 gray_id,视作普通新缺陷直接添加
|
|
|
|
|
+ if not gray_id:
|
|
|
|
|
+ ring_defects.append(new_defect)
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ # 在 Ring 图现有的缺陷中寻找匹配的 gray_id
|
|
|
|
|
+ match_index = -1
|
|
|
|
|
+ for i, old_defect in enumerate(ring_defects):
|
|
|
|
|
+ if old_defect.get("gray_id") == gray_id:
|
|
|
|
|
+ match_index = i
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if match_index != -1:
|
|
|
|
|
+ # 存在:替换 (Replace)
|
|
|
|
|
+ ring_defects[match_index] = new_defect
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 不存在:添加 (Append)
|
|
|
|
|
+ ring_defects.append(new_defect)
|
|
|
|
|
+
|
|
|
|
|
+ # 6. 调用计算服务 (对 Ring 图数据进行重算)
|
|
|
|
|
+ score_type = IMAGE_TYPE_TO_SCORE_TYPE.get(target_ring_type) # e.g., 'front_ring'
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(f"开始重计算 Ring 图分数 (GrayID: {id} -> RingID: {ring_image_id}, Type: {score_type})")
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ response = await run_in_threadpool(
|
|
|
|
|
+ lambda: requests.post(
|
|
|
|
|
+ settings.SCORE_RECALCULATE_ENDPOINT,
|
|
|
|
|
+ params={"score_type": score_type},
|
|
|
|
|
+ json=ring_json_data, # 发送合并后的 Ring 数据
|
|
|
|
|
+ timeout=20
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ raise HTTPException(status_code=500, detail=f"调用分数计算服务失败: {e}")
|
|
|
|
|
+
|
|
|
|
|
+ if response.status_code != 200:
|
|
|
|
|
+ logger.error(f"分数计算接口返回错误: {response.text}")
|
|
|
|
|
+ raise HTTPException(status_code=response.status_code,
|
|
|
|
|
+ detail=f"分数计算接口返回错误: {response.text}")
|
|
|
|
|
+
|
|
|
|
|
+ final_ring_json = response.json()
|
|
|
|
|
+
|
|
|
|
|
+ # 7. 保存结果到数据库 (保存到 Ring 图记录)
|
|
|
|
|
+ final_json_str = json.dumps(final_ring_json, ensure_ascii=False)
|
|
|
|
|
+
|
|
|
|
|
+ update_query = (
|
|
|
|
|
+ f"UPDATE {settings.DB_IMAGE_TABLE_NAME} "
|
|
|
|
|
+ f"SET modified_json = %s, is_edited = TRUE "
|
|
|
|
|
+ f"WHERE id = %s"
|
|
|
|
|
+ )
|
|
|
|
|
+ cursor.execute(update_query, (final_json_str, ring_image_id))
|
|
|
|
|
+ db_conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(f"Ring 图 {ring_image_id} 已根据灰度图 {id} 的修改进行了更新。")
|
|
|
|
|
+
|
|
|
|
|
+ # 8. 更新卡牌总分状态
|
|
|
|
|
+ try:
|
|
|
|
|
+ crud_card.update_card_scores_and_status(db_conn, card_id)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"更新卡牌 {card_id} 分数状态失败: {e}")
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ "detail": f"成功应用灰度图修改到 {target_ring_type}",
|
|
|
|
|
+ "target_ring_id": ring_image_id,
|
|
|
|
|
+ "gray_id": id
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ except HTTPException:
|
|
|
|
|
+ db_conn.rollback()
|
|
|
|
|
+ raise
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ db_conn.rollback()
|
|
|
|
|
+ logger.error(f"灰度图更新失败 ({id}): {e}")
|
|
|
|
|
+ raise HTTPException(status_code=500, detail=f"系统内部错误: {e}")
|
|
|
|
|
+ finally:
|
|
|
|
|
+ if cursor:
|
|
|
|
|
+ cursor.close()
|