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