diff --git a/src/chat/focus_chat/expressors/default_expressor.py b/src/chat/focus_chat/expressors/default_expressor.py index 7cb69498..f0a8306e 100644 --- a/src/chat/focus_chat/expressors/default_expressor.py +++ b/src/chat/focus_chat/expressors/default_expressor.py @@ -106,7 +106,7 @@ class DefaultExpressor: if reply: with Timer("发送消息", cycle_timers): - await self._send_response_messages( + sent_msg_list = await self._send_response_messages( anchor_message=anchor_message, thinking_id=thinking_id, response_set=reply, @@ -118,7 +118,7 @@ class DefaultExpressor: if not has_sent_something: logger.warning(f"{self.log_prefix} 回复动作未包含任何有效内容") - return has_sent_something, reply + return has_sent_something, sent_msg_list except Exception as e: logger.error(f"回复失败: {e}") @@ -250,6 +250,8 @@ class DefaultExpressor: mark_head = False first_bot_msg: Optional[MessageSending] = None reply_message_ids = [] # 记录实际发送的消息ID + + sent_msg_list = [] for i, msg_text in enumerate(response_set): # 为每个消息片段生成唯一ID @@ -285,9 +287,11 @@ class DefaultExpressor: if type == "emoji": typing = False - await self.heart_fc_sender.send_message(bot_message, has_thinking=True, typing=typing) + sent_msg = await self.heart_fc_sender.send_message(bot_message, has_thinking=True, typing=typing) reply_message_ids.append(part_message_id) # 记录我们生成的ID + + sent_msg_list.append((type, sent_msg)) except Exception as e: logger.error(f"{self.log_prefix}发送回复片段 {i} ({part_message_id}) 时失败: {e}") @@ -296,10 +300,11 @@ class DefaultExpressor: # 在尝试发送完所有片段后,完成原始的 thinking_id 状态 try: await self.heart_fc_sender.complete_thinking(chat_id, thinking_id) + except Exception as e: logger.error(f"{self.log_prefix}完成思考状态 {thinking_id} 时出错: {e}") - return first_bot_msg # 返回第一个成功发送的消息对象 + return sent_msg_list async def _choose_emoji(self, send_emoji: str): """ diff --git a/src/chat/focus_chat/expressors/exprssion_learner.py b/src/chat/focus_chat/expressors/exprssion_learner.py index 57908402..ea3205c8 100644 --- a/src/chat/focus_chat/expressors/exprssion_learner.py +++ b/src/chat/focus_chat/expressors/exprssion_learner.py @@ -4,7 +4,7 @@ from typing import List, Dict, Optional, Any, Tuple from src.common.logger_manager import get_logger from src.chat.models.utils_model import LLMRequest from src.config.config import global_config -from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages +from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages, build_anonymous_messages from src.chat.focus_chat.heartflow_prompt_builder import Prompt, global_prompt_manager import os import json @@ -225,14 +225,15 @@ class ExpressionLearner: return None # 转化成str chat_id: str = random_msg[0]["chat_id"] - random_msg_str: str = await build_readable_messages(random_msg, timestamp_mode="normal") + # random_msg_str: str = await build_readable_messages(random_msg, timestamp_mode="normal") + random_msg_str: str = await build_anonymous_messages(random_msg) prompt: str = await global_prompt_manager.format_prompt( prompt, chat_str=random_msg_str, ) - logger.debug(f"学习{type_str}的prompt: {prompt}") + logger.info(f"学习{type_str}的prompt: {prompt}") try: response, _ = await self.express_learn_model.generate_response_async(prompt) @@ -240,7 +241,7 @@ class ExpressionLearner: logger.error(f"学习{type_str}失败: {e}") return None - logger.debug(f"学习{type_str}的response: {response}") + logger.info(f"学习{type_str}的response: {response}") expressions: List[Tuple[str, str, str]] = self.parse_expression_response(response, chat_id) diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 001754b0..6060f52a 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -907,15 +907,19 @@ class HeartFChatting: ) # --- 概率性忽略文本回复附带的表情 (逻辑保持不变) --- - emoji = action_data.get("emojis") - if action == "reply" and emoji: - logger.debug(f"{self.log_prefix}[Planner] 大模型建议文字回复带表情: '{emoji}'") - if random.random() > EMOJI_SEND_PRO: - logger.info(f"{self.log_prefix}但是麦麦这次不想加表情 ({1 - EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji}'") - action_data["emojis"] = "" # 清空表情请求 - else: - logger.info(f"{self.log_prefix}好吧,加上表情 '{emoji}'") - # --- 结束概率性忽略 --- + try: + emoji = action_data.get("emojis") + if action == "reply" and emoji: + logger.debug(f"{self.log_prefix}[Planner] 大模型建议文字回复带表情: '{emoji}'") + if random.random() > EMOJI_SEND_PRO: + logger.info(f"{self.log_prefix}但是麦麦这次不想加表情 ({1 - EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji}'") + action_data["emojis"] = "" # 清空表情请求 + else: + logger.info(f"{self.log_prefix}好吧,加上表情 '{emoji}'") + except Exception as e: + logger.error(f"{self.log_prefix}[Planner] 概率性忽略表情时发生错误: {e}") + traceback.print_exc() + # --- 结束概率性忽略 --- # 返回结果字典 return { diff --git a/src/chat/focus_chat/heartFC_sender.py b/src/chat/focus_chat/heartFC_sender.py index 846ad1fe..bce43563 100644 --- a/src/chat/focus_chat/heartFC_sender.py +++ b/src/chat/focus_chat/heartFC_sender.py @@ -15,7 +15,7 @@ install(extra_lines=3) logger = get_logger("sender") -async def send_message(message: MessageSending) -> None: +async def send_message(message: MessageSending) -> str: """合并后的消息发送函数,包含WS发送和日志记录""" message_preview = truncate_message(message.processed_plain_text, max_length=40) @@ -23,6 +23,7 @@ async def send_message(message: MessageSending) -> None: # 直接调用API发送消息 await global_api.send_message(message) logger.success(f"已将消息 '{message_preview}' 发往平台'{message.message_info.platform}'") + return message.processed_plain_text except Exception as e: logger.error(f"发送消息 '{message_preview}' 发往平台'{message.message_info.platform}' 失败: {str(e)}") @@ -120,8 +121,13 @@ class HeartFCSender: else: await asyncio.sleep(0.5) - await send_message(message) + sent_msg = await send_message(message) await self.storage.store_message(message, message.chat_stream) + + if sent_msg: + return sent_msg + else: + return "发送失败" except Exception as e: logger.error(f"[{chat_id}] 处理或存储消息 {message_id} 时出错: {e}") diff --git a/src/chat/models/utils_model.py b/src/chat/models/utils_model.py index 18c9c737..e662a8e3 100644 --- a/src/chat/models/utils_model.py +++ b/src/chat/models/utils_model.py @@ -577,7 +577,7 @@ class LLMRequest: ) # 安全地检查和记录请求详情 handled_payload = await _safely_record(request_content, payload) - logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload}") + logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload[:100]}") raise RuntimeError( f"模型 {self.model_name} API请求失败: 状态码 {exception.status}, {exception.message}" ) @@ -591,7 +591,7 @@ class LLMRequest: logger.critical(f"模型 {self.model_name} 请求失败: {str(exception)}") # 安全地检查和记录请求详情 handled_payload = await _safely_record(request_content, payload) - logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload}") + logger.critical(f"请求头: {await self._build_headers(no_key=True)} 请求体: {handled_payload[:100]}") raise RuntimeError(f"模型 {self.model_name} API请求失败: {str(exception)}") async def _transform_parameters(self, params: dict) -> dict: diff --git a/src/chat/utils/chat_message_builder.py b/src/chat/utils/chat_message_builder.py index dcd98e19..41d88e6a 100644 --- a/src/chat/utils/chat_message_builder.py +++ b/src/chat/utils/chat_message_builder.py @@ -413,6 +413,53 @@ async def build_readable_messages( return read_mark_line.strip() # 如果前后都无消息,只返回标记行 +async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str: + """ + 构建匿名可读消息,将不同人的名称转为唯一占位符(A、B、C...),bot自己用SELF。 + """ + if not messages: + return "" + + # 分配占位符 + person_map = {} + current_char = ord('A') + output_lines = [] + + for msg in messages: + user_info = msg.get("user_info", {}) + platform = user_info.get("platform") + user_id = user_info.get("user_id") + timestamp = msg.get("time") + content = msg.get("processed_plain_text", "") + + if not all([platform, user_id, timestamp is not None]): + continue + + # 判断是否为bot + if user_id == global_config.BOT_QQ: + anon_name = "SELF" + else: + person_id = person_info_manager.get_person_id(platform, user_id) + if person_id not in person_map: + person_map[person_id] = chr(current_char) + current_char += 1 + anon_name = person_map[person_id] + + # 格式化时间 + readable_time = translate_timestamp_to_human_readable(timestamp, mode="relative") + header = f"{readable_time}{anon_name}说:" + output_lines.append(header) + stripped_line = content.strip() + if stripped_line: + if stripped_line.endswith("。"): + stripped_line = stripped_line[:-1] + output_lines.append(f"{stripped_line};") + output_lines.append("\n") + + formatted_string = "".join(output_lines).strip() + return formatted_string + + async def get_person_id_list(messages: List[Dict[str, Any]]) -> List[str]: """ 从消息列表中提取不重复的 person_id 列表 (忽略机器人自身)。