🤖 自动格式化代码 [skip ci]
This commit is contained in:
@@ -660,7 +660,6 @@ class HeartFChatting:
|
||||
}
|
||||
|
||||
with Timer("执行动作", cycle_timers):
|
||||
|
||||
action_type, action_data, reasoning = (
|
||||
plan_result.get("action_result", {}).get("action_type", "error"),
|
||||
plan_result.get("action_result", {}).get("action_data", {}),
|
||||
@@ -675,7 +674,7 @@ class HeartFChatting:
|
||||
action_str = action_type
|
||||
|
||||
logger.debug(f"{self.log_prefix} 麦麦想要:'{action_str}'")
|
||||
|
||||
|
||||
success, reply_text, command = await self._handle_action(
|
||||
action_type, reasoning, action_data, cycle_timers, thinking_id
|
||||
)
|
||||
|
||||
@@ -80,7 +80,7 @@ class ObsInfo(InfoBase):
|
||||
chat_target (str): 聊天目标,可以是 "private"(私聊)、"group"(群聊)或 "other"(其他)
|
||||
"""
|
||||
self.data["chat_target"] = chat_target
|
||||
|
||||
|
||||
def set_chat_id(self, chat_id: str) -> None:
|
||||
"""设置聊天ID
|
||||
|
||||
@@ -88,7 +88,7 @@ class ObsInfo(InfoBase):
|
||||
chat_id (str): 聊天ID
|
||||
"""
|
||||
self.data["chat_id"] = chat_id
|
||||
|
||||
|
||||
def get_chat_id(self) -> Optional[str]:
|
||||
"""获取聊天ID
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ class ExpressionSelectorProcessor(BaseProcessor):
|
||||
if observations:
|
||||
for observation in observations:
|
||||
if isinstance(observation, ChattingObservation):
|
||||
# chat_info = observation.get_observe_info()
|
||||
# chat_info = observation.get_observe_info()
|
||||
chat_info = observation.talking_message_str_truncate_short
|
||||
break
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ def init_prompt():
|
||||
""",
|
||||
"simple_planner_prompt",
|
||||
)
|
||||
|
||||
|
||||
Prompt(
|
||||
"""
|
||||
{time_block}
|
||||
@@ -62,19 +62,19 @@ def init_prompt():
|
||||
"simple_planner_prompt_private",
|
||||
)
|
||||
|
||||
# Prompt(
|
||||
# """
|
||||
# 动作:{action_name}
|
||||
# 该动作的描述:{action_description}
|
||||
# 使用该动作的场景:
|
||||
# {action_require}
|
||||
# 输出要求:
|
||||
# {{
|
||||
# "action": "{action_name}",{action_parameters}
|
||||
# }}
|
||||
# """,
|
||||
# "action_prompt",
|
||||
# )
|
||||
# Prompt(
|
||||
# """
|
||||
# 动作:{action_name}
|
||||
# 该动作的描述:{action_description}
|
||||
# 使用该动作的场景:
|
||||
# {action_require}
|
||||
# 输出要求:
|
||||
# {{
|
||||
# "action": "{action_name}",{action_parameters}
|
||||
# }}
|
||||
# """,
|
||||
# "action_prompt",
|
||||
# )
|
||||
Prompt(
|
||||
"""
|
||||
{action_require}
|
||||
@@ -84,7 +84,7 @@ def init_prompt():
|
||||
""",
|
||||
"action_prompt",
|
||||
)
|
||||
|
||||
|
||||
Prompt(
|
||||
"""
|
||||
{action_require}
|
||||
@@ -96,7 +96,6 @@ def init_prompt():
|
||||
)
|
||||
|
||||
|
||||
|
||||
class ActionPlanner(BasePlanner):
|
||||
def __init__(self, log_prefix: str, action_manager: ActionManager):
|
||||
super().__init__(log_prefix, action_manager)
|
||||
@@ -141,7 +140,7 @@ class ActionPlanner(BasePlanner):
|
||||
relation_info = ""
|
||||
selected_expressions = []
|
||||
chat_id = None # 添加chat_id变量
|
||||
|
||||
|
||||
for info in all_plan_info:
|
||||
if isinstance(info, ObsInfo):
|
||||
observed_messages = info.get_talking_message()
|
||||
@@ -170,7 +169,9 @@ class ActionPlanner(BasePlanner):
|
||||
# 如果获取成功,更新is_group_chat
|
||||
if is_group_chat_updated is not None:
|
||||
is_group_chat = is_group_chat_updated
|
||||
logger.debug(f"{self.log_prefix}获取到聊天信息 - 群聊: {is_group_chat}, 目标信息: {chat_target_info}")
|
||||
logger.debug(
|
||||
f"{self.log_prefix}获取到聊天信息 - 群聊: {is_group_chat}, 目标信息: {chat_target_info}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.log_prefix}获取聊天目标信息失败: {e}")
|
||||
chat_target_info = None
|
||||
@@ -372,7 +373,7 @@ class ActionPlanner(BasePlanner):
|
||||
action_options_block = ""
|
||||
# 根据聊天类型选择不同的动作prompt模板
|
||||
action_template_name = "action_prompt_private" if not is_group_chat else "action_prompt"
|
||||
|
||||
|
||||
for using_actions_name, using_actions_info in current_available_actions.items():
|
||||
using_action_prompt = await global_prompt_manager.get_prompt_async(action_template_name)
|
||||
|
||||
|
||||
@@ -232,11 +232,11 @@ class ChattingObservation(Observation):
|
||||
truncate=True,
|
||||
show_actions=True,
|
||||
)
|
||||
|
||||
|
||||
# 构建简短版本 - 使用最新一半的消息
|
||||
half_count = len(self.talking_message) // 2
|
||||
recent_messages = self.talking_message[-half_count:] if half_count > 0 else self.talking_message
|
||||
|
||||
|
||||
self.talking_message_str_short = build_readable_messages(
|
||||
messages=recent_messages,
|
||||
timestamp_mode="lite",
|
||||
|
||||
@@ -56,8 +56,6 @@ class ReplyAction(BaseAction):
|
||||
logger.info(f"{self.log_prefix} 决定回复: {self.reasoning}")
|
||||
|
||||
start_time = self.action_data.get("loop_start_time", time.time())
|
||||
|
||||
|
||||
|
||||
try:
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
@@ -68,7 +66,6 @@ class ReplyAction(BaseAction):
|
||||
is_group=self.is_group,
|
||||
)
|
||||
|
||||
|
||||
# 检查从start_time以来的新消息数量
|
||||
# 获取动作触发时间或使用默认值
|
||||
current_time = time.time()
|
||||
@@ -89,15 +86,14 @@ class ReplyAction(BaseAction):
|
||||
data = reply_seg[1]
|
||||
if not first_replyed:
|
||||
if need_reply:
|
||||
await self.send_text(content=data, reply_to=self.action_data.get("reply_to", ""),typing=False)
|
||||
await self.send_text(content=data, reply_to=self.action_data.get("reply_to", ""), typing=False)
|
||||
first_replyed = True
|
||||
else:
|
||||
await self.send_text(content=data,typing=False)
|
||||
await self.send_text(content=data, typing=False)
|
||||
first_replyed = True
|
||||
else:
|
||||
await self.send_text(content=data,typing=True)
|
||||
await self.send_text(content=data, typing=True)
|
||||
reply_text += data
|
||||
|
||||
|
||||
# 存储动作记录
|
||||
await self.store_action_info(
|
||||
@@ -118,7 +114,7 @@ class ReplyAction(BaseAction):
|
||||
|
||||
class NoReplyAction(BaseAction):
|
||||
"""不回复动作,使用智能判断机制决定何时结束等待
|
||||
|
||||
|
||||
新的等待逻辑:
|
||||
- 每0.2秒检查是否有新消息(提高响应性)
|
||||
- 如果累计消息数量达到阈值(默认20条),直接结束等待
|
||||
@@ -139,13 +135,13 @@ class NoReplyAction(BaseAction):
|
||||
|
||||
# 连续no_reply计数器
|
||||
_consecutive_count = 0
|
||||
|
||||
|
||||
# LLM判断的最小间隔时间
|
||||
_min_judge_interval = 1.0 # 最快1秒一次LLM判断
|
||||
|
||||
|
||||
# 自动结束的消息数量阈值
|
||||
_auto_exit_message_count = 20 # 累计20条消息自动结束
|
||||
|
||||
|
||||
# 最大等待超时时间
|
||||
_max_timeout = 1200 # 1200秒
|
||||
|
||||
@@ -161,7 +157,7 @@ class NoReplyAction(BaseAction):
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行不回复动作,有新消息时进行判断,但最快1秒一次"""
|
||||
import asyncio
|
||||
|
||||
|
||||
try:
|
||||
# 增加连续计数
|
||||
NoReplyAction._consecutive_count += 1
|
||||
@@ -172,33 +168,30 @@ class NoReplyAction(BaseAction):
|
||||
last_judge_time = 0 # 上次进行LLM判断的时间
|
||||
min_judge_interval = self._min_judge_interval # 最小判断间隔,从配置获取
|
||||
check_interval = 0.2 # 检查新消息的间隔,设为0.2秒提高响应性
|
||||
|
||||
|
||||
# 获取no_reply开始时的上下文消息(5条),用于后续记录
|
||||
context_messages = message_api.get_messages_by_time_in_chat(
|
||||
chat_id=self.chat_id,
|
||||
start_time=start_time - 300, # 获取开始前5分钟内的消息
|
||||
end_time=start_time,
|
||||
limit=5,
|
||||
limit_mode="latest"
|
||||
limit_mode="latest",
|
||||
)
|
||||
|
||||
|
||||
# 构建上下文字符串
|
||||
context_str = ""
|
||||
if context_messages:
|
||||
context_str = message_api.build_readable_messages(
|
||||
messages=context_messages,
|
||||
timestamp_mode="normal_no_YMD",
|
||||
truncate=False,
|
||||
show_actions=False
|
||||
messages=context_messages, timestamp_mode="normal_no_YMD", truncate=False, show_actions=False
|
||||
)
|
||||
context_str = f"当时选择no_reply前的聊天上下文:\n{context_str}\n"
|
||||
|
||||
|
||||
logger.info(f"{self.log_prefix} 选择不回复(第{count}次),开始智能等待,原因: {reason}")
|
||||
|
||||
while True:
|
||||
current_time = time.time()
|
||||
elapsed_time = current_time - start_time
|
||||
|
||||
|
||||
# 检查是否超时
|
||||
if elapsed_time >= self._max_timeout:
|
||||
logger.info(f"{self.log_prefix} 达到最大等待时间{self._max_timeout}秒,结束等待")
|
||||
@@ -210,12 +203,12 @@ class NoReplyAction(BaseAction):
|
||||
action_done=True,
|
||||
)
|
||||
return True, exit_reason
|
||||
|
||||
|
||||
# 检查是否有新消息
|
||||
new_message_count = message_api.count_new_messages(
|
||||
chat_id=self.chat_id, start_time=start_time, end_time=current_time
|
||||
)
|
||||
|
||||
|
||||
# 如果累计消息数量达到阈值,直接结束等待
|
||||
if new_message_count >= self._auto_exit_message_count:
|
||||
logger.info(f"{self.log_prefix} 累计消息数量达到{new_message_count}条,直接结束等待")
|
||||
@@ -227,31 +220,28 @@ class NoReplyAction(BaseAction):
|
||||
action_done=True,
|
||||
)
|
||||
return True, f"累计消息数量达到{new_message_count}条,直接结束等待 (等待时间: {elapsed_time:.1f}秒)"
|
||||
|
||||
|
||||
# 如果有新消息且距离上次判断>=1秒,进行LLM判断
|
||||
if new_message_count > 0 and (current_time - last_judge_time) >= min_judge_interval:
|
||||
logger.info(f"{self.log_prefix} 检测到{new_message_count}条新消息,进行智能判断...")
|
||||
|
||||
|
||||
# 获取最近的消息内容用于判断
|
||||
recent_messages = message_api.get_messages_by_time_in_chat(
|
||||
chat_id=self.chat_id,
|
||||
chat_id=self.chat_id,
|
||||
start_time=start_time,
|
||||
end_time=current_time,
|
||||
)
|
||||
|
||||
|
||||
if recent_messages:
|
||||
# 使用message_api构建可读的消息字符串
|
||||
messages_text = message_api.build_readable_messages(
|
||||
messages=recent_messages,
|
||||
timestamp_mode="normal_no_YMD",
|
||||
truncate=False,
|
||||
show_actions=False
|
||||
messages=recent_messages, timestamp_mode="normal_no_YMD", truncate=False, show_actions=False
|
||||
)
|
||||
|
||||
|
||||
# 参考simple_planner构建更完整的判断信息
|
||||
# 获取时间信息
|
||||
time_block = f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
|
||||
|
||||
# 获取身份信息
|
||||
bot_name = global_config.bot.nickname
|
||||
bot_nickname = ""
|
||||
@@ -259,7 +249,7 @@ class NoReplyAction(BaseAction):
|
||||
bot_nickname = f",也有人叫你{','.join(global_config.bot.alias_names)}"
|
||||
bot_core_personality = global_config.personality.personality_core
|
||||
identity_block = f"你的名字是{bot_name}{bot_nickname},你{bot_core_personality}"
|
||||
|
||||
|
||||
# 构建判断上下文
|
||||
judge_prompt = f"""
|
||||
{time_block}
|
||||
@@ -282,35 +272,35 @@ class NoReplyAction(BaseAction):
|
||||
判断:需要回复/不需要回复
|
||||
理由:[说明你的判断理由]
|
||||
"""
|
||||
|
||||
|
||||
try:
|
||||
# 获取可用的模型配置
|
||||
available_models = llm_api.get_available_models()
|
||||
|
||||
|
||||
# 使用 utils_small 模型
|
||||
small_model = getattr(available_models, 'utils_small', None)
|
||||
|
||||
small_model = getattr(available_models, "utils_small", None)
|
||||
|
||||
if small_model:
|
||||
# 使用小模型进行判断
|
||||
success, response, reasoning, model_name = await llm_api.generate_with_model(
|
||||
prompt=judge_prompt,
|
||||
model_config=small_model,
|
||||
request_type="plugin.no_reply_judge",
|
||||
temperature=0.7 # 降低温度,提高判断的一致性
|
||||
temperature=0.7, # 降低温度,提高判断的一致性
|
||||
)
|
||||
|
||||
|
||||
# 更新上次判断时间
|
||||
last_judge_time = time.time()
|
||||
|
||||
|
||||
if success and response:
|
||||
response = response.strip()
|
||||
logger.info(f"{self.log_prefix} 模型({model_name})原始判断结果: {response}")
|
||||
|
||||
|
||||
# 解析LLM响应,提取判断结果和理由
|
||||
judge_result, reason = self._parse_llm_judge_response(response)
|
||||
|
||||
|
||||
logger.info(f"{self.log_prefix} 解析结果 - 判断: {judge_result}, 理由: {reason}")
|
||||
|
||||
|
||||
if judge_result == "需要回复":
|
||||
logger.info(f"{self.log_prefix} 模型判断需要回复,结束等待")
|
||||
full_prompt = f"你的想法是:{reason},你思考是否要进行回复"
|
||||
@@ -329,15 +319,15 @@ class NoReplyAction(BaseAction):
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} 未找到可用的模型配置,继续等待")
|
||||
last_judge_time = time.time() # 即使失败也更新时间,避免频繁重试
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 模型判断异常: {e},继续等待")
|
||||
last_judge_time = time.time() # 异常时也更新时间,避免频繁重试
|
||||
|
||||
|
||||
# 每10秒输出一次等待状态
|
||||
if int(elapsed_time) % 10 == 0 and int(elapsed_time) > 0:
|
||||
logger.info(f"{self.log_prefix} 已等待{elapsed_time:.0f}秒,继续监听...")
|
||||
|
||||
|
||||
# 短暂等待后继续检查
|
||||
await asyncio.sleep(check_interval)
|
||||
|
||||
@@ -366,49 +356,49 @@ class NoReplyAction(BaseAction):
|
||||
|
||||
def _parse_llm_judge_response(self, response: str) -> tuple[str, str]:
|
||||
"""解析LLM判断响应,提取判断结果和理由
|
||||
|
||||
|
||||
Args:
|
||||
response: LLM的原始响应
|
||||
|
||||
|
||||
Returns:
|
||||
tuple: (判断结果, 理由)
|
||||
"""
|
||||
try:
|
||||
lines = response.strip().split('\n')
|
||||
lines = response.strip().split("\n")
|
||||
judge_result = "不需要回复" # 默认值
|
||||
reason = "解析失败,使用默认判断"
|
||||
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith('判断:') or line.startswith('判断:'):
|
||||
if line.startswith("判断:") or line.startswith("判断:"):
|
||||
# 提取判断结果
|
||||
result_part = line.split(':', 1)[-1] if ':' in line else line.split(':', 1)[-1]
|
||||
result_part = line.split(":", 1)[-1] if ":" in line else line.split(":", 1)[-1]
|
||||
result_part = result_part.strip()
|
||||
|
||||
|
||||
if "需要回复" in result_part:
|
||||
judge_result = "需要回复"
|
||||
elif "不需要回复" in result_part:
|
||||
judge_result = "不需要回复"
|
||||
|
||||
elif line.startswith('理由:') or line.startswith('理由:'):
|
||||
|
||||
elif line.startswith("理由:") or line.startswith("理由:"):
|
||||
# 提取理由
|
||||
reason_part = line.split(':', 1)[-1] if ':' in line else line.split(':', 1)[-1]
|
||||
reason_part = line.split(":", 1)[-1] if ":" in line else line.split(":", 1)[-1]
|
||||
reason = reason_part.strip()
|
||||
|
||||
|
||||
# 如果没有找到标准格式,尝试简单的关键词匹配
|
||||
if reason == "解析失败,使用默认判断":
|
||||
if "需要回复" in response:
|
||||
judge_result = "需要回复"
|
||||
reason = "检测到'需要回复'关键词"
|
||||
elif "不需要回复" in response:
|
||||
judge_result = "不需要回复"
|
||||
judge_result = "不需要回复"
|
||||
reason = "检测到'不需要回复'关键词"
|
||||
else:
|
||||
reason = f"无法解析响应格式,原文: {response[:50]}..."
|
||||
|
||||
|
||||
logger.debug(f"{self.log_prefix} 解析LLM响应 - 判断: {judge_result}, 理由: {reason}")
|
||||
return judge_result, reason
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 解析LLM响应时出错: {e}")
|
||||
return "不需要回复", f"解析异常: {str(e)}"
|
||||
@@ -486,7 +476,6 @@ class EmojiAction(BaseAction):
|
||||
return False, f"表情发送失败: {str(e)}"
|
||||
|
||||
|
||||
|
||||
class ExitFocusChatAction(BaseAction):
|
||||
"""退出专注聊天动作 - 从专注模式切换到普通模式"""
|
||||
|
||||
@@ -588,8 +577,12 @@ class CoreActionsPlugin(BasePlugin):
|
||||
},
|
||||
"no_reply": {
|
||||
"max_timeout": ConfigField(type=int, default=1200, description="最大等待超时时间(秒)"),
|
||||
"min_judge_interval": ConfigField(type=float, default=1.0, description="LLM判断的最小间隔时间(秒),防止过于频繁"),
|
||||
"auto_exit_message_count": ConfigField(type=int, default=20, description="累计消息数量达到此阈值时自动结束等待"),
|
||||
"min_judge_interval": ConfigField(
|
||||
type=float, default=1.0, description="LLM判断的最小间隔时间(秒),防止过于频繁"
|
||||
),
|
||||
"auto_exit_message_count": ConfigField(
|
||||
type=int, default=20, description="累计消息数量达到此阈值时自动结束等待"
|
||||
),
|
||||
"random_probability": ConfigField(
|
||||
type=float, default=0.8, description="Focus模式下,随机选择不回复的概率(0.0到1.0)", example=0.8
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user