fix:修复引用回复逻辑
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,6 +5,8 @@ NapCat.Framework.Windows.Once/
|
||||
log/
|
||||
logs/
|
||||
tool_call_benchmark.py
|
||||
run_maibot_core.bat
|
||||
run_napcat_adapter.bat
|
||||
run_ad.bat
|
||||
llm_tool_benchmark_results.json
|
||||
MaiBot-Napcat-Adapter-main
|
||||
|
||||
@@ -52,7 +52,7 @@ class SearchKnowledgeFromLPMMTool(BaseTool):
|
||||
except Exception as e:
|
||||
logger.error(f"知识库搜索工具执行失败: {str(e)}")
|
||||
# 在其他异常情况下,确保 id 仍然是 query (如果它被定义了)
|
||||
query_id = query if 'query' in locals() else 'unknown_query'
|
||||
query_id = query if "query" in locals() else "unknown_query"
|
||||
return {"type": "info", "id": query_id, "content": f"lpmm知识库搜索失败,炸了: {str(e)}"}
|
||||
|
||||
# def get_info_from_db(
|
||||
@@ -143,13 +143,15 @@ class SearchKnowledgeFromLPMMTool(BaseTool):
|
||||
|
||||
formatted_string = "我找到了一些相关知识:\n"
|
||||
for i, result in enumerate(results):
|
||||
chunk_id = result.get("chunk_id")
|
||||
# chunk_id = result.get("chunk_id")
|
||||
text = result.get("text", "")
|
||||
source = result.get("source", "未知来源")
|
||||
source_type = result.get("source_type", "未知类型")
|
||||
similarity = result.get("similarity", 0.0)
|
||||
|
||||
formatted_string += f"{i + 1}. (相似度: {similarity:.2f}) 类型: {source_type}, 来源: {source} \n内容片段: {text}\n\n"
|
||||
formatted_string += (
|
||||
f"{i + 1}. (相似度: {similarity:.2f}) 类型: {source_type}, 来源: {source} \n内容片段: {text}\n\n"
|
||||
)
|
||||
# 暂时去掉chunk_id
|
||||
# formatted_string += f"{i + 1}. (相似度: {similarity:.2f}) 类型: {source_type}, 来源: {source}, Chunk ID: {chunk_id} \n内容片段: {text}\n\n"
|
||||
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
from src.do_tool.tool_can_use.base_tool import BaseTool, register_tool
|
||||
from src.plugins.person_info.person_info import person_info_manager
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.plugins.person_info.relationship_manager import relationship_manager
|
||||
import json
|
||||
import time
|
||||
|
||||
logger = get_logger("rename_person_tool")
|
||||
|
||||
|
||||
class RenamePersonTool(BaseTool):
|
||||
name = "rename_person"
|
||||
description = "这个工具可以改变用户的昵称。你可以选择改变对他人的称呼。"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"person_name": {
|
||||
"type": "string",
|
||||
"description": "需要重新取名的用户的当前昵称"
|
||||
},
|
||||
"person_name": {"type": "string", "description": "需要重新取名的用户的当前昵称"},
|
||||
"message_content": {
|
||||
"type": "string",
|
||||
"description": "可选的。当前的聊天内容或特定要求,用于提供取名建议的上下文。"
|
||||
}
|
||||
"description": "可选的。当前的聊天内容或特定要求,用于提供取名建议的上下文。",
|
||||
},
|
||||
},
|
||||
"required": ["person_name"]
|
||||
"required": ["person_name"],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: dict, message_txt=""):
|
||||
@@ -37,13 +33,10 @@ class RenamePersonTool(BaseTool):
|
||||
dict: 包含执行结果的字典
|
||||
"""
|
||||
person_name_to_find = function_args.get("person_name")
|
||||
request_context = function_args.get("message_content", "") # 如果没有提供,则为空字符串
|
||||
request_context = function_args.get("message_content", "") # 如果没有提供,则为空字符串
|
||||
|
||||
if not person_name_to_find:
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": "错误:必须提供需要重命名的用户昵称 (person_name)。"
|
||||
}
|
||||
return {"name": self.name, "content": "错误:必须提供需要重命名的用户昵称 (person_name)。"}
|
||||
|
||||
try:
|
||||
# 1. 根据昵称查找用户信息
|
||||
@@ -54,35 +47,34 @@ class RenamePersonTool(BaseTool):
|
||||
logger.info(f"未找到昵称为 '{person_name_to_find}' 的用户。")
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"找不到昵称为 '{person_name_to_find}' 的用户。请确保输入的是我之前为该用户取的昵称。"
|
||||
"content": f"找不到昵称为 '{person_name_to_find}' 的用户。请确保输入的是我之前为该用户取的昵称。",
|
||||
}
|
||||
|
||||
person_id = person_info.get("person_id")
|
||||
user_nickname = person_info.get("nickname") # 这是用户原始昵称
|
||||
user_nickname = person_info.get("nickname") # 这是用户原始昵称
|
||||
user_cardname = person_info.get("user_cardname")
|
||||
user_avatar = person_info.get("user_avatar")
|
||||
|
||||
if not person_id:
|
||||
logger.error(f"找到了用户 '{person_name_to_find}' 但无法获取 person_id")
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"找到了用户 '{person_name_to_find}' 但获取内部ID时出错。"
|
||||
}
|
||||
logger.error(f"找到了用户 '{person_name_to_find}' 但无法获取 person_id")
|
||||
return {"name": self.name, "content": f"找到了用户 '{person_name_to_find}' 但获取内部ID时出错。"}
|
||||
|
||||
# 2. 调用 qv_person_name 进行取名
|
||||
logger.debug(f"为用户 {person_id} (原昵称: {person_name_to_find}) 调用 qv_person_name,请求上下文: '{request_context}'")
|
||||
logger.debug(
|
||||
f"为用户 {person_id} (原昵称: {person_name_to_find}) 调用 qv_person_name,请求上下文: '{request_context}'"
|
||||
)
|
||||
result = await person_info_manager.qv_person_name(
|
||||
person_id=person_id,
|
||||
user_nickname=user_nickname,
|
||||
user_cardname=user_cardname,
|
||||
user_avatar=user_avatar,
|
||||
request=request_context
|
||||
request=request_context,
|
||||
)
|
||||
|
||||
# 3. 处理结果
|
||||
if result and result.get("nickname"):
|
||||
new_name = result["nickname"]
|
||||
reason = result.get("reason", "未提供理由")
|
||||
# reason = result.get("reason", "未提供理由")
|
||||
logger.info(f"成功为用户 {person_id} 取了新昵称: {new_name}")
|
||||
|
||||
content = f"已成功将用户 {person_name_to_find} 的备注名更新为 {new_name}"
|
||||
@@ -93,14 +85,14 @@ class RenamePersonTool(BaseTool):
|
||||
# 尝试从内存中获取可能已经更新的名字
|
||||
current_name = await person_info_manager.get_value(person_id, "person_name")
|
||||
if current_name and current_name != person_name_to_find:
|
||||
return {
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"尝试取新昵称时遇到一点小问题,但我已经将 '{person_name_to_find}' 的昵称更新为 '{current_name}' 了。"
|
||||
"content": f"尝试取新昵称时遇到一点小问题,但我已经将 '{person_name_to_find}' 的昵称更新为 '{current_name}' 了。",
|
||||
}
|
||||
else:
|
||||
return {
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"尝试为 '{person_name_to_find}' 取新昵称时遇到了问题,未能成功生成。可能需要稍后再试。"
|
||||
"content": f"尝试为 '{person_name_to_find}' 取新昵称时遇到了问题,未能成功生成。可能需要稍后再试。",
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -108,5 +100,6 @@ class RenamePersonTool(BaseTool):
|
||||
logger.error(error_msg, exc_info=True)
|
||||
return {"type": "info_error", "id": f"rename_error_{time.time()}", "content": error_msg}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(RenamePersonTool)
|
||||
register_tool(RenamePersonTool)
|
||||
|
||||
@@ -18,7 +18,7 @@ INTEREST_EVAL_INTERVAL_SECONDS = 5
|
||||
# 新增聊天超时检查间隔
|
||||
NORMAL_CHAT_TIMEOUT_CHECK_INTERVAL_SECONDS = 60
|
||||
# 新增状态评估间隔
|
||||
HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS = 60
|
||||
HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS = 20
|
||||
# 新增私聊激活检查间隔
|
||||
PRIVATE_CHAT_ACTIVATION_CHECK_INTERVAL_SECONDS = 5 # 与兴趣评估类似,设为5秒
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ from src.plugins.utils.chat_message_builder import (
|
||||
)
|
||||
from src.plugins.utils.prompt_builder import Prompt, global_prompt_manager
|
||||
from typing import Optional
|
||||
import difflib
|
||||
from src.plugins.chat.message import MessageRecv # 添加 MessageRecv 导入
|
||||
|
||||
# Import the new utility function
|
||||
from .utils_chat import get_chat_type_and_target_info
|
||||
@@ -227,6 +229,70 @@ class ChattingObservation(Observation):
|
||||
f"Chat {self.chat_id} - 压缩早期记忆:{self.mid_memory_info}\n现在聊天内容:{self.talking_message_str}"
|
||||
)
|
||||
|
||||
async def find_best_matching_message(self, search_str: str, min_similarity: float = 0.6) -> Optional[MessageRecv]:
|
||||
"""
|
||||
在 talking_message 中查找与 search_str 最匹配的消息。
|
||||
|
||||
Args:
|
||||
search_str: 要搜索的字符串。
|
||||
min_similarity: 要求的最低相似度(0到1之间)。
|
||||
|
||||
Returns:
|
||||
匹配的 MessageRecv 实例,如果找不到则返回 None。
|
||||
"""
|
||||
best_match_score = -1.0
|
||||
best_match_dict = None
|
||||
|
||||
if not self.talking_message:
|
||||
logger.debug(f"Chat {self.chat_id}: talking_message is empty, cannot find match for '{search_str}'")
|
||||
return None
|
||||
|
||||
for message_dict in self.talking_message:
|
||||
try:
|
||||
# 临时创建 MessageRecv 以处理文本
|
||||
temp_msg = MessageRecv(message_dict)
|
||||
await temp_msg.process() # 处理消息以获取 processed_plain_text
|
||||
current_text = temp_msg.processed_plain_text
|
||||
|
||||
if not current_text: # 跳过没有文本内容的消息
|
||||
continue
|
||||
|
||||
# 计算相似度
|
||||
matcher = difflib.SequenceMatcher(None, search_str, current_text)
|
||||
score = matcher.ratio()
|
||||
|
||||
# logger.debug(f"Comparing '{search_str}' with '{current_text}', score: {score}") # 可选:用于调试
|
||||
|
||||
if score > best_match_score:
|
||||
best_match_score = score
|
||||
best_match_dict = message_dict
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing message for matching in chat {self.chat_id}: {e}", exc_info=True)
|
||||
continue # 继续处理下一条消息
|
||||
|
||||
if best_match_dict is not None and best_match_score >= min_similarity:
|
||||
logger.debug(f"Found best match for '{search_str}' with score {best_match_score:.2f}")
|
||||
try:
|
||||
final_msg = MessageRecv(best_match_dict)
|
||||
await final_msg.process()
|
||||
# 确保 MessageRecv 实例有关联的 chat_stream
|
||||
if hasattr(self, "chat_stream"):
|
||||
final_msg.update_chat_stream(self.chat_stream)
|
||||
else:
|
||||
logger.warning(
|
||||
f"ChattingObservation instance for chat {self.chat_id} does not have a chat_stream attribute set."
|
||||
)
|
||||
return final_msg
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating final MessageRecv for chat {self.chat_id}: {e}", exc_info=True)
|
||||
return None
|
||||
else:
|
||||
logger.debug(
|
||||
f"No suitable match found for '{search_str}' in chat {self.chat_id} (best score: {best_match_score:.2f}, threshold: {min_similarity})"
|
||||
)
|
||||
return None
|
||||
|
||||
async def has_new_messages_since(self, timestamp: float) -> bool:
|
||||
"""检查指定时间戳之后是否有新消息"""
|
||||
count = num_new_messages_since(chat_id=self.chat_id, timestamp_start=timestamp)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .observation import Observation, ChattingObservation
|
||||
from .observation import ChattingObservation
|
||||
from src.plugins.models.utils_model import LLMRequest
|
||||
from src.config.config import global_config
|
||||
import time
|
||||
@@ -146,10 +146,9 @@ class SubMind:
|
||||
lines = ["【信息】"]
|
||||
for item in self.structured_info:
|
||||
# 简化展示,突出内容和类型,包含TTL供调试
|
||||
type_str = item.get('type', '未知类型')
|
||||
content_str = item.get('content', '')
|
||||
ttl = item.get('ttl', '?')
|
||||
|
||||
type_str = item.get("type", "未知类型")
|
||||
content_str = item.get("content", "")
|
||||
|
||||
if type_str == "info":
|
||||
lines.append(f"刚刚: {content_str}")
|
||||
elif type_str == "memory":
|
||||
@@ -178,18 +177,24 @@ class SubMind:
|
||||
|
||||
# ---------- 0. 更新和清理 structured_info ----------
|
||||
if self.structured_info:
|
||||
logger.debug(f"{self.log_prefix} 更新前的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}")
|
||||
logger.debug(
|
||||
f"{self.log_prefix} 更新前的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}"
|
||||
)
|
||||
updated_info = []
|
||||
for item in self.structured_info:
|
||||
item['ttl'] -= 1
|
||||
if item['ttl'] > 0:
|
||||
item["ttl"] -= 1
|
||||
if item["ttl"] > 0:
|
||||
updated_info.append(item)
|
||||
else:
|
||||
logger.debug(f"{self.log_prefix} 移除过期的 structured_info 项: {item['id']}")
|
||||
self.structured_info = updated_info
|
||||
logger.debug(f"{self.log_prefix} 更新后的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}")
|
||||
logger.debug(
|
||||
f"{self.log_prefix} 更新后的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}"
|
||||
)
|
||||
self._update_structured_info_str()
|
||||
logger.debug(f"{self.log_prefix} 当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}")
|
||||
logger.debug(
|
||||
f"{self.log_prefix} 当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}"
|
||||
)
|
||||
|
||||
# ---------- 1. 准备基础数据 ----------
|
||||
# 获取现有想法和情绪状态
|
||||
@@ -202,10 +207,10 @@ class SubMind:
|
||||
logger.error(f"{self.log_prefix} 无法获取有效的观察对象或缺少聊天类型信息")
|
||||
self.update_current_mind("(观察出错了...)")
|
||||
return self.current_mind, self.past_mind
|
||||
|
||||
|
||||
is_group_chat = observation.is_group_chat
|
||||
# logger.debug(f"is_group_chat: {is_group_chat}")
|
||||
|
||||
|
||||
chat_target_info = observation.chat_target_info
|
||||
chat_target_name = "对方" # Default for private
|
||||
if not is_group_chat and chat_target_info:
|
||||
@@ -496,7 +501,7 @@ class SubMind:
|
||||
tool_instance: 工具使用器实例
|
||||
"""
|
||||
tool_results = []
|
||||
new_structured_items = [] # 收集新产生的结构化信息
|
||||
new_structured_items = [] # 收集新产生的结构化信息
|
||||
|
||||
# 执行所有工具调用
|
||||
for tool_call in tool_calls:
|
||||
@@ -506,26 +511,26 @@ class SubMind:
|
||||
tool_results.append(result)
|
||||
# 创建新的结构化信息项
|
||||
new_item = {
|
||||
"type": result.get("type", "unknown_type"), # 使用 'type' 键
|
||||
"id": result.get("id", f"fallback_id_{time.time()}"), # 使用 'id' 键
|
||||
"content": result.get("content", ""), # 'content' 键保持不变
|
||||
"ttl": 3
|
||||
"type": result.get("type", "unknown_type"), # 使用 'type' 键
|
||||
"id": result.get("id", f"fallback_id_{time.time()}"), # 使用 'id' 键
|
||||
"content": result.get("content", ""), # 'content' 键保持不变
|
||||
"ttl": 3,
|
||||
}
|
||||
new_structured_items.append(new_item)
|
||||
|
||||
except Exception as tool_e:
|
||||
logger.error(f"[{self.subheartflow_id}] 工具执行失败: {tool_e}")
|
||||
logger.error(traceback.format_exc()) # 添加 traceback 记录
|
||||
logger.error(traceback.format_exc()) # 添加 traceback 记录
|
||||
|
||||
# 如果有新的工具结果,记录并更新结构化信息
|
||||
if new_structured_items:
|
||||
self.structured_info.extend(new_structured_items) # 添加到现有列表
|
||||
self.structured_info.extend(new_structured_items) # 添加到现有列表
|
||||
logger.debug(f"工具调用收集到新的结构化信息: {safe_json_dumps(new_structured_items, ensure_ascii=False)}")
|
||||
# logger.debug(f"当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}") # 可以取消注释以查看完整列表
|
||||
self._update_structured_info_str() # 添加新信息后,更新字符串表示
|
||||
self._update_structured_info_str() # 添加新信息后,更新字符串表示
|
||||
|
||||
def update_current_mind(self, response):
|
||||
if self.current_mind: # 只有当 current_mind 非空时才添加到 past_mind
|
||||
if self.current_mind: # 只有当 current_mind 非空时才添加到 past_mind
|
||||
self.past_mind.append(self.current_mind)
|
||||
# 可以考虑限制 past_mind 的大小,例如:
|
||||
# max_past_mind_size = 10
|
||||
|
||||
@@ -128,7 +128,7 @@ class SubHeartflowManager:
|
||||
# 添加聊天观察者
|
||||
observation = ChattingObservation(chat_id=subheartflow_id)
|
||||
await observation.initialize()
|
||||
|
||||
|
||||
new_subflow.add_observation(observation)
|
||||
|
||||
# 注册子心流
|
||||
|
||||
@@ -82,15 +82,14 @@ class ChatBot:
|
||||
if userinfo.user_id in global_config.ban_user_id:
|
||||
logger.debug(f"用户{userinfo.user_id}被禁止回复")
|
||||
return
|
||||
|
||||
|
||||
if groupinfo is None:
|
||||
logger.trace("检测到私聊消息,检查")
|
||||
# 好友黑名单拦截
|
||||
# 好友黑名单拦截
|
||||
if userinfo.user_id not in global_config.talk_allowed_private:
|
||||
logger.debug(f"用户{userinfo.user_id}没有私聊权限")
|
||||
return
|
||||
|
||||
|
||||
# 群聊黑名单拦截
|
||||
if groupinfo is not None and groupinfo.group_id not in global_config.talk_allowed_groups:
|
||||
logger.trace(f"群{groupinfo.group_id}被禁止回复")
|
||||
|
||||
@@ -294,7 +294,9 @@ class MessageSending(MessageProcessBase):
|
||||
|
||||
def set_reply(self, reply: Optional["MessageRecv"] = None):
|
||||
"""设置回复消息"""
|
||||
if self.message_info.format_info is not None and "reply" in self.message_info.format_info.accept_format:
|
||||
# print(f"set_reply: {reply}")
|
||||
# if self.message_info.format_info is not None and "reply" in self.message_info.format_info.accept_format:
|
||||
if True:
|
||||
if reply:
|
||||
self.reply = reply
|
||||
if self.reply:
|
||||
|
||||
@@ -209,24 +209,31 @@ class MessageManager:
|
||||
_ = message.update_thinking_time() # 更新思考时间
|
||||
thinking_start_time = message.thinking_start_time
|
||||
now_time = time.time()
|
||||
logger.debug(f"thinking_start_time:{thinking_start_time},now_time:{now_time}")
|
||||
thinking_messages_count, thinking_messages_length = count_messages_between(
|
||||
start_time=thinking_start_time, end_time=now_time, stream_id=message.chat_stream.stream_id
|
||||
)
|
||||
# print(f"message.reply:{message.reply}")
|
||||
|
||||
# --- 条件应用 set_reply 逻辑 ---
|
||||
logger.debug(
|
||||
f"[message.apply_set_reply_logic:{message.apply_set_reply_logic},message.is_head:{message.is_head},thinking_messages_count:{thinking_messages_count},thinking_messages_length:{thinking_messages_length},message.is_private_message():{message.is_private_message()}]"
|
||||
)
|
||||
if (
|
||||
message.apply_set_reply_logic # 检查标记
|
||||
and message.is_head
|
||||
and (thinking_messages_count > 4 or thinking_messages_length > 250)
|
||||
and (thinking_messages_count > 1 or thinking_messages_length > 20)
|
||||
and not message.is_private_message()
|
||||
):
|
||||
logger.debug(
|
||||
f"[{message.chat_stream.stream_id}] 应用 set_reply 逻辑: {message.processed_plain_text[:20]}..."
|
||||
)
|
||||
message.set_reply()
|
||||
message.set_reply(message.reply)
|
||||
# --- 结束条件 set_reply ---
|
||||
|
||||
await message.process() # 预处理消息内容
|
||||
|
||||
logger.debug(f"{message}")
|
||||
|
||||
# 使用全局 message_sender 实例
|
||||
await send_message(message)
|
||||
|
||||
@@ -6,13 +6,13 @@ from collections import Counter
|
||||
import jieba
|
||||
import numpy as np
|
||||
from src.common.logger import get_module_logger
|
||||
from pymongo.errors import PyMongoError
|
||||
|
||||
from ..models.utils_model import LLMRequest
|
||||
from ..utils.typo_generator import ChineseTypoGenerator
|
||||
from ...config.config import global_config
|
||||
from .message import MessageRecv, Message
|
||||
from .message import MessageRecv
|
||||
from maim_message import UserInfo
|
||||
from .chat_stream import ChatStream
|
||||
from ..moods.moods import MoodManager
|
||||
from ...common.database import db
|
||||
|
||||
@@ -107,8 +107,6 @@ async def get_embedding(text, request_type="embedding"):
|
||||
return embedding
|
||||
|
||||
|
||||
|
||||
|
||||
def get_recent_group_detailed_plain_text(chat_stream_id: str, limit: int = 12, combine=False):
|
||||
recent_messages = list(
|
||||
db.messages.find(
|
||||
@@ -566,93 +564,45 @@ def count_messages_between(start_time: float, end_time: float, stream_id: str) -
|
||||
"""计算两个时间点之间的消息数量和文本总长度
|
||||
|
||||
Args:
|
||||
start_time (float): 起始时间戳
|
||||
end_time (float): 结束时间戳
|
||||
start_time (float): 起始时间戳 (不包含)
|
||||
end_time (float): 结束时间戳 (包含)
|
||||
stream_id (str): 聊天流ID
|
||||
|
||||
Returns:
|
||||
tuple[int, int]: (消息数量, 文本总长度)
|
||||
- 消息数量:包含起始时间的消息,不包含结束时间的消息
|
||||
- 文本总长度:所有消息的processed_plain_text长度之和
|
||||
"""
|
||||
count = 0
|
||||
total_length = 0
|
||||
|
||||
# 参数校验 (可选但推荐)
|
||||
if start_time >= end_time:
|
||||
# logger.debug(f"开始时间 {start_time} 大于或等于结束时间 {end_time},返回 0, 0")
|
||||
return 0, 0
|
||||
if not stream_id:
|
||||
logger.error("stream_id 不能为空")
|
||||
return 0, 0
|
||||
|
||||
# 直接查询时间范围内的消息
|
||||
# time > start_time AND time <= end_time
|
||||
query = {"chat_id": stream_id, "time": {"$gt": start_time, "$lte": end_time}}
|
||||
|
||||
try:
|
||||
# 获取开始时间之前最新的一条消息
|
||||
start_message = db.messages.find_one(
|
||||
{"chat_id": stream_id, "time": {"$lte": start_time}},
|
||||
sort=[("time", -1), ("_id", -1)], # 按时间倒序,_id倒序(最后插入的在前)
|
||||
)
|
||||
# 执行查询
|
||||
messages_cursor = db.messages.find(query)
|
||||
|
||||
# 获取结束时间最近的一条消息
|
||||
# 先找到结束时间点的所有消息
|
||||
end_time_messages = list(
|
||||
db.messages.find(
|
||||
{"chat_id": stream_id, "time": {"$lte": end_time}},
|
||||
sort=[("time", -1)], # 先按时间倒序
|
||||
).limit(10)
|
||||
) # 限制查询数量,避免性能问题
|
||||
|
||||
if not end_time_messages:
|
||||
logger.warning(f"未找到结束时间 {end_time} 之前的消息")
|
||||
return 0, 0
|
||||
|
||||
# 找到最大时间
|
||||
max_time = end_time_messages[0]["time"]
|
||||
# 在最大时间的消息中找最后插入的(_id最大的)
|
||||
end_message = max([msg for msg in end_time_messages if msg["time"] == max_time], key=lambda x: x["_id"])
|
||||
|
||||
if not start_message:
|
||||
logger.warning(f"未找到开始时间 {start_time} 之前的消息")
|
||||
return 0, 0
|
||||
|
||||
# 调试输出
|
||||
# print("\n=== 消息范围信息 ===")
|
||||
# print("Start message:", {
|
||||
# "message_id": start_message.get("message_id"),
|
||||
# "time": start_message.get("time"),
|
||||
# "text": start_message.get("processed_plain_text", ""),
|
||||
# "_id": str(start_message.get("_id"))
|
||||
# })
|
||||
# print("End message:", {
|
||||
# "message_id": end_message.get("message_id"),
|
||||
# "time": end_message.get("time"),
|
||||
# "text": end_message.get("processed_plain_text", ""),
|
||||
# "_id": str(end_message.get("_id"))
|
||||
# })
|
||||
# print("Stream ID:", stream_id)
|
||||
|
||||
# 如果结束消息的时间等于开始时间,返回0
|
||||
if end_message["time"] == start_message["time"]:
|
||||
return 0, 0
|
||||
|
||||
# 获取并打印这个时间范围内的所有消息
|
||||
# print("\n=== 时间范围内的所有消息 ===")
|
||||
all_messages = list(
|
||||
db.messages.find(
|
||||
{"chat_id": stream_id, "time": {"$gte": start_message["time"], "$lte": end_message["time"]}},
|
||||
sort=[("time", 1), ("_id", 1)], # 按时间正序,_id正序
|
||||
)
|
||||
)
|
||||
|
||||
count = 0
|
||||
total_length = 0
|
||||
for msg in all_messages:
|
||||
# 遍历结果计算数量和长度
|
||||
for msg in messages_cursor:
|
||||
count += 1
|
||||
text_length = len(msg.get("processed_plain_text", ""))
|
||||
total_length += text_length
|
||||
# print(f"\n消息 {count}:")
|
||||
# print({
|
||||
# "message_id": msg.get("message_id"),
|
||||
# "time": msg.get("time"),
|
||||
# "text": msg.get("processed_plain_text", ""),
|
||||
# "text_length": text_length,
|
||||
# "_id": str(msg.get("_id"))
|
||||
# })
|
||||
total_length += len(msg.get("processed_plain_text", ""))
|
||||
|
||||
# 如果时间不同,需要把end_message本身也计入
|
||||
return count - 1, total_length
|
||||
# logger.debug(f"查询范围 ({start_time}, {end_time}] 内找到 {count} 条消息,总长度 {total_length}")
|
||||
return count, total_length
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"计算消息数量时出错: {str(e)}")
|
||||
except PyMongoError as e:
|
||||
logger.error(f"查询 stream_id={stream_id} 在 ({start_time}, {end_time}] 范围内的消息时出错: {e}")
|
||||
return 0, 0
|
||||
except Exception as e: # 保留一个通用异常捕获以防万一
|
||||
logger.error(f"计算消息数量时发生意外错误: {e}")
|
||||
return 0, 0
|
||||
|
||||
|
||||
|
||||
@@ -372,6 +372,7 @@ class PromptBuilder:
|
||||
memory_prompt = await global_prompt_manager.format_prompt(
|
||||
"memory_prompt", related_memory_info=related_memory_info
|
||||
)
|
||||
|
||||
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=chat_stream.stream_id,
|
||||
timestamp=time.time(),
|
||||
|
||||
@@ -86,11 +86,12 @@ class NormalChat:
|
||||
bot_user_info=bot_user_info,
|
||||
reply=message,
|
||||
thinking_start_time=thinking_time_point,
|
||||
timestamp=timestamp if timestamp is not None else None
|
||||
timestamp=timestamp if timestamp is not None else None,
|
||||
)
|
||||
|
||||
await message_manager.add_message(thinking_message)
|
||||
return thinking_id
|
||||
|
||||
# 改为实例方法
|
||||
async def _add_messages_to_manager(
|
||||
self, message: MessageRecv, response_set: List[str], thinking_id
|
||||
@@ -206,7 +207,10 @@ class NormalChat:
|
||||
try:
|
||||
# 处理消息
|
||||
await self.normal_response(
|
||||
message=message, is_mentioned=is_mentioned, interested_rate=interest_value, rewind_response = False
|
||||
message=message,
|
||||
is_mentioned=is_mentioned,
|
||||
interested_rate=interest_value,
|
||||
rewind_response=False,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.stream_name}] 处理兴趣消息{msg_id}时出错: {e}\n{traceback.format_exc()}")
|
||||
@@ -214,7 +218,9 @@ class NormalChat:
|
||||
self.interest_dict.pop(msg_id, None)
|
||||
|
||||
# 改为实例方法, 移除 chat 参数
|
||||
async def normal_response(self, message: MessageRecv, is_mentioned: bool, interested_rate: float, rewind_response: bool = False) -> None:
|
||||
async def normal_response(
|
||||
self, message: MessageRecv, is_mentioned: bool, interested_rate: float, rewind_response: bool = False
|
||||
) -> None:
|
||||
# 检查收到的消息是否属于当前实例处理的 chat stream
|
||||
if message.chat_stream.stream_id != self.stream_id:
|
||||
logger.error(
|
||||
@@ -393,13 +399,17 @@ class NormalChat:
|
||||
|
||||
try:
|
||||
logger.info(f"[{self.stream_name}] 处理初始高兴趣消息 {msg_id} (兴趣值: {interest_value:.2f})")
|
||||
await self.normal_response(message=message, is_mentioned=is_mentioned, interested_rate=interest_value, rewind_response = True)
|
||||
await self.normal_response(
|
||||
message=message, is_mentioned=is_mentioned, interested_rate=interest_value, rewind_response=True
|
||||
)
|
||||
processed_count += 1
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.stream_name}] 处理初始兴趣消息 {msg_id} 时出错: {e}\\n{traceback.format_exc()}")
|
||||
|
||||
# --- 新增:处理完后清空整个字典 ---
|
||||
logger.info(f"[{self.stream_name}] 处理了 {processed_count} 条初始高兴趣消息。现在清空所有剩余的初始兴趣消息...")
|
||||
logger.info(
|
||||
f"[{self.stream_name}] 处理了 {processed_count} 条初始高兴趣消息。现在清空所有剩余的初始兴趣消息..."
|
||||
)
|
||||
self.interest_dict.clear()
|
||||
# --- 新增结束 ---
|
||||
|
||||
|
||||
@@ -188,7 +188,9 @@ class PersonInfoManager:
|
||||
logger.warning(f"无法从文本中提取有效的JSON字典: {text}")
|
||||
return {"nickname": "", "reason": ""}
|
||||
|
||||
async def qv_person_name(self, person_id: str, user_nickname: str, user_cardname: str, user_avatar: str, request: str = ""):
|
||||
async def qv_person_name(
|
||||
self, person_id: str, user_nickname: str, user_cardname: str, user_avatar: str, request: str = ""
|
||||
):
|
||||
"""给某个用户取名"""
|
||||
if not person_id:
|
||||
logger.debug("取名失败:person_id不能为空")
|
||||
@@ -214,7 +216,7 @@ class PersonInfoManager:
|
||||
qv_name_prompt += f"你之前叫他{old_name},是因为{old_reason},"
|
||||
|
||||
qv_name_prompt += f"\n其他取名的要求是:{request}"
|
||||
|
||||
|
||||
qv_name_prompt += "\n请根据以上用户信息,想想你叫他什么比较好,请最好使用用户的qq昵称,可以稍作修改"
|
||||
if existing_names:
|
||||
qv_name_prompt += f"\n请注意,以下名称已被使用,不要使用以下昵称:{existing_names}。\n"
|
||||
@@ -526,7 +528,7 @@ class PersonInfoManager:
|
||||
for pid, name in self.person_name_list.items():
|
||||
if name == person_name:
|
||||
found_person_id = pid
|
||||
break # 找到第一个匹配就停止
|
||||
break # 找到第一个匹配就停止
|
||||
|
||||
if not found_person_id:
|
||||
# 如果内存没有,尝试数据库查询(可能内存未及时更新或启动时未加载)
|
||||
@@ -535,21 +537,21 @@ class PersonInfoManager:
|
||||
found_person_id = document.get("person_id")
|
||||
else:
|
||||
logger.debug(f"数据库中也未找到名为 '{person_name}' 的用户")
|
||||
return None # 数据库也找不到
|
||||
return None # 数据库也找不到
|
||||
|
||||
# 根据找到的 person_id 获取所需信息
|
||||
if found_person_id:
|
||||
required_fields = ["person_id", "platform", "user_id", "nickname", "user_cardname", "user_avatar"]
|
||||
person_data = await self.get_values(found_person_id, required_fields)
|
||||
if person_data: # 确保 get_values 成功返回
|
||||
if person_data: # 确保 get_values 成功返回
|
||||
return person_data
|
||||
else:
|
||||
logger.warning(f"找到了 person_id '{found_person_id}' 但获取详细信息失败")
|
||||
return None
|
||||
else:
|
||||
# 这理论上不应该发生,因为上面已经处理了找不到的情况
|
||||
logger.error(f"逻辑错误:未能为 '{person_name}' 确定 person_id")
|
||||
return None
|
||||
# 这理论上不应该发生,因为上面已经处理了找不到的情况
|
||||
logger.error(f"逻辑错误:未能为 '{person_name}' 确定 person_id")
|
||||
return None
|
||||
|
||||
|
||||
person_info_manager = PersonInfoManager()
|
||||
|
||||
Reference in New Issue
Block a user