mirror of https://github.com/Mai-with-u/MaiBot.git
Merge branch 'PFC-test' of https://github.com/Dax233/MaiMBot into PFC-test
commit
e6258adbb9
|
|
@ -668,8 +668,12 @@ class BotConfig:
|
||||||
def idle_conversation(parent: dict):
|
def idle_conversation(parent: dict):
|
||||||
idle_conversation_config = parent["idle_conversation"]
|
idle_conversation_config = parent["idle_conversation"]
|
||||||
if config.INNER_VERSION in SpecifierSet(">=1.6.2"):
|
if config.INNER_VERSION in SpecifierSet(">=1.6.2"):
|
||||||
config.enable_idle_conversation = idle_conversation_config.get("enable_idle_conversation", config.enable_idle_conversation)
|
config.enable_idle_conversation = idle_conversation_config.get(
|
||||||
config.idle_check_interval = idle_conversation_config.get("idle_check_interval", config.idle_check_interval)
|
"enable_idle_conversation", config.enable_idle_conversation
|
||||||
|
)
|
||||||
|
config.idle_check_interval = idle_conversation_config.get(
|
||||||
|
"idle_check_interval", config.idle_check_interval
|
||||||
|
)
|
||||||
config.min_idle_time = idle_conversation_config.get("min_idle_time", config.min_idle_time)
|
config.min_idle_time = idle_conversation_config.get("min_idle_time", config.min_idle_time)
|
||||||
config.max_idle_time = idle_conversation_config.get("max_idle_time", config.max_idle_time)
|
config.max_idle_time = idle_conversation_config.get("max_idle_time", config.max_idle_time)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,6 @@ class ActionPlanner:
|
||||||
# 获取 ChatObserver 实例 (单例模式)
|
# 获取 ChatObserver 实例 (单例模式)
|
||||||
self.chat_observer = ChatObserver.get_instance(stream_id, private_name)
|
self.chat_observer = ChatObserver.get_instance(stream_id, private_name)
|
||||||
|
|
||||||
|
|
||||||
async def plan(
|
async def plan(
|
||||||
self,
|
self,
|
||||||
observation_info: ObservationInfo,
|
observation_info: ObservationInfo,
|
||||||
|
|
@ -253,8 +252,14 @@ class ActionPlanner:
|
||||||
|
|
||||||
# --- 5. 验证最终行动类型 ---
|
# --- 5. 验证最终行动类型 ---
|
||||||
valid_actions = [
|
valid_actions = [
|
||||||
"direct_reply", "send_new_message", "wait", "listening",
|
"direct_reply",
|
||||||
"rethink_goal", "end_conversation", "block_and_ignore", "say_goodbye"
|
"send_new_message",
|
||||||
|
"wait",
|
||||||
|
"listening",
|
||||||
|
"rethink_goal",
|
||||||
|
"end_conversation",
|
||||||
|
"block_and_ignore",
|
||||||
|
"say_goodbye",
|
||||||
]
|
]
|
||||||
if final_action not in valid_actions:
|
if final_action not in valid_actions:
|
||||||
logger.warning(f"[私聊][{self.private_name}] LLM 返回了未知的行动类型: '{final_action}',强制改为 wait")
|
logger.warning(f"[私聊][{self.private_name}] LLM 返回了未知的行动类型: '{final_action}',强制改为 wait")
|
||||||
|
|
@ -266,7 +271,6 @@ class ActionPlanner:
|
||||||
logger.info(f"[私聊][{self.private_name}] 行动原因: {final_reason}")
|
logger.info(f"[私聊][{self.private_name}] 行动原因: {final_reason}")
|
||||||
return final_action, final_reason
|
return final_action, final_reason
|
||||||
|
|
||||||
|
|
||||||
# --- Helper methods for preparing prompt inputs ---
|
# --- Helper methods for preparing prompt inputs ---
|
||||||
|
|
||||||
def _get_bot_last_speak_time_info(self, observation_info: ObservationInfo) -> str:
|
def _get_bot_last_speak_time_info(self, observation_info: ObservationInfo) -> str:
|
||||||
|
|
@ -307,7 +311,11 @@ class ActionPlanner:
|
||||||
last_goal_text = last_goal_item.get("goal", "")
|
last_goal_text = last_goal_item.get("goal", "")
|
||||||
elif isinstance(last_goal_item, str):
|
elif isinstance(last_goal_item, str):
|
||||||
last_goal_text = last_goal_item
|
last_goal_text = last_goal_item
|
||||||
if isinstance(last_goal_text, str) and "分钟," in last_goal_text and "思考接下来要做什么" in last_goal_text:
|
if (
|
||||||
|
isinstance(last_goal_text, str)
|
||||||
|
and "分钟," in last_goal_text
|
||||||
|
and "思考接下来要做什么" in last_goal_text
|
||||||
|
):
|
||||||
wait_time_str = last_goal_text.split("分钟,")[0].replace("你等待了", "").strip()
|
wait_time_str = last_goal_text.split("分钟,")[0].replace("你等待了", "").strip()
|
||||||
timeout_context = f"重要提示:对方已经长时间(约 {wait_time_str} 分钟)没有回复你的消息了,请基于此情况规划下一步。\n"
|
timeout_context = f"重要提示:对方已经长时间(约 {wait_time_str} 分钟)没有回复你的消息了,请基于此情况规划下一步。\n"
|
||||||
logger.debug(f"[私聊][{self.private_name}] 检测到超时目标: {last_goal_text}")
|
logger.debug(f"[私聊][{self.private_name}] 检测到超时目标: {last_goal_text}")
|
||||||
|
|
@ -356,18 +364,30 @@ class ActionPlanner:
|
||||||
chat_history_text = observation_info.chat_history_str
|
chat_history_text = observation_info.chat_history_str
|
||||||
elif hasattr(observation_info, "chat_history") and observation_info.chat_history:
|
elif hasattr(observation_info, "chat_history") and observation_info.chat_history:
|
||||||
history_slice = observation_info.chat_history[-20:]
|
history_slice = observation_info.chat_history[-20:]
|
||||||
chat_history_text = await build_readable_messages(history_slice, replace_bot_name=True, merge_messages=False, timestamp_mode="relative", read_mark=0.0)
|
chat_history_text = await build_readable_messages(
|
||||||
|
history_slice, replace_bot_name=True, merge_messages=False, timestamp_mode="relative", read_mark=0.0
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
chat_history_text = "还没有聊天记录。\n"
|
chat_history_text = "还没有聊天记录。\n"
|
||||||
unread_count = getattr(observation_info, 'new_messages_count', 0)
|
unread_count = getattr(observation_info, "new_messages_count", 0)
|
||||||
unread_messages = getattr(observation_info, 'unprocessed_messages', [])
|
unread_messages = getattr(observation_info, "unprocessed_messages", [])
|
||||||
if unread_count > 0 and unread_messages:
|
if unread_count > 0 and unread_messages:
|
||||||
bot_qq_str = str(global_config.BOT_QQ)
|
bot_qq_str = str(global_config.BOT_QQ)
|
||||||
other_unread_messages = [msg for msg in unread_messages if msg.get("user_info", {}).get("user_id") != bot_qq_str]
|
other_unread_messages = [
|
||||||
|
msg for msg in unread_messages if msg.get("user_info", {}).get("user_id") != bot_qq_str
|
||||||
|
]
|
||||||
other_unread_count = len(other_unread_messages)
|
other_unread_count = len(other_unread_messages)
|
||||||
if other_unread_count > 0:
|
if other_unread_count > 0:
|
||||||
new_messages_str = await build_readable_messages(other_unread_messages, replace_bot_name=True, merge_messages=False, timestamp_mode="relative", read_mark=0.0)
|
new_messages_str = await build_readable_messages(
|
||||||
chat_history_text += f"\n--- 以下是 {other_unread_count} 条你需要处理的新消息 ---\n{new_messages_str}\n------\n"
|
other_unread_messages,
|
||||||
|
replace_bot_name=True,
|
||||||
|
merge_messages=False,
|
||||||
|
timestamp_mode="relative",
|
||||||
|
read_mark=0.0,
|
||||||
|
)
|
||||||
|
chat_history_text += (
|
||||||
|
f"\n--- 以下是 {other_unread_count} 条你需要处理的新消息 ---\n{new_messages_str}\n------\n"
|
||||||
|
)
|
||||||
logger.debug(f"[私聊][{self.private_name}] 向 LLM 追加了 {other_unread_count} 条未读消息。")
|
logger.debug(f"[私聊][{self.private_name}] 向 LLM 追加了 {other_unread_count} 条未读消息。")
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
logger.warning(f"[私聊][{self.private_name}] 构建聊天记录文本时属性错误: {e}")
|
logger.warning(f"[私聊][{self.private_name}] 构建聊天记录文本时属性错误: {e}")
|
||||||
|
|
@ -377,7 +397,6 @@ class ActionPlanner:
|
||||||
chat_history_text = "[处理聊天记录时出错]\n"
|
chat_history_text = "[处理聊天记录时出错]\n"
|
||||||
return chat_history_text
|
return chat_history_text
|
||||||
|
|
||||||
|
|
||||||
def _build_action_history_context(self, conversation_info: ConversationInfo) -> Tuple[str, str]:
|
def _build_action_history_context(self, conversation_info: ConversationInfo) -> Tuple[str, str]:
|
||||||
"""构建行动历史概要和上一次行动详细情况"""
|
"""构建行动历史概要和上一次行动详细情况"""
|
||||||
|
|
||||||
|
|
@ -437,7 +456,14 @@ class ActionPlanner:
|
||||||
end_content, _ = await self.llm.generate_response_async(end_decision_prompt)
|
end_content, _ = await self.llm.generate_response_async(end_decision_prompt)
|
||||||
llm_duration = time.time() - llm_start_time
|
llm_duration = time.time() - llm_start_time
|
||||||
logger.debug(f"[私聊][{self.private_name}] LLM (结束决策) 耗时: {llm_duration:.3f} 秒, 原始返回: {end_content}")
|
logger.debug(f"[私聊][{self.private_name}] LLM (结束决策) 耗时: {llm_duration:.3f} 秒, 原始返回: {end_content}")
|
||||||
end_success, end_result = get_items_from_json(end_content, self.private_name, "say_bye", "reason", default_values={"say_bye": "no", "reason": "结束决策LLM返回格式错误,默认不告别"}, required_types={"say_bye": str, "reason": str})
|
end_success, end_result = get_items_from_json(
|
||||||
|
end_content,
|
||||||
|
self.private_name,
|
||||||
|
"say_bye",
|
||||||
|
"reason",
|
||||||
|
default_values={"say_bye": "no", "reason": "结束决策LLM返回格式错误,默认不告别"},
|
||||||
|
required_types={"say_bye": str, "reason": str},
|
||||||
|
)
|
||||||
say_bye_decision = end_result.get("say_bye", "no").lower()
|
say_bye_decision = end_result.get("say_bye", "no").lower()
|
||||||
end_decision_reason = end_result.get("reason", "未提供原因")
|
end_decision_reason = end_result.get("reason", "未提供原因")
|
||||||
if end_success and say_bye_decision == "yes":
|
if end_success and say_bye_decision == "yes":
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,8 @@ class IdleConversationStarter:
|
||||||
# 重新随机化下一次触发的时间阈值
|
# 重新随机化下一次触发的时间阈值
|
||||||
self.actual_idle_threshold = random.randint(global_config.min_idle_time, global_config.max_idle_time)
|
self.actual_idle_threshold = random.randint(global_config.min_idle_time, global_config.max_idle_time)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[私聊][{self.private_name}]更新最后消息时间: {self.last_message_time},新阈值: {self.actual_idle_threshold}秒")
|
f"[私聊][{self.private_name}]更新最后消息时间: {self.last_message_time},新阈值: {self.actual_idle_threshold}秒"
|
||||||
|
)
|
||||||
|
|
||||||
def reload_config(self) -> None:
|
def reload_config(self) -> None:
|
||||||
"""重新加载配置
|
"""重新加载配置
|
||||||
|
|
@ -108,13 +109,15 @@ class IdleConversationStarter:
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[私聊][{self.private_name}]重新加载主动对话配置: 启用={global_config.enable_idle_conversation}, 检查间隔={global_config.idle_check_interval}秒, 最短间隔={global_config.min_idle_time}秒, 最长间隔={global_config.max_idle_time}秒")
|
f"[私聊][{self.private_name}]重新加载主动对话配置: 启用={global_config.enable_idle_conversation}, 检查间隔={global_config.idle_check_interval}秒, 最短间隔={global_config.min_idle_time}秒, 最长间隔={global_config.max_idle_time}秒"
|
||||||
|
)
|
||||||
|
|
||||||
# 重新计算实际阈值
|
# 重新计算实际阈值
|
||||||
async def update_threshold():
|
async def update_threshold():
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
self.actual_idle_threshold = random.randint(global_config.min_idle_time,
|
self.actual_idle_threshold = random.randint(
|
||||||
global_config.max_idle_time)
|
global_config.min_idle_time, global_config.max_idle_time
|
||||||
|
)
|
||||||
logger.debug(f"[私聊][{self.private_name}]更新空闲检测阈值为: {self.actual_idle_threshold}秒")
|
logger.debug(f"[私聊][{self.private_name}]更新空闲检测阈值为: {self.actual_idle_threshold}秒")
|
||||||
|
|
||||||
# 创建一个任务来异步更新阈值
|
# 创建一个任务来异步更新阈值
|
||||||
|
|
@ -202,7 +205,7 @@ class IdleConversationStarter:
|
||||||
try:
|
try:
|
||||||
content, _ = await asyncio.wait_for(
|
content, _ = await asyncio.wait_for(
|
||||||
self.llm.generate_response_async(prompt),
|
self.llm.generate_response_async(prompt),
|
||||||
timeout=30 # 30秒超时
|
timeout=30, # 30秒超时
|
||||||
)
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
logger.error(f"[私聊][{self.private_name}]生成主动对话内容超时")
|
logger.error(f"[私聊][{self.private_name}]生成主动对话内容超时")
|
||||||
|
|
@ -213,7 +216,7 @@ class IdleConversationStarter:
|
||||||
|
|
||||||
# 清理结果
|
# 清理结果
|
||||||
content = content.strip()
|
content = content.strip()
|
||||||
content = content.strip('"\'')
|
content = content.strip("\"'")
|
||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
logger.error(f"[私聊][{self.private_name}]生成的主动对话内容为空")
|
logger.error(f"[私聊][{self.private_name}]生成的主动对话内容为空")
|
||||||
|
|
@ -254,17 +257,13 @@ class IdleConversationStarter:
|
||||||
|
|
||||||
# 发送消息
|
# 发送消息
|
||||||
try:
|
try:
|
||||||
await self.message_sender.send_message(
|
await self.message_sender.send_message(chat_stream=chat_stream, content=content, reply_to_message=None)
|
||||||
chat_stream=chat_stream,
|
|
||||||
content=content,
|
|
||||||
reply_to_message=None
|
|
||||||
)
|
|
||||||
|
|
||||||
# 更新空闲会话启动器的最后消息时间
|
# 更新空闲会话启动器的最后消息时间
|
||||||
await self.update_last_message_time()
|
await self.update_last_message_time()
|
||||||
|
|
||||||
# 如果新对话实例有一个聊天观察者,请触发更新
|
# 如果新对话实例有一个聊天观察者,请触发更新
|
||||||
if new_conversation and hasattr(new_conversation, 'chat_observer'):
|
if new_conversation and hasattr(new_conversation, "chat_observer"):
|
||||||
logger.info(f"[私聊][{self.private_name}]触发聊天观察者更新")
|
logger.info(f"[私聊][{self.private_name}]触发聊天观察者更新")
|
||||||
try:
|
try:
|
||||||
new_conversation.chat_observer.trigger_update()
|
new_conversation.chat_observer.trigger_update()
|
||||||
|
|
@ -279,7 +278,7 @@ class IdleConversationStarter:
|
||||||
# 顶级异常处理,确保任何未捕获的异常都不会导致整个进程崩溃
|
# 顶级异常处理,确保任何未捕获的异常都不会导致整个进程崩溃
|
||||||
logger.error(f"[私聊][{self.private_name}]主动发起对话过程中发生未预期的错误: {str(e)}")
|
logger.error(f"[私聊][{self.private_name}]主动发起对话过程中发生未预期的错误: {str(e)}")
|
||||||
|
|
||||||
async def _get_chat_stream(self, conversation: Optional['Conversation'] = None) -> Optional[ChatStream]:
|
async def _get_chat_stream(self, conversation: Optional["Conversation"] = None) -> Optional[ChatStream]:
|
||||||
"""获取可用的聊天流
|
"""获取可用的聊天流
|
||||||
|
|
||||||
尝试多种方式获取聊天流:
|
尝试多种方式获取聊天流:
|
||||||
|
|
@ -296,7 +295,7 @@ class IdleConversationStarter:
|
||||||
chat_stream = None
|
chat_stream = None
|
||||||
|
|
||||||
# 1. 尝试从对话实例获取
|
# 1. 尝试从对话实例获取
|
||||||
if conversation and hasattr(conversation, 'should_continue'):
|
if conversation and hasattr(conversation, "should_continue"):
|
||||||
# 等待一小段时间,确保初始化完成
|
# 等待一小段时间,确保初始化完成
|
||||||
retry_count = 0
|
retry_count = 0
|
||||||
max_retries = 10
|
max_retries = 10
|
||||||
|
|
@ -309,12 +308,13 @@ class IdleConversationStarter:
|
||||||
logger.warning(f"[私聊][{self.private_name}]新对话实例初始化可能未完成,但仍将尝试获取聊天流")
|
logger.warning(f"[私聊][{self.private_name}]新对话实例初始化可能未完成,但仍将尝试获取聊天流")
|
||||||
|
|
||||||
# 尝试使用对话实例的聊天流
|
# 尝试使用对话实例的聊天流
|
||||||
if hasattr(conversation, 'chat_stream') and conversation.chat_stream:
|
if hasattr(conversation, "chat_stream") and conversation.chat_stream:
|
||||||
logger.info(f"[私聊][{self.private_name}]使用新对话实例的聊天流")
|
logger.info(f"[私聊][{self.private_name}]使用新对话实例的聊天流")
|
||||||
return conversation.chat_stream
|
return conversation.chat_stream
|
||||||
|
|
||||||
# 2. 尝试从聊天管理器获取
|
# 2. 尝试从聊天管理器获取
|
||||||
from src.plugins.chat.chat_stream import chat_manager
|
from src.plugins.chat.chat_stream import chat_manager
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(f"[私聊][{self.private_name}]尝试从chat_manager获取聊天流")
|
logger.info(f"[私聊][{self.private_name}]尝试从chat_manager获取聊天流")
|
||||||
chat_stream = chat_manager.get_stream(self.stream_id)
|
chat_stream = chat_manager.get_stream(self.stream_id)
|
||||||
|
|
@ -327,11 +327,7 @@ class IdleConversationStarter:
|
||||||
try:
|
try:
|
||||||
logger.warning(f"[私聊][{self.private_name}]无法获取现有聊天流,创建新的聊天流")
|
logger.warning(f"[私聊][{self.private_name}]无法获取现有聊天流,创建新的聊天流")
|
||||||
# 创建用户信息对象
|
# 创建用户信息对象
|
||||||
user_info = UserInfo(
|
user_info = UserInfo(user_id=global_config.BOT_QQ, user_nickname=global_config.BOT_NICKNAME, platform="qq")
|
||||||
user_id=global_config.BOT_QQ,
|
|
||||||
user_nickname=global_config.BOT_NICKNAME,
|
|
||||||
platform="qq"
|
|
||||||
)
|
|
||||||
# 创建聊天流
|
# 创建聊天流
|
||||||
return ChatStream(self.stream_id, "qq", user_info)
|
return ChatStream(self.stream_id, "qq", user_info)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,13 @@ class ObservationInfoHandler(NotificationHandler):
|
||||||
try:
|
try:
|
||||||
user_info = UserInfo.from_dict(user_info_dict)
|
user_info = UserInfo.from_dict(user_info_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[私聊][{self.private_name}] 从字典创建 UserInfo 时出错: {e}, dict: {user_info_dict}")
|
logger.error(
|
||||||
|
f"[私聊][{self.private_name}] 从字典创建 UserInfo 时出错: {e}, dict: {user_info_dict}"
|
||||||
|
)
|
||||||
elif user_info_dict is not None:
|
elif user_info_dict is not None:
|
||||||
logger.warning(f"[私聊][{self.private_name}] 收到的 user_info 不是预期的字典类型: {type(user_info_dict)}")
|
logger.warning(
|
||||||
|
f"[私聊][{self.private_name}] 收到的 user_info 不是预期的字典类型: {type(user_info_dict)}"
|
||||||
|
)
|
||||||
|
|
||||||
# 更新 ObservationInfo
|
# 更新 ObservationInfo
|
||||||
await self.observation_info.update_from_message(message_dict, user_info)
|
await self.observation_info.update_from_message(message_dict, user_info)
|
||||||
|
|
@ -142,6 +146,7 @@ class ObservationInfo:
|
||||||
# 初始化 bot_id
|
# 初始化 bot_id
|
||||||
try:
|
try:
|
||||||
from ...config.config import global_config
|
from ...config.config import global_config
|
||||||
|
|
||||||
self.bot_id = str(global_config.BOT_QQ) if global_config.BOT_QQ else None
|
self.bot_id = str(global_config.BOT_QQ) if global_config.BOT_QQ else None
|
||||||
if not self.bot_id:
|
if not self.bot_id:
|
||||||
logger.error(f"[私聊][{self.private_name}] 未能从配置中获取 BOT_QQ ID!")
|
logger.error(f"[私聊][{self.private_name}] 未能从配置中获取 BOT_QQ ID!")
|
||||||
|
|
@ -150,7 +155,6 @@ class ObservationInfo:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[私聊][{self.private_name}] 获取 BOT_QQ ID 时出错: {e}")
|
logger.error(f"[私聊][{self.private_name}] 获取 BOT_QQ ID 时出错: {e}")
|
||||||
|
|
||||||
|
|
||||||
def bind_to_chat_observer(self, chat_observer: ChatObserver):
|
def bind_to_chat_observer(self, chat_observer: ChatObserver):
|
||||||
"""绑定到指定的 ChatObserver 并注册通知处理器"""
|
"""绑定到指定的 ChatObserver 并注册通知处理器"""
|
||||||
if self.chat_observer:
|
if self.chat_observer:
|
||||||
|
|
@ -181,7 +185,6 @@ class ObservationInfo:
|
||||||
logger.error(f"[私聊][{self.private_name}] 绑定到 ChatObserver 时出错: {e}")
|
logger.error(f"[私聊][{self.private_name}] 绑定到 ChatObserver 时出错: {e}")
|
||||||
self.chat_observer = None # 绑定失败
|
self.chat_observer = None # 绑定失败
|
||||||
|
|
||||||
|
|
||||||
def unbind_from_chat_observer(self):
|
def unbind_from_chat_observer(self):
|
||||||
"""解除与 ChatObserver 的绑定"""
|
"""解除与 ChatObserver 的绑定"""
|
||||||
if self.chat_observer and hasattr(self.chat_observer, "notification_manager") and self.handler:
|
if self.chat_observer and hasattr(self.chat_observer, "notification_manager") and self.handler:
|
||||||
|
|
@ -189,7 +192,9 @@ class ObservationInfo:
|
||||||
notification_manager = self.chat_observer.notification_manager
|
notification_manager = self.chat_observer.notification_manager
|
||||||
notification_manager.unregister_handler("observation_info", NotificationType.NEW_MESSAGE, self.handler)
|
notification_manager.unregister_handler("observation_info", NotificationType.NEW_MESSAGE, self.handler)
|
||||||
notification_manager.unregister_handler("observation_info", NotificationType.COLD_CHAT, self.handler)
|
notification_manager.unregister_handler("observation_info", NotificationType.COLD_CHAT, self.handler)
|
||||||
notification_manager.unregister_handler("observation_info", NotificationType.MESSAGE_DELETED, self.handler)
|
notification_manager.unregister_handler(
|
||||||
|
"observation_info", NotificationType.MESSAGE_DELETED, self.handler
|
||||||
|
)
|
||||||
# ... 注销其他已注册的类型 ...
|
# ... 注销其他已注册的类型 ...
|
||||||
|
|
||||||
logger.info(f"[私聊][{self.private_name}] ObservationInfo 成功从 ChatObserver 解绑")
|
logger.info(f"[私聊][{self.private_name}] ObservationInfo 成功从 ChatObserver 解绑")
|
||||||
|
|
@ -200,7 +205,6 @@ class ObservationInfo:
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[私聊][{self.private_name}] 尝试解绑时 ChatObserver 无效或 handler 未设置")
|
logger.warning(f"[私聊][{self.private_name}] 尝试解绑时 ChatObserver 无效或 handler 未设置")
|
||||||
|
|
||||||
|
|
||||||
async def update_from_message(self, message: Dict[str, Any], user_info: Optional[UserInfo]):
|
async def update_from_message(self, message: Dict[str, Any], user_info: Optional[UserInfo]):
|
||||||
"""根据收到的新消息更新 ObservationInfo 的状态"""
|
"""根据收到的新消息更新 ObservationInfo 的状态"""
|
||||||
message_time = message.get("time")
|
message_time = message.get("time")
|
||||||
|
|
@ -240,12 +244,13 @@ class ObservationInfo:
|
||||||
# 创建消息的副本以避免修改原始数据(如果需要)
|
# 创建消息的副本以避免修改原始数据(如果需要)
|
||||||
self.unprocessed_messages.append(message.copy())
|
self.unprocessed_messages.append(message.copy())
|
||||||
self.new_messages_count = len(self.unprocessed_messages)
|
self.new_messages_count = len(self.unprocessed_messages)
|
||||||
logger.debug(f"[私聊][{self.private_name}] 添加新未处理消息 ID: {message_id}, 发送者: {sender_id_str}, 当前未处理数: {self.new_messages_count}")
|
logger.debug(
|
||||||
|
f"[私聊][{self.private_name}] 添加新未处理消息 ID: {message_id}, 发送者: {sender_id_str}, 当前未处理数: {self.new_messages_count}"
|
||||||
|
)
|
||||||
self.update_changed()
|
self.update_changed()
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[私聊][{self.private_name}] 尝试重复添加未处理消息 ID: {message_id}")
|
logger.warning(f"[私聊][{self.private_name}] 尝试重复添加未处理消息 ID: {message_id}")
|
||||||
|
|
||||||
|
|
||||||
async def remove_unprocessed_message(self, message_id_to_delete: str):
|
async def remove_unprocessed_message(self, message_id_to_delete: str):
|
||||||
"""从 unprocessed_messages 列表中移除指定 ID 的消息"""
|
"""从 unprocessed_messages 列表中移除指定 ID 的消息"""
|
||||||
original_count = len(self.unprocessed_messages)
|
original_count = len(self.unprocessed_messages)
|
||||||
|
|
@ -256,12 +261,13 @@ class ObservationInfo:
|
||||||
|
|
||||||
if new_count < original_count:
|
if new_count < original_count:
|
||||||
self.new_messages_count = new_count
|
self.new_messages_count = new_count
|
||||||
logger.info(f"[私聊][{self.private_name}] 移除了未处理的消息 (ID: {message_id_to_delete}), 当前未处理数: {self.new_messages_count}")
|
logger.info(
|
||||||
|
f"[私聊][{self.private_name}] 移除了未处理的消息 (ID: {message_id_to_delete}), 当前未处理数: {self.new_messages_count}"
|
||||||
|
)
|
||||||
self.update_changed()
|
self.update_changed()
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[私聊][{self.private_name}] 尝试移除不存在的未处理消息 ID: {message_id_to_delete}")
|
logger.warning(f"[私聊][{self.private_name}] 尝试移除不存在的未处理消息 ID: {message_id_to_delete}")
|
||||||
|
|
||||||
|
|
||||||
async def update_cold_chat_status(self, is_cold: bool, current_time: float):
|
async def update_cold_chat_status(self, is_cold: bool, current_time: float):
|
||||||
"""更新冷场状态"""
|
"""更新冷场状态"""
|
||||||
if is_cold != self.is_cold_chat:
|
if is_cold != self.is_cold_chat:
|
||||||
|
|
@ -281,13 +287,11 @@ class ObservationInfo:
|
||||||
if self.is_cold_chat and self.cold_chat_start_time:
|
if self.is_cold_chat and self.cold_chat_start_time:
|
||||||
self.cold_chat_duration = current_time - self.cold_chat_start_time
|
self.cold_chat_duration = current_time - self.cold_chat_start_time
|
||||||
|
|
||||||
|
|
||||||
def update_changed(self):
|
def update_changed(self):
|
||||||
"""标记状态已改变"""
|
"""标记状态已改变"""
|
||||||
self.changed = True
|
self.changed = True
|
||||||
# 这个标记通常在处理完改变后由外部逻辑重置为 False
|
# 这个标记通常在处理完改变后由外部逻辑重置为 False
|
||||||
|
|
||||||
|
|
||||||
# --- [修改点 15] 重命名并修改 clear_unprocessed_messages ---
|
# --- [修改点 15] 重命名并修改 clear_unprocessed_messages ---
|
||||||
async def clear_processed_messages(self, message_ids_to_clear: Set[str]):
|
async def clear_processed_messages(self, message_ids_to_clear: Set[str]):
|
||||||
"""将指定 ID 的未处理消息移入历史记录,并更新相关状态"""
|
"""将指定 ID 的未处理消息移入历史记录,并更新相关状态"""
|
||||||
|
|
@ -309,7 +313,9 @@ class ObservationInfo:
|
||||||
remaining_messages.append(msg)
|
remaining_messages.append(msg)
|
||||||
|
|
||||||
if not messages_to_move:
|
if not messages_to_move:
|
||||||
logger.debug(f"[私聊][{self.private_name}] 未找到与 ID 列表 {message_ids_to_clear} 匹配的未处理消息进行清理。")
|
logger.debug(
|
||||||
|
f"[私聊][{self.private_name}] 未找到与 ID 列表 {message_ids_to_clear} 匹配的未处理消息进行清理。"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug(f"[私聊][{self.private_name}] 准备清理 {cleared_count} 条已处理消息...")
|
logger.debug(f"[私聊][{self.private_name}] 准备清理 {cleared_count} 条已处理消息...")
|
||||||
|
|
@ -342,16 +348,17 @@ class ObservationInfo:
|
||||||
self.new_messages_count = len(self.unprocessed_messages)
|
self.new_messages_count = len(self.unprocessed_messages)
|
||||||
self.chat_history_count = len(self.chat_history)
|
self.chat_history_count = len(self.chat_history)
|
||||||
|
|
||||||
logger.info(f"[私聊][{self.private_name}] 已清理 {cleared_count} 条消息 (IDs: {message_ids_to_clear}),剩余未处理 {self.new_messages_count} 条,当前历史记录 {self.chat_history_count} 条。")
|
logger.info(
|
||||||
|
f"[私聊][{self.private_name}] 已清理 {cleared_count} 条消息 (IDs: {message_ids_to_clear}),剩余未处理 {self.new_messages_count} 条,当前历史记录 {self.chat_history_count} 条。"
|
||||||
|
)
|
||||||
|
|
||||||
self.update_changed() # 状态改变
|
self.update_changed() # 状态改变
|
||||||
|
|
||||||
|
|
||||||
# --- Helper methods (可以根据需要添加) ---
|
# --- Helper methods (可以根据需要添加) ---
|
||||||
def get_active_duration(self) -> float:
|
def get_active_duration(self) -> float:
|
||||||
"""获取当前活跃时长(距离最后一条消息的时间)"""
|
"""获取当前活跃时长(距离最后一条消息的时间)"""
|
||||||
if not self.last_message_time:
|
if not self.last_message_time:
|
||||||
return float('inf') # 或返回 0.0,取决于定义
|
return float("inf") # 或返回 0.0,取决于定义
|
||||||
return time.time() - self.last_message_time
|
return time.time() - self.last_message_time
|
||||||
|
|
||||||
def get_user_response_time(self) -> Optional[float]:
|
def get_user_response_time(self) -> Optional[float]:
|
||||||
|
|
@ -365,4 +372,3 @@ class ObservationInfo:
|
||||||
if not self.last_bot_speak_time:
|
if not self.last_bot_speak_time:
|
||||||
return None
|
return None
|
||||||
return time.time() - self.last_bot_speak_time
|
return time.time() - self.last_bot_speak_time
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,11 @@ class PFCManager:
|
||||||
if stream_id in self._instances:
|
if stream_id in self._instances:
|
||||||
instance = self._instances[stream_id]
|
instance = self._instances[stream_id]
|
||||||
# 检查忽略状态
|
# 检查忽略状态
|
||||||
if (hasattr(instance, "ignore_until_timestamp") and
|
if (
|
||||||
instance.ignore_until_timestamp and
|
hasattr(instance, "ignore_until_timestamp")
|
||||||
time.time() < instance.ignore_until_timestamp):
|
and instance.ignore_until_timestamp
|
||||||
|
and time.time() < instance.ignore_until_timestamp
|
||||||
|
):
|
||||||
logger.debug(f"[私聊][{private_name}] 会话实例当前处于忽略状态: {stream_id}")
|
logger.debug(f"[私聊][{private_name}] 会话实例当前处于忽略状态: {stream_id}")
|
||||||
return None # 处于忽略状态,不返回实例
|
return None # 处于忽略状态,不返回实例
|
||||||
|
|
||||||
|
|
@ -66,7 +68,6 @@ class PFCManager:
|
||||||
if stream_id in self._initializing:
|
if stream_id in self._initializing:
|
||||||
del self._initializing[stream_id]
|
del self._initializing[stream_id]
|
||||||
|
|
||||||
|
|
||||||
# --- 创建并初始化新实例 ---
|
# --- 创建并初始化新实例 ---
|
||||||
conversation_instance: Optional[Conversation] = None
|
conversation_instance: Optional[Conversation] = None
|
||||||
try:
|
try:
|
||||||
|
|
@ -120,19 +121,24 @@ class PFCManager:
|
||||||
await conversation._initialize() # 调用实例自身的初始化方法
|
await conversation._initialize() # 调用实例自身的初始化方法
|
||||||
# 注意:初始化成功与否由 conversation._initialized 和 conversation.should_continue 标志决定
|
# 注意:初始化成功与否由 conversation._initialized 和 conversation.should_continue 标志决定
|
||||||
if conversation._initialized:
|
if conversation._initialized:
|
||||||
logger.info(f"[私聊][{private_name}] conversation._initialize() 调用完成,实例标记为已初始化: {stream_id}")
|
logger.info(
|
||||||
|
f"[私聊][{private_name}] conversation._initialize() 调用完成,实例标记为已初始化: {stream_id}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[私聊][{private_name}] conversation._initialize() 调用完成,但实例未成功标记为已初始化: {stream_id}")
|
logger.warning(
|
||||||
|
f"[私聊][{private_name}] conversation._initialize() 调用完成,但实例未成功标记为已初始化: {stream_id}"
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# _initialize 内部应该处理自己的异常,但这里也捕获以防万一
|
# _initialize 内部应该处理自己的异常,但这里也捕获以防万一
|
||||||
logger.error(f"[私聊][{private_name}] 调用 conversation._initialize() 时发生未捕获错误: {stream_id}, 错误: {e}")
|
logger.error(
|
||||||
|
f"[私聊][{private_name}] 调用 conversation._initialize() 时发生未捕获错误: {stream_id}, 错误: {e}"
|
||||||
|
)
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
# 确保实例状态反映失败
|
# 确保实例状态反映失败
|
||||||
conversation._initialized = False
|
conversation._initialized = False
|
||||||
conversation.should_continue = False
|
conversation.should_continue = False
|
||||||
|
|
||||||
|
|
||||||
async def _cleanup_conversation(self, conversation: Conversation):
|
async def _cleanup_conversation(self, conversation: Conversation):
|
||||||
"""清理会话实例的资源"""
|
"""清理会话实例的资源"""
|
||||||
if not conversation:
|
if not conversation:
|
||||||
|
|
@ -142,14 +148,14 @@ class PFCManager:
|
||||||
logger.info(f"[私聊][{private_name}] 开始清理会话实例资源: {stream_id}")
|
logger.info(f"[私聊][{private_name}] 开始清理会话实例资源: {stream_id}")
|
||||||
try:
|
try:
|
||||||
# 调用 conversation 的 stop 方法来停止其内部组件
|
# 调用 conversation 的 stop 方法来停止其内部组件
|
||||||
if hasattr(conversation, 'stop') and callable(conversation.stop):
|
if hasattr(conversation, "stop") and callable(conversation.stop):
|
||||||
await conversation.stop() # stop 方法应处理内部组件的停止
|
await conversation.stop() # stop 方法应处理内部组件的停止
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[私聊][{private_name}] Conversation 对象缺少 stop 方法,可能无法完全清理资源。")
|
logger.warning(f"[私聊][{private_name}] Conversation 对象缺少 stop 方法,可能无法完全清理资源。")
|
||||||
# 尝试手动停止已知组件 (作为后备)
|
# 尝试手动停止已知组件 (作为后备)
|
||||||
if hasattr(conversation, 'idle_conversation_starter') and conversation.idle_conversation_starter:
|
if hasattr(conversation, "idle_conversation_starter") and conversation.idle_conversation_starter:
|
||||||
conversation.idle_conversation_starter.stop()
|
conversation.idle_conversation_starter.stop()
|
||||||
if hasattr(conversation, 'observation_info') and conversation.observation_info:
|
if hasattr(conversation, "observation_info") and conversation.observation_info:
|
||||||
conversation.observation_info.unbind_from_chat_observer()
|
conversation.observation_info.unbind_from_chat_observer()
|
||||||
# ChatObserver 是单例,不在此处停止
|
# ChatObserver 是单例,不在此处停止
|
||||||
|
|
||||||
|
|
@ -163,9 +169,11 @@ class PFCManager:
|
||||||
instance = self._instances.get(stream_id)
|
instance = self._instances.get(stream_id)
|
||||||
if instance and instance._initialized and instance.should_continue:
|
if instance and instance._initialized and instance.should_continue:
|
||||||
# 检查忽略状态
|
# 检查忽略状态
|
||||||
if (hasattr(instance, "ignore_until_timestamp") and
|
if (
|
||||||
instance.ignore_until_timestamp and
|
hasattr(instance, "ignore_until_timestamp")
|
||||||
time.time() < instance.ignore_until_timestamp):
|
and instance.ignore_until_timestamp
|
||||||
|
and time.time() < instance.ignore_until_timestamp
|
||||||
|
):
|
||||||
return None # 忽略期间不返回
|
return None # 忽略期间不返回
|
||||||
return instance
|
return instance
|
||||||
return None # 不存在或无效则返回 None
|
return None # 不存在或无效则返回 None
|
||||||
|
|
@ -188,4 +196,3 @@ class PFCManager:
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[管理器] 尝试移除不存在的会话实例: {stream_id}")
|
logger.warning(f"[管理器] 尝试移除不存在的会话实例: {stream_id}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,3 @@ class ConversationState(Enum):
|
||||||
|
|
||||||
|
|
||||||
ActionType = Literal["direct_reply", "fetch_knowledge", "wait"]
|
ActionType = Literal["direct_reply", "fetch_knowledge", "wait"]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue