diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index d4f13452e..ad69fea1d 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -1,14 +1,12 @@ -import datetime -from typing import List, Dict, Tuple +from typing import Tuple from src.common.logger import get_module_logger -from ..message.message_base import UserInfo from ..models.utils_model import LLM_request from ..config.config import global_config from .chat_observer import ChatObserver from .pfc_utils import get_items_from_json from src.individuality.individuality import Individuality from .observation_info import ObservationInfo -from .conversation import ConversationInfo +from .conversation_info import ConversationInfo logger = get_module_logger("action_planner") @@ -78,7 +76,7 @@ class ActionPlanner: personality_text = f"你的名字是{self.name},{self.personality_info}" # 构建action历史文本 - action_history_list = conversation_info.action_history + action_history_list = conversation_info.done_action action_history_text = "你之前做的事情是:" for action in action_history_list: action_history_text += f"{action}\n" diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 0d9457980..fecac1523 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -3,30 +3,20 @@ import datetime from typing import Dict, Any from ..chat.message import Message from .pfc_types import ConversationState -from .pfc import ChatObserver, GoalAnalyzer, Waiter, DirectMessageSender, PFCNotificationHandler +from .pfc import ChatObserver, GoalAnalyzer, Waiter, DirectMessageSender from src.common.logger import get_module_logger from .action_planner import ActionPlanner from .observation_info import ObservationInfo +from .conversation_info import ConversationInfo from .reply_generator import ReplyGenerator from ..chat.chat_stream import ChatStream from ..message.message_base import UserInfo -from ..config.config import global_config from src.plugins.chat.chat_stream import chat_manager from .pfc_KnowledgeFetcher import KnowledgeFetcher -from .chat_states import NotificationType -import time import traceback logger = get_module_logger("pfc_conversation") -class ConversationInfo: - def __init__(self): - self.done_action = [] - self.goal_list = [] - self.knowledge_list = [] - self.memory_list = [] - - class Conversation: """对话类,负责管理单个对话的状态和行为""" @@ -58,9 +48,6 @@ class Conversation: # 获取聊天流信息 self.chat_stream = chat_manager.get_stream(self.stream_id) - # 创建通知处理器 - self.notification_handler = PFCNotificationHandler(self) - self.stop_action_planner = False except Exception as e: logger.error(f"初始化对话实例:注册运行组件失败: {e}") @@ -113,7 +100,7 @@ class Conversation: # 执行行动 await self._handle_action(action, reason, self.observation_info, self.conversation_info) - async def _check_new_messages_after_planning(self): + def _check_new_messages_after_planning(self): """检查在规划后是否有新消息""" if self.observation_info.new_messages_count > 0: logger.info(f"发现{self.observation_info.new_messages_count}条新消息,可能需要重新考虑行动") @@ -146,33 +133,33 @@ class Conversation: logger.info(f"执行行动: {action}, 原因: {reason}") # 记录action历史,先设置为stop,完成后再设置为done - conversation_info.action_history.append({ + conversation_info.done_action.append({ "action": action, "reason": reason, - "status": "stop", + "status": "start", "time": datetime.datetime.now().strftime("%H:%M:%S") }) if action == "direct_reply": self.state = ConversationState.GENERATING - messages = self.chat_observer.get_message_history(limit=30) self.generated_reply = await self.reply_generator.generate( - self.current_goal, - self.current_method, - [self._convert_to_message(msg) for msg in messages], - self.knowledge_cache + observation_info, + conversation_info ) - # 检查回复是否合适 - is_suitable, reason, need_replan = await self.reply_generator.check_reply( - self.generated_reply, - self.current_goal - ) + # # 检查回复是否合适 + # is_suitable, reason, need_replan = await self.reply_generator.check_reply( + # self.generated_reply, + # self.current_goal + # ) + + if self._check_new_messages_after_planning(): + return None await self._send_reply() - conversation_info.action_history.append({ + conversation_info.done_action.append({ "action": action, "reason": reason, "status": "done", @@ -197,9 +184,8 @@ class Conversation: elif action == "rethink_goal": self.state = ConversationState.RETHINKING - goal_list = observation_info.goal_list - new_goal_list = await self.goal_analyzer.analyze_goal(goal_list) - observation_info.goal_list = new_goal_list + await self.goal_analyzer.analyze_goal(conversation_info, observation_info) + elif action == "listening": self.state = ConversationState.LISTENING diff --git a/src/plugins/PFC/conversation_info.py b/src/plugins/PFC/conversation_info.py new file mode 100644 index 000000000..5b8262a16 --- /dev/null +++ b/src/plugins/PFC/conversation_info.py @@ -0,0 +1,8 @@ + + +class ConversationInfo: + def __init__(self): + self.done_action = [] + self.goal_list = [] + self.knowledge_list = [] + self.memory_list = [] \ No newline at end of file diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index 96c147650..25c4728e0 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -15,14 +15,12 @@ from ..storage.storage import MessageStorage from .chat_observer import ChatObserver from .pfc_utils import get_items_from_json from src.individuality.individuality import Individuality -from .chat_states import NotificationHandler, Notification, NotificationType -from .waiter import Waiter -from .message_sender import DirectMessageSender -from .notification_handler import PFCNotificationHandler +from .conversation_info import ConversationInfo +from .observation_info import ObservationInfo import time if TYPE_CHECKING: - from .conversation import Conversation + pass logger = get_module_logger("pfc") @@ -45,42 +43,55 @@ class GoalAnalyzer: self.max_goals = 3 # 同时保持的最大目标数量 self.current_goal_and_reason = None - async def analyze_goal(self) -> Tuple[str, str, str]: + async def analyze_goal(self, conversation_info: ConversationInfo, observation_info: ObservationInfo): """分析对话历史并设定目标 Args: - chat_history: 聊天历史记录列表 - + conversation_info: 对话信息 + observation_info: 观察信息 + Returns: Tuple[str, str, str]: (目标, 方法, 原因) """ - max_retries = 3 - for retry in range(max_retries): - try: - # 构建提示词 - messages = self.chat_observer.get_message_history(limit=20) - chat_history_text = "" - for msg in messages: - time_str = datetime.datetime.fromtimestamp(msg["time"]).strftime("%H:%M:%S") - user_info = UserInfo.from_dict(msg.get("user_info", {})) - sender = user_info.user_nickname or f"用户{user_info.user_id}" - if sender == self.name: - sender = "你说" - chat_history_text += f"{time_str},{sender}:{msg.get('processed_plain_text', '')}\n" - - personality_text = f"你的名字是{self.name},{self.personality_info}" - - # 构建当前已有目标的文本 - existing_goals_text = "" - if self.goals: - existing_goals_text = "当前已有的对话目标:\n" - for i, (goal, _, reason) in enumerate(self.goals): - existing_goals_text += f"{i + 1}. 目标: {goal}, 原因: {reason}\n" - - prompt = f"""{personality_text}。现在你在参与一场QQ聊天,请分析以下聊天记录,并根据你的性格特征确定多个明确的对话目标。 + #构建对话目标 + goal_list = conversation_info.goal_list + goal_text = "" + for goal, reason in goal_list: + goal_text += f"目标:{goal};" + goal_text += f"原因:{reason}\n" + + + # 获取聊天历史记录 + chat_history_list = observation_info.chat_history + chat_history_text = "" + for msg in chat_history_list: + chat_history_text += f"{msg}\n" + + if observation_info.new_messages_count > 0: + new_messages_list = observation_info.unprocessed_messages + + chat_history_text += f"有{observation_info.new_messages_count}条新消息:\n" + for msg in new_messages_list: + chat_history_text += f"{msg}\n" + + observation_info.clear_unprocessed_messages() + + + personality_text = f"你的名字是{self.name},{self.personality_info}" + + # 构建action历史文本 + action_history_list = conversation_info.done_action + action_history_text = "你之前做的事情是:" + for action in action_history_list: + action_history_text += f"{action}\n" + + + prompt = f"""{personality_text}。现在你在参与一场QQ聊天,请分析以下聊天记录,并根据你的性格特征确定多个明确的对话目标。 这些目标应该反映出对话的不同方面和意图。 -{existing_goals_text} +{action_history_text} +当前对话目标: +{goal_text} 聊天记录: {chat_history_text} @@ -91,54 +102,37 @@ class GoalAnalyzer: 3. 添加新目标 4. 删除不再相关的目标 -请以JSON格式输出一个当前最主要的对话目标,包含以下字段: +请以JSON格式输出当前的所有对话目标,包含以下字段: 1. goal: 对话目标(简短的一句话) 2. reasoning: 对话原因,为什么设定这个目标(简要解释) 输出格式示例: {{ - "goal": "回答用户关于Python编程的具体问题", - "reasoning": "用户提出了关于Python的技术问题,需要专业且准确的解答" +"goal": "回答用户关于Python编程的具体问题", +"reasoning": "用户提出了关于Python的技术问题,需要专业且准确的解答" +}}, +{{ +"goal": "回答用户关于python安装的具体问题", +"reasoning": "用户提出了关于Python的技术问题,需要专业且准确的解答" }}""" - logger.debug(f"发送到LLM的提示词: {prompt}") - content, _ = await self.llm.generate_response_async(prompt) - logger.debug(f"LLM原始返回内容: {content}") - - # 使用简化函数提取JSON内容 - success, result = get_items_from_json( - content, "goal", "reasoning", required_types={"goal": str, "reasoning": str} - ) - - if not success: - logger.error(f"无法解析JSON,重试第{retry + 1}次") - continue - - goal = result["goal"] - reasoning = result["reasoning"] - - # 使用默认的方法 - method = "以友好的态度回应" - - # 更新目标列表 - await self._update_goals(goal, method, reasoning) - - # 返回当前最主要的目标 - if self.goals: - current_goal, current_method, current_reasoning = self.goals[0] - return current_goal, current_method, current_reasoning - else: - return goal, method, reasoning - - except Exception as e: - logger.error(f"分析对话目标时出错: {str(e)},重试第{retry + 1}次") - if retry == max_retries - 1: - return "保持友好的对话", "以友好的态度回应", "确保对话顺利进行" - continue - - # 所有重试都失败后的默认返回 - return "保持友好的对话", "以友好的态度回应", "确保对话顺利进行" + logger.debug(f"发送到LLM的提示词: {prompt}") + content, _ = await self.llm.generate_response_async(prompt) + logger.debug(f"LLM原始返回内容: {content}") + + # 使用简化函数提取JSON内容 + success, result = get_items_from_json( + content, + "goal", "reasoning", + required_types={"goal": str, "reasoning": str} + ) + #TODO + + + conversation_info.goal_list.append(result) + + async def _update_goals(self, new_goal: str, method: str, reasoning: str): """更新目标列表 diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index 6ef5f1e20..beec9dd3e 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -1,13 +1,12 @@ -import datetime -from typing import List, Optional, Dict, Tuple +from typing import Tuple from src.common.logger import get_module_logger -from ..message.message_base import UserInfo -from ..chat.message import Message from ..models.utils_model import LLM_request from ..config.config import global_config from .chat_observer import ChatObserver from .reply_checker import ReplyChecker from src.individuality.individuality import Individuality +from .observation_info import ObservationInfo +from .conversation_info import ConversationInfo logger = get_module_logger("reply_generator") @@ -29,11 +28,8 @@ class ReplyGenerator: async def generate( self, - goal: str, - chat_history: List[Message], - knowledge_cache: Dict[str, str], - previous_reply: Optional[str] = None, - retry_count: int = 0 + observation_info: ObservationInfo, + conversation_info: ConversationInfo ) -> str: """生成回复 @@ -48,44 +44,33 @@ class ReplyGenerator: str: 生成的回复 """ # 构建提示词 - logger.debug(f"开始生成回复:当前目标: {goal}") - self.chat_observer.trigger_update() # 触发立即更新 - if not await self.chat_observer.wait_for_update(): - logger.warning("等待消息更新超时") - - messages = self.chat_observer.get_message_history(limit=20) + logger.debug(f"开始生成回复:当前目标: {conversation_info.goal_list}") + + goal_list = conversation_info.goal_list + goal_text = "" + for goal, reason in goal_list: + goal_text += f"目标:{goal};" + goal_text += f"原因:{reason}\n" + + # 获取聊天历史记录 + chat_history_list = observation_info.chat_history chat_history_text = "" - for msg in messages: - time_str = datetime.datetime.fromtimestamp(msg["time"]).strftime("%H:%M:%S") - user_info = UserInfo.from_dict(msg.get("user_info", {})) - sender = user_info.user_nickname or f"用户{user_info.user_id}" - if sender == self.name: - sender = "你说" - chat_history_text += f"{time_str},{sender}:{msg.get('processed_plain_text', '')}\n" + for msg in chat_history_list: + chat_history_text += f"{msg}\n" + # 整理知识缓存 knowledge_text = "" - if knowledge_cache: - knowledge_text = "\n相关知识:" - if isinstance(knowledge_cache, dict): - for _source, content in knowledge_cache.items(): - knowledge_text += f"\n{content}" - elif isinstance(knowledge_cache, list): - for item in knowledge_cache: - knowledge_text += f"\n{item}" + knowledge_list = conversation_info.knowledge_list + for knowledge in knowledge_list: + knowledge_text += f"知识:{knowledge}\n" - # 添加上一次生成的回复信息 - previous_reply_text = "" - if previous_reply: - previous_reply_text = f"\n上一次生成的回复(需要改进):\n{previous_reply}" - personality_text = f"你的名字是{self.name},{self.personality_info}" prompt = f"""{personality_text}。现在你在参与一场QQ聊天,请根据以下信息生成回复: -当前对话目标:{goal} +当前对话目标:{goal_text} {knowledge_text} -{previous_reply_text} 最近的聊天记录: {chat_history_text} @@ -94,7 +79,6 @@ class ReplyGenerator: 2. 体现你的性格特征 3. 自然流畅,像正常聊天一样,简短 4. 适当利用相关知识,但不要生硬引用 -{'5. 改进上一次回复中的问题' if previous_reply else ''} 请注意把握聊天内容,不要回复的太有条理,可以有个性。请分清"你"和对方说的话,不要把"你"说的话当做对方说的话,这是你自己说的话。 请你回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,尽量不要说你说过的话