230 lines
8.7 KiB
Python
230 lines
8.7 KiB
Python
import asyncio
|
||
import datetime
|
||
from typing import Dict, Any
|
||
from ..chat.message import Message
|
||
from .pfc_types import ConversationState
|
||
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 src.plugins.chat.chat_stream import chat_manager
|
||
from .pfc_KnowledgeFetcher import KnowledgeFetcher
|
||
import traceback
|
||
|
||
logger = get_module_logger("pfc_conversation")
|
||
|
||
|
||
class Conversation:
|
||
"""对话类,负责管理单个对话的状态和行为"""
|
||
|
||
def __init__(self, stream_id: str):
|
||
"""初始化对话实例
|
||
|
||
Args:
|
||
stream_id: 聊天流ID
|
||
"""
|
||
self.stream_id = stream_id
|
||
self.state = ConversationState.INIT
|
||
self.should_continue = False
|
||
|
||
# 回复相关
|
||
self.generated_reply = ""
|
||
|
||
async def _initialize(self):
|
||
"""初始化实例,注册所有组件"""
|
||
|
||
try:
|
||
self.action_planner = ActionPlanner(self.stream_id)
|
||
self.goal_analyzer = GoalAnalyzer(self.stream_id)
|
||
self.reply_generator = ReplyGenerator(self.stream_id)
|
||
self.knowledge_fetcher = KnowledgeFetcher()
|
||
self.waiter = Waiter(self.stream_id)
|
||
self.direct_sender = DirectMessageSender()
|
||
|
||
# 获取聊天流信息
|
||
self.chat_stream = chat_manager.get_stream(self.stream_id)
|
||
|
||
self.stop_action_planner = False
|
||
except Exception as e:
|
||
logger.error(f"初始化对话实例:注册运行组件失败: {e}")
|
||
logger.error(traceback.format_exc())
|
||
raise
|
||
|
||
try:
|
||
# 决策所需要的信息,包括自身自信和观察信息两部分
|
||
# 注册观察器和观测信息
|
||
self.chat_observer = ChatObserver.get_instance(self.stream_id)
|
||
self.chat_observer.start()
|
||
self.observation_info = ObservationInfo()
|
||
self.observation_info.bind_to_chat_observer(self.chat_observer)
|
||
# print(self.chat_observer.get_cached_messages(limit=)
|
||
|
||
|
||
self.conversation_info = ConversationInfo()
|
||
except Exception as e:
|
||
logger.error(f"初始化对话实例:注册信息组件失败: {e}")
|
||
logger.error(traceback.format_exc())
|
||
raise
|
||
|
||
# 组件准备完成,启动该论对话
|
||
self.should_continue = True
|
||
asyncio.create_task(self.start())
|
||
|
||
async def start(self):
|
||
"""开始对话流程"""
|
||
try:
|
||
logger.info("对话系统启动中...")
|
||
asyncio.create_task(self._plan_and_action_loop())
|
||
except Exception as e:
|
||
logger.error(f"启动对话系统失败: {e}")
|
||
raise
|
||
|
||
async def _plan_and_action_loop(self):
|
||
"""思考步,PFC核心循环模块"""
|
||
# 获取最近的消息历史
|
||
while self.should_continue:
|
||
# 使用决策信息来辅助行动规划
|
||
action, reason = await self.action_planner.plan(self.observation_info, self.conversation_info)
|
||
if self._check_new_messages_after_planning():
|
||
continue
|
||
|
||
# 执行行动
|
||
await self._handle_action(action, reason, self.observation_info, self.conversation_info)
|
||
|
||
def _check_new_messages_after_planning(self):
|
||
"""检查在规划后是否有新消息"""
|
||
if self.observation_info.new_messages_count > 0:
|
||
logger.info(f"发现{self.observation_info.new_messages_count}条新消息,可能需要重新考虑行动")
|
||
# 如果需要,可以在这里添加逻辑来根据新消息重新决定行动
|
||
return True
|
||
return False
|
||
|
||
def _convert_to_message(self, msg_dict: Dict[str, Any]) -> Message:
|
||
"""将消息字典转换为Message对象"""
|
||
try:
|
||
chat_info = msg_dict.get("chat_info", {})
|
||
chat_stream = ChatStream.from_dict(chat_info)
|
||
user_info = UserInfo.from_dict(msg_dict.get("user_info", {}))
|
||
|
||
return Message(
|
||
message_id=msg_dict["message_id"],
|
||
chat_stream=chat_stream,
|
||
time=msg_dict["time"],
|
||
user_info=user_info,
|
||
processed_plain_text=msg_dict.get("processed_plain_text", ""),
|
||
detailed_plain_text=msg_dict.get("detailed_plain_text", ""),
|
||
)
|
||
except Exception as e:
|
||
logger.warning(f"转换消息时出错: {e}")
|
||
raise
|
||
|
||
async def _handle_action(
|
||
self, action: str, reason: str, observation_info: ObservationInfo, conversation_info: ConversationInfo
|
||
):
|
||
"""处理规划的行动"""
|
||
logger.info(f"执行行动: {action}, 原因: {reason}")
|
||
|
||
# 记录action历史,先设置为stop,完成后再设置为done
|
||
conversation_info.done_action.append(
|
||
{
|
||
"action": action,
|
||
"reason": reason,
|
||
"status": "start",
|
||
"time": datetime.datetime.now().strftime("%H:%M:%S"),
|
||
}
|
||
)
|
||
|
||
if action == "direct_reply":
|
||
self.state = ConversationState.GENERATING
|
||
self.generated_reply = await self.reply_generator.generate(observation_info, conversation_info)
|
||
print(f"生成回复: {self.generated_reply}")
|
||
|
||
# # 检查回复是否合适
|
||
# is_suitable, reason, need_replan = await self.reply_generator.check_reply(
|
||
# self.generated_reply,
|
||
# self.current_goal
|
||
# )
|
||
|
||
if self._check_new_messages_after_planning():
|
||
logger.info("333333发现新消息,重新考虑行动")
|
||
return None
|
||
|
||
await self._send_reply()
|
||
|
||
conversation_info.done_action.append(
|
||
{
|
||
"action": action,
|
||
"reason": reason,
|
||
"status": "done",
|
||
"time": datetime.datetime.now().strftime("%H:%M:%S"),
|
||
}
|
||
)
|
||
|
||
elif action == "fetch_knowledge":
|
||
self.state = ConversationState.FETCHING
|
||
knowledge = "TODO:知识"
|
||
topic = "TODO:关键词"
|
||
|
||
logger.info(f"假装获取到知识{knowledge},关键词是: {topic}")
|
||
|
||
if knowledge:
|
||
if topic not in self.conversation_info.knowledge_list:
|
||
self.conversation_info.knowledge_list.append({"topic": topic, "knowledge": knowledge})
|
||
else:
|
||
self.conversation_info.knowledge_list[topic] += knowledge
|
||
|
||
elif action == "rethink_goal":
|
||
self.state = ConversationState.RETHINKING
|
||
await self.goal_analyzer.analyze_goal(conversation_info, observation_info)
|
||
|
||
elif action == "listening":
|
||
self.state = ConversationState.LISTENING
|
||
logger.info("倾听对方发言...")
|
||
if await self.waiter.wait(): # 如果返回True表示超时
|
||
await self._send_timeout_message()
|
||
await self._stop_conversation()
|
||
|
||
else: # wait
|
||
self.state = ConversationState.WAITING
|
||
logger.info("等待更多信息...")
|
||
if await self.waiter.wait(): # 如果返回True表示超时
|
||
await self._send_timeout_message()
|
||
await self._stop_conversation()
|
||
|
||
async def _send_timeout_message(self):
|
||
"""发送超时结束消息"""
|
||
try:
|
||
messages = self.chat_observer.get_cached_messages(limit=1)
|
||
if not messages:
|
||
return
|
||
|
||
latest_message = self._convert_to_message(messages[0])
|
||
await self.direct_sender.send_message(
|
||
chat_stream=self.chat_stream, content="TODO:超时消息", reply_to_message=latest_message
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"发送超时消息失败: {str(e)}")
|
||
|
||
async def _send_reply(self):
|
||
"""发送回复"""
|
||
if not self.generated_reply:
|
||
logger.warning("没有生成回复")
|
||
return
|
||
|
||
try:
|
||
await self.direct_sender.send_message(
|
||
chat_stream=self.chat_stream, content=self.generated_reply
|
||
)
|
||
self.chat_observer.trigger_update() # 触发立即更新
|
||
if not await self.chat_observer.wait_for_update():
|
||
logger.warning("等待消息更新超时")
|
||
|
||
self.state = ConversationState.ANALYZING
|
||
except Exception as e:
|
||
logger.error(f"发送消息失败: {str(e)}")
|
||
self.state = ConversationState.ANALYZING
|