first commit

This commit is contained in:
2025-09-07 21:48:21 +08:00
commit 4e0c898cef
13 changed files with 3116 additions and 0 deletions
+384
View File
@@ -0,0 +1,384 @@
"""错误处理模块"""
import logging
from typing import Dict, Any, Optional
from homeassistant.exceptions import HomeAssistantError
_LOGGER = logging.getLogger(__name__)
# 错误消息本地化
ERROR_MESSAGES = {
"zh_CN": {
# 配置错误
"missing_config": "缺少必需的配置项: {key}",
"invalid_secret_id": "Secret ID 必须是非空字符串,且应以 AKID 开头",
"invalid_secret_key": "Secret Key 必须是非空字符串",
"invalid_region": "区域必须是非空字符串,且为有效的腾讯云区域",
"invalid_person_group_id": "人员库ID必须是非空字符串,只能包含字母、数字、连字符和下划线",
# 图片错误
"image_not_found": "图片未找到: {path}",
"image_too_large": "图片文件过大: {path}, 大小: {size} 字节,最大支持: {max_size}",
"image_format_not_supported": "不支持的图片格式: {format}, 支持的格式: {supported_formats}",
"image_decode_failed": "图片解码失败,请确保图片格式正确",
"image_download_timeout": "下载图片超时: {url}",
"image_download_error": "下载图片失败: {url}, 错误: {error}",
"invalid_image_url": "无效的图片URL: {url}",
"permission_denied": "没有权限读取图片文件: {path}",
# 人脸检测错误
"face_not_detected": "未检测到人脸,请确保图片中包含清晰的人脸",
"face_too_small": "人脸太小,请使用包含更大人脸的图片",
"face_quality_poor": "人脸质量较差,请使用更清晰的图片",
# API错误
"api_error": "API调用失败: {code} - {message}",
"person_not_found": "人员未找到: {person_id}",
"group_not_found": "人员库未找到: {group_id}",
"face_not_found": "人脸未找到: {face_id}",
# 网络错误
"network_error": "网络连接错误,请检查网络连接",
"timeout_error": "请求超时,请稍后重试",
# 认证错误
"auth_failure": "认证失败,请检查Secret ID和Secret Key是否正确",
"auth_expired": "认证已过期,请更新凭证",
# 限制错误
"rate_limit_exceeded": "API调用频率超限,请稍后重试",
"quota_exceeded": "API调用配额已用完,请等待配额重置或升级套餐",
# 通用错误
"unknown_error": "未知错误: {message}",
"invalid_parameter": "无效参数: {parameter}",
},
"en_US": {
# Configuration errors
"missing_config": "Missing required configuration: {key}",
"invalid_secret_id": "Secret ID must be a non-empty string starting with AKID",
"invalid_secret_key": "Secret Key must be a non-empty string",
"invalid_region": "Region must be a non-empty string and a valid Tencent Cloud region",
"invalid_person_group_id": "Person Group ID must be a non-empty string containing only letters, numbers, hyphens, and underscores",
# Image errors
"image_not_found": "Image not found: {path}",
"image_too_large": "Image file too large: {path}, size: {size} bytes, maximum supported: {max_size}",
"image_format_not_supported": "Unsupported image format: {format}, supported formats: {supported_formats}",
"image_decode_failed": "Image decode failed, please ensure the image format is correct",
"image_download_timeout": "Image download timeout: {url}",
"image_download_error": "Image download failed: {url}, error: {error}",
"invalid_image_url": "Invalid image URL: {url}",
"permission_denied": "Permission denied when reading image file: {path}",
# Face detection errors
"face_not_detected": "No face detected, please ensure the image contains clear faces",
"face_too_small": "Face too small, please use an image with larger faces",
"face_quality_poor": "Poor face quality, please use a clearer image",
# API errors
"api_error": "API call failed: {code} - {message}",
"person_not_found": "Person not found: {person_id}",
"group_not_found": "Person group not found: {group_id}",
"face_not_found": "Face not found: {face_id}",
# Network errors
"network_error": "Network connection error, please check your network connection",
"timeout_error": "Request timeout, please try again later",
# Authentication errors
"auth_failure": "Authentication failed, please check if Secret ID and Secret Key are correct",
"auth_expired": "Authentication expired, please update credentials",
# Limit errors
"rate_limit_exceeded": "API call rate limit exceeded, please try again later",
"quota_exceeded": "API call quota used up, please wait for quota reset or upgrade plan",
# General errors
"unknown_error": "Unknown error: {message}",
"invalid_parameter": "Invalid parameter: {parameter}",
}
}
# 错误解决建议
ERROR_SOLUTIONS = {
"zh_CN": {
"missing_config": "请在配置中添加缺少的配置项",
"invalid_secret_id": "请检查Secret ID格式,应以AKID开头",
"invalid_secret_key": "请检查Secret Key格式,确保输入正确",
"invalid_region": "请选择有效的腾讯云区域,如ap-shanghai",
"invalid_person_group_id": "请使用字母、数字、连字符和下划线组合",
"image_not_found": "请检查图片路径是否正确",
"image_too_large": "请使用小于10MB的图片,或对图片进行压缩",
"image_format_not_supported": "请将图片转换为JPG、PNG、BMP或GIF格式",
"image_decode_failed": "请确保图片文件未损坏,并尝试重新保存",
"image_download_timeout": "请检查网络连接,或尝试使用其他图片URL",
"image_download_error": "请检查图片URL是否有效,或稍后重试",
"invalid_image_url": "请提供有效的图片URL",
"permission_denied": "请检查文件权限,或使用其他图片",
"face_not_detected": "请使用包含清晰人脸的图片",
"face_too_small": "请使用人脸更大的图片,或调整拍摄距离",
"face_quality_poor": "请使用光线充足、对焦清晰的图片",
"api_error": "请稍后重试,如果问题持续,请联系技术支持",
"person_not_found": "请检查人员ID是否正确,或确保人员已添加到人员库",
"group_not_found": "请检查人员库ID是否正确,或创建新的人员库",
"face_not_found": "请检查人脸ID是否正确",
"network_error": "请检查网络连接,确保网络通畅",
"timeout_error": "请稍后重试,或在网络状况良好时使用",
"auth_failure": "请检查Secret ID和Secret Key是否正确",
"auth_expired": "请更新腾讯云凭证",
"rate_limit_exceeded": "请降低调用频率,稍后重试",
"quota_exceeded": "请等待配额重置,或升级腾讯云套餐",
"unknown_error": "请记录错误信息并联系技术支持",
"invalid_parameter": "请检查API调用参数是否正确",
},
"en_US": {
"missing_config": "Please add the missing configuration item",
"invalid_secret_id": "Please check the Secret ID format, it should start with AKID",
"invalid_secret_key": "Please check the Secret Key format, ensure it's entered correctly",
"invalid_region": "Please select a valid Tencent Cloud region, such as ap-shanghai",
"invalid_person_group_id": "Please use a combination of letters, numbers, hyphens, and underscores",
"image_not_found": "Please check if the image path is correct",
"image_too_large": "Please use an image smaller than 10MB, or compress the image",
"image_format_not_supported": "Please convert the image to JPG, PNG, BMP, or GIF format",
"image_decode_failed": "Please ensure the image file is not corrupted and try saving it again",
"image_download_timeout": "Please check your network connection, or try using a different image URL",
"image_download_error": "Please check if the image URL is valid, or try again later",
"invalid_image_url": "Please provide a valid image URL",
"permission_denied": "Please check file permissions, or use a different image",
"face_not_detected": "Please use an image that contains clear faces",
"face_too_small": "Please use an image with larger faces, or adjust the shooting distance",
"face_quality_poor": "Please use a well-lit and focused image",
"api_error": "Please try again later, if the problem persists, please contact technical support",
"person_not_found": "Please check if the person ID is correct, or ensure the person has been added to the person group",
"group_not_found": "Please check if the person group ID is correct, or create a new person group",
"face_not_found": "Please check if the face ID is correct",
"network_error": "Please check your network connection, ensure it's working properly",
"timeout_error": "Please try again later, or use when network conditions are good",
"auth_failure": "Please check if Secret ID and Secret Key are correct",
"auth_expired": "Please update Tencent Cloud credentials",
"rate_limit_exceeded": "Please reduce call frequency and try again later",
"quota_exceeded": "Please wait for quota reset, or upgrade Tencent Cloud plan",
"unknown_error": "Please record the error information and contact technical support",
"invalid_parameter": "Please check if the API call parameters are correct",
}
}
class TencentFaceRecognitionError(HomeAssistantError):
"""腾讯云人脸识别基础错误类"""
def __init__(
self,
message: str,
error_key: Optional[str] = None,
error_details: Optional[Dict[str, Any]] = None,
locale: str = "zh_CN"
):
"""初始化错误"""
super().__init__(message)
self.error_key = error_key
self.error_details = error_details or {}
self.locale = locale
# 获取本地化消息
self.localized_message = self._get_localized_message()
# 获取解决建议
self.solution = self._get_solution()
def _get_localized_message(self) -> str:
"""获取本地化错误消息"""
if not self.error_key:
return str(self)
messages = ERROR_MESSAGES.get(self.locale, ERROR_MESSAGES["zh_CN"])
template = messages.get(self.error_key, str(self))
try:
# 使用错误详情填充模板
return template.format(**self.error_details)
except (KeyError, ValueError):
# 如果填充失败,返回原始消息
return str(self)
def _get_solution(self) -> str:
"""获取错误解决建议"""
if not self.error_key:
return ""
solutions = ERROR_SOLUTIONS.get(self.locale, ERROR_SOLUTIONS["zh_CN"])
return solutions.get(self.error_key, "")
class InvalidConfigError(TencentFaceRecognitionError):
"""无效配置错误"""
pass
class ApiError(TencentFaceRecognitionError):
"""API调用错误"""
pass
class ImageNotFoundError(TencentFaceRecognitionError):
"""图片未找到错误"""
pass
class FaceNotDetectedError(TencentFaceRecognitionError):
"""未检测到人脸错误"""
pass
class PersonNotFoundError(TencentFaceRecognitionError):
"""人员未找到错误"""
pass
class PersonGroupNotFoundError(TencentFaceRecognitionError):
"""人员库未找到错误"""
pass
class FaceNotFoundError(TencentFaceRecognitionError):
"""人脸未找到错误"""
pass
class NetworkError(TencentFaceRecognitionError):
"""网络错误"""
pass
class AuthenticationError(TencentFaceRecognitionError):
"""认证错误"""
pass
class RateLimitError(TencentFaceRecognitionError):
"""速率限制错误"""
pass
class QuotaExceededError(TencentFaceRecognitionError):
"""配额超限错误"""
pass
def handle_api_error(error_code: str, error_message: str) -> None:
"""处理API错误"""
error_mapping = {
"FailedOperation.ImageDecodeFailed": (ImageNotFoundError, "image_decode_failed"),
"InvalidParameterValue.NoFaceInPhoto": (FaceNotDetectedError, "face_not_detected"),
"FailedOperation.PersonNotFound": (PersonNotFoundError, "person_not_found"),
"FailedOperation.GroupNotFound": (PersonGroupNotFoundError, "group_not_found"),
"FailedOperation.FaceNotFound": (FaceNotFoundError, "face_not_found"),
"AuthFailure": (AuthenticationError, "auth_failure"),
"RequestLimitExceeded": (RateLimitError, "rate_limit_exceeded"),
"RequestQuotaExceeded": (QuotaExceededError, "quota_exceeded"),
"ResourceUnavailable.NetworkError": (NetworkError, "network_error"),
}
error_info = error_mapping.get(error_code, (ApiError, "api_error"))
error_class = error_info[0]
error_key = error_info[1]
_LOGGER.error("腾讯云API错误: %s - %s", error_code, error_message)
# 创建带有本地化消息的错误
error_details = {
"code": error_code,
"message": error_message
}
raise error_class(
f"{error_code}: {error_message}",
error_key=error_key,
error_details=error_details
)
def log_and_raise_error(error_class, message: str, details: Dict[str, Any] = None, error_key: Optional[str] = None) -> None:
"""记录日志并抛出错误"""
if details:
_LOGGER.error("%s: %s, 详情: %s", error_class.__name__, message, details)
else:
_LOGGER.error("%s: %s", error_class.__name__, message)
# 创建带有本地化消息的错误
raise error_class(
message,
error_key=error_key,
error_details=details or {}
)
def validate_config(config: Dict[str, Any]) -> None:
"""验证配置"""
required_keys = ["secret_id", "secret_key"]
for key in required_keys:
if not config.get(key):
log_and_raise_error(
InvalidConfigError,
f"缺少必需的配置项: {key}",
{"key": key},
"missing_config"
)
# 验证Secret ID格式
secret_id = config.get("secret_id")
if not isinstance(secret_id, str) or len(secret_id.strip()) == 0:
log_and_raise_error(
InvalidConfigError,
"Secret ID必须是非空字符串,且应以 AKID 开头",
{"secret_id": str(secret_id)},
"invalid_secret_id"
)
# 验证Secret Key格式
secret_key = config.get("secret_key")
if not isinstance(secret_key, str) or len(secret_key.strip()) == 0:
log_and_raise_error(
InvalidConfigError,
"Secret Key必须是非空字符串",
{"secret_key": str(secret_key)},
"invalid_secret_key"
)
# 验证区域格式
region = config.get("region", "ap-shanghai")
if not isinstance(region, str) or len(region.strip()) == 0:
log_and_raise_error(
InvalidConfigError,
"区域必须是非空字符串,且为有效的腾讯云区域",
{"region": str(region)},
"invalid_region"
)
# 验证人员库ID格式
person_group_id = config.get("person_group_id", "Hass")
if not isinstance(person_group_id, str) or len(person_group_id.strip()) == 0:
log_and_raise_error(
InvalidConfigError,
"人员库ID必须是非空字符串,只能包含字母、数字、连字符和下划线",
{"person_group_id": str(person_group_id)},
"invalid_person_group_id"
)
_LOGGER.debug("配置验证通过")