feat(chat): 私聊专注模式下强制回复

在私聊的专注模式下,即使用户的发言没有触发任何功能,机器人也会进行回复,而不是选择“no_reply”。
此举旨在提升私聊场景下的用户体验,避免机器人因未匹配到关键词而沉默,让对话感觉更自然。
This commit is contained in:
minecraft1024a
2025-08-17 16:48:42 +08:00
committed by Windpicker-owo
parent f0b1e66477
commit ebf811a85c
2 changed files with 107 additions and 20 deletions

View File

@@ -607,26 +607,32 @@ class HeartFChatting:
available_actions=available_actions,
)
# 3. 并行执行所有动作
async def execute_action(action_info,actions):
"""执行单个动作的通用函数"""
try:
if action_info["action_type"] == "no_reply":
# 直接处理no_reply逻辑不再通过动作系统
reason = action_info.get("reasoning", "选择不回复")
logger.info(f"{self.log_prefix} 选择不回复,原因: {reason}")
# 存储no_reply信息到数据库
await database_api.store_action_info(
chat_stream=self.chat_stream,
action_build_into_prompt=False,
action_prompt_display=reason,
action_done=True,
thinking_id=thinking_id,
action_data={"reason": reason},
action_name="no_reply",
action_data["loop_start_time"] = loop_start_time
# 在私聊的专注模式下如果规划动作为no_reply则强制改为reply
is_private_chat = self.chat_stream.group_info is None
if self.loop_mode == ChatMode.FOCUS and is_private_chat and action_type == "no_reply":
action_type = "reply"
logger.info(f"{self.log_prefix} 私聊专注模式下强制回复")
if action_type == "reply":
logger.info(f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复")
elif is_parallel:
logger.info(f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复, 同时执行{action_type}动作")
else:
# 只有在gen_task存在时才进行相关操作
if gen_task:
if not gen_task.done():
gen_task.cancel()
logger.debug(f"{self.log_prefix} 已取消预生成的回复任务")
logger.info(
f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复,但选择执行{action_type},不发表回复"
)
elif generation_result := gen_task.result():
content = " ".join([item[1] for item in generation_result if item[0] == "text"])
logger.debug(f"{self.log_prefix} 预生成的回复任务已完成")
logger.info(
f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复:{content},但选择执行{action_type},不发表回复"
)
return {

View File

@@ -0,0 +1,81 @@
from typing import Tuple, List
from collections import deque
# 导入新插件系统
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
from src.plugin_system.base.component_types import ChatType
# 导入依赖的系统组件
from src.common.logger import get_logger
logger = get_logger("no_reply_action")
class NoReplyAction(BaseAction):
"""不回复动作支持waiting和breaking两种形式."""
focus_activation_type = ActionActivationType.NEVER
normal_activation_type = ActionActivationType.NEVER
mode_enable = ChatMode.FOCUS
parallel_action = False
# 动作基本信息
action_name = "no_reply"
action_description = "暂时不回复消息"
# 最近三次no_reply的新消息兴趣度记录
_recent_interest_records: deque = deque(maxlen=3)
# 兴趣值退出阈值
_interest_exit_threshold = 3.0
# 消息数量退出阈值
_min_exit_message_count = 3
_max_exit_message_count = 6
# 动作参数定义
action_parameters = {}
# 动作使用场景
action_require = [""]
# 关联类型
associated_types = []
async def execute(self) -> Tuple[bool, str]:
"""执行不回复动作"""
try:
reason = self.action_data.get("reason", "")
logger.info(f"{self.log_prefix} 选择不回复,原因: {reason}")
await self.store_action_info(
action_build_into_prompt=False,
action_prompt_display=reason,
action_done=True,
)
return True, reason
except Exception as e:
logger.error(f"{self.log_prefix} 不回复动作执行失败: {e}")
exit_reason = f"执行异常: {str(e)}"
full_prompt = f"no_reply执行异常: {exit_reason},你思考是否要进行回复"
await self.store_action_info(
action_build_into_prompt=True,
action_prompt_display=full_prompt,
action_done=True,
)
return False, f"不回复动作执行失败: {e}"
@classmethod
def reset_consecutive_count(cls):
"""重置连续计数器和兴趣度记录"""
cls._recent_interest_records.clear()
logger.debug("NoReplyAction连续计数器和兴趣度记录已重置")
@classmethod
def get_recent_interest_records(cls) -> List[float]:
"""获取最近的兴趣度记录"""
return list(cls._recent_interest_records)