mirror of https://github.com/Mai-with-u/MaiBot.git
feat:大幅优化聊天流控制,更精准简洁
parent
4bee6002ff
commit
a11e65f794
|
|
@ -64,6 +64,11 @@
|
||||||
> - QQ 机器人存在被限制风险,请自行了解,谨慎使用。
|
> - QQ 机器人存在被限制风险,请自行了解,谨慎使用。
|
||||||
> - 由于程序处于开发中,可能消耗较多 token。
|
> - 由于程序处于开发中,可能消耗较多 token。
|
||||||
|
|
||||||
|
## 麦麦MC项目(早期开发)
|
||||||
|
[让麦麦玩MC](https://github.com/MaiM-with-u/Maicraft)
|
||||||
|
|
||||||
|
交流群:1058573197
|
||||||
|
|
||||||
## 💬 讨论
|
## 💬 讨论
|
||||||
|
|
||||||
**技术交流群:**
|
**技术交流群:**
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
|
||||||
TODO:回复频率动态控制
|
## [0.10.2] - 2025-8-31
|
||||||
|
|
||||||
## [0.10.2] - 2025-8-24
|
|
||||||
### 🌟 主要功能更改
|
### 🌟 主要功能更改
|
||||||
|
- 大幅优化了聊天逻辑,更易配置
|
||||||
- 记忆系统重新启用,更好更优秀
|
- 记忆系统重新启用,更好更优秀
|
||||||
- 更好的event系统
|
- 更好的event系统
|
||||||
- 为空回复添加重试机制
|
- 现在支持提及100%回复
|
||||||
|
|
||||||
### 细节功能更改
|
### 细节功能更改
|
||||||
|
- 为空回复添加重试机制
|
||||||
- 修复tts插件可能的复读问题
|
- 修复tts插件可能的复读问题
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,7 @@ from src.config.config import global_config
|
||||||
from src.chat.frequency_control.utils import parse_stream_config_to_chat_id
|
from src.chat.frequency_control.utils import parse_stream_config_to_chat_id
|
||||||
|
|
||||||
|
|
||||||
class FocusValueControl:
|
def get_config_base_focus_value(chat_id: Optional[str] = None) -> float:
|
||||||
def __init__(self, chat_id: str):
|
|
||||||
self.chat_id = chat_id
|
|
||||||
self.focus_value_adjust: float = 1
|
|
||||||
|
|
||||||
def get_current_focus_value(self) -> float:
|
|
||||||
return get_current_focus_value(self.chat_id) * self.focus_value_adjust
|
|
||||||
|
|
||||||
|
|
||||||
class FocusValueControlManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.focus_value_controls: dict[str, FocusValueControl] = {}
|
|
||||||
|
|
||||||
def get_focus_value_control(self, chat_id: str) -> FocusValueControl:
|
|
||||||
if chat_id not in self.focus_value_controls:
|
|
||||||
self.focus_value_controls[chat_id] = FocusValueControl(chat_id)
|
|
||||||
return self.focus_value_controls[chat_id]
|
|
||||||
|
|
||||||
|
|
||||||
def get_current_focus_value(chat_id: Optional[str] = None) -> float:
|
|
||||||
"""
|
"""
|
||||||
根据当前时间和聊天流获取对应的 focus_value
|
根据当前时间和聊天流获取对应的 focus_value
|
||||||
"""
|
"""
|
||||||
|
|
@ -139,5 +120,3 @@ def get_global_focus_value() -> Optional[float]:
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
focus_value_control = FocusValueControlManager()
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,275 @@
|
||||||
|
import time
|
||||||
|
from typing import Optional, Dict, List
|
||||||
|
from src.plugin_system.apis import message_api
|
||||||
|
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
||||||
|
from src.common.logger import get_logger
|
||||||
|
from src.config.config import global_config
|
||||||
|
from src.chat.frequency_control.talk_frequency_control import get_config_base_talk_frequency
|
||||||
|
from src.chat.frequency_control.focus_value_control import get_config_base_focus_value
|
||||||
|
|
||||||
|
logger = get_logger("frequency_control")
|
||||||
|
|
||||||
|
|
||||||
|
class FrequencyControl:
|
||||||
|
"""
|
||||||
|
频率控制类,可以根据最近时间段的发言数量和发言人数动态调整频率
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, chat_id: str):
|
||||||
|
self.chat_id = chat_id
|
||||||
|
self.chat_stream: ChatStream = get_chat_manager().get_stream(self.chat_id)
|
||||||
|
if not self.chat_stream:
|
||||||
|
raise ValueError(f"无法找到聊天流: {self.chat_id}")
|
||||||
|
self.log_prefix = f"[{get_chat_manager().get_stream_name(self.chat_id) or self.chat_id}]"
|
||||||
|
# 发言频率调整值
|
||||||
|
self.talk_frequency_adjust: float = 1.0
|
||||||
|
self.talk_frequency_external_adjust: float = 1.0
|
||||||
|
# 专注度调整值
|
||||||
|
self.focus_value_adjust: float = 1.0
|
||||||
|
self.focus_value_external_adjust: float = 1.0
|
||||||
|
|
||||||
|
# 动态调整相关参数
|
||||||
|
self.last_update_time = time.time()
|
||||||
|
self.update_interval = 60 # 每60秒更新一次
|
||||||
|
|
||||||
|
# 历史数据缓存
|
||||||
|
self._message_count_cache = 0
|
||||||
|
self._user_count_cache = 0
|
||||||
|
self._last_cache_time = 0
|
||||||
|
self._cache_duration = 30 # 缓存30秒
|
||||||
|
|
||||||
|
# 调整参数
|
||||||
|
self.min_adjust = 0.3 # 最小调整值
|
||||||
|
self.max_adjust = 2.0 # 最大调整值
|
||||||
|
|
||||||
|
# 基准值(可根据实际情况调整)
|
||||||
|
self.base_message_count = 5 # 基准消息数量
|
||||||
|
self.base_user_count = 3 # 基准用户数量
|
||||||
|
|
||||||
|
# 平滑因子
|
||||||
|
self.smoothing_factor = 0.3
|
||||||
|
|
||||||
|
|
||||||
|
def get_dynamic_talk_frequency_adjust(self) -> float:
|
||||||
|
"""
|
||||||
|
获取纯动态调整值(不包含配置文件基础值)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: 动态调整值
|
||||||
|
"""
|
||||||
|
self._update_talk_frequency_adjust()
|
||||||
|
return self.talk_frequency_adjust
|
||||||
|
|
||||||
|
def get_dynamic_focus_value_adjust(self) -> float:
|
||||||
|
"""
|
||||||
|
获取纯动态调整值(不包含配置文件基础值)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: 动态调整值
|
||||||
|
"""
|
||||||
|
self._update_focus_value_adjust()
|
||||||
|
return self.focus_value_adjust
|
||||||
|
|
||||||
|
def _update_talk_frequency_adjust(self):
|
||||||
|
"""
|
||||||
|
更新发言频率调整值
|
||||||
|
适合人少话多的时候:人少但消息多,提高回复频率
|
||||||
|
"""
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# 检查是否需要更新
|
||||||
|
if current_time - self.last_update_time < self.update_interval:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取最近30分钟的数据(发言频率更敏感)
|
||||||
|
recent_messages = message_api.get_messages_by_time_in_chat(
|
||||||
|
chat_id=self.chat_stream.stream_id,
|
||||||
|
start_time=current_time - 1800, # 30分钟前
|
||||||
|
end_time=current_time,
|
||||||
|
filter_mai=True,
|
||||||
|
filter_command=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# 计算消息数量和用户数量
|
||||||
|
message_count = len(recent_messages)
|
||||||
|
user_ids = set()
|
||||||
|
for msg in recent_messages:
|
||||||
|
if msg.user_info and msg.user_info.user_id:
|
||||||
|
user_ids.add(msg.user_info.user_id)
|
||||||
|
user_count = len(user_ids)
|
||||||
|
|
||||||
|
# 发言频率调整逻辑:人少话多时提高回复频率
|
||||||
|
if user_count > 0:
|
||||||
|
# 计算人均消息数
|
||||||
|
messages_per_user = message_count / user_count
|
||||||
|
# 基准人均消息数
|
||||||
|
base_messages_per_user = self.base_message_count / self.base_user_count if self.base_user_count > 0 else 1.0
|
||||||
|
|
||||||
|
# 如果人均消息数高,说明活跃度高,提高回复频率
|
||||||
|
if messages_per_user > base_messages_per_user:
|
||||||
|
# 人少话多:提高回复频率
|
||||||
|
target_talk_adjust = min(self.max_adjust, messages_per_user / base_messages_per_user)
|
||||||
|
else:
|
||||||
|
# 活跃度一般:保持正常
|
||||||
|
target_talk_adjust = 1.0
|
||||||
|
else:
|
||||||
|
target_talk_adjust = 1.0
|
||||||
|
|
||||||
|
# 限制调整范围
|
||||||
|
target_talk_adjust = max(self.min_adjust, min(self.max_adjust, target_talk_adjust))
|
||||||
|
|
||||||
|
# 平滑调整
|
||||||
|
self.talk_frequency_adjust = (
|
||||||
|
self.talk_frequency_adjust * (1 - self.smoothing_factor) +
|
||||||
|
target_talk_adjust * self.smoothing_factor
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"{self.log_prefix} 发言频率调整更新: "
|
||||||
|
f"消息数={message_count}, 用户数={user_count}, "
|
||||||
|
f"人均消息数={message_count/user_count if user_count > 0 else 0:.2f}, "
|
||||||
|
f"调整值={self.talk_frequency_adjust:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{self.log_prefix} 更新发言频率调整值时出错: {e}")
|
||||||
|
|
||||||
|
def _update_focus_value_adjust(self):
|
||||||
|
"""
|
||||||
|
更新专注度调整值
|
||||||
|
适合人多话多的时候:人多且消息多,提高专注度(LLM消耗更多,但回复更精准)
|
||||||
|
"""
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# 检查是否需要更新
|
||||||
|
if current_time - self.last_update_time < self.update_interval:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取最近1小时的数据
|
||||||
|
recent_messages = message_api.get_messages_by_time_in_chat(
|
||||||
|
chat_id=self.chat_stream.stream_id,
|
||||||
|
start_time=current_time - 3600, # 1小时前
|
||||||
|
end_time=current_time,
|
||||||
|
filter_mai=True,
|
||||||
|
filter_command=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# 计算消息数量和用户数量
|
||||||
|
message_count = len(recent_messages)
|
||||||
|
user_ids = set()
|
||||||
|
for msg in recent_messages:
|
||||||
|
if msg.user_info and msg.user_info.user_id:
|
||||||
|
user_ids.add(msg.user_info.user_id)
|
||||||
|
user_count = len(user_ids)
|
||||||
|
|
||||||
|
# 专注度调整逻辑:人多话多时提高专注度
|
||||||
|
if user_count > 0 and self.base_user_count > 0:
|
||||||
|
# 计算用户活跃度比率
|
||||||
|
user_ratio = user_count / self.base_user_count
|
||||||
|
# 计算消息活跃度比率
|
||||||
|
message_ratio = message_count / self.base_message_count if self.base_message_count > 0 else 1.0
|
||||||
|
|
||||||
|
# 如果用户多且消息多,提高专注度
|
||||||
|
if user_ratio > 1.2 and message_ratio > 1.2:
|
||||||
|
# 人多话多:提高专注度,消耗更多LLM资源但回复更精准
|
||||||
|
target_focus_adjust = min(self.max_adjust, (user_ratio + message_ratio) / 2)
|
||||||
|
elif user_ratio > 1.5:
|
||||||
|
# 用户特别多:适度提高专注度
|
||||||
|
target_focus_adjust = min(self.max_adjust, 1.0 + (user_ratio - 1.0) * 0.3)
|
||||||
|
else:
|
||||||
|
# 正常情况:保持默认专注度
|
||||||
|
target_focus_adjust = 1.0
|
||||||
|
else:
|
||||||
|
target_focus_adjust = 1.0
|
||||||
|
|
||||||
|
# 限制调整范围
|
||||||
|
target_focus_adjust = max(self.min_adjust, min(self.max_adjust, target_focus_adjust))
|
||||||
|
|
||||||
|
# 平滑调整
|
||||||
|
self.focus_value_adjust = (
|
||||||
|
self.focus_value_adjust * (1 - self.smoothing_factor) +
|
||||||
|
target_focus_adjust * self.smoothing_factor
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"{self.log_prefix} 专注度调整更新: "
|
||||||
|
f"消息数={message_count}, 用户数={user_count}, "
|
||||||
|
f"用户比率={user_count/self.base_user_count if self.base_user_count > 0 else 0:.2f}, "
|
||||||
|
f"消息比率={message_count/self.base_message_count if self.base_message_count > 0 else 0:.2f}, "
|
||||||
|
f"调整值={self.focus_value_adjust:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"{self.log_prefix} 更新专注度调整值时出错: {e}")
|
||||||
|
|
||||||
|
def get_final_talk_frequency(self) -> float:
|
||||||
|
return get_config_base_talk_frequency(self.chat_stream.stream_id) * self.get_dynamic_talk_frequency_adjust() * self.talk_frequency_external_adjust
|
||||||
|
|
||||||
|
def get_final_focus_value(self) -> float:
|
||||||
|
return get_config_base_focus_value(self.chat_stream.stream_id) * self.get_dynamic_focus_value_adjust() * self.focus_value_external_adjust
|
||||||
|
|
||||||
|
|
||||||
|
def set_adjustment_parameters(
|
||||||
|
self,
|
||||||
|
min_adjust: Optional[float] = None,
|
||||||
|
max_adjust: Optional[float] = None,
|
||||||
|
base_message_count: Optional[int] = None,
|
||||||
|
base_user_count: Optional[int] = None,
|
||||||
|
smoothing_factor: Optional[float] = None,
|
||||||
|
update_interval: Optional[int] = None
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
设置调整参数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
min_adjust: 最小调整值
|
||||||
|
max_adjust: 最大调整值
|
||||||
|
base_message_count: 基准消息数量
|
||||||
|
base_user_count: 基准用户数量
|
||||||
|
smoothing_factor: 平滑因子
|
||||||
|
update_interval: 更新间隔(秒)
|
||||||
|
"""
|
||||||
|
if min_adjust is not None:
|
||||||
|
self.min_adjust = max(0.1, min_adjust)
|
||||||
|
if max_adjust is not None:
|
||||||
|
self.max_adjust = max(1.0, max_adjust)
|
||||||
|
if base_message_count is not None:
|
||||||
|
self.base_message_count = max(1, base_message_count)
|
||||||
|
if base_user_count is not None:
|
||||||
|
self.base_user_count = max(1, base_user_count)
|
||||||
|
if smoothing_factor is not None:
|
||||||
|
self.smoothing_factor = max(0.0, min(1.0, smoothing_factor))
|
||||||
|
if update_interval is not None:
|
||||||
|
self.update_interval = max(10, update_interval)
|
||||||
|
|
||||||
|
|
||||||
|
class FrequencyControlManager:
|
||||||
|
"""
|
||||||
|
频率控制管理器,管理多个聊天流的频率控制实例
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.frequency_control_dict: Dict[str, FrequencyControl] = {}
|
||||||
|
|
||||||
|
def get_or_create_frequency_control(self, chat_id: str) -> FrequencyControl:
|
||||||
|
"""
|
||||||
|
获取或创建指定聊天流的频率控制实例
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id: 聊天流ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
FrequencyControl: 频率控制实例
|
||||||
|
"""
|
||||||
|
if chat_id not in self.frequency_control_dict:
|
||||||
|
self.frequency_control_dict[chat_id] = FrequencyControl(chat_id)
|
||||||
|
return self.frequency_control_dict[chat_id]
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
frequency_control_manager = FrequencyControlManager()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,26 +3,7 @@ from src.config.config import global_config
|
||||||
from src.chat.frequency_control.utils import parse_stream_config_to_chat_id
|
from src.chat.frequency_control.utils import parse_stream_config_to_chat_id
|
||||||
|
|
||||||
|
|
||||||
class TalkFrequencyControl:
|
def get_config_base_talk_frequency(chat_id: Optional[str] = None) -> float:
|
||||||
def __init__(self, chat_id: str):
|
|
||||||
self.chat_id = chat_id
|
|
||||||
self.talk_frequency_adjust: float = 1
|
|
||||||
|
|
||||||
def get_current_talk_frequency(self) -> float:
|
|
||||||
return get_current_talk_frequency(self.chat_id) * self.talk_frequency_adjust
|
|
||||||
|
|
||||||
|
|
||||||
class TalkFrequencyControlManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.talk_frequency_controls = {}
|
|
||||||
|
|
||||||
def get_talk_frequency_control(self, chat_id: str) -> TalkFrequencyControl:
|
|
||||||
if chat_id not in self.talk_frequency_controls:
|
|
||||||
self.talk_frequency_controls[chat_id] = TalkFrequencyControl(chat_id)
|
|
||||||
return self.talk_frequency_controls[chat_id]
|
|
||||||
|
|
||||||
|
|
||||||
def get_current_talk_frequency(chat_id: Optional[str] = None) -> float:
|
|
||||||
"""
|
"""
|
||||||
根据当前时间和聊天流获取对应的 talk_frequency
|
根据当前时间和聊天流获取对应的 talk_frequency
|
||||||
|
|
||||||
|
|
@ -145,4 +126,3 @@ def get_global_frequency() -> Optional[float]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
talk_frequency_control = TalkFrequencyControlManager()
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ from src.chat.planner_actions.action_modifier import ActionModifier
|
||||||
from src.chat.planner_actions.action_manager import ActionManager
|
from src.chat.planner_actions.action_manager import ActionManager
|
||||||
from src.chat.heart_flow.hfc_utils import CycleDetail
|
from src.chat.heart_flow.hfc_utils import CycleDetail
|
||||||
from src.chat.heart_flow.hfc_utils import send_typing, stop_typing
|
from src.chat.heart_flow.hfc_utils import send_typing, stop_typing
|
||||||
from src.chat.frequency_control.talk_frequency_control import talk_frequency_control
|
from src.chat.frequency_control.frequency_control import frequency_control_manager
|
||||||
from src.chat.frequency_control.focus_value_control import focus_value_control
|
|
||||||
from src.chat.express.expression_learner import expression_learner_manager
|
from src.chat.express.expression_learner import expression_learner_manager
|
||||||
from src.person_info.person_info import Person
|
from src.person_info.person_info import Person
|
||||||
from src.plugin_system.base.component_types import ChatMode, EventType, ActionInfo
|
from src.plugin_system.base.component_types import ChatMode, EventType, ActionInfo
|
||||||
|
|
@ -85,8 +84,7 @@ class HeartFChatting:
|
||||||
|
|
||||||
self.expression_learner = expression_learner_manager.get_expression_learner(self.stream_id)
|
self.expression_learner = expression_learner_manager.get_expression_learner(self.stream_id)
|
||||||
|
|
||||||
self.talk_frequency_control = talk_frequency_control.get_talk_frequency_control(self.stream_id)
|
self.frequency_control = frequency_control_manager.get_or_create_frequency_control(self.stream_id)
|
||||||
self.focus_value_control = focus_value_control.get_focus_value_control(self.stream_id)
|
|
||||||
|
|
||||||
self.action_manager = ActionManager()
|
self.action_manager = ActionManager()
|
||||||
self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager)
|
self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager)
|
||||||
|
|
@ -101,15 +99,8 @@ class HeartFChatting:
|
||||||
self._cycle_counter = 0
|
self._cycle_counter = 0
|
||||||
self._current_cycle_detail: CycleDetail = None # type: ignore
|
self._current_cycle_detail: CycleDetail = None # type: ignore
|
||||||
|
|
||||||
self.reply_timeout_count = 0
|
|
||||||
self.plan_timeout_count = 0
|
|
||||||
|
|
||||||
self.last_read_time = time.time() - 10
|
self.last_read_time = time.time() - 10
|
||||||
|
|
||||||
self.focus_energy = 1
|
|
||||||
self.no_action_consecutive = 0
|
|
||||||
# 最近三次no_action的新消息兴趣度记录
|
|
||||||
self.recent_interest_records: deque = deque(maxlen=3)
|
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
"""检查是否需要启动主循环,如果未激活则启动。"""
|
"""检查是否需要启动主循环,如果未激活则启动。"""
|
||||||
|
|
@ -187,87 +178,14 @@ class HeartFChatting:
|
||||||
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, " # type: ignore
|
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, " # type: ignore
|
||||||
f"选择动作: {action_type}" + (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
f"选择动作: {action_type}" + (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
def _determine_form_type(self) -> None:
|
async def caculate_interest_value(self, recent_messages_list: List["DatabaseMessages"]) -> float:
|
||||||
"""判断使用哪种形式的no_action"""
|
|
||||||
# 如果连续no_action次数少于3次,使用waiting形式
|
|
||||||
if self.no_action_consecutive <= 3:
|
|
||||||
self.focus_energy = 1
|
|
||||||
else:
|
|
||||||
# 计算最近三次记录的兴趣度总和
|
|
||||||
total_recent_interest = sum(self.recent_interest_records)
|
|
||||||
|
|
||||||
# 计算调整后的阈值
|
|
||||||
adjusted_threshold = 1 / self.talk_frequency_control.get_current_talk_frequency()
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"{self.log_prefix} 最近三次兴趣度总和: {total_recent_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 如果兴趣度总和小于阈值,进入breaking形式
|
|
||||||
if total_recent_interest < adjusted_threshold:
|
|
||||||
logger.info(f"{self.log_prefix} 兴趣度不足,进入休息")
|
|
||||||
self.focus_energy = random.randint(3, 6)
|
|
||||||
else:
|
|
||||||
logger.info(f"{self.log_prefix} 兴趣度充足,等待新消息")
|
|
||||||
self.focus_energy = 1
|
|
||||||
|
|
||||||
async def _should_process_messages(self, new_message: List["DatabaseMessages"]) -> tuple[bool, float]:
|
|
||||||
"""
|
|
||||||
判断是否应该处理消息
|
|
||||||
|
|
||||||
Args:
|
|
||||||
new_message: 新消息列表
|
|
||||||
mode: 当前聊天模式
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否应该处理消息
|
|
||||||
"""
|
|
||||||
new_message_count = len(new_message)
|
|
||||||
talk_frequency = self.talk_frequency_control.get_current_talk_frequency()
|
|
||||||
|
|
||||||
modified_exit_count_threshold = self.focus_energy * 0.5 / talk_frequency
|
|
||||||
modified_exit_interest_threshold = 1.5 / talk_frequency
|
|
||||||
total_interest = 0.0
|
total_interest = 0.0
|
||||||
for msg in new_message:
|
for msg in recent_messages_list:
|
||||||
interest_value = msg.interest_value
|
interest_value = msg.interest_value
|
||||||
if interest_value is not None and msg.processed_plain_text:
|
if interest_value is not None and msg.processed_plain_text:
|
||||||
total_interest += float(interest_value)
|
total_interest += float(interest_value)
|
||||||
|
return total_interest / len(recent_messages_list)
|
||||||
if new_message_count >= modified_exit_count_threshold:
|
|
||||||
self.recent_interest_records.append(total_interest)
|
|
||||||
logger.info(
|
|
||||||
f"{self.log_prefix} 累计消息数量达到{new_message_count}条(>{modified_exit_count_threshold:.1f}),结束等待"
|
|
||||||
)
|
|
||||||
# logger.info(self.last_read_time)
|
|
||||||
# logger.info(new_message)
|
|
||||||
return True, total_interest / new_message_count if new_message_count > 0 else 0.0
|
|
||||||
|
|
||||||
# 检查累计兴趣值
|
|
||||||
if new_message_count > 0:
|
|
||||||
# 只在兴趣值变化时输出log
|
|
||||||
if not hasattr(self, "_last_accumulated_interest") or total_interest != self._last_accumulated_interest:
|
|
||||||
logger.info(
|
|
||||||
f"{self.log_prefix} 休息中,新消息:{new_message_count}条,累计兴趣值: {total_interest:.2f}, 活跃度: {talk_frequency:.1f}"
|
|
||||||
)
|
|
||||||
self._last_accumulated_interest = total_interest
|
|
||||||
|
|
||||||
if total_interest >= modified_exit_interest_threshold:
|
|
||||||
# 记录兴趣度到列表
|
|
||||||
self.recent_interest_records.append(total_interest)
|
|
||||||
logger.info(
|
|
||||||
f"{self.log_prefix} 累计兴趣值达到{total_interest:.2f}(>{modified_exit_interest_threshold:.1f}),结束等待"
|
|
||||||
)
|
|
||||||
return True, total_interest / new_message_count if new_message_count > 0 else 0.0
|
|
||||||
|
|
||||||
# 每10秒输出一次等待状态
|
|
||||||
if int(time.time() - self.last_read_time) > 0 and int(time.time() - self.last_read_time) % 15 == 0:
|
|
||||||
logger.debug(
|
|
||||||
f"{self.log_prefix} 已等待{time.time() - self.last_read_time:.0f}秒,累计{new_message_count}条消息,累计兴趣{total_interest:.1f},继续等待..."
|
|
||||||
)
|
|
||||||
await asyncio.sleep(0.5)
|
|
||||||
|
|
||||||
return False, 0.0
|
|
||||||
|
|
||||||
async def _loopbody(self):
|
async def _loopbody(self):
|
||||||
recent_messages_list = message_api.get_messages_by_time_in_chat(
|
recent_messages_list = message_api.get_messages_by_time_in_chat(
|
||||||
|
|
@ -279,16 +197,13 @@ class HeartFChatting:
|
||||||
filter_mai=True,
|
filter_mai=True,
|
||||||
filter_command=True,
|
filter_command=True,
|
||||||
)
|
)
|
||||||
# 统一的消息处理逻辑
|
|
||||||
should_process, interest_value = await self._should_process_messages(recent_messages_list)
|
if recent_messages_list:
|
||||||
|
|
||||||
if should_process:
|
|
||||||
self.last_read_time = time.time()
|
self.last_read_time = time.time()
|
||||||
await self._observe(interest_value=interest_value)
|
await self._observe(interest_value=await self.caculate_interest_value(recent_messages_list),recent_messages_list=recent_messages_list)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Normal模式:消息数量不足,等待
|
# Normal模式:消息数量不足,等待
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.2)
|
||||||
return True
|
return True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -342,8 +257,7 @@ class HeartFChatting:
|
||||||
|
|
||||||
return loop_info, reply_text, cycle_timers
|
return loop_info, reply_text, cycle_timers
|
||||||
|
|
||||||
async def _observe(self, interest_value: float = 0.0) -> bool:
|
async def _observe(self, interest_value: float = 0.0,recent_messages_list: List["DatabaseMessages"] = []) -> bool:
|
||||||
action_type = "no_action"
|
|
||||||
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||||
|
|
||||||
# 使用sigmoid函数将interest_value转换为概率
|
# 使用sigmoid函数将interest_value转换为概率
|
||||||
|
|
@ -362,22 +276,28 @@ class HeartFChatting:
|
||||||
normal_mode_probability = (
|
normal_mode_probability = (
|
||||||
calculate_normal_mode_probability(interest_value)
|
calculate_normal_mode_probability(interest_value)
|
||||||
* 2
|
* 2
|
||||||
* self.talk_frequency_control.get_current_talk_frequency()
|
* self.frequency_control.get_final_talk_frequency()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#对呼唤名字进行增幅
|
||||||
|
for msg in recent_messages_list:
|
||||||
|
if msg.reply_probability_boost is not None and msg.reply_probability_boost > 0.0:
|
||||||
|
normal_mode_probability += msg.reply_probability_boost
|
||||||
|
if global_config.chat.mentioned_bot_reply and msg.is_mentioned:
|
||||||
|
normal_mode_probability += global_config.chat.mentioned_bot_reply
|
||||||
|
if global_config.chat.at_bot_inevitable_reply and msg.is_at:
|
||||||
|
normal_mode_probability += global_config.chat.at_bot_inevitable_reply
|
||||||
|
|
||||||
|
|
||||||
# 根据概率决定使用哪种模式
|
# 根据概率决定使用直接回复
|
||||||
|
interest_triggerd = False
|
||||||
|
focus_triggerd = False
|
||||||
|
|
||||||
if random.random() < normal_mode_probability:
|
if random.random() < normal_mode_probability:
|
||||||
mode = ChatMode.NORMAL
|
interest_triggerd = True
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{self.log_prefix} 有兴趣({interest_value:.2f}),在{normal_mode_probability * 100:.0f}%概率下选择回复"
|
f"{self.log_prefix} 有新消息,在{normal_mode_probability * 100:.0f}%概率下选择回复"
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
mode = ChatMode.FOCUS
|
|
||||||
|
|
||||||
# 创建新的循环信息
|
|
||||||
cycle_timers, thinking_id = self.start_cycle()
|
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考")
|
|
||||||
|
|
||||||
if s4u_config.enable_s4u:
|
if s4u_config.enable_s4u:
|
||||||
await send_typing()
|
await send_typing()
|
||||||
|
|
@ -386,16 +306,21 @@ class HeartFChatting:
|
||||||
await self.expression_learner.trigger_learning_for_chat()
|
await self.expression_learner.trigger_learning_for_chat()
|
||||||
|
|
||||||
available_actions: Dict[str, ActionInfo] = {}
|
available_actions: Dict[str, ActionInfo] = {}
|
||||||
if random.random() > self.focus_value_control.get_current_focus_value() and mode == ChatMode.FOCUS:
|
|
||||||
# 如果激活度没有激活,并且聊天活跃度低,有可能不进行plan,相当于不在电脑前,不进行认真思考
|
#如果兴趣度不足以激活
|
||||||
action_to_use_info = [
|
if not interest_triggerd:
|
||||||
ActionPlannerInfo(
|
#看看专注值够不够
|
||||||
action_type="no_action",
|
if random.random() < self.frequency_control.get_final_focus_value():
|
||||||
reasoning="专注不足",
|
#专注值足够,仍然进入正式思考
|
||||||
action_data={},
|
focus_triggerd = True #都没触发,路边
|
||||||
)
|
|
||||||
]
|
|
||||||
else:
|
# 任意一种触发都行
|
||||||
|
if interest_triggerd or focus_triggerd:
|
||||||
|
# 进入正式思考模式
|
||||||
|
cycle_timers, thinking_id = self.start_cycle()
|
||||||
|
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考")
|
||||||
|
|
||||||
# 第一步:动作检查
|
# 第一步:动作检查
|
||||||
with Timer("动作检查", cycle_timers):
|
with Timer("动作检查", cycle_timers):
|
||||||
try:
|
try:
|
||||||
|
|
@ -433,103 +358,93 @@ class HeartFChatting:
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
with Timer("规划器", cycle_timers):
|
with Timer("规划器", cycle_timers):
|
||||||
|
# 根据不同触发,进入不同plan
|
||||||
|
if focus_triggerd:
|
||||||
|
mode = ChatMode.FOCUS
|
||||||
|
else:
|
||||||
|
mode = ChatMode.NORMAL
|
||||||
|
|
||||||
action_to_use_info, _ = await self.action_planner.plan(
|
action_to_use_info, _ = await self.action_planner.plan(
|
||||||
mode=mode,
|
mode=mode,
|
||||||
loop_start_time=self.last_read_time,
|
loop_start_time=self.last_read_time,
|
||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
)
|
)
|
||||||
|
|
||||||
# for action in action_to_use_info:
|
# 3. 并行执行所有动作
|
||||||
# print(action.action_type)
|
action_tasks = [
|
||||||
|
asyncio.create_task(
|
||||||
|
self._execute_action(action, action_to_use_info, thinking_id, available_actions, cycle_timers)
|
||||||
|
)
|
||||||
|
for action in action_to_use_info
|
||||||
|
]
|
||||||
|
|
||||||
# 3. 并行执行所有动作
|
# 并行执行所有任务
|
||||||
action_tasks = [
|
results = await asyncio.gather(*action_tasks, return_exceptions=True)
|
||||||
asyncio.create_task(
|
|
||||||
self._execute_action(action, action_to_use_info, thinking_id, available_actions, cycle_timers)
|
|
||||||
)
|
|
||||||
for action in action_to_use_info
|
|
||||||
]
|
|
||||||
|
|
||||||
# 并行执行所有任务
|
# 处理执行结果
|
||||||
results = await asyncio.gather(*action_tasks, return_exceptions=True)
|
reply_loop_info = None
|
||||||
|
reply_text_from_reply = ""
|
||||||
|
action_success = False
|
||||||
|
action_reply_text = ""
|
||||||
|
action_command = ""
|
||||||
|
|
||||||
# 处理执行结果
|
for i, result in enumerate(results):
|
||||||
reply_loop_info = None
|
if isinstance(result, BaseException):
|
||||||
reply_text_from_reply = ""
|
logger.error(f"{self.log_prefix} 动作执行异常: {result}")
|
||||||
action_success = False
|
continue
|
||||||
action_reply_text = ""
|
|
||||||
action_command = ""
|
|
||||||
|
|
||||||
for i, result in enumerate(results):
|
_cur_action = action_to_use_info[i]
|
||||||
if isinstance(result, BaseException):
|
if result["action_type"] != "reply":
|
||||||
logger.error(f"{self.log_prefix} 动作执行异常: {result}")
|
action_success = result["success"]
|
||||||
continue
|
action_reply_text = result["reply_text"]
|
||||||
|
action_command = result.get("command", "")
|
||||||
|
elif result["action_type"] == "reply":
|
||||||
|
if result["success"]:
|
||||||
|
reply_loop_info = result["loop_info"]
|
||||||
|
reply_text_from_reply = result["reply_text"]
|
||||||
|
else:
|
||||||
|
logger.warning(f"{self.log_prefix} 回复动作执行失败")
|
||||||
|
|
||||||
_cur_action = action_to_use_info[i]
|
# 构建最终的循环信息
|
||||||
if result["action_type"] != "reply":
|
if reply_loop_info:
|
||||||
action_success = result["success"]
|
# 如果有回复信息,使用回复的loop_info作为基础
|
||||||
action_reply_text = result["reply_text"]
|
loop_info = reply_loop_info
|
||||||
action_command = result.get("command", "")
|
# 更新动作执行信息
|
||||||
elif result["action_type"] == "reply":
|
loop_info["loop_action_info"].update(
|
||||||
if result["success"]:
|
{
|
||||||
reply_loop_info = result["loop_info"]
|
"action_taken": action_success,
|
||||||
reply_text_from_reply = result["reply_text"]
|
"command": action_command,
|
||||||
else:
|
"taken_time": time.time(),
|
||||||
logger.warning(f"{self.log_prefix} 回复动作执行失败")
|
}
|
||||||
|
)
|
||||||
# 构建最终的循环信息
|
reply_text = reply_text_from_reply
|
||||||
if reply_loop_info:
|
else:
|
||||||
# 如果有回复信息,使用回复的loop_info作为基础
|
# 没有回复信息,构建纯动作的loop_info
|
||||||
loop_info = reply_loop_info
|
loop_info = {
|
||||||
# 更新动作执行信息
|
"loop_plan_info": {
|
||||||
loop_info["loop_action_info"].update(
|
"action_result": action_to_use_info,
|
||||||
{
|
},
|
||||||
"action_taken": action_success,
|
"loop_action_info": {
|
||||||
"command": action_command,
|
"action_taken": action_success,
|
||||||
"taken_time": time.time(),
|
"reply_text": action_reply_text,
|
||||||
|
"command": action_command,
|
||||||
|
"taken_time": time.time(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
reply_text = action_reply_text
|
||||||
reply_text = reply_text_from_reply
|
|
||||||
else:
|
|
||||||
# 没有回复信息,构建纯动作的loop_info
|
self.end_cycle(loop_info, cycle_timers)
|
||||||
loop_info = {
|
self.print_cycle_info(cycle_timers)
|
||||||
"loop_plan_info": {
|
|
||||||
"action_result": action_to_use_info,
|
|
||||||
},
|
|
||||||
"loop_action_info": {
|
|
||||||
"action_taken": action_success,
|
|
||||||
"reply_text": action_reply_text,
|
|
||||||
"command": action_command,
|
|
||||||
"taken_time": time.time(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
reply_text = action_reply_text
|
|
||||||
|
|
||||||
if s4u_config.enable_s4u:
|
"""S4U内容,暂时保留"""
|
||||||
await stop_typing()
|
if s4u_config.enable_s4u:
|
||||||
await mai_thinking_manager.get_mai_think(self.stream_id).do_think_after_response(reply_text)
|
await stop_typing()
|
||||||
|
await mai_thinking_manager.get_mai_think(self.stream_id).do_think_after_response(reply_text)
|
||||||
|
"""S4U内容,暂时保留"""
|
||||||
|
|
||||||
self.end_cycle(loop_info, cycle_timers)
|
|
||||||
self.print_cycle_info(cycle_timers)
|
|
||||||
|
|
||||||
# await self.willing_manager.after_generate_reply_handle(message_data.get("message_id", ""))
|
|
||||||
|
|
||||||
action_type = action_to_use_info[0].action_type if action_to_use_info else "no_action"
|
|
||||||
|
|
||||||
# 管理no_action计数器:当执行了非no_action动作时,重置计数器
|
|
||||||
if action_type != "no_action":
|
|
||||||
# no_action逻辑已集成到heartFC_chat.py中,直接重置计数器
|
|
||||||
self.recent_interest_records.clear()
|
|
||||||
self.no_action_consecutive = 0
|
|
||||||
logger.debug(f"{self.log_prefix} 执行了{action_type}动作,重置no_action计数器")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if action_type == "no_action":
|
|
||||||
self.no_action_consecutive += 1
|
|
||||||
self._determine_form_type()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def _main_chat_loop(self):
|
async def _main_chat_loop(self):
|
||||||
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,10 @@ async def _calculate_interest(message: MessageRecv) -> Tuple[float, list[str]]:
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[float, bool, list[str]]: (兴趣度, 是否被提及, 关键词)
|
Tuple[float, bool, list[str]]: (兴趣度, 是否被提及, 关键词)
|
||||||
"""
|
"""
|
||||||
if message.is_picid:
|
if message.is_picid or message.is_emoji:
|
||||||
return 0.0, []
|
return 0.0, []
|
||||||
|
|
||||||
is_mentioned, _ = is_mentioned_bot_in_message(message)
|
is_mentioned,is_at,reply_probability_boost = is_mentioned_bot_in_message(message)
|
||||||
interested_rate = 0.0
|
interested_rate = 0.0
|
||||||
|
|
||||||
with Timer("记忆激活"):
|
with Timer("记忆激活"):
|
||||||
|
|
@ -79,17 +79,13 @@ async def _calculate_interest(message: MessageRecv) -> Tuple[float, list[str]]:
|
||||||
# 确保在范围内
|
# 确保在范围内
|
||||||
base_interest = min(max(base_interest, 0.01), 0.3)
|
base_interest = min(max(base_interest, 0.01), 0.3)
|
||||||
|
|
||||||
interested_rate += base_interest
|
|
||||||
|
|
||||||
if is_mentioned:
|
|
||||||
interest_increase_on_mention = 2
|
|
||||||
interested_rate += interest_increase_on_mention
|
|
||||||
|
|
||||||
|
message.interest_value = base_interest
|
||||||
message.interest_value = interested_rate
|
|
||||||
message.is_mentioned = is_mentioned
|
message.is_mentioned = is_mentioned
|
||||||
|
message.is_at = is_at
|
||||||
return interested_rate, keywords
|
message.reply_probability_boost = reply_probability_boost
|
||||||
|
|
||||||
|
return base_interest, keywords
|
||||||
|
|
||||||
|
|
||||||
class HeartFCMessageReceiver:
|
class HeartFCMessageReceiver:
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,8 @@ class MessageRecv(Message):
|
||||||
self.has_picid = False
|
self.has_picid = False
|
||||||
self.is_voice = False
|
self.is_voice = False
|
||||||
self.is_mentioned = None
|
self.is_mentioned = None
|
||||||
|
self.is_at = False
|
||||||
|
self.reply_probability_boost = 0.0
|
||||||
self.is_notify = False
|
self.is_notify = False
|
||||||
|
|
||||||
self.is_command = False
|
self.is_command = False
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ class MessageStorage:
|
||||||
filtered_display_message = ""
|
filtered_display_message = ""
|
||||||
interest_value = 0
|
interest_value = 0
|
||||||
is_mentioned = False
|
is_mentioned = False
|
||||||
|
is_at = False
|
||||||
|
reply_probability_boost = 0.0
|
||||||
reply_to = message.reply_to
|
reply_to = message.reply_to
|
||||||
priority_mode = ""
|
priority_mode = ""
|
||||||
priority_info = {}
|
priority_info = {}
|
||||||
|
|
@ -70,6 +72,8 @@ class MessageStorage:
|
||||||
filtered_display_message = ""
|
filtered_display_message = ""
|
||||||
interest_value = message.interest_value
|
interest_value = message.interest_value
|
||||||
is_mentioned = message.is_mentioned
|
is_mentioned = message.is_mentioned
|
||||||
|
is_at = message.is_at
|
||||||
|
reply_probability_boost = message.reply_probability_boost
|
||||||
reply_to = ""
|
reply_to = ""
|
||||||
priority_mode = message.priority_mode
|
priority_mode = message.priority_mode
|
||||||
priority_info = message.priority_info
|
priority_info = message.priority_info
|
||||||
|
|
@ -100,6 +104,8 @@ class MessageStorage:
|
||||||
# Flattened chat_info
|
# Flattened chat_info
|
||||||
reply_to=reply_to,
|
reply_to=reply_to,
|
||||||
is_mentioned=is_mentioned,
|
is_mentioned=is_mentioned,
|
||||||
|
is_at=is_at,
|
||||||
|
reply_probability_boost=reply_probability_boost,
|
||||||
chat_info_stream_id=chat_info_dict.get("stream_id"),
|
chat_info_stream_id=chat_info_dict.get("stream_id"),
|
||||||
chat_info_platform=chat_info_dict.get("platform"),
|
chat_info_platform=chat_info_dict.get("platform"),
|
||||||
chat_info_user_platform=user_info_from_chat.get("platform"),
|
chat_info_user_platform=user_info_from_chat.get("platform"),
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ def init_prompt():
|
||||||
动作描述:参与聊天回复,发送文本进行表达
|
动作描述:参与聊天回复,发送文本进行表达
|
||||||
- 你想要闲聊或者随便附和
|
- 你想要闲聊或者随便附和
|
||||||
- 有人提到了你,但是你还没有回应
|
- 有人提到了你,但是你还没有回应
|
||||||
- {mentioned_bonus}
|
|
||||||
- 如果你刚刚进行了回复,不要对同一个话题重复回应
|
- 如果你刚刚进行了回复,不要对同一个话题重复回应
|
||||||
{{
|
{{
|
||||||
"action": "reply",
|
"action": "reply",
|
||||||
|
|
@ -93,7 +92,6 @@ def init_prompt():
|
||||||
现在,最新的聊天消息引起了你的兴趣,你想要对其中的消息进行回复,回复标准如下:
|
现在,最新的聊天消息引起了你的兴趣,你想要对其中的消息进行回复,回复标准如下:
|
||||||
- 你想要闲聊或者随便附和
|
- 你想要闲聊或者随便附和
|
||||||
- 有人提到了你,但是你还没有回应
|
- 有人提到了你,但是你还没有回应
|
||||||
- {mentioned_bonus}
|
|
||||||
- 如果你刚刚进行了回复,不要对同一个话题重复回应
|
- 如果你刚刚进行了回复,不要对同一个话题重复回应
|
||||||
|
|
||||||
你之前的动作记录:
|
你之前的动作记录:
|
||||||
|
|
@ -465,7 +463,7 @@ class ActionPlanner:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix}副规划器返回了{len(action_planner_infos)}个action")
|
logger.debug(f"{self.log_prefix}副规划器返回了{len(action_planner_infos)}个action")
|
||||||
return action_planner_infos
|
return action_planner_infos
|
||||||
|
|
||||||
async def plan(
|
async def plan(
|
||||||
|
|
@ -553,7 +551,7 @@ class ActionPlanner:
|
||||||
for i, (action_name, action_info) in enumerate(action_items):
|
for i, (action_name, action_info) in enumerate(action_items):
|
||||||
sub_planner_lists[i % sub_planner_num].append((action_name, action_info))
|
sub_planner_lists[i % sub_planner_num].append((action_name, action_info))
|
||||||
|
|
||||||
logger.info(
|
logger.debug(
|
||||||
f"{self.log_prefix}成功将{sub_planner_actions_num}个actions分配到{sub_planner_num}个子列表中"
|
f"{self.log_prefix}成功将{sub_planner_actions_num}个actions分配到{sub_planner_num}个子列表中"
|
||||||
)
|
)
|
||||||
for i, action_list in enumerate(sub_planner_lists):
|
for i, action_list in enumerate(sub_planner_lists):
|
||||||
|
|
@ -585,7 +583,7 @@ class ActionPlanner:
|
||||||
for sub_result in sub_plan_results:
|
for sub_result in sub_plan_results:
|
||||||
all_sub_planner_results.extend(sub_result)
|
all_sub_planner_results.extend(sub_result)
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix}所有副规划器共返回了{len(all_sub_planner_results)}个action")
|
logger.info(f"{self.log_prefix}小脑决定执行{len(all_sub_planner_results)}个动作")
|
||||||
|
|
||||||
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
|
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
|
||||||
prompt, message_id_list = await self.build_planner_prompt(
|
prompt, message_id_list = await self.build_planner_prompt(
|
||||||
|
|
@ -777,12 +775,6 @@ class ActionPlanner:
|
||||||
else:
|
else:
|
||||||
actions_before_now_block = ""
|
actions_before_now_block = ""
|
||||||
|
|
||||||
mentioned_bonus = ""
|
|
||||||
if global_config.chat.mentioned_bot_inevitable_reply:
|
|
||||||
mentioned_bonus = "\n- 有人提到你"
|
|
||||||
if global_config.chat.at_bot_inevitable_reply:
|
|
||||||
mentioned_bonus = "\n- 有人提到你,或者at你"
|
|
||||||
|
|
||||||
chat_context_description = "你现在正在一个群聊中"
|
chat_context_description = "你现在正在一个群聊中"
|
||||||
chat_target_name = None
|
chat_target_name = None
|
||||||
if not is_group_chat and chat_target_info:
|
if not is_group_chat and chat_target_info:
|
||||||
|
|
@ -838,7 +830,6 @@ class ActionPlanner:
|
||||||
chat_context_description=chat_context_description,
|
chat_context_description=chat_context_description,
|
||||||
chat_content_block=chat_content_block,
|
chat_content_block=chat_content_block,
|
||||||
actions_before_now_block=actions_before_now_block,
|
actions_before_now_block=actions_before_now_block,
|
||||||
mentioned_bonus=mentioned_bonus,
|
|
||||||
# action_options_text=action_options_block,
|
# action_options_text=action_options_block,
|
||||||
moderation_prompt=moderation_prompt_block,
|
moderation_prompt=moderation_prompt_block,
|
||||||
name_block=name_block,
|
name_block=name_block,
|
||||||
|
|
@ -850,7 +841,6 @@ class ActionPlanner:
|
||||||
time_block=time_block,
|
time_block=time_block,
|
||||||
chat_context_description=chat_context_description,
|
chat_context_description=chat_context_description,
|
||||||
chat_content_block=chat_content_block,
|
chat_content_block=chat_content_block,
|
||||||
mentioned_bonus=mentioned_bonus,
|
|
||||||
moderation_prompt=moderation_prompt_block,
|
moderation_prompt=moderation_prompt_block,
|
||||||
name_block=name_block,
|
name_block=name_block,
|
||||||
actions_before_now_block=actions_before_now_block,
|
actions_before_now_block=actions_before_now_block,
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,15 @@ def db_message_to_str(message_dict: dict) -> str:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]:
|
def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, bool, float]:
|
||||||
"""检查消息是否提到了机器人"""
|
"""检查消息是否提到了机器人"""
|
||||||
keywords = [global_config.bot.nickname]
|
keywords = [global_config.bot.nickname] + list(global_config.bot.alias_names)
|
||||||
nicknames = global_config.bot.alias_names
|
|
||||||
reply_probability = 0.0
|
reply_probability = 0.0
|
||||||
is_at = False
|
is_at = False
|
||||||
is_mentioned = False
|
is_mentioned = False
|
||||||
if message.is_mentioned is not None:
|
|
||||||
return bool(message.is_mentioned), message.is_mentioned
|
# 这部分怎么处理啊啊啊啊
|
||||||
|
#我觉得可以给消息加一个 reply_probability_boost字段
|
||||||
if (
|
if (
|
||||||
message.message_info.additional_config is not None
|
message.message_info.additional_config is not None
|
||||||
and message.message_info.additional_config.get("is_mentioned") is not None
|
and message.message_info.additional_config.get("is_mentioned") is not None
|
||||||
|
|
@ -59,18 +59,15 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]:
|
||||||
try:
|
try:
|
||||||
reply_probability = float(message.message_info.additional_config.get("is_mentioned")) # type: ignore
|
reply_probability = float(message.message_info.additional_config.get("is_mentioned")) # type: ignore
|
||||||
is_mentioned = True
|
is_mentioned = True
|
||||||
return is_mentioned, reply_probability
|
return is_mentioned, is_at, reply_probability
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"消息中包含不合理的设置 is_mentioned: {message.message_info.additional_config.get('is_mentioned')}"
|
f"消息中包含不合理的设置 is_mentioned: {message.message_info.additional_config.get('is_mentioned')}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if global_config.bot.nickname in message.processed_plain_text:
|
for keyword in keywords:
|
||||||
is_mentioned = True
|
if keyword in message.processed_plain_text:
|
||||||
|
|
||||||
for alias_name in global_config.bot.alias_names:
|
|
||||||
if alias_name in message.processed_plain_text:
|
|
||||||
is_mentioned = True
|
is_mentioned = True
|
||||||
|
|
||||||
# 判断是否被@
|
# 判断是否被@
|
||||||
|
|
@ -78,10 +75,6 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]:
|
||||||
is_at = True
|
is_at = True
|
||||||
is_mentioned = True
|
is_mentioned = True
|
||||||
|
|
||||||
# print(f"message.processed_plain_text: {message.processed_plain_text}")
|
|
||||||
# print(f"is_mentioned: {is_mentioned}")
|
|
||||||
# print(f"is_at: {is_at}")
|
|
||||||
|
|
||||||
if is_at and global_config.chat.at_bot_inevitable_reply:
|
if is_at and global_config.chat.at_bot_inevitable_reply:
|
||||||
reply_probability = 1.0
|
reply_probability = 1.0
|
||||||
logger.debug("被@,回复概率设置为100%")
|
logger.debug("被@,回复概率设置为100%")
|
||||||
|
|
@ -104,13 +97,10 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]:
|
||||||
for keyword in keywords:
|
for keyword in keywords:
|
||||||
if keyword in message_content:
|
if keyword in message_content:
|
||||||
is_mentioned = True
|
is_mentioned = True
|
||||||
for nickname in nicknames:
|
if is_mentioned and global_config.chat.mentioned_bot_reply:
|
||||||
if nickname in message_content:
|
|
||||||
is_mentioned = True
|
|
||||||
if is_mentioned and global_config.chat.mentioned_bot_inevitable_reply:
|
|
||||||
reply_probability = 1.0
|
reply_probability = 1.0
|
||||||
logger.debug("被提及,回复概率设置为100%")
|
logger.debug("被提及,回复概率设置为100%")
|
||||||
return is_mentioned, reply_probability
|
return is_mentioned, is_at, reply_probability
|
||||||
|
|
||||||
|
|
||||||
async def get_embedding(text, request_type="embedding") -> Optional[List[float]]:
|
async def get_embedding(text, request_type="embedding") -> Optional[List[float]]:
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ class DatabaseMessages(BaseDataModel):
|
||||||
key_words: Optional[str] = None,
|
key_words: Optional[str] = None,
|
||||||
key_words_lite: Optional[str] = None,
|
key_words_lite: Optional[str] = None,
|
||||||
is_mentioned: Optional[bool] = None,
|
is_mentioned: Optional[bool] = None,
|
||||||
|
is_at: Optional[bool] = None,
|
||||||
|
reply_probability_boost: Optional[float] = None,
|
||||||
processed_plain_text: Optional[str] = None,
|
processed_plain_text: Optional[str] = None,
|
||||||
display_message: Optional[str] = None,
|
display_message: Optional[str] = None,
|
||||||
priority_mode: Optional[str] = None,
|
priority_mode: Optional[str] = None,
|
||||||
|
|
@ -104,6 +106,9 @@ class DatabaseMessages(BaseDataModel):
|
||||||
self.key_words_lite = key_words_lite
|
self.key_words_lite = key_words_lite
|
||||||
self.is_mentioned = is_mentioned
|
self.is_mentioned = is_mentioned
|
||||||
|
|
||||||
|
self.is_at = is_at
|
||||||
|
self.reply_probability_boost = reply_probability_boost
|
||||||
|
|
||||||
self.processed_plain_text = processed_plain_text
|
self.processed_plain_text = processed_plain_text
|
||||||
self.display_message = display_message
|
self.display_message = display_message
|
||||||
|
|
||||||
|
|
@ -171,6 +176,8 @@ class DatabaseMessages(BaseDataModel):
|
||||||
"key_words": self.key_words,
|
"key_words": self.key_words,
|
||||||
"key_words_lite": self.key_words_lite,
|
"key_words_lite": self.key_words_lite,
|
||||||
"is_mentioned": self.is_mentioned,
|
"is_mentioned": self.is_mentioned,
|
||||||
|
"is_at": self.is_at,
|
||||||
|
"reply_probability_boost": self.reply_probability_boost,
|
||||||
"processed_plain_text": self.processed_plain_text,
|
"processed_plain_text": self.processed_plain_text,
|
||||||
"display_message": self.display_message,
|
"display_message": self.display_message,
|
||||||
"priority_mode": self.priority_mode,
|
"priority_mode": self.priority_mode,
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,8 @@ class Messages(BaseModel):
|
||||||
key_words_lite = TextField(null=True)
|
key_words_lite = TextField(null=True)
|
||||||
|
|
||||||
is_mentioned = BooleanField(null=True)
|
is_mentioned = BooleanField(null=True)
|
||||||
|
is_at = BooleanField(null=True)
|
||||||
|
reply_probability_boost = DoubleField(null=True)
|
||||||
# 从 chat_info 扁平化而来的字段
|
# 从 chat_info 扁平化而来的字段
|
||||||
chat_info_stream_id = TextField()
|
chat_info_stream_id = TextField()
|
||||||
chat_info_platform = TextField()
|
chat_info_platform = TextField()
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,7 @@ MODULE_COLORS = {
|
||||||
# 核心模块
|
# 核心模块
|
||||||
"main": "\033[1;97m", # 亮白色+粗体 (主程序)
|
"main": "\033[1;97m", # 亮白色+粗体 (主程序)
|
||||||
|
|
||||||
|
"memory": "\033[38;5;34m", # 天蓝色
|
||||||
|
|
||||||
"config": "\033[93m", # 亮黄色
|
"config": "\033[93m", # 亮黄色
|
||||||
"common": "\033[95m", # 亮紫色
|
"common": "\033[95m", # 亮紫色
|
||||||
|
|
@ -366,10 +367,9 @@ MODULE_COLORS = {
|
||||||
"llm_models": "\033[36m", # 青色
|
"llm_models": "\033[36m", # 青色
|
||||||
"remote": "\033[38;5;242m", # 深灰色,更不显眼
|
"remote": "\033[38;5;242m", # 深灰色,更不显眼
|
||||||
"planner": "\033[36m",
|
"planner": "\033[36m",
|
||||||
"memory": "\033[38;5;117m", # 天蓝色
|
|
||||||
"hfc": "\033[38;5;81m", # 稍微暗一些的青色,保持可读
|
|
||||||
"action_manager": "\033[38;5;208m", # 橙色,不与replyer重复
|
|
||||||
# 关系系统
|
|
||||||
"relation": "\033[38;5;139m", # 柔和的紫色,不刺眼
|
"relation": "\033[38;5;139m", # 柔和的紫色,不刺眼
|
||||||
# 聊天相关模块
|
# 聊天相关模块
|
||||||
"normal_chat": "\033[38;5;81m", # 亮蓝绿色
|
"normal_chat": "\033[38;5;81m", # 亮蓝绿色
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ TEMPLATE_DIR = os.path.join(PROJECT_ROOT, "template")
|
||||||
|
|
||||||
# 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
|
# 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
|
||||||
# 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/
|
# 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/
|
||||||
MMC_VERSION = "0.10.2-snapshot.1"
|
MMC_VERSION = "0.10.2-snapshot.2"
|
||||||
|
|
||||||
|
|
||||||
def get_key_comment(toml_table, key):
|
def get_key_comment(toml_table, key):
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,14 @@ class ChatConfig(ConfigBase):
|
||||||
interest_rate_mode: Literal["fast", "accurate"] = "fast"
|
interest_rate_mode: Literal["fast", "accurate"] = "fast"
|
||||||
"""兴趣值计算模式,fast为快速计算,accurate为精确计算"""
|
"""兴趣值计算模式,fast为快速计算,accurate为精确计算"""
|
||||||
|
|
||||||
mentioned_bot_inevitable_reply: bool = False
|
mentioned_bot_reply: float = 1
|
||||||
"""提及 bot 必然回复"""
|
"""提及 bot 必然回复,1为100%回复,0为不额外增幅"""
|
||||||
|
|
||||||
planner_size: float = 1.5
|
planner_size: float = 1.5
|
||||||
"""副规划器大小,越小,麦麦的动作执行能力越精细,但是消耗更多token,调大可以缓解429类错误"""
|
"""副规划器大小,越小,麦麦的动作执行能力越精细,但是消耗更多token,调大可以缓解429类错误"""
|
||||||
|
|
||||||
at_bot_inevitable_reply: bool = False
|
at_bot_inevitable_reply: float = 1
|
||||||
"""@bot 必然回复"""
|
"""@bot 必然回复,1为100%回复,0为不额外增幅"""
|
||||||
|
|
||||||
talk_frequency: float = 0.5
|
talk_frequency: float = 0.5
|
||||||
"""回复频率阈值"""
|
"""回复频率阈值"""
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,26 @@
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.chat.frequency_control.focus_value_control import focus_value_control
|
from src.chat.frequency_control.frequency_control import frequency_control_manager
|
||||||
from src.chat.frequency_control.talk_frequency_control import talk_frequency_control
|
|
||||||
|
|
||||||
logger = get_logger("frequency_api")
|
logger = get_logger("frequency_api")
|
||||||
|
|
||||||
|
|
||||||
def get_current_focus_value(chat_id: str) -> float:
|
def get_current_focus_value(chat_id: str) -> float:
|
||||||
return focus_value_control.get_focus_value_control(chat_id).get_current_focus_value()
|
return frequency_control_manager.get_or_create_frequency_control(chat_id).get_final_focus_value()
|
||||||
|
|
||||||
def get_current_talk_frequency(chat_id: str) -> float:
|
def get_current_talk_frequency(chat_id: str) -> float:
|
||||||
return talk_frequency_control.get_talk_frequency_control(chat_id).get_current_talk_frequency()
|
return frequency_control_manager.get_or_create_frequency_control(chat_id).get_final_talk_frequency()
|
||||||
|
|
||||||
def set_focus_value_adjust(chat_id: str, focus_value_adjust: float) -> None:
|
def set_focus_value_adjust(chat_id: str, focus_value_adjust: float) -> None:
|
||||||
focus_value_control.get_focus_value_control(chat_id).focus_value_adjust = focus_value_adjust
|
frequency_control_manager.get_or_create_frequency_control(chat_id).focus_value_external_adjust = focus_value_adjust
|
||||||
|
|
||||||
def set_talk_frequency_adjust(chat_id: str, talk_frequency_adjust: float) -> None:
|
def set_talk_frequency_adjust(chat_id: str, talk_frequency_adjust: float) -> None:
|
||||||
talk_frequency_control.get_talk_frequency_control(chat_id).talk_frequency_adjust = talk_frequency_adjust
|
frequency_control_manager.get_or_create_frequency_control(chat_id).talk_frequency_external_adjust = talk_frequency_adjust
|
||||||
|
|
||||||
def get_focus_value_adjust(chat_id: str) -> float:
|
def get_focus_value_adjust(chat_id: str) -> float:
|
||||||
return focus_value_control.get_focus_value_control(chat_id).focus_value_adjust
|
return frequency_control_manager.get_or_create_frequency_control(chat_id).focus_value_external_adjust
|
||||||
|
|
||||||
def get_talk_frequency_adjust(chat_id: str) -> float:
|
def get_talk_frequency_adjust(chat_id: str) -> float:
|
||||||
return talk_frequency_control.get_talk_frequency_control(chat_id).talk_frequency_adjust
|
return frequency_control_manager.get_or_create_frequency_control(chat_id).talk_frequency_external_adjust
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[inner]
|
[inner]
|
||||||
version = "6.7.2"
|
version = "6.8.0"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||||
#如果你想要修改配置文件,请递增version的值
|
#如果你想要修改配置文件,请递增version的值
|
||||||
|
|
@ -59,17 +59,17 @@ expression_groups = [
|
||||||
|
|
||||||
[chat] #麦麦的聊天设置
|
[chat] #麦麦的聊天设置
|
||||||
talk_frequency = 0.5
|
talk_frequency = 0.5
|
||||||
# 麦麦活跃度,越高,麦麦回复越多,范围0-1
|
# 麦麦活跃度,越高,麦麦越容易回复,范围0-1
|
||||||
focus_value = 0.5
|
focus_value = 0.5
|
||||||
# 麦麦的专注度,越高越容易持续连续对话,可能消耗更多token, 范围0-1
|
# 麦麦的专注度,越高越容易持续连续对话,可能消耗更多token, 范围0-1
|
||||||
|
|
||||||
|
mentioned_bot_reply = 1 # 提及时,回复概率增幅,1为100%回复,0为不额外增幅
|
||||||
|
at_bot_inevitable_reply = 1 # at时,回复概率增幅,1为100%回复,0为不额外增幅
|
||||||
|
|
||||||
max_context_size = 20 # 上下文长度
|
max_context_size = 20 # 上下文长度
|
||||||
|
|
||||||
planner_size = 2.5 # 副规划器大小,越小,麦麦的动作执行能力越精细,但是消耗更多token,调大可以缓解429类错误
|
planner_size = 2.5 # 副规划器大小,越小,麦麦的动作执行能力越精细,但是消耗更多token,调大可以缓解429类错误
|
||||||
|
|
||||||
mentioned_bot_inevitable_reply = true # 提及 bot 大概率回复
|
|
||||||
at_bot_inevitable_reply = true # @bot 或 提及bot 大概率回复
|
|
||||||
|
|
||||||
focus_value_adjust = [
|
focus_value_adjust = [
|
||||||
["", "8:00,1", "12:00,0.8", "18:00,1", "01:00,0.3"],
|
["", "8:00,1", "12:00,0.8", "18:00,1", "01:00,0.3"],
|
||||||
["qq:114514:group", "12:20,0.6", "16:10,0.5", "20:10,0.8", "00:10,0.3"],
|
["qq:114514:group", "12:20,0.6", "16:10,0.5", "20:10,0.8", "00:10,0.3"],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue