fix(chat): 优化breaking模式下的兴趣值累积逻辑
重构heartFC_chat中的消息处理机制,使用累积兴趣值替代最近三次记录来判断是否进入breaking模式。主要变更包括: - 将breaking模式判断基于累积兴趣值而非最近3次记录 - 在消息成功处理时重置累积兴趣值 - 调整阈值计算方式,使用聊天频率进行动态调整 - 修复send_api中的消息查找函数,提高回复消息匹配准确性 这些改动提高了对话节奏控制的稳定性,使breaking模式触发更加合理。
This commit is contained in:
@@ -128,7 +128,7 @@ class CycleProcessor:
|
||||
x0 = 1.0 # 控制曲线中心点
|
||||
return 1.0 / (1.0 + math.exp(-k * (interest_val - x0)))
|
||||
|
||||
normal_mode_probability = calculate_normal_mode_probability(interest_value) / global_config.chat.get_current_talk_frequency(self.context.stream_id)
|
||||
normal_mode_probability = calculate_normal_mode_probability(interest_value) * 0.5 / global_config.chat.get_current_talk_frequency(self.context.stream_id)
|
||||
|
||||
# 根据概率决定使用哪种模式
|
||||
if random.random() < normal_mode_probability:
|
||||
|
||||
@@ -255,10 +255,12 @@ class HeartFChatting:
|
||||
for message in recent_messages:
|
||||
await self.cycle_processor.observe(interest_value = interest_value)
|
||||
|
||||
# 如果成功观察,增加能量值
|
||||
# 如果成功观察,增加能量值并重置累积兴趣值
|
||||
if has_new_messages:
|
||||
self.context.energy_value += 1 / global_config.chat.focus_value
|
||||
logger.info(f"{self.context.log_prefix} 能量值增加,当前能量值:{self.context.energy_value:.1f}")
|
||||
# 重置累积兴趣值,因为消息已经被成功处理
|
||||
self.context.breaking_accumulated_interest = 0.0
|
||||
logger.info(f"{self.context.log_prefix} 能量值增加,当前能量值:{self.context.energy_value:.1f},重置累积兴趣值")
|
||||
|
||||
self._check_focus_exit()
|
||||
|
||||
@@ -384,23 +386,20 @@ class HeartFChatting:
|
||||
if self.context.no_reply_consecutive <= 3:
|
||||
self.context.focus_energy = 1
|
||||
else:
|
||||
# 计算最近三次记录的兴趣度总和
|
||||
total_recent_interest = sum(self.recent_interest_records)
|
||||
|
||||
# 获取当前聊天频率和意愿系数
|
||||
talk_frequency = global_config.chat.get_current_talk_frequency(self.context.stream_id)
|
||||
# 使用累积兴趣值而不是最近3次的记录
|
||||
total_interest = self.context.breaking_accumulated_interest
|
||||
|
||||
# 计算调整后的阈值
|
||||
adjusted_threshold = 3 / talk_frequency
|
||||
adjusted_threshold = 1 / global_config.chat.get_current_talk_frequency(self.context.stream_id)
|
||||
|
||||
logger.info(f"{self.context.log_prefix} 最近三次兴趣度总和: {total_recent_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}")
|
||||
logger.info(f"{self.context.log_prefix} 累积兴趣值: {total_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}")
|
||||
|
||||
# 如果兴趣度总和小于阈值,进入breaking形式
|
||||
if total_recent_interest < adjusted_threshold:
|
||||
logger.info(f"{self.context.log_prefix} 兴趣度不足,进入breaking形式")
|
||||
# 如果累积兴趣值小于阈值,进入breaking形式
|
||||
if total_interest < adjusted_threshold:
|
||||
logger.info(f"{self.context.log_prefix} 累积兴趣度不足,进入breaking形式")
|
||||
self.context.focus_energy = random.randint(3, 6)
|
||||
else:
|
||||
logger.info(f"{self.context.log_prefix} 兴趣度充足")
|
||||
logger.info(f"{self.context.log_prefix} 累积兴趣度充足,使用waiting形式")
|
||||
self.context.focus_energy = 1
|
||||
|
||||
async def _should_process_messages(self, new_message: List[Dict[str, Any]]) -> tuple[bool,float]:
|
||||
@@ -409,36 +408,48 @@ class HeartFChatting:
|
||||
根据当前循环模式和消息内容决定是否继续处理
|
||||
"""
|
||||
new_message_count = len(new_message)
|
||||
# talk_frequency = global_config.chat.get_current_talk_frequency(self.context.chat_stream.stream_id)
|
||||
modified_exit_count_threshold = self.context.focus_energy / global_config.chat.focus_value
|
||||
|
||||
modified_exit_interest_threshold = 3 / global_config.chat.focus_value
|
||||
total_interest = 0.0
|
||||
talk_frequency = global_config.chat.get_current_talk_frequency(self.context.chat_stream.stream_id)
|
||||
|
||||
modified_exit_count_threshold = self.context.focus_energy * 0.5 / talk_frequency
|
||||
modified_exit_interest_threshold = 1.5 / talk_frequency
|
||||
|
||||
# 计算当前批次消息的兴趣值
|
||||
batch_interest = 0.0
|
||||
for msg_dict in new_message:
|
||||
interest_value = msg_dict.get("interest_value", 0.0)
|
||||
if msg_dict.get("processed_plain_text", ""):
|
||||
total_interest += interest_value
|
||||
batch_interest += interest_value
|
||||
|
||||
# 在breaking形式下累积所有消息的兴趣值
|
||||
if new_message_count > 0:
|
||||
self.context.breaking_accumulated_interest += batch_interest
|
||||
total_interest = self.context.breaking_accumulated_interest
|
||||
else:
|
||||
total_interest = self.context.breaking_accumulated_interest
|
||||
|
||||
if new_message_count >= modified_exit_count_threshold:
|
||||
# 记录兴趣度到列表
|
||||
self.recent_interest_records.append(total_interest)
|
||||
# 重置累积兴趣值,因为已经达到了消息数量阈值
|
||||
self.context.breaking_accumulated_interest = 0.0
|
||||
|
||||
logger.info(
|
||||
f"{self.context.log_prefix} 累计消息数量达到{new_message_count}条(>{modified_exit_count_threshold:.1f}),结束等待"
|
||||
f"{self.context.log_prefix} 累计消息数量达到{new_message_count}条(>{modified_exit_count_threshold:.1f}),结束等待,累积兴趣值: {total_interest:.2f}"
|
||||
)
|
||||
# logger.info(self.context.last_read_time)
|
||||
# logger.info(new_message)
|
||||
return True,total_interest/new_message_count
|
||||
|
||||
# 检查累计兴趣值
|
||||
if new_message_count > 0:
|
||||
# 只在兴趣值变化时输出log
|
||||
if not hasattr(self, "_last_accumulated_interest") or total_interest != self._last_accumulated_interest:
|
||||
logger.info(f"{self.context.log_prefix} breaking形式当前累计兴趣值: {total_interest:.2f}, 专注度: {global_config.chat.focus_value:.1f}")
|
||||
logger.info(f"{self.context.log_prefix} breaking形式当前累积兴趣值: {total_interest:.2f}, 专注度: {global_config.chat.focus_value:.1f}")
|
||||
self._last_accumulated_interest = total_interest
|
||||
if total_interest >= modified_exit_interest_threshold:
|
||||
# 记录兴趣度到列表
|
||||
self.recent_interest_records.append(total_interest)
|
||||
# 重置累积兴趣值,因为已经达到了兴趣值阈值
|
||||
self.context.breaking_accumulated_interest = 0.0
|
||||
logger.info(
|
||||
f"{self.context.log_prefix} 累计兴趣值达到{total_interest:.2f}(>{modified_exit_interest_threshold:.1f}),结束等待"
|
||||
)
|
||||
@@ -447,7 +458,7 @@ class HeartFChatting:
|
||||
# 每10秒输出一次等待状态
|
||||
if int(time.time() - self.context.last_read_time) > 0 and int(time.time() - self.context.last_read_time) % 10 == 0:
|
||||
logger.info(
|
||||
f"{self.context.log_prefix} 已等待{time.time() - self.last_read_time:.0f}秒,累计{new_message_count}条消息,累计兴趣{total_interest:.1f},继续等待..."
|
||||
f"{self.context.log_prefix} 已等待{time.time() - self.last_read_time:.0f}秒,累计{new_message_count}条消息,累积兴趣{total_interest:.1f},继续等待..."
|
||||
)
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ class HfcContext:
|
||||
self.last_message_time = time.time()
|
||||
self.last_read_time = time.time() - 10
|
||||
|
||||
# 从聊天流恢复breaking累积兴趣值
|
||||
self.breaking_accumulated_interest = getattr(self.chat_stream, 'breaking_accumulated_interest', 0.0)
|
||||
|
||||
self.action_manager = ActionManager()
|
||||
|
||||
self.running: bool = False
|
||||
@@ -63,6 +66,8 @@ class HfcContext:
|
||||
self.focus_energy = 1
|
||||
self.no_reply_consecutive = 0
|
||||
self.total_interest = 0.0
|
||||
# breaking形式下的累积兴趣值
|
||||
self.breaking_accumulated_interest = 0.0
|
||||
# 引用HeartFChatting实例,以便其他组件可以调用其方法
|
||||
self.chat_instance = None
|
||||
|
||||
@@ -73,3 +78,4 @@ class HfcContext:
|
||||
self.chat_stream.sleep_pressure = self.sleep_pressure
|
||||
self.chat_stream.focus_energy = self.focus_energy
|
||||
self.chat_stream.no_reply_consecutive = self.no_reply_consecutive
|
||||
self.chat_stream.breaking_accumulated_interest = self.breaking_accumulated_interest
|
||||
@@ -480,10 +480,18 @@ class ActionPlanner:
|
||||
mentioned_bonus = "\n- 有人提到你,或者at你"
|
||||
|
||||
if mode == ChatMode.FOCUS:
|
||||
no_action_block = """重要说明:
|
||||
no_action_block = """
|
||||
- 'no_reply' 表示不进行回复,等待合适的回复时机
|
||||
- 当你刚刚发送了消息,没有人回复时,选择no_reply
|
||||
- 当你一次发送了太多消息,为了避免打扰聊天节奏,选择no_reply
|
||||
动作:no_reply
|
||||
动作描述:不进行回复,等待合适的回复时机
|
||||
- 当你刚刚发送了消息,没有人回复时,选择no_reply
|
||||
- 当你一次发送了太多消息,为了避免打扰聊天节奏,选择no_reply
|
||||
{{
|
||||
"action": "no_reply",
|
||||
"reason":"不回复的原因"
|
||||
}}
|
||||
"""
|
||||
else: # NORMAL Mode
|
||||
no_action_block = """重要说明:
|
||||
|
||||
@@ -51,6 +51,55 @@ logger = get_logger("send_api")
|
||||
# 适配器命令响应等待池
|
||||
_adapter_response_pool: Dict[str, asyncio.Future] = {}
|
||||
|
||||
def message_dict_to_message_recv(message_dict: Dict[str, Any]) -> Optional[MessageRecv]:
|
||||
"""查找要回复的消息
|
||||
|
||||
Args:
|
||||
message_dict: 消息字典
|
||||
|
||||
Returns:
|
||||
Optional[MessageRecv]: 找到的消息,如果没找到则返回None
|
||||
"""
|
||||
# 构建MessageRecv对象
|
||||
user_info = {
|
||||
"platform": message_dict.get("user_platform", ""),
|
||||
"user_id": message_dict.get("user_id", ""),
|
||||
"user_nickname": message_dict.get("user_nickname", ""),
|
||||
"user_cardname": message_dict.get("user_cardname", ""),
|
||||
}
|
||||
|
||||
group_info = {}
|
||||
if message_dict.get("chat_info_group_id"):
|
||||
group_info = {
|
||||
"platform": message_dict.get("chat_info_group_platform", ""),
|
||||
"group_id": message_dict.get("chat_info_group_id", ""),
|
||||
"group_name": message_dict.get("chat_info_group_name", ""),
|
||||
}
|
||||
|
||||
format_info = {"content_format": "", "accept_format": ""}
|
||||
template_info = {"template_items": {}}
|
||||
|
||||
message_info = {
|
||||
"platform": message_dict.get("chat_info_platform", ""),
|
||||
"message_id": message_dict.get("message_id"),
|
||||
"time": message_dict.get("time"),
|
||||
"group_info": group_info,
|
||||
"user_info": user_info,
|
||||
"additional_config": message_dict.get("additional_config"),
|
||||
"format_info": format_info,
|
||||
"template_info": template_info,
|
||||
}
|
||||
|
||||
message_dict = {
|
||||
"message_info": message_info,
|
||||
"raw_message": message_dict.get("processed_plain_text"),
|
||||
"processed_plain_text": message_dict.get("processed_plain_text"),
|
||||
}
|
||||
|
||||
message_recv = MessageRecv(message_dict)
|
||||
|
||||
logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {message_dict.get('user_nickname', '')}")
|
||||
return message_recv
|
||||
|
||||
def put_adapter_response(request_id: str, response_data: dict) -> None:
|
||||
"""将适配器响应放入响应池"""
|
||||
@@ -139,7 +188,7 @@ async def _send_to_target(
|
||||
message_segment = Seg(type=message_type, data=content) # type: ignore
|
||||
|
||||
if reply_to_message:
|
||||
anchor_message = MessageRecv(message_dict=reply_to_message)
|
||||
anchor_message = message_dict_to_message_recv(message_dict=reply_to_message)
|
||||
anchor_message.update_chat_stream(target_stream)
|
||||
reply_to_platform_id = (
|
||||
f"{anchor_message.message_info.platform}:{anchor_message.message_info.user_info.user_id}"
|
||||
@@ -184,112 +233,6 @@ async def _send_to_target(
|
||||
return False
|
||||
|
||||
|
||||
async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageRecv]:
|
||||
# sourcery skip: inline-variable, use-named-expression
|
||||
"""查找要回复的消息
|
||||
|
||||
Args:
|
||||
target_stream: 目标聊天流
|
||||
reply_to: 回复格式,如"发送者:消息内容"或"发送者:消息内容"
|
||||
|
||||
Returns:
|
||||
Optional[MessageRecv]: 找到的消息,如果没找到则返回None
|
||||
"""
|
||||
try:
|
||||
# 解析reply_to参数
|
||||
if ":" in reply_to:
|
||||
parts = reply_to.split(":", 1)
|
||||
elif ":" in reply_to:
|
||||
parts = reply_to.split(":", 1)
|
||||
else:
|
||||
logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}")
|
||||
return None
|
||||
|
||||
if len(parts) != 2:
|
||||
logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}")
|
||||
return None
|
||||
|
||||
sender = parts[0].strip()
|
||||
text = parts[1].strip()
|
||||
|
||||
# 获取聊天流的最新20条消息
|
||||
reverse_talking_message = get_raw_msg_before_timestamp_with_chat(
|
||||
target_stream.stream_id,
|
||||
time.time(), # 当前时间之前的消息
|
||||
20, # 最新的20条消息
|
||||
)
|
||||
|
||||
# 反转列表,使最新的消息在前面
|
||||
reverse_talking_message = list(reversed(reverse_talking_message))
|
||||
|
||||
find_msg = None
|
||||
for message in reverse_talking_message:
|
||||
user_id = message["user_id"]
|
||||
platform = message["chat_info_platform"]
|
||||
person_id = get_person_info_manager().get_person_id(platform, user_id)
|
||||
person_name = await get_person_info_manager().get_value(person_id, "person_name")
|
||||
if person_name == sender:
|
||||
translate_text = message["processed_plain_text"]
|
||||
|
||||
# 使用独立函数处理用户引用格式
|
||||
translate_text = await replace_user_references_async(translate_text, platform)
|
||||
|
||||
similarity = difflib.SequenceMatcher(None, text, translate_text).ratio()
|
||||
if similarity >= 0.9:
|
||||
find_msg = message
|
||||
break
|
||||
|
||||
if not find_msg:
|
||||
logger.info("[SendAPI] 未找到匹配的回复消息")
|
||||
return None
|
||||
|
||||
# 构建MessageRecv对象
|
||||
user_info = {
|
||||
"platform": find_msg.get("user_platform", ""),
|
||||
"user_id": find_msg.get("user_id", ""),
|
||||
"user_nickname": find_msg.get("user_nickname", ""),
|
||||
"user_cardname": find_msg.get("user_cardname", ""),
|
||||
}
|
||||
|
||||
group_info = {}
|
||||
if find_msg.get("chat_info_group_id"):
|
||||
group_info = {
|
||||
"platform": find_msg.get("chat_info_group_platform", ""),
|
||||
"group_id": find_msg.get("chat_info_group_id", ""),
|
||||
"group_name": find_msg.get("chat_info_group_name", ""),
|
||||
}
|
||||
|
||||
format_info = {"content_format": "", "accept_format": ""}
|
||||
template_info = {"template_items": {}}
|
||||
|
||||
message_info = {
|
||||
"platform": target_stream.platform,
|
||||
"message_id": find_msg.get("message_id"),
|
||||
"time": find_msg.get("time"),
|
||||
"group_info": group_info,
|
||||
"user_info": user_info,
|
||||
"additional_config": find_msg.get("additional_config"),
|
||||
"format_info": format_info,
|
||||
"template_info": template_info,
|
||||
}
|
||||
|
||||
message_dict = {
|
||||
"message_info": message_info,
|
||||
"raw_message": find_msg.get("processed_plain_text"),
|
||||
"processed_plain_text": find_msg.get("processed_plain_text"),
|
||||
}
|
||||
|
||||
find_rec_msg = MessageRecv(message_dict)
|
||||
find_rec_msg.update_chat_stream(target_stream)
|
||||
|
||||
logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {sender}")
|
||||
return find_rec_msg
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[SendAPI] 查找回复消息时出错: {e}")
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 公共API函数 - 预定义类型的发送函数
|
||||
|
||||
Reference in New Issue
Block a user