mirror of https://github.com/Mai-with-u/MaiBot.git
336 lines
18 KiB
Python
336 lines
18 KiB
Python
import time
|
||
import traceback
|
||
from typing import TYPE_CHECKING
|
||
|
||
from src.common.logger_manager import get_logger
|
||
from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat
|
||
from maim_message import UserInfo
|
||
from src.plugins.chat.chat_stream import chat_manager
|
||
from src.config.config import global_config
|
||
|
||
# 导入 PFC 内部组件和类型
|
||
from .pfc_types import ConversationState
|
||
from .pfc import GoalAnalyzer
|
||
from .chat_observer import ChatObserver
|
||
from .message_sender import DirectMessageSender
|
||
from .action_planner import ActionPlanner
|
||
from .observation_info import ObservationInfo
|
||
from .conversation_info import ConversationInfo
|
||
from .reply_generator import ReplyGenerator
|
||
from .PFC_idle.idle_chat import IdleChat
|
||
from .pfc_KnowledgeFetcher import KnowledgeFetcher # 修正大小写
|
||
from .waiter import Waiter
|
||
from .pfc_utils import get_person_id
|
||
from .reply_checker import ReplyChecker
|
||
from .pfc_relationship import PfcRelationshipUpdater, PfcRepationshipTranslator
|
||
from .pfc_emotion import PfcEmotionUpdater
|
||
|
||
|
||
if TYPE_CHECKING:
|
||
from .conversation import Conversation # 用于类型提示以避免循环导入
|
||
|
||
logger = get_logger("pfc_initializer")
|
||
|
||
|
||
async def load_initial_history(conversation_instance: "Conversation"):
|
||
"""
|
||
加载并处理初始的聊天记录。
|
||
之前是 Conversation 类中的 _load_initial_history 方法。
|
||
"""
|
||
if not conversation_instance.observation_info: # 确保 ObservationInfo 已初始化
|
||
logger.warning(f"[私聊][{conversation_instance.private_name}] ObservationInfo 未初始化,无法加载历史记录。")
|
||
return
|
||
|
||
try:
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] 为 {conversation_instance.stream_id} 加载初始聊天记录..."
|
||
)
|
||
# 从聊天核心获取原始消息列表
|
||
initial_messages = get_raw_msg_before_timestamp_with_chat(
|
||
chat_id=conversation_instance.stream_id,
|
||
timestamp=time.time(),
|
||
limit=30, # limit 可以根据需要调整或配置
|
||
)
|
||
|
||
if initial_messages:
|
||
# 更新 ObservationInfo 中的历史记录列表和计数
|
||
conversation_instance.observation_info.chat_history = initial_messages
|
||
conversation_instance.observation_info.chat_history_count = len(initial_messages)
|
||
|
||
# 获取最后一条消息的信息
|
||
last_msg = initial_messages[-1]
|
||
conversation_instance.observation_info.last_message_time = last_msg.get("time")
|
||
conversation_instance.observation_info.last_message_id = last_msg.get("message_id")
|
||
|
||
# 安全地解析最后一条消息的发送者信息
|
||
last_user_info_dict = last_msg.get("user_info", {})
|
||
if isinstance(last_user_info_dict, dict):
|
||
try:
|
||
last_user_info = UserInfo.from_dict(last_user_info_dict)
|
||
# 存储发送者的 user_id 字符串
|
||
conversation_instance.observation_info.last_message_sender = (
|
||
str(last_user_info.user_id) if last_user_info else None
|
||
)
|
||
except Exception as e:
|
||
logger.warning(
|
||
f"[私聊][{conversation_instance.private_name}] 解析最后一条消息的用户信息时出错: {e}"
|
||
)
|
||
conversation_instance.observation_info.last_message_sender = None
|
||
else:
|
||
# 如果 user_info 不是字典,也标记为未知
|
||
conversation_instance.observation_info.last_message_sender = None
|
||
|
||
# 存储最后一条消息的文本内容
|
||
conversation_instance.observation_info.last_message_content = last_msg.get("processed_plain_text", "")
|
||
|
||
# 构建用于 Prompt 的历史记录字符串 (只使用最近的一部分)
|
||
history_slice_for_str = initial_messages[-30:] # 可配置
|
||
conversation_instance.observation_info.chat_history_str = await build_readable_messages(
|
||
history_slice_for_str,
|
||
replace_bot_name=True,
|
||
merge_messages=False,
|
||
timestamp_mode="relative",
|
||
read_mark=0.0, # read_mark 可能需要根据实际情况调整
|
||
)
|
||
|
||
# 更新 ChatObserver 和 IdleChat 的时间戳
|
||
if conversation_instance.chat_observer:
|
||
# 更新观察者的最后消息时间,避免重复处理这些初始消息
|
||
conversation_instance.chat_observer.last_message_time = (
|
||
conversation_instance.observation_info.last_message_time
|
||
)
|
||
if conversation_instance.idle_chat and conversation_instance.observation_info.last_message_time:
|
||
# 更新空闲计时器的起始时间
|
||
await conversation_instance.idle_chat.update_last_message_time(
|
||
conversation_instance.observation_info.last_message_time
|
||
)
|
||
|
||
logger.info(
|
||
f"[私聊][{conversation_instance.private_name}] 成功加载 {len(initial_messages)} 条初始聊天记录。最后一条消息时间: {conversation_instance.observation_info.last_message_time}"
|
||
)
|
||
else:
|
||
# 如果没有历史记录
|
||
logger.info(f"[私聊][{conversation_instance.private_name}] 没有找到初始聊天记录。")
|
||
conversation_instance.observation_info.chat_history_str = "还没有聊天记录。" # 设置默认提示
|
||
|
||
except Exception as load_err:
|
||
# 捕获加载过程中的异常
|
||
logger.error(f"[私聊][{conversation_instance.private_name}] 加载初始聊天记录时出错: {load_err}")
|
||
# 即使出错,也设置一个提示,避免后续使用 None 值
|
||
if conversation_instance.observation_info:
|
||
conversation_instance.observation_info.chat_history_str = "[加载聊天记录出错]"
|
||
|
||
|
||
async def initialize_core_components(conversation_instance: "Conversation"):
|
||
"""
|
||
异步初始化对话实例及其所有依赖的核心组件。
|
||
之前是 Conversation 类中的 _initialize 方法。
|
||
"""
|
||
# 防止重复初始化 (在 PFCManager层面已经有 _initializing 标志,这里可以简化或移除)
|
||
# if conversation_instance._initialized or conversation_instance._initializing_flag_from_manager: # 假设 manager 设置了一个标志
|
||
# logger.warning(f"[私聊][{conversation_instance.private_name}] 尝试重复初始化或正在初始化中 (initializer)。")
|
||
# return
|
||
|
||
# conversation_instance._initializing_flag_from_manager = True # 标记开始初始化
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 开始初始化对话实例核心组件: {conversation_instance.stream_id}"
|
||
)
|
||
|
||
try:
|
||
# 1. 初始化核心功能组件
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 ActionPlanner...")
|
||
conversation_instance.action_planner = ActionPlanner(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
|
||
conversation_instance.relationship_updater = PfcRelationshipUpdater(
|
||
private_name=conversation_instance.private_name, bot_name=global_config.BOT_NICKNAME
|
||
)
|
||
conversation_instance.relationship_translator = PfcRepationshipTranslator(
|
||
private_name=conversation_instance.private_name
|
||
)
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) PfcRelationship 初始化完成。")
|
||
|
||
conversation_instance.emotion_updater = PfcEmotionUpdater(
|
||
private_name=conversation_instance.private_name, bot_name=global_config.BOT_NICKNAME
|
||
)
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) PfcEmotion 初始化完成。")
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 GoalAnalyzer...")
|
||
conversation_instance.goal_analyzer = GoalAnalyzer(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 ReplyGenerator...")
|
||
conversation_instance.reply_generator = ReplyGenerator(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 KnowledgeFetcher...")
|
||
conversation_instance.knowledge_fetcher = KnowledgeFetcher(conversation_instance.private_name)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 Waiter...")
|
||
conversation_instance.waiter = Waiter(conversation_instance.stream_id, conversation_instance.private_name)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 DirectMessageSender...")
|
||
conversation_instance.direct_sender = DirectMessageSender(conversation_instance.private_name)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 ReplyChecker...")
|
||
conversation_instance.reply_checker = ReplyChecker(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
|
||
# 获取关联的 ChatStream
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 获取 ChatStream...")
|
||
conversation_instance.chat_stream = chat_manager.get_stream(conversation_instance.stream_id)
|
||
if not conversation_instance.chat_stream:
|
||
logger.error(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化错误:无法从 chat_manager 获取 stream_id {conversation_instance.stream_id} 的 ChatStream。"
|
||
)
|
||
raise ValueError(f"无法获取 stream_id {conversation_instance.stream_id} 的 ChatStream")
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 IdleChat...")
|
||
conversation_instance.idle_chat = IdleChat.get_instance(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
await conversation_instance.idle_chat.increment_active_instances()
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) IdleChat实例已获取并增加活跃计数")
|
||
|
||
# 2. 初始化信息存储和观察组件
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 获取 ChatObserver 实例...")
|
||
conversation_instance.chat_observer = ChatObserver.get_instance(
|
||
conversation_instance.stream_id, conversation_instance.private_name
|
||
)
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 ObservationInfo...")
|
||
conversation_instance.observation_info = ObservationInfo(conversation_instance.private_name)
|
||
if not conversation_instance.observation_info.bot_id: # 确保 ObservationInfo 知道机器人的 ID
|
||
logger.warning(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) ObservationInfo 未能自动获取 bot_id,尝试手动设置。"
|
||
)
|
||
conversation_instance.observation_info.bot_id = conversation_instance.bot_qq_str
|
||
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化 ConversationInfo...")
|
||
conversation_instance.conversation_info = ConversationInfo()
|
||
|
||
# 3. 绑定观察者和信息处理器
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 绑定 ObservationInfo 到 ChatObserver..."
|
||
)
|
||
if conversation_instance.observation_info and conversation_instance.chat_observer: # 确保二者都存在
|
||
conversation_instance.observation_info.bind_to_chat_observer(conversation_instance.chat_observer)
|
||
|
||
# 4. 加载初始聊天记录 (调用本文件内的函数)
|
||
await load_initial_history(conversation_instance)
|
||
|
||
# 4.1 加载用户数据
|
||
if (
|
||
conversation_instance.conversation_info and conversation_instance.chat_stream
|
||
): # 确保 conversation_info 和 chat_stream 都存在
|
||
person_id_tuple = await get_person_id(
|
||
private_name=conversation_instance.private_name,
|
||
chat_stream=conversation_instance.chat_stream,
|
||
)
|
||
if person_id_tuple: # 确保元组不为空
|
||
conversation_instance.conversation_info.person_id = person_id_tuple[0] # 第一个元素是 person_id
|
||
private_platform_str = person_id_tuple[1]
|
||
private_user_id_str = person_id_tuple[2]
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 获取到 person_id: {conversation_instance.conversation_info.person_id} for {private_platform_str}:{private_user_id_str}"
|
||
)
|
||
else:
|
||
logger.warning(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 未能从 get_person_id 获取到 person_id 相关信息。"
|
||
)
|
||
|
||
# 5. 启动需要后台运行的组件
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 启动 ChatObserver...")
|
||
if conversation_instance.chat_observer: # 确保存在
|
||
conversation_instance.chat_observer.start()
|
||
|
||
if conversation_instance.idle_chat:
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) 启动 IdleChat...")
|
||
# 不需要再次启动,只需确保已初始化
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) IdleChat实例已初始化")
|
||
|
||
if (
|
||
conversation_instance.mood_mng
|
||
and hasattr(conversation_instance.mood_mng, "start_mood_update")
|
||
and not conversation_instance.mood_mng._running
|
||
): # type: ignore
|
||
conversation_instance.mood_mng.start_mood_update(update_interval=global_config.mood_update_interval) # type: ignore
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) MoodManager 已启动后台更新,间隔: {global_config.mood_update_interval} 秒。"
|
||
)
|
||
elif conversation_instance.mood_mng and conversation_instance.mood_mng._running: # type: ignore
|
||
logger.debug(f"[私聊][{conversation_instance.private_name}] (Initializer) MoodManager 已在运行中。")
|
||
else:
|
||
logger.warning(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) MoodManager 未能启动,相关功能可能受限。"
|
||
)
|
||
|
||
if (
|
||
conversation_instance.conversation_info
|
||
and conversation_instance.conversation_info.person_id
|
||
and conversation_instance.relationship_translator
|
||
and conversation_instance.person_info_mng
|
||
): # 确保都存在
|
||
try:
|
||
numeric_relationship_value = await conversation_instance.person_info_mng.get_value(
|
||
conversation_instance.conversation_info.person_id, "relationship_value"
|
||
)
|
||
if not isinstance(numeric_relationship_value, (int, float)):
|
||
from bson.decimal128 import Decimal128
|
||
|
||
if isinstance(numeric_relationship_value, Decimal128):
|
||
numeric_relationship_value = float(numeric_relationship_value.to_decimal())
|
||
else:
|
||
numeric_relationship_value = 0.0
|
||
conversation_instance.conversation_info.relationship_text = (
|
||
await conversation_instance.relationship_translator.translate_relationship_value_to_text(
|
||
numeric_relationship_value
|
||
)
|
||
)
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化时加载关系文本: {conversation_instance.conversation_info.relationship_text}"
|
||
)
|
||
except Exception as e_init_rel:
|
||
logger.error(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化时加载关系文本出错: {e_init_rel}"
|
||
)
|
||
conversation_instance.conversation_info.relationship_text = "你们的关系是:普通。"
|
||
|
||
if conversation_instance.conversation_info and conversation_instance.mood_mng: # 确保都存在
|
||
try:
|
||
conversation_instance.conversation_info.current_emotion_text = (
|
||
conversation_instance.mood_mng.get_prompt()
|
||
) # type: ignore
|
||
logger.debug(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化时加载情绪文本: {conversation_instance.conversation_info.current_emotion_text}"
|
||
)
|
||
except Exception as e_init_emo:
|
||
logger.error(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化时加载情绪文本出错: {e_init_emo}"
|
||
)
|
||
# 保留 ConversationInfo 中的默认值
|
||
|
||
# 6. 标记初始化成功并设置运行状态 (这些标志由PFCManager控制和检查)
|
||
# conversation_instance._initialized = True -> 由 manager 设置
|
||
# conversation_instance.should_continue = True -> 由 manager 设置
|
||
conversation_instance.state = ConversationState.ANALYZING # 设置初始状态为分析
|
||
|
||
logger.info(
|
||
f"[私聊][{conversation_instance.private_name}] (Initializer) 对话实例 {conversation_instance.stream_id} 核心组件初始化完成。"
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"[私聊][{conversation_instance.private_name}] (Initializer) 初始化对话实例核心组件失败: {e}")
|
||
logger.error(f"[私聊][{conversation_instance.private_name}] (Initializer) {traceback.format_exc()}")
|
||
# conversation_instance.should_continue = False # 由 manager 处理
|
||
# conversation_instance._initialized = False # 由 manager 处理
|
||
# 外部(PFCManager)会捕获这个异常并处理 should_continue 和 _initialized 标志
|
||
# 以及调用 conversation_instance.stop()
|
||
raise # 将异常重新抛出,通知 PFCManager 初始化失败
|
||
# finally:
|
||
# conversation_instance._initializing_flag_from_manager = False # 清除标志
|