From b8d243873b8cccc3e5020d050b09e9222fa7945a Mon Sep 17 00:00:00 2001 From: Bakadax Date: Fri, 2 May 2025 22:42:49 +0800 Subject: [PATCH] =?UTF-8?q?=E9=81=BF=E5=85=8Dtry=20catch=E5=B5=8C=E5=A5=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/group_nickname/nickname_mapper.py | 139 ++++++++++-------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/src/plugins/group_nickname/nickname_mapper.py b/src/plugins/group_nickname/nickname_mapper.py index 783013b1..e3e47d66 100644 --- a/src/plugins/group_nickname/nickname_mapper.py +++ b/src/plugins/group_nickname/nickname_mapper.py @@ -103,76 +103,87 @@ async def analyze_chat_for_nicknames( # 清理可能的 Markdown 代码块标记 response_content = response_content.strip() - # 使用正则表达式处理各种 Markdown 代码块情况 markdown_code_regex = re.compile(r"^```(?:\w+)?\s*\n(.*?)\n\s*```$", re.DOTALL) match = markdown_code_regex.match(response_content) if match: response_content = match.group(1).strip() - try: - result = json.loads(response_content) - if isinstance(result, dict) and "is_exist" in result: - if result["is_exist"] is True: - original_data = result.get("data") # 使用 .get() 更安全 - if isinstance(original_data, dict) and original_data: # 确保 data 是非空字典 - logger.info(f"LLM 找到的原始绰号映射: {original_data}") + # 解析 JSON + result = json.loads(response_content) # 可能抛出 json.JSONDecodeError - # --- 开始过滤 --- - filtered_data = {} - bot_qq_str = str(global_config.BOT_QQ) # 将机器人QQ转为字符串以便比较 - - for user_id, nickname in original_data.items(): - # 检查 user_id 是否是字符串,以防万一 - if not isinstance(user_id, str): - logger.warning(f"LLM 返回的 user_id '{user_id}' 不是字符串,跳过。") - continue - - # 条件 1: 排除机器人自身 - if user_id == bot_qq_str: - logger.debug(f"过滤掉机器人自身的映射: ID {user_id}") - continue - - # 有了改名工具后,该过滤器已不适合了,尝试通过修改 prompt 获得更好的结果 - # # 条件 2: 排除 nickname 与 person_name 相同的情况 - # person_name = user_name_map.get(user_id) # 从传入的映射中查找 person_name - # if person_name and person_name == nickname: - # logger.debug(f"过滤掉用户 {user_id} 的映射: 绰号 '{nickname}' 与其名称 '{person_name}' 相同。") - # continue - - # 如果通过所有过滤条件,则保留 - filtered_data[user_id] = nickname - # --- 结束过滤 --- - - # 检查过滤后是否还有数据 - if not filtered_data: - logger.info("所有找到的绰号映射都被过滤掉了。") - return {"is_exist": False} - else: - logger.info(f"过滤后的绰号映射: {filtered_data}") - return {"is_exist": True, "data": filtered_data} # 返回过滤后的数据 - - else: - # is_exist 为 True 但 data 缺失、不是字典或为空 - if "data" not in result: - logger.warning("LLM 响应格式错误: is_exist 为 True 但 'data' 键缺失。") - elif not isinstance(result.get("data"), dict): - logger.warning("LLM 响应格式错误: is_exist 为 True 但 'data' 不是字典。") - else: # data 为空字典 - logger.debug("LLM 指示 is_exist=True 但 data 为空字典。视为 False 处理。") - return {"is_exist": False} - elif result["is_exist"] is False: - logger.info("LLM 未找到可靠的绰号映射。") - return {"is_exist": False} - else: - logger.warning("LLM 响应格式错误: 'is_exist' 不是布尔值。") - return {"is_exist": False} - else: - logger.warning("LLM 响应格式错误: 缺少 'is_exist' 键或不是字典。") - return {"is_exist": False} - except json.JSONDecodeError as json_err: - logger.error(f"解析 LLM 响应 JSON 失败: {json_err}\n原始响应: {response_content}") + # 检查 result 是否为字典 + if not isinstance(result, dict): + logger.warning(f"LLM 响应不是一个有效的 JSON 对象 (字典类型)。响应内容: {response_content}") return {"is_exist": False} - except Exception as e: - logger.error(f"绰号映射 LLM 调用或处理过程中出错: {e}", exc_info=True) + # 使用 get 获取 is_exist,避免 KeyError + is_exist = result.get("is_exist") # 如果 result 不是字典,下面 get 会在 except AttributeError 中捕获 + + if is_exist is True: + original_data = result.get("data") + if isinstance(original_data, dict) and original_data: # 确保 data 是非空字典 + logger.info(f"LLM 找到的原始绰号映射: {original_data}") + + # --- 开始过滤 --- + filtered_data = {} + bot_qq_str = str(global_config.BOT_QQ) + + for user_id, nickname in original_data.items(): + if not isinstance(user_id, str): + logger.warning(f"LLM 返回的 user_id '{user_id}' 不是字符串,跳过。") + continue + if user_id == bot_qq_str: + logger.debug(f"过滤掉机器人自身的映射: ID {user_id}") + continue + + # 有了改名工具后,该过滤器已不适合了,尝试通过修改 prompt 获得更好的结果 + # # 条件 2: 排除 nickname 与 person_name 相同的情况 + # person_name = user_name_map.get(user_id) # 从传入的映射中查找 person_name + # if person_name and person_name == nickname: + # logger.debug(f"过滤掉用户 {user_id} 的映射: 绰号 '{nickname}' 与其名称 '{person_name}' 相同。") + # continue + + # 如果通过所有过滤条件,则保留 + filtered_data[user_id] = nickname + + # 检查过滤后是否还有数据 + if not filtered_data: + logger.info("所有找到的绰号映射都被过滤掉了。") + return {"is_exist": False} + else: + logger.info(f"过滤后的绰号映射: {filtered_data}") + return {"is_exist": True, "data": filtered_data} + else: + # is_exist 为 True 但 data 缺失、不是字典或为空 + if "data" not in result: + logger.warning("LLM 响应格式错误: is_exist 为 True 但 'data' 键缺失。") + elif not isinstance(original_data, dict): + logger.warning(f"LLM 响应格式错误: is_exist 为 True 但 'data' 不是字典。 原始 data: {original_data}") + else: # data 为空字典 + logger.debug("LLM 指示 is_exist=True 但 data 为空字典。视为 False 处理。") + return {"is_exist": False} + + elif is_exist is False: + logger.info("LLM 未找到可靠的绰号映射。") + return {"is_exist": False} + + elif is_exist is None: # 处理 is_exist 键存在但值为 null/None 的情况 + logger.warning("LLM 响应格式错误: 'is_exist' 键的值为 None。") + return {"is_exist": False} + + else: # 处理 is_exist 存在但值不是 True/False/None 的情况 + logger.warning(f"LLM 响应格式错误: 'is_exist' 的值 '{is_exist}' 不是预期的布尔值或 None。") + return {"is_exist": False} + + + except json.JSONDecodeError as json_err: + logger.error(f"解析 LLM 响应 JSON 失败: {json_err}\n原始响应: {response_content}") + return {"is_exist": False} + except AttributeError as attr_err: + # 这个理论上不应该发生,因为在调用 get 前检查了 result 是否是 dict + logger.error(f"处理 LLM 响应时发生属性错误 (可能尝试在非字典对象上使用 .get): {attr_err}\n原始响应: {response_content}") + return {"is_exist": False} + except Exception as e: + # 捕获其他所有未预料到的异常 + logger.error(f"绰号映射 LLM 调用或处理过程中发生未预料的错误: {e}", exc_info=True) return {"is_exist": False}