From c56f295072d75642bd35cdcf2b06f6bbff1d6d11 Mon Sep 17 00:00:00 2001 From: Zylan Date: Thu, 24 Apr 2025 15:18:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9C=BA=E5=99=A8=E4=BA=BA?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=8E=B7=E5=8F=96=E7=89=B9=E5=AE=9A=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E6=B6=88=E6=81=AF=E6=95=B0=E9=87=8F=E9=99=90=E5=88=B6?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6=E5=9C=A8=20ChatGP?= =?UTF-8?q?T=20=E5=92=8C=20DeepSeek=20=E7=B1=BB=E4=B8=AD=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=AF=A5=E9=99=90=E5=88=B6=E3=80=82=E5=90=8C=E6=97=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=91=BD=E4=BB=A4=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=9C=A8=E8=B0=83=E7=94=A8=20AI=20?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=97=B6=E4=BC=A0=E9=80=92=E7=89=B9=E5=AE=9A?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E9=99=90=E5=88=B6=EF=BC=8C=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86=E7=9A=84=E7=81=B5=E6=B4=BB?= =?UTF-8?q?=E6=80=A7=E5=92=8C=E5=87=86=E7=A1=AE=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ai_providers/ai_chatgpt.py | 14 +++++--- ai_providers/ai_deepseek.py | 14 +++++--- commands/handlers.py | 20 +++++++++-- robot.py | 72 +++++++++++++++++++++++++++++-------- 4 files changed, 96 insertions(+), 24 deletions(-) diff --git a/ai_providers/ai_chatgpt.py b/ai_providers/ai_chatgpt.py index 3d35377..7184c3a 100644 --- a/ai_providers/ai_chatgpt.py +++ b/ai_providers/ai_chatgpt.py @@ -56,7 +56,7 @@ class ChatGPT(): return True return False - def get_answer(self, question: str, wxid: str, system_prompt_override=None) -> str: + def get_answer(self, question: str, wxid: str, system_prompt_override=None, specific_max_history=None) -> str: # 获取并格式化数据库历史记录 api_messages = [] @@ -76,10 +76,16 @@ class ChatGPT(): history = self.message_summary.get_messages(wxid) # -限制历史消息数量 - if self.max_history_messages is not None and self.max_history_messages > 0: - history = history[-self.max_history_messages:] # 取最新的 N 条 - elif self.max_history_messages == 0: # 如果设置为0,则不包含历史 + # 优先使用传入的特定限制,如果没有则使用模型默认限制 + limit_to_use = specific_max_history if specific_max_history is not None else self.max_history_messages + self.LOG.debug(f"获取历史记录 for {wxid}, 原始条数: {len(history)}, 使用限制: {limit_to_use}") + + if limit_to_use is not None and limit_to_use > 0: + history = history[-limit_to_use:] # 取最新的 N 条 + elif limit_to_use == 0: # 如果设置为0,则不包含历史 history = [] + + self.LOG.debug(f"应用限制后历史条数: {len(history)}") for msg in history: role = "assistant" if msg.get("sender_wxid") == self.bot_wxid else "user" diff --git a/ai_providers/ai_deepseek.py b/ai_providers/ai_deepseek.py index a11ba71..2e11e1c 100644 --- a/ai_providers/ai_deepseek.py +++ b/ai_providers/ai_deepseek.py @@ -52,7 +52,7 @@ class DeepSeek(): return True return False - def get_answer(self, question: str, wxid: str, system_prompt_override=None) -> str: + def get_answer(self, question: str, wxid: str, system_prompt_override=None, specific_max_history=None) -> str: # 获取并格式化数据库历史记录 api_messages = [] @@ -72,10 +72,16 @@ class DeepSeek(): history = self.message_summary.get_messages(wxid) # 限制历史消息数量 - if self.max_history_messages is not None and self.max_history_messages > 0: - history = history[-self.max_history_messages:] # 取最新的 N 条 - elif self.max_history_messages == 0: # 如果设置为0,则不包含历史 + # 优先使用传入的特定限制,如果没有则使用模型默认限制 + limit_to_use = specific_max_history if specific_max_history is not None else self.max_history_messages + self.LOG.debug(f"获取历史记录 for {wxid}, 原始条数: {len(history)}, 使用限制: {limit_to_use}") + + if limit_to_use is not None and limit_to_use > 0: + history = history[-limit_to_use:] # 取最新的 N 条 + elif limit_to_use == 0: # 如果设置为0,则不包含历史 history = [] + + self.LOG.debug(f"应用限制后历史条数: {len(history)}") for msg in history: role = "assistant" if msg.get("sender_wxid") == self.bot_wxid else "user" diff --git a/commands/handlers.py b/commands/handlers.py index 2c60cda..4124973 100644 --- a/commands/handlers.py +++ b/commands/handlers.py @@ -268,6 +268,11 @@ def handle_chitchat(ctx: 'MessageContext', match: Optional[Match]) -> bool: ctx.send_text("抱歉,我现在无法进行对话。") return False + # 获取特定的历史消息数量限制 + specific_max_history = getattr(ctx, 'specific_max_history', None) + if ctx.logger and specific_max_history is not None: + ctx.logger.debug(f"为 {ctx.get_receiver()} 使用特定历史限制: {specific_max_history}") + # 处理引用图片情况 if getattr(ctx, 'is_quoted_image', False): ctx.logger.info("检测到引用图片消息,尝试处理图片内容...") @@ -374,7 +379,12 @@ def handle_chitchat(ctx: 'MessageContext', match: Optional[Match]) -> bool: if ctx.logger: ctx.logger.info(f"【发送内容】将以下消息发送给AI: \n{q_with_info}") - rsp = chat_model.get_answer(q_with_info, ctx.get_receiver()) + # 调用AI模型,传递特定历史限制 + rsp = chat_model.get_answer( + question=q_with_info, + wxid=ctx.get_receiver(), + specific_max_history=specific_max_history + ) if rsp: # 发送回复 @@ -547,7 +557,13 @@ def handle_perplexity_ask(ctx: 'MessageContext', match: Optional[Match]) -> bool # 调用 AI 模型时传入备选 prompt # 需要调整 get_answer 方法以支持 system_prompt_override 参数 # 这里我们假设已对各AI模型实现了这个参数 - rsp = chat_model.get_answer(q_with_info, ctx.get_receiver(), system_prompt_override=fallback_prompt) + specific_max_history = getattr(ctx, 'specific_max_history', None) + rsp = chat_model.get_answer( + question=q_with_info, + wxid=ctx.get_receiver(), + system_prompt_override=fallback_prompt, + specific_max_history=specific_max_history + ) if rsp: # 发送回复 diff --git a/robot.py b/robot.py index 4b15d76..1c96892 100644 --- a/robot.py +++ b/robot.py @@ -181,24 +181,29 @@ class Robot(Job): # 2. 根据消息来源选择使用的AI模型 self._select_model_for_message(msg) - # 3. 预处理消息,生成MessageContext - ctx = self.preprocess(msg) - # 确保context能访问到当前选定的chat模型 - setattr(ctx, 'chat', self.chat) + # 3. 获取本次对话特定的历史消息限制 + specific_limit = self._get_specific_history_limit(msg) + self.LOG.debug(f"本次对话 ({msg.sender} in {msg.roomid or msg.sender}) 使用历史限制: {specific_limit}") - # 4. 使用命令路由器分发处理消息 + # 4. 预处理消息,生成MessageContext + ctx = self.preprocess(msg) + # 确保context能访问到当前选定的chat模型及特定历史限制 + setattr(ctx, 'chat', self.chat) + setattr(ctx, 'specific_max_history', specific_limit) + + # 5. 使用命令路由器分发处理消息 handled = self.command_router.dispatch(ctx) - # 5. 如果没有命令处理器处理,则进行特殊逻辑处理 + # 6. 如果没有命令处理器处理,则进行特殊逻辑处理 if not handled: - # 5.1 好友请求自动处理 + # 6.1 好友请求自动处理 if msg.type == 37: # 好友请求 self.autoAcceptFriendRequest(msg) return - # 5.2 系统消息处理 + # 6.2 系统消息处理 elif msg.type == 10000: - # 5.2.1 处理新成员入群 + # 6.2.1 处理新成员入群 if "加入了群聊" in msg.content and msg.from_group(): new_member_match = re.search(r'"(.+?)"邀请"(.+?)"加入了群聊', msg.content) if new_member_match: @@ -209,26 +214,26 @@ class Robot(Job): self.sendTextMsg(welcome_msg, msg.roomid) self.LOG.info(f"已发送欢迎消息给新成员 {new_member} 在群 {msg.roomid}") return - # 5.2.2 处理新好友添加 + # 6.2.2 处理新好友添加 elif "你已添加了" in msg.content: self.sayHiToNewFriend(msg) return - # 5.3 群聊消息,且配置了响应该群 + # 6.3 群聊消息,且配置了响应该群 if msg.from_group() and msg.roomid in self.config.GROUPS: # 如果在群里被@了,但命令路由器没有处理,则进行闲聊 if msg.is_at(self.wxid): - # 调用handle_chitchat函数处理闲聊 + # 调用handle_chitchat函数处理闲聊,传递完整的上下文 handle_chitchat(ctx, None) else: pass - # 5.4 私聊消息,未被命令处理,进行闲聊 + # 6.4 私聊消息,未被命令处理,进行闲聊 elif not msg.from_group() and not msg.from_self(): # 检查是否是文本消息(type 1)或者是包含用户输入的类型49消息 if msg.type == 1 or (msg.type == 49 and ctx.text): self.LOG.info(f"准备回复私聊消息: 类型={msg.type}, 文本内容='{ctx.text}'") - # 调用handle_chitchat函数处理闲聊 + # 调用handle_chitchat函数处理闲聊,传递完整的上下文 handle_chitchat(ctx, None) except Exception as e: @@ -500,6 +505,45 @@ class Robot(Job): # 如果没有找到对应配置,使用默认模型 if self.default_model_id in self.chat_models: self.chat = self.chat_models[self.default_model_id] + + def _get_specific_history_limit(self, msg: WxMsg) -> int: + """根据消息来源和配置,获取特定的历史消息数量限制 + + :param msg: 微信消息对象 + :return: 历史消息数量限制,如果没有特定配置则返回None + """ + if not hasattr(self.config, 'GROUP_MODELS'): + # 没有配置,使用当前模型默认值 + return getattr(self.chat, 'max_history_messages', None) + + # 获取消息来源ID + source_id = msg.roomid if msg.from_group() else msg.sender + + # 确定查找的映射和字段名 + if msg.from_group(): + mappings = self.config.GROUP_MODELS.get('mapping', []) + key_field = 'room_id' + else: + mappings = self.config.GROUP_MODELS.get('private_mapping', []) + key_field = 'wxid' + + # 在映射中查找特定配置 + for mapping in mappings: + if mapping.get(key_field) == source_id: + # 找到了对应的配置 + if 'max_history' in mapping: + specific_limit = mapping['max_history'] + self.LOG.debug(f"为 {source_id} 找到特定历史限制: {specific_limit}") + return specific_limit + else: + # 找到了配置但没有max_history,使用模型默认值 + self.LOG.debug(f"为 {source_id} 找到映射但无特定历史限制,使用模型默认值") + break + + # 没有找到特定限制,使用当前模型的默认值 + default_limit = getattr(self.chat, 'max_history_messages', None) + self.LOG.debug(f"未找到 {source_id} 的特定历史限制,使用模型默认值: {default_limit}") + return default_limit def onMsg(self, msg: WxMsg) -> int: try: