|
|
@@ -375,7 +375,22 @@ async def hazard(
|
|
|
e,
|
|
|
traceback.format_exc(),
|
|
|
)
|
|
|
- return {"statusCode": 500, "msg": f"下载图片失败: {str(e)}"}
|
|
|
+ error_msg = "图片下载失败"
|
|
|
+ if isinstance(e, httpx.TimeoutException):
|
|
|
+ error_msg = "图片下载超时,请检查网络连接或稍后重试"
|
|
|
+ elif isinstance(e, httpx.ConnectError):
|
|
|
+ error_msg = "无法连接到图片服务器,请检查图片链接是否正确"
|
|
|
+ elif hasattr(e, 'response') and e.response is not None:
|
|
|
+ status_code = e.response.status_code
|
|
|
+ if status_code == 404:
|
|
|
+ error_msg = "图片不存在,请检查图片链接是否正确"
|
|
|
+ elif status_code == 403:
|
|
|
+ error_msg = "无权访问该图片,请检查图片链接权限"
|
|
|
+ elif status_code >= 500:
|
|
|
+ error_msg = "图片服务器暂时不可用,请稍后重试"
|
|
|
+ else:
|
|
|
+ error_msg = f"图片下载失败(错误代码:{status_code})"
|
|
|
+ return {"statusCode": 500, "msg": error_msg}
|
|
|
|
|
|
logger.info(
|
|
|
"[hazard][%s] image downloaded: bytes=%s",
|
|
|
@@ -396,6 +411,51 @@ async def hazard(
|
|
|
(yolo_result or {}).get("model_type", "") if isinstance(yolo_result, dict) else "",
|
|
|
)
|
|
|
logger.debug("[hazard][%s] yolo result raw: %s", request_id, json.dumps(yolo_result, ensure_ascii=False, default=str))
|
|
|
+ except httpx.TimeoutException as e:
|
|
|
+ logger.error(
|
|
|
+ "[hazard][%s] YOLO检测超时: scene_key=%r, error=%s, traceback=%s",
|
|
|
+ request_id,
|
|
|
+ scene_key,
|
|
|
+ e,
|
|
|
+ traceback.format_exc(),
|
|
|
+ )
|
|
|
+ return {"statusCode": 500, "msg": "AI识别服务响应超时,请稍后重试"}
|
|
|
+ except httpx.ConnectError as e:
|
|
|
+ logger.error(
|
|
|
+ "[hazard][%s] YOLO服务连接失败: scene_key=%r, error=%s, traceback=%s",
|
|
|
+ request_id,
|
|
|
+ scene_key,
|
|
|
+ e,
|
|
|
+ traceback.format_exc(),
|
|
|
+ )
|
|
|
+ return {"statusCode": 500, "msg": "无法连接到AI识别服务,请联系管理员"}
|
|
|
+ except httpx.HTTPStatusError as e:
|
|
|
+ logger.error(
|
|
|
+ "[hazard][%s] YOLO服务返回错误状态: scene_key=%r, status_code=%s, error=%s, traceback=%s",
|
|
|
+ request_id,
|
|
|
+ scene_key,
|
|
|
+ e.response.status_code if hasattr(e, 'response') else 'unknown',
|
|
|
+ e,
|
|
|
+ traceback.format_exc(),
|
|
|
+ )
|
|
|
+ status_code = e.response.status_code if hasattr(e, 'response') else 500
|
|
|
+ if status_code == 400:
|
|
|
+ return {"statusCode": 500, "msg": "图片格式不支持或图片已损坏,请更换图片"}
|
|
|
+ elif status_code == 404:
|
|
|
+ return {"statusCode": 500, "msg": f"未找到场景'{SCENE_DISPLAY_NAMES.get(scene_key, scene_key)}'的识别模型"}
|
|
|
+ elif status_code >= 500:
|
|
|
+ return {"statusCode": 500, "msg": "AI识别服务暂时不可用,请稍后重试"}
|
|
|
+ else:
|
|
|
+ return {"statusCode": 500, "msg": f"AI识别服务返回错误(代码:{status_code})"}
|
|
|
+ except ValueError as e:
|
|
|
+ logger.error(
|
|
|
+ "[hazard][%s] YOLO返回数据格式错误: scene_key=%r, error=%s, traceback=%s",
|
|
|
+ request_id,
|
|
|
+ scene_key,
|
|
|
+ e,
|
|
|
+ traceback.format_exc(),
|
|
|
+ )
|
|
|
+ return {"statusCode": 500, "msg": "AI识别服务返回数据格式错误,请联系管理员"}
|
|
|
except Exception as e:
|
|
|
logger.error(
|
|
|
"[hazard][%s] YOLO检测失败: scene_key=%r, error=%s, traceback=%s",
|
|
|
@@ -404,7 +464,13 @@ async def hazard(
|
|
|
e,
|
|
|
traceback.format_exc(),
|
|
|
)
|
|
|
- return {"statusCode": 500, "msg": f"YOLO API返回错误: {str(e)}"}
|
|
|
+ error_msg = str(e)
|
|
|
+ if "timeout" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "AI识别服务响应超时,请稍后重试"}
|
|
|
+ elif "connection" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "无法连接到AI识别服务,请联系管理员"}
|
|
|
+ else:
|
|
|
+ return {"statusCode": 500, "msg": f"AI识别失败:{error_msg}"}
|
|
|
|
|
|
labels = yolo_result.get("labels", []) or []
|
|
|
boxes = yolo_result.get("boxes", []) or []
|
|
|
@@ -421,7 +487,7 @@ async def hazard(
|
|
|
)
|
|
|
return {
|
|
|
"statusCode": 200,
|
|
|
- "msg": "识别成功",
|
|
|
+ "msg": "未检测到隐患",
|
|
|
"data": {
|
|
|
"scene_name": scene_key,
|
|
|
"scene_display_name": SCENE_DISPLAY_NAMES.get(scene_key, scene_key),
|
|
|
@@ -436,6 +502,7 @@ async def hazard(
|
|
|
"display_labels": [],
|
|
|
"third_scenes": [],
|
|
|
"element_hazards": {},
|
|
|
+ "no_hazards_detected": True,
|
|
|
},
|
|
|
}
|
|
|
|
|
|
@@ -594,7 +661,18 @@ async def hazard(
|
|
|
)
|
|
|
db.rollback()
|
|
|
logger.info("[hazard][%s] db rollback executed after record save failure", request_id)
|
|
|
- return {"statusCode": 500, "msg": f"识别失败: {str(e)}"}
|
|
|
+
|
|
|
+ error_msg = str(e)
|
|
|
+ if "connection" in error_msg.lower() or "lost connection" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "数据库连接失败,请稍后重试"}
|
|
|
+ elif "duplicate" in error_msg.lower() or "unique" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "记录已存在,请勿重复提交"}
|
|
|
+ elif "timeout" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "数据库操作超时,请稍后重试"}
|
|
|
+ elif "disk" in error_msg.lower() or "space" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "存储空间不足,请联系管理员"}
|
|
|
+ else:
|
|
|
+ return {"statusCode": 500, "msg": f"保存识别记录失败:{error_msg}"}
|
|
|
|
|
|
display_labels = _dedupe_list([item["label"] for item in detection_results])
|
|
|
|
|
|
@@ -638,7 +716,18 @@ async def hazard(
|
|
|
)
|
|
|
db.rollback()
|
|
|
logger.info("[hazard][%s] db rollback executed in outer exception handler", request_id)
|
|
|
- return {"statusCode": 500, "msg": f"处理失败: {str(e)}"}
|
|
|
+
|
|
|
+ error_msg = str(e)
|
|
|
+ if "connection" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "服务连接失败,请稍后重试"}
|
|
|
+ elif "timeout" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "服务响应超时,请稍后重试"}
|
|
|
+ elif "memory" in error_msg.lower() or "out of memory" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "系统资源不足,请稍后重试或联系管理员"}
|
|
|
+ elif "permission" in error_msg.lower() or "denied" in error_msg.lower():
|
|
|
+ return {"statusCode": 500, "msg": "权限不足,请联系管理员"}
|
|
|
+ else:
|
|
|
+ return {"statusCode": 500, "msg": f"识别处理失败:{error_msg}"}
|
|
|
|
|
|
|
|
|
@router.post("/save_step")
|