Merge branch 'dev' of https://github.com/MaiM-with-u/MaiBot into dev
This commit is contained in:
@@ -241,7 +241,7 @@ class ActionPlanner:
|
|||||||
last_action_context += f"- 该行动当前状态: {status}\n"
|
last_action_context += f"- 该行动当前状态: {status}\n"
|
||||||
|
|
||||||
# --- 构建最终的 Prompt ---
|
# --- 构建最终的 Prompt ---
|
||||||
prompt = f"""{persona_text}。现在你在参与一场QQ私聊,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以发言,可以等待,可以倾听,可以调取知识:
|
prompt = f"""{persona_text}。现在你在参与一场QQ私聊,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以发言,可以等待,可以倾听,可以调取知识,甚至可以屏蔽对方:
|
||||||
|
|
||||||
【当前对话目标】
|
【当前对话目标】
|
||||||
{goals_str if goals_str.strip() else "- 目前没有明确对话目标,请考虑设定一个。"}
|
{goals_str if goals_str.strip() else "- 目前没有明确对话目标,请考虑设定一个。"}
|
||||||
@@ -258,12 +258,13 @@ class ActionPlanner:
|
|||||||
|
|
||||||
------
|
------
|
||||||
可选行动类型以及解释:
|
可选行动类型以及解释:
|
||||||
etch_knowledge: 需要调取知识,当需要专业知识或特定信息时选择,对方若提到你太认识的人名或实体也可以尝试
|
fetch_knowledge: 需要调取知识,当需要专业知识或特定信息时选择,对方若提到你不太认识的人名或实体也可以尝试选择
|
||||||
wait: 暂时不说话,等待对方回复(尤其是在你刚发言后、或上次发言因重复、发言过多被拒时、或不确定做什么时,这是较安全的选择)
|
wait: 暂时不说话,等待对方回复(尤其是在你刚发言后、或上次发言因重复、发言过多被拒时、或不确定做什么时,这是较安全的选择)
|
||||||
listening: 倾听对方发言,当你认为对方话才说到一半,发言明显未结束时采用
|
listening: 倾听对方发言,当你认为对方话才说到一半,发言明显未结束时选择
|
||||||
direct_reply: 直接回复或发送新消息,允许适当的追问和深入话题,**但是避免在因重复被拒后立即使用,也不要在对方没有回复的情况下过多的“消息轰炸”或重复发言**
|
direct_reply: 直接回复或发送新消息,允许适当的追问和深入话题,**但是避免在因重复被拒后立即使用,也不要在对方没有回复的情况下过多的“消息轰炸”或重复发言**
|
||||||
rethink_goal: 重新思考对话目标,当发现对话目标不再适用或对话卡住时选择,注意私聊的环境是灵活的,有可能需要经常选择
|
rethink_goal: 重新思考对话目标,当发现对话目标不再适用或对话卡住时选择,注意私聊的环境是灵活的,有可能需要经常选择
|
||||||
end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择
|
end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择
|
||||||
|
block_and_ignore: 更加极端的结束对话方式,直接结束对话并在一段时间内无视对方所有发言(屏蔽),当对话让你感到十分不适,或你遭到各类骚扰时选择
|
||||||
|
|
||||||
请以JSON格式输出你的决策:
|
请以JSON格式输出你的决策:
|
||||||
{{
|
{{
|
||||||
@@ -289,7 +290,15 @@ end_conversation: 结束对话,对方长时间没回复或者当你觉得对
|
|||||||
reason = result.get("reason", "LLM未提供原因,默认等待")
|
reason = result.get("reason", "LLM未提供原因,默认等待")
|
||||||
|
|
||||||
# 验证action类型
|
# 验证action类型
|
||||||
valid_actions = ["direct_reply", "fetch_knowledge", "wait", "listening", "rethink_goal", "end_conversation"]
|
valid_actions = [
|
||||||
|
"direct_reply",
|
||||||
|
"fetch_knowledge",
|
||||||
|
"wait",
|
||||||
|
"listening",
|
||||||
|
"rethink_goal",
|
||||||
|
"end_conversation",
|
||||||
|
"block_and_ignore",
|
||||||
|
]
|
||||||
if action not in valid_actions:
|
if action not in valid_actions:
|
||||||
logger.warning(f"LLM返回了未知的行动类型: '{action}',强制改为 wait")
|
logger.warning(f"LLM返回了未知的行动类型: '{action}',强制改为 wait")
|
||||||
reason = f"(原始行动'{action}'无效,已强制改为wait) {reason}"
|
reason = f"(原始行动'{action}'无效,已强制改为wait) {reason}"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import datetime
|
|||||||
from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat
|
from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat
|
||||||
|
|
||||||
# from ...config.config import global_config
|
# from ...config.config import global_config
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any, Optional
|
||||||
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, DirectMessageSender
|
from .pfc import ChatObserver, GoalAnalyzer, DirectMessageSender
|
||||||
@@ -38,6 +38,7 @@ class Conversation:
|
|||||||
self.stream_id = stream_id
|
self.stream_id = stream_id
|
||||||
self.state = ConversationState.INIT
|
self.state = ConversationState.INIT
|
||||||
self.should_continue = False
|
self.should_continue = False
|
||||||
|
self.ignore_until_timestamp: Optional[float] = None
|
||||||
|
|
||||||
# 回复相关
|
# 回复相关
|
||||||
self.generated_reply = ""
|
self.generated_reply = ""
|
||||||
@@ -135,6 +136,18 @@ class Conversation:
|
|||||||
async def _plan_and_action_loop(self):
|
async def _plan_and_action_loop(self):
|
||||||
"""思考步,PFC核心循环模块"""
|
"""思考步,PFC核心循环模块"""
|
||||||
while self.should_continue:
|
while self.should_continue:
|
||||||
|
if self.ignore_until_timestamp and time.time() < self.ignore_until_timestamp:
|
||||||
|
# 仍在忽略期间,等待下次检查
|
||||||
|
await asyncio.sleep(30) # 每 30 秒检查一次
|
||||||
|
continue # 跳过本轮循环的剩余部分
|
||||||
|
elif self.ignore_until_timestamp and time.time() >= self.ignore_until_timestamp:
|
||||||
|
# 忽略期结束,现在正常地结束对话
|
||||||
|
logger.info(f"忽略时间已到 {self.stream_id},准备结束对话。")
|
||||||
|
self.ignore_until_timestamp = None # 清除时间戳
|
||||||
|
self.should_continue = False # 现在停止循环
|
||||||
|
# (可选)在这里记录一个 'end_conversation' 动作
|
||||||
|
# 或者确保管理器会基于 should_continue 为 False 来清理它
|
||||||
|
continue # 跳过本轮循环的剩余部分,让它终止
|
||||||
try:
|
try:
|
||||||
# --- 在规划前记录当前新消息数量 ---
|
# --- 在规划前记录当前新消息数量 ---
|
||||||
initial_new_message_count = 0
|
initial_new_message_count = 0
|
||||||
@@ -275,7 +288,7 @@ class Conversation:
|
|||||||
# 2. 检查回复
|
# 2. 检查回复
|
||||||
self.state = ConversationState.CHECKING
|
self.state = ConversationState.CHECKING
|
||||||
try:
|
try:
|
||||||
current_goal_str = conversation_info.goal_list[0][0] if conversation_info.goal_list else ""
|
current_goal_str = conversation_info.goal_list[0]["goal"] if conversation_info.goal_list else ""
|
||||||
# 注意:这里传递的是 reply_attempt_count - 1 作为 retry_count 给 checker
|
# 注意:这里传递的是 reply_attempt_count - 1 作为 retry_count 给 checker
|
||||||
is_suitable, check_reason, need_replan = await self.reply_generator.check_reply(
|
is_suitable, check_reason, need_replan = await self.reply_generator.check_reply(
|
||||||
reply=self.generated_reply,
|
reply=self.generated_reply,
|
||||||
@@ -412,6 +425,21 @@ class Conversation:
|
|||||||
)
|
)
|
||||||
# 这里不需要 return,主循环会在下一轮检查 should_continue
|
# 这里不需要 return,主循环会在下一轮检查 should_continue
|
||||||
|
|
||||||
|
elif action == "block_and_ignore":
|
||||||
|
logger.info("不想再理你了...")
|
||||||
|
# 1. 标记对话为暂时忽略
|
||||||
|
ignore_duration_seconds = 10 * 60 # 10 分钟
|
||||||
|
self.ignore_until_timestamp = time.time() + ignore_duration_seconds
|
||||||
|
logger.info(f"将忽略此对话直到: {datetime.datetime.fromtimestamp(self.ignore_until_timestamp)}")
|
||||||
|
conversation_info.done_action[action_index].update(
|
||||||
|
{
|
||||||
|
"status": "done", # 或者一个自定义状态,比如 "ignored"
|
||||||
|
"final_reason": "Detected potential harassment, ignoring temporarily.", # 检测到潜在骚扰,暂时忽略
|
||||||
|
"time": datetime.datetime.now().strftime("%H:%M:%S"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.state = ConversationState.IGNORED
|
||||||
|
|
||||||
else: # 对应 'wait' 动作
|
else: # 对应 'wait' 动作
|
||||||
self.state = ConversationState.WAITING
|
self.state = ConversationState.WAITING
|
||||||
logger.info("等待更多信息...")
|
logger.info("等待更多信息...")
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import time
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
from src.common.logger import get_module_logger
|
from src.common.logger import get_module_logger
|
||||||
from .conversation import Conversation
|
from .conversation import Conversation
|
||||||
@@ -44,7 +45,23 @@ class PFCManager:
|
|||||||
if stream_id in self._instances and self._instances[stream_id].should_continue:
|
if stream_id in self._instances and self._instances[stream_id].should_continue:
|
||||||
logger.debug(f"使用现有会话实例: {stream_id}")
|
logger.debug(f"使用现有会话实例: {stream_id}")
|
||||||
return self._instances[stream_id]
|
return self._instances[stream_id]
|
||||||
|
if stream_id in self._instances:
|
||||||
|
instance = self._instances[stream_id]
|
||||||
|
if (
|
||||||
|
hasattr(instance, "ignore_until_timestamp")
|
||||||
|
and instance.ignore_until_timestamp
|
||||||
|
and time.time() < instance.ignore_until_timestamp
|
||||||
|
):
|
||||||
|
logger.debug(f"会话实例当前处于忽略状态: {stream_id}")
|
||||||
|
# 返回 None 阻止交互。或者可以返回实例但标记它被忽略了喵?
|
||||||
|
# 还是返回 None 吧喵。
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 检查 should_continue 状态
|
||||||
|
if instance.should_continue:
|
||||||
|
logger.debug(f"使用现有会话实例: {stream_id}")
|
||||||
|
return instance
|
||||||
|
# else: 实例存在但不应继续
|
||||||
try:
|
try:
|
||||||
# 创建新实例
|
# 创建新实例
|
||||||
logger.info(f"创建新的对话实例: {stream_id}")
|
logger.info(f"创建新的对话实例: {stream_id}")
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class ConversationState(Enum):
|
|||||||
LISTENING = "倾听"
|
LISTENING = "倾听"
|
||||||
ENDED = "结束"
|
ENDED = "结束"
|
||||||
JUDGING = "判断"
|
JUDGING = "判断"
|
||||||
|
IGNORED = "屏蔽"
|
||||||
|
|
||||||
|
|
||||||
ActionType = Literal["direct_reply", "fetch_knowledge", "wait"]
|
ActionType = Literal["direct_reply", "fetch_knowledge", "wait"]
|
||||||
|
|||||||
Reference in New Issue
Block a user