feat:为normal_chat提供选项,有效控制回复频率
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
- 重构表情包模块
|
||||
- 移除日程系统
|
||||
|
||||
**重构专注聊天(HFC)**
|
||||
- 模块化HFC,可以自定义不同的部件
|
||||
**重构专注聊天(HFC - focus_chat)**
|
||||
- 模块化设计,可以自定义不同的部件
|
||||
- 观察器(获取信息)
|
||||
- 信息处理器(处理信息)
|
||||
- 重构:聊天思考(子心流)处理器
|
||||
@@ -31,6 +31,10 @@
|
||||
- 在专注模式下,麦麦可以决定自行发送语音消息(需要搭配tts适配器)
|
||||
- 优化reply,减少复读
|
||||
|
||||
**优化普通聊天(normal_chat)**
|
||||
- 增加了talk_frequency参数来有效控制回复频率
|
||||
- 优化了进入和离开normal_chat的方式
|
||||
|
||||
**新增表达方式学习**
|
||||
- 在专注模式下,麦麦可以有独特的表达方式
|
||||
- 自主学习群聊中的表达方式,更贴近群友
|
||||
@@ -50,6 +54,7 @@
|
||||
|
||||
**人格**
|
||||
- 简化了人格身份的配置
|
||||
- 优化了在focus模式下人格的表现和稳定性
|
||||
|
||||
**数据库重构**
|
||||
- 移除了默认使用MongoDB,采用轻量sqlite
|
||||
|
||||
@@ -8,6 +8,7 @@ from ..utils.utils import is_mentioned_bot_in_message
|
||||
from src.chat.heart_flow.heartflow import heartflow
|
||||
from src.common.logger_manager import get_logger
|
||||
from ..message_receive.chat_stream import chat_manager
|
||||
import math
|
||||
|
||||
# from ..message_receive.message_buffer import message_buffer
|
||||
from ..utils.timer_calculator import Timer
|
||||
@@ -69,6 +70,15 @@ async def _calculate_interest(message: MessageRecv) -> Tuple[float, bool]:
|
||||
message.processed_plain_text,
|
||||
fast_retrieval=True,
|
||||
)
|
||||
text_len = len(message.processed_plain_text)
|
||||
# 根据文本长度调整兴趣度,长度越大兴趣度越高,但增长率递减,最低0.01,最高0.05
|
||||
# 采用对数函数实现递减增长
|
||||
|
||||
base_interest = 0.01 + (0.05 - 0.01) * (math.log10(text_len + 1) / math.log10(1000 + 1))
|
||||
base_interest = min(max(base_interest, 0.01), 0.05)
|
||||
|
||||
interested_rate += base_interest
|
||||
|
||||
logger.trace(f"记忆激活率: {interested_rate:.2f}")
|
||||
|
||||
if is_mentioned:
|
||||
@@ -205,17 +215,15 @@ class HeartFCMessageReceiver:
|
||||
|
||||
# 6. 兴趣度计算与更新
|
||||
interested_rate, is_mentioned = await _calculate_interest(message)
|
||||
# await subheartflow.interest_chatting.increase_interest(value=interested_rate)
|
||||
subheartflow.add_interest_message(message, interested_rate, is_mentioned)
|
||||
subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
||||
|
||||
# 7. 日志记录
|
||||
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||
current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||
logger.info(
|
||||
f"[{current_time}][{mes_name}]"
|
||||
f"[{mes_name}]"
|
||||
f"{userinfo.user_nickname}:"
|
||||
f"{message.processed_plain_text}"
|
||||
f"[激活: {interested_rate:.1f}]"
|
||||
)
|
||||
|
||||
# 8. 关系处理
|
||||
|
||||
@@ -2,25 +2,18 @@ import asyncio
|
||||
import traceback
|
||||
from typing import Optional, Coroutine, Callable, Any, List
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.chat.heart_flow.mai_state_manager import MaiStateManager, MaiStateInfo
|
||||
from src.chat.heart_flow.subheartflow_manager import SubHeartflowManager
|
||||
from src.config.config import global_config
|
||||
|
||||
logger = get_logger("background_tasks")
|
||||
|
||||
|
||||
# 新增兴趣评估间隔
|
||||
INTEREST_EVAL_INTERVAL_SECONDS = 5
|
||||
# 新增聊天超时检查间隔
|
||||
NORMAL_CHAT_TIMEOUT_CHECK_INTERVAL_SECONDS = 60
|
||||
# 新增状态评估间隔
|
||||
HF_JUDGE_STATE_UPDATE_INTERVAL_SECONDS = 20
|
||||
|
||||
|
||||
# 新增私聊激活检查间隔
|
||||
PRIVATE_CHAT_ACTIVATION_CHECK_INTERVAL_SECONDS = 5 # 与兴趣评估类似,设为5秒
|
||||
|
||||
CLEANUP_INTERVAL_SECONDS = 1200
|
||||
STATE_UPDATE_INTERVAL_SECONDS = 60
|
||||
LOG_INTERVAL_SECONDS = 3
|
||||
|
||||
|
||||
async def _run_periodic_loop(
|
||||
@@ -55,19 +48,13 @@ class BackgroundTaskManager:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mai_state_info: MaiStateInfo, # Needs current state info
|
||||
mai_state_manager: MaiStateManager,
|
||||
subheartflow_manager: SubHeartflowManager,
|
||||
):
|
||||
self.mai_state_info = mai_state_info
|
||||
self.mai_state_manager = mai_state_manager
|
||||
self.subheartflow_manager = subheartflow_manager
|
||||
|
||||
# Task references
|
||||
self._state_update_task: Optional[asyncio.Task] = None
|
||||
self._cleanup_task: Optional[asyncio.Task] = None
|
||||
self._hf_judge_state_update_task: Optional[asyncio.Task] = None
|
||||
self._into_focus_task: Optional[asyncio.Task] = None
|
||||
self._private_chat_activation_task: Optional[asyncio.Task] = None # 新增私聊激活任务引用
|
||||
self._tasks: List[Optional[asyncio.Task]] = [] # Keep track of all tasks
|
||||
|
||||
@@ -80,15 +67,7 @@ class BackgroundTaskManager:
|
||||
- 将任务引用保存到任务列表
|
||||
"""
|
||||
|
||||
# 任务配置列表: (任务函数, 任务名称, 日志级别, 额外日志信息, 任务对象引用属性名)
|
||||
task_configs = [
|
||||
(
|
||||
lambda: self._run_state_update_cycle(STATE_UPDATE_INTERVAL_SECONDS),
|
||||
"debug",
|
||||
f"聊天状态更新任务已启动 间隔:{STATE_UPDATE_INTERVAL_SECONDS}s",
|
||||
"_state_update_task",
|
||||
),
|
||||
]
|
||||
task_configs = []
|
||||
|
||||
# 根据 chat_mode 条件添加其他任务
|
||||
if not (global_config.chat.chat_mode == "normal"):
|
||||
@@ -108,12 +87,6 @@ class BackgroundTaskManager:
|
||||
f"私聊激活检查任务已启动 间隔:{PRIVATE_CHAT_ACTIVATION_CHECK_INTERVAL_SECONDS}s",
|
||||
"_private_chat_activation_task",
|
||||
),
|
||||
# (
|
||||
# self._run_into_focus_cycle,
|
||||
# "debug", # 设为debug,避免过多日志
|
||||
# f"专注评估任务已启动 间隔:{INTEREST_EVAL_INTERVAL_SECONDS}s",
|
||||
# "_into_focus_task",
|
||||
# )
|
||||
]
|
||||
)
|
||||
else:
|
||||
@@ -163,33 +136,9 @@ class BackgroundTaskManager:
|
||||
# 第三步:清空任务列表
|
||||
self._tasks = [] # 重置任务列表
|
||||
|
||||
async def _perform_state_update_work(self):
|
||||
"""执行状态更新工作"""
|
||||
previous_status = self.mai_state_info.get_current_state()
|
||||
next_state = self.mai_state_manager.check_and_decide_next_state(self.mai_state_info)
|
||||
|
||||
state_changed = False
|
||||
|
||||
if next_state is not None:
|
||||
state_changed = self.mai_state_info.update_mai_status(next_state)
|
||||
|
||||
# 处理保持离线状态的特殊情况
|
||||
if not state_changed and next_state == previous_status == self.mai_state_info.mai_status.OFFLINE:
|
||||
self.mai_state_info.reset_state_timer()
|
||||
logger.debug("[后台任务] 保持离线状态并重置计时器")
|
||||
state_changed = True # 触发后续处理
|
||||
|
||||
if state_changed:
|
||||
current_state = self.mai_state_info.get_current_state()
|
||||
|
||||
# 状态转换处理
|
||||
|
||||
if (
|
||||
current_state == self.mai_state_info.mai_status.OFFLINE
|
||||
and previous_status != self.mai_state_info.mai_status.OFFLINE
|
||||
):
|
||||
logger.info("检测到离线,停用所有子心流")
|
||||
await self.subheartflow_manager.deactivate_all_subflows()
|
||||
|
||||
|
||||
async def _perform_cleanup_work(self):
|
||||
"""执行子心流清理任务
|
||||
@@ -216,27 +165,12 @@ class BackgroundTaskManager:
|
||||
# 记录最终清理结果
|
||||
logger.info(f"[清理任务] 清理完成, 共停止 {stopped_count}/{len(flows_to_stop)} 个子心流")
|
||||
|
||||
# --- 新增兴趣评估工作函数 ---
|
||||
# async def _perform_into_focus_work(self):
|
||||
# """执行一轮子心流兴趣评估与提升检查。"""
|
||||
# # 直接调用 subheartflow_manager 的方法,并传递当前状态信息
|
||||
# await self.subheartflow_manager.sbhf_normal_into_focus()
|
||||
|
||||
async def _run_state_update_cycle(self, interval: int):
|
||||
await _run_periodic_loop(task_name="State Update", interval=interval, task_func=self._perform_state_update_work)
|
||||
|
||||
async def _run_cleanup_cycle(self):
|
||||
await _run_periodic_loop(
|
||||
task_name="Subflow Cleanup", interval=CLEANUP_INTERVAL_SECONDS, task_func=self._perform_cleanup_work
|
||||
)
|
||||
|
||||
# --- 新增兴趣评估任务运行器 ---
|
||||
# async def _run_into_focus_cycle(self):
|
||||
# await _run_periodic_loop(
|
||||
# task_name="Into Focus",
|
||||
# interval=INTEREST_EVAL_INTERVAL_SECONDS,
|
||||
# task_func=self._perform_into_focus_work,
|
||||
# )
|
||||
|
||||
# 新增私聊激活任务运行器
|
||||
async def _run_private_chat_activation_cycle(self, interval: int):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from src.chat.heart_flow.sub_heartflow import SubHeartflow, ChatState
|
||||
from src.common.logger_manager import get_logger
|
||||
from typing import Any, Optional, List
|
||||
from src.chat.heart_flow.mai_state_manager import MaiStateInfo, MaiStateManager
|
||||
from src.chat.heart_flow.subheartflow_manager import SubHeartflowManager
|
||||
from src.chat.heart_flow.background_tasks import BackgroundTaskManager # Import BackgroundTaskManager
|
||||
|
||||
@@ -16,17 +15,12 @@ class Heartflow:
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# 状态管理相关
|
||||
self.current_state: MaiStateInfo = MaiStateInfo() # 当前状态信息
|
||||
self.mai_state_manager: MaiStateManager = MaiStateManager() # 状态决策管理器
|
||||
|
||||
# 子心流管理 (在初始化时传入 current_state)
|
||||
self.subheartflow_manager: SubHeartflowManager = SubHeartflowManager(self.current_state)
|
||||
self.subheartflow_manager: SubHeartflowManager = SubHeartflowManager()
|
||||
|
||||
# 后台任务管理器 (整合所有定时任务)
|
||||
self.background_task_manager: BackgroundTaskManager = BackgroundTaskManager(
|
||||
mai_state_info=self.current_state,
|
||||
mai_state_manager=self.mai_state_manager,
|
||||
subheartflow_manager=self.subheartflow_manager,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import enum
|
||||
import time
|
||||
import random
|
||||
from typing import List, Tuple, Optional
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.manager.mood_manager import mood_manager
|
||||
|
||||
logger = get_logger("mai_state")
|
||||
|
||||
|
||||
class MaiState(enum.Enum):
|
||||
"""
|
||||
聊天状态:
|
||||
OFFLINE: 不在线:回复概率极低,不会进行任何聊天
|
||||
NORMAL_CHAT: 正常看手机:回复概率较高,会进行一些普通聊天和少量的专注聊天
|
||||
FOCUSED_CHAT: 专注聊天:回复概率极高,会进行专注聊天和少量的普通聊天
|
||||
"""
|
||||
|
||||
OFFLINE = "不在线"
|
||||
NORMAL_CHAT = "正常看手机"
|
||||
FOCUSED_CHAT = "专心看手机"
|
||||
|
||||
|
||||
class MaiStateInfo:
|
||||
def __init__(self):
|
||||
self.mai_status: MaiState = MaiState.NORMAL_CHAT # 初始状态改为 NORMAL_CHAT
|
||||
self.mai_status_history: List[Tuple[MaiState, float]] = [] # 历史状态,包含 状态,时间戳
|
||||
self.last_status_change_time: float = time.time() # 状态最后改变时间
|
||||
self.last_min_check_time: float = time.time() # 上次1分钟规则检查时间
|
||||
|
||||
# Mood management is now part of MaiStateInfo
|
||||
self.mood_manager = mood_manager # Use singleton instance
|
||||
|
||||
def update_mai_status(self, new_status: MaiState) -> bool:
|
||||
"""
|
||||
更新聊天状态。
|
||||
|
||||
Args:
|
||||
new_status: 新的 MaiState 状态。
|
||||
|
||||
Returns:
|
||||
bool: 如果状态实际发生了改变则返回 True,否则返回 False。
|
||||
"""
|
||||
if new_status != self.mai_status:
|
||||
self.mai_status = new_status
|
||||
current_time = time.time()
|
||||
self.last_status_change_time = current_time
|
||||
self.last_min_check_time = current_time # Reset 1-min check on any state change
|
||||
self.mai_status_history.append((new_status, current_time))
|
||||
logger.info(f"麦麦状态更新为: {self.mai_status.value}")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def reset_state_timer(self):
|
||||
"""
|
||||
重置状态持续时间计时器和一分钟规则检查计时器。
|
||||
通常在状态保持不变但需要重新开始计时的情况下调用(例如,保持 OFFLINE)。
|
||||
"""
|
||||
current_time = time.time()
|
||||
self.last_status_change_time = current_time
|
||||
self.last_min_check_time = current_time # Also reset the 1-min check timer
|
||||
logger.debug("MaiStateInfo 状态计时器已重置。")
|
||||
|
||||
def get_mood_prompt(self) -> str:
|
||||
"""获取当前的心情提示词"""
|
||||
# Delegate to the internal mood manager
|
||||
return self.mood_manager.get_mood_prompt()
|
||||
|
||||
def get_current_state(self) -> MaiState:
|
||||
"""获取当前的 MaiState"""
|
||||
return self.mai_status
|
||||
|
||||
|
||||
class MaiStateManager:
|
||||
"""管理 Mai 的整体状态转换逻辑"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def check_and_decide_next_state(current_state_info: MaiStateInfo) -> Optional[MaiState]:
|
||||
"""
|
||||
根据当前状态和规则检查是否需要转换状态,并决定下一个状态。
|
||||
"""
|
||||
current_time = time.time()
|
||||
current_status = current_state_info.mai_status
|
||||
time_in_current_status = current_time - current_state_info.last_status_change_time
|
||||
next_state: Optional[MaiState] = None
|
||||
|
||||
def _resolve_offline(candidate_state: MaiState) -> MaiState:
|
||||
if candidate_state == MaiState.OFFLINE:
|
||||
return current_status
|
||||
return candidate_state
|
||||
|
||||
if current_status == MaiState.OFFLINE:
|
||||
logger.info("当前[离线],没看手机,思考要不要上线看看......")
|
||||
elif current_status == MaiState.NORMAL_CHAT:
|
||||
logger.info("当前在[正常看手机]思考要不要继续聊下去......")
|
||||
elif current_status == MaiState.FOCUSED_CHAT:
|
||||
logger.info("当前在[专心看手机]思考要不要继续聊下去......")
|
||||
|
||||
if next_state is None:
|
||||
time_limit_exceeded = False
|
||||
choices_list = []
|
||||
weights = []
|
||||
rule_id = ""
|
||||
|
||||
if current_status == MaiState.OFFLINE:
|
||||
return None
|
||||
elif current_status == MaiState.NORMAL_CHAT:
|
||||
if time_in_current_status >= 300: # NORMAL_CHAT 最多持续 300 秒
|
||||
time_limit_exceeded = True
|
||||
rule_id = "2.3 (From NORMAL_CHAT)"
|
||||
weights = [100]
|
||||
choices_list = [MaiState.FOCUSED_CHAT]
|
||||
elif current_status == MaiState.FOCUSED_CHAT:
|
||||
if time_in_current_status >= 600: # FOCUSED_CHAT 最多持续 600 秒
|
||||
time_limit_exceeded = True
|
||||
rule_id = "2.4 (From FOCUSED_CHAT)"
|
||||
weights = [100]
|
||||
choices_list = [MaiState.NORMAL_CHAT]
|
||||
|
||||
if time_limit_exceeded:
|
||||
next_state_candidate = random.choices(choices_list, weights=weights, k=1)[0]
|
||||
resolved_candidate = _resolve_offline(next_state_candidate)
|
||||
logger.debug(
|
||||
f"规则{rule_id}:时间到,切换到 {next_state_candidate.value},resolve 为 {resolved_candidate.value}"
|
||||
)
|
||||
next_state = resolved_candidate
|
||||
|
||||
if next_state is not None and next_state != current_status:
|
||||
return next_state
|
||||
else:
|
||||
return None
|
||||
@@ -9,7 +9,6 @@ from src.chat.message_receive.message import MessageRecv
|
||||
from src.chat.message_receive.chat_stream import chat_manager
|
||||
from src.chat.focus_chat.heartFC_chat import HeartFChatting
|
||||
from src.chat.normal_chat.normal_chat import NormalChat
|
||||
from src.chat.heart_flow.mai_state_manager import MaiStateInfo
|
||||
from src.chat.heart_flow.chat_state_info import ChatState, ChatStateInfo
|
||||
from .utils_chat import get_chat_type_and_target_info
|
||||
from src.config.config import global_config
|
||||
@@ -23,7 +22,6 @@ class SubHeartflow:
|
||||
def __init__(
|
||||
self,
|
||||
subheartflow_id,
|
||||
mai_states: MaiStateInfo,
|
||||
):
|
||||
"""子心流初始化函数
|
||||
|
||||
@@ -36,9 +34,6 @@ class SubHeartflow:
|
||||
self.subheartflow_id = subheartflow_id
|
||||
self.chat_id = subheartflow_id
|
||||
|
||||
# 麦麦的状态
|
||||
self.mai_states = mai_states
|
||||
|
||||
# 这个聊天流的状态
|
||||
self.chat_state: ChatStateInfo = ChatStateInfo()
|
||||
self.chat_state_changed_time: float = time.time()
|
||||
@@ -334,10 +329,10 @@ class SubHeartflow:
|
||||
return self.normal_chat_instance.get_recent_replies(limit)
|
||||
return []
|
||||
|
||||
def add_interest_message(self, message: MessageRecv, interest_value: float, is_mentioned: bool):
|
||||
def add_message_to_normal_chat_cache(self, message: MessageRecv, interest_value: float, is_mentioned: bool):
|
||||
self.interest_dict[message.message_info.message_id] = (message, interest_value, is_mentioned)
|
||||
# 如果字典长度超过10,删除最旧的消息
|
||||
if len(self.interest_dict) > 10:
|
||||
if len(self.interest_dict) > 30:
|
||||
oldest_key = next(iter(self.interest_dict))
|
||||
self.interest_dict.pop(oldest_key)
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ from typing import Dict, Any, Optional, List
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.chat.message_receive.chat_stream import chat_manager
|
||||
from src.chat.heart_flow.sub_heartflow import SubHeartflow, ChatState
|
||||
from src.chat.heart_flow.mai_state_manager import MaiStateInfo
|
||||
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
|
||||
|
||||
|
||||
@@ -54,10 +53,9 @@ async def _try_set_subflow_absent_internal(subflow: "SubHeartflow", log_prefix:
|
||||
class SubHeartflowManager:
|
||||
"""管理所有活跃的 SubHeartflow 实例。"""
|
||||
|
||||
def __init__(self, mai_state_info: MaiStateInfo):
|
||||
def __init__(self):
|
||||
self.subheartflows: Dict[Any, "SubHeartflow"] = {}
|
||||
self._lock = asyncio.Lock() # 用于保护 self.subheartflows 的访问
|
||||
self.mai_state_info: MaiStateInfo = mai_state_info # 存储传入的 MaiStateInfo 实例
|
||||
|
||||
async def force_change_state(self, subflow_id: Any, target_state: ChatState) -> bool:
|
||||
"""强制改变指定子心流的状态"""
|
||||
@@ -97,7 +95,6 @@ class SubHeartflowManager:
|
||||
# 初始化子心流, 传入 mai_state_info
|
||||
new_subflow = SubHeartflow(
|
||||
subheartflow_id,
|
||||
self.mai_state_info,
|
||||
)
|
||||
|
||||
# 首先创建并添加聊天观察者
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import asyncio
|
||||
import statistics # 导入 statistics 模块
|
||||
import time
|
||||
import traceback
|
||||
from random import random
|
||||
from typing import List, Optional # 导入 Optional
|
||||
|
||||
from maim_message import UserInfo, Seg
|
||||
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
|
||||
from src.manager.mood_manager import mood_manager
|
||||
@@ -21,6 +18,7 @@ from src.chat.message_receive.message_sender import message_manager
|
||||
from src.chat.utils.utils_image import image_path_to_base64
|
||||
from src.chat.emoji_system.emoji_manager import emoji_manager
|
||||
from src.chat.normal_chat.willing.willing_manager import willing_manager
|
||||
from src.chat.normal_chat.normal_chat_utils import get_recent_message_stats
|
||||
from src.config.config import global_config
|
||||
|
||||
logger = get_logger("normal_chat")
|
||||
@@ -39,6 +37,8 @@ class NormalChat:
|
||||
|
||||
self.is_group_chat: bool = False
|
||||
self.chat_target_info: Optional[dict] = None
|
||||
|
||||
self.willing_amplifier = 1
|
||||
|
||||
# Other sync initializations
|
||||
self.gpt = NormalChatGenerator()
|
||||
@@ -209,10 +209,12 @@ class NormalChat:
|
||||
for msg_id, (message, interest_value, is_mentioned) in items_to_process:
|
||||
try:
|
||||
# 处理消息
|
||||
self.adjust_reply_frequency()
|
||||
|
||||
await self.normal_response(
|
||||
message=message,
|
||||
is_mentioned=is_mentioned,
|
||||
interested_rate=interest_value,
|
||||
interested_rate=interest_value * self.willing_amplifier,
|
||||
rewind_response=False,
|
||||
)
|
||||
except Exception as e:
|
||||
@@ -228,26 +230,18 @@ class NormalChat:
|
||||
if self._disabled:
|
||||
logger.info(f"[{self.stream_name}] 已停用,忽略 normal_response。")
|
||||
return
|
||||
# 检查收到的消息是否属于当前实例处理的 chat stream
|
||||
if message.chat_stream.stream_id != self.stream_id:
|
||||
logger.error(
|
||||
f"[{self.stream_name}] normal_response 收到不匹配的消息 (来自 {message.chat_stream.stream_id}),预期 {self.stream_id}。已忽略。"
|
||||
)
|
||||
return
|
||||
|
||||
timing_results = {}
|
||||
|
||||
reply_probability = 1.0 if is_mentioned else 0.0 # 如果被提及,基础概率为1,否则需要意愿判断
|
||||
|
||||
|
||||
# 意愿管理器:设置当前message信息
|
||||
|
||||
willing_manager.setup(message, self.chat_stream, is_mentioned, interested_rate)
|
||||
|
||||
# 获取回复概率
|
||||
is_willing = False
|
||||
# is_willing = False
|
||||
# 仅在未被提及或基础概率不为1时查询意愿概率
|
||||
if reply_probability < 1: # 简化逻辑,如果未提及 (reply_probability 为 0),则获取意愿概率
|
||||
is_willing = True
|
||||
# is_willing = True
|
||||
reply_probability = await willing_manager.get_reply_probability(message.message_info.message_id)
|
||||
|
||||
if message.message_info.additional_config:
|
||||
@@ -257,13 +251,13 @@ class NormalChat:
|
||||
|
||||
# 打印消息信息
|
||||
mes_name = self.chat_stream.group_info.group_name if self.chat_stream.group_info else "私聊"
|
||||
current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||
# 使用 self.stream_id
|
||||
willing_log = f"[回复意愿:{await willing_manager.get_willing(self.stream_id):.2f}]" if is_willing else ""
|
||||
# willing_log = f"[激活值:{await willing_manager.get_willing(self.stream_id):.2f}]" if is_willing else ""
|
||||
logger.info(
|
||||
f"[{current_time}][{mes_name}]"
|
||||
f"[{mes_name}]"
|
||||
f"{message.message_info.user_info.user_nickname}:" # 使用 self.chat_stream
|
||||
f"{message.processed_plain_text}{willing_log}[概率:{reply_probability * 100:.1f}%]"
|
||||
f"{message.processed_plain_text}[回复概率:{reply_probability * 100:.1f}%]"
|
||||
)
|
||||
do_reply = False
|
||||
response_set = None # 初始化 response_set
|
||||
@@ -346,16 +340,13 @@ class NormalChat:
|
||||
# 检查是否需要切换到focus模式
|
||||
await self._check_switch_to_focus()
|
||||
|
||||
else:
|
||||
logger.warning(f"[{self.stream_name}] 思考消息 {thinking_id} 在发送前丢失,无法记录 info_catcher")
|
||||
|
||||
info_catcher.done_catch()
|
||||
|
||||
# 处理表情包 (不再需要传入 chat)
|
||||
with Timer("处理表情包", timing_results):
|
||||
await self._handle_emoji(message, response_set[0])
|
||||
|
||||
# 更新关系情绪 (不再需要传入 chat)
|
||||
|
||||
with Timer("关系更新", timing_results):
|
||||
await self._update_relationship(message, response_set)
|
||||
|
||||
@@ -479,9 +470,6 @@ class NormalChat:
|
||||
|
||||
# 统计1分钟内的回复数量
|
||||
recent_reply_count = sum(1 for reply in self.recent_replies if reply["time"] > one_minute_ago)
|
||||
# print(111111111111111333333333333333333333333331111111111111111111111111111111111)
|
||||
# print(recent_reply_count)
|
||||
# 如果1分钟内回复数量大于8,触发切换到focus模式
|
||||
if recent_reply_count > reply_threshold:
|
||||
logger.info(
|
||||
f"[{self.stream_name}] 检测到1分钟内回复数量({recent_reply_count})大于{reply_threshold},触发切换到focus模式"
|
||||
@@ -491,3 +479,29 @@ class NormalChat:
|
||||
await self.on_switch_to_focus_callback()
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.stream_name}] 触发切换到focus模式时出错: {e}\n{traceback.format_exc()}")
|
||||
|
||||
|
||||
def adjust_reply_frequency(self, duration: int = 10):
|
||||
"""
|
||||
调整回复频率
|
||||
"""
|
||||
# 获取最近30分钟内的消息统计
|
||||
print(f"willing_amplifier: {self.willing_amplifier}")
|
||||
stats = get_recent_message_stats(minutes=duration, chat_id=self.stream_id)
|
||||
bot_reply_count = stats["bot_reply_count"]
|
||||
print(f"[{self.stream_name}] 最近{duration}分钟内回复数量: {bot_reply_count}")
|
||||
total_message_count = stats["total_message_count"]
|
||||
print(f"[{self.stream_name}] 最近{duration}分钟内消息总数: {total_message_count}")
|
||||
|
||||
# 计算回复频率
|
||||
_reply_frequency = bot_reply_count / total_message_count
|
||||
|
||||
# 如果回复频率低于0.5,增加回复概率
|
||||
if bot_reply_count/duration < global_config.normal_chat.talk_frequency:
|
||||
# differ = global_config.normal_chat.talk_frequency - reply_frequency
|
||||
logger.info(f"[{self.stream_name}] 回复频率低于{global_config.normal_chat.talk_frequency},增加回复概率")
|
||||
self.willing_amplifier += 0.1
|
||||
else:
|
||||
logger.info(f"[{self.stream_name}] 回复频率高于{global_config.normal_chat.talk_frequency},减少回复概率")
|
||||
self.willing_amplifier -= 0.1
|
||||
|
||||
|
||||
33
src/chat/normal_chat/normal_chat_utils.py
Normal file
33
src/chat/normal_chat/normal_chat_utils.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import time
|
||||
from src.config.config import global_config
|
||||
from src.common.message_repository import count_messages
|
||||
|
||||
|
||||
def get_recent_message_stats(minutes: int = 30, chat_id: str = None) -> dict:
|
||||
"""
|
||||
Args:
|
||||
minutes (int): 检索的分钟数,默认30分钟
|
||||
chat_id (str, optional): 指定的chat_id,仅统计该chat下的消息。为None时统计全部。
|
||||
Returns:
|
||||
dict: {"bot_reply_count": int, "total_message_count": int}
|
||||
"""
|
||||
|
||||
now = time.time()
|
||||
start_time = now - minutes * 60
|
||||
bot_id = global_config.bot.qq_account
|
||||
|
||||
filter_base = {"time": {"$gte": start_time}}
|
||||
if chat_id is not None:
|
||||
filter_base["chat_id"] = chat_id
|
||||
|
||||
# 总消息数
|
||||
total_message_count = count_messages(filter_base)
|
||||
# bot自身回复数
|
||||
bot_filter = filter_base.copy()
|
||||
bot_filter["user_id"] = bot_id
|
||||
bot_reply_count = count_messages(bot_filter)
|
||||
|
||||
return {
|
||||
"bot_reply_count": bot_reply_count,
|
||||
"total_message_count": total_message_count
|
||||
}
|
||||
@@ -271,7 +271,7 @@ CHAT_STYLE_CONFIG = {
|
||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
|
||||
},
|
||||
"simple": {
|
||||
"console_format": "<level>{time:HH:mm:ss}</level> | <green>见闻</green> | <green>{message}</green>", # noqa: E501
|
||||
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #1AFF5E>见闻</fg #1AFF5E> | <fg #1AFF5E>{message}</fg #1AFF5E>", # noqa: E501
|
||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
|
||||
},
|
||||
}
|
||||
@@ -288,7 +288,7 @@ NORMAL_CHAT_STYLE_CONFIG = {
|
||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 一般水群 | {message}",
|
||||
},
|
||||
"simple": {
|
||||
"console_format": "<level>{time:HH:mm:ss}</level> | <green>一般水群</green> | <green>{message}</green>", # noqa: E501
|
||||
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #00B741>一般水群</fg #00B741> | <fg #00B741>{message}</fg #00B741>", # noqa: E501
|
||||
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 一般水群 | {message}",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class NormalChatConfig(ConfigBase):
|
||||
max_context_size: int = 15
|
||||
"""上下文长度"""
|
||||
|
||||
message_buffer: bool = True
|
||||
message_buffer: bool = False
|
||||
"""消息缓冲器"""
|
||||
|
||||
emoji_chance: float = 0.2
|
||||
@@ -103,6 +103,9 @@ class NormalChatConfig(ConfigBase):
|
||||
willing_mode: str = "classical"
|
||||
"""意愿模式"""
|
||||
|
||||
talk_frequency: float = 1
|
||||
"""回复频率阈值"""
|
||||
|
||||
response_willing_amplifier: float = 1.0
|
||||
"""回复意愿放大系数"""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[inner]
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
|
||||
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
|
||||
#如果你想要修改配置文件,请在修改后将version的值进行变更
|
||||
@@ -18,22 +18,24 @@ nickname = "麦麦"
|
||||
alias_names = ["麦叠", "牢麦"] #仅在 专注聊天 有效
|
||||
|
||||
[personality]
|
||||
personality_core = "是一个积极向上的女大学生" # 建议20字以内,谁再写3000字小作文敲谁脑袋
|
||||
personality_core = "是一个积极向上的女大学生" # 建议50字以内
|
||||
personality_sides = [
|
||||
"用一句话或几句话描述人格的一些细节",
|
||||
"用一句话或几句话描述人格的一些细节",
|
||||
"用一句话或几句话描述人格的一些细节",
|
||||
]# 条数任意,不能为0
|
||||
]
|
||||
# 条数任意,不能为0
|
||||
|
||||
# 身份特点
|
||||
[identity] #アイデンティティがない 生まれないらららら
|
||||
#アイデンティティがない 生まれないらららら
|
||||
[identity]
|
||||
identity_detail = [
|
||||
"年龄为19岁",
|
||||
"是女孩子",
|
||||
"身高为160cm",
|
||||
"有橙色的短发",
|
||||
]
|
||||
# 可以描述外贸,性别,身高,职业,属性等等描述
|
||||
# 可以描述外貌,性别,身高,职业,属性等等描述
|
||||
# 条数任意,不能为0
|
||||
|
||||
[relationship]
|
||||
@@ -69,15 +71,18 @@ normal_chat_first_probability = 0.3 # 麦麦回答时选择首要模型的概率
|
||||
max_context_size = 15 #上下文长度
|
||||
emoji_chance = 0.2 # 麦麦一般回复时使用表情包的概率,设置为1让麦麦自己决定发不发
|
||||
thinking_timeout = 120 # 麦麦最长思考时间,超过这个时间的思考会放弃(往往是api反应太慢)
|
||||
message_buffer = true # 启用消息缓冲器?启用此项以解决消息的拆分问题,但会使麦麦的回复延迟
|
||||
|
||||
willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical,mxp模式:mxp,自定义模式:custom(需要你自己实现)
|
||||
talk_frequency = 1 # 麦麦回复频率,一般为1,默认频率下,30分钟麦麦回复30条(约数)
|
||||
|
||||
response_willing_amplifier = 1 # 麦麦回复意愿放大系数,一般为1
|
||||
response_interested_rate_amplifier = 1 # 麦麦回复兴趣度放大系数,听到记忆里的内容时放大系数
|
||||
down_frequency_rate = 3 # 降低回复频率的群组回复意愿降低系数 除法
|
||||
|
||||
emoji_response_penalty = 0 # 表情包回复惩罚系数,设为0为不回复单个表情包,减少单独回复表情包的概率
|
||||
mentioned_bot_inevitable_reply = false # 提及 bot 必然回复
|
||||
at_bot_inevitable_reply = false # @bot 必然回复
|
||||
|
||||
down_frequency_rate = 3 # 降低回复频率的群组回复意愿降低系数 除法
|
||||
talk_frequency_down_groups = [] #降低回复频率的群号码
|
||||
|
||||
[focus_chat] #专注聊天
|
||||
@@ -163,26 +168,8 @@ max_length = 256 # 回复允许的最大长度
|
||||
max_sentence_num = 4 # 回复允许的最大句子数
|
||||
enable_kaomoji_protection = false # 是否启用颜文字保护
|
||||
|
||||
[maim_message]
|
||||
auth_token = [] # 认证令牌,用于API验证,为空则不启用验证
|
||||
# 以下项目若要使用需要打开use_custom,并单独配置maim_message的服务器
|
||||
use_custom = false # 是否启用自定义的maim_message服务器,注意这需要设置新的端口,不能与.env重复
|
||||
host="127.0.0.1"
|
||||
port=8090
|
||||
mode="ws" # 支持ws和tcp两种模式
|
||||
use_wss = false # 是否使用WSS安全连接,只支持ws模式
|
||||
cert_file = "" # SSL证书文件路径,仅在use_wss=true时有效
|
||||
key_file = "" # SSL密钥文件路径,仅在use_wss=true时有效
|
||||
|
||||
|
||||
[telemetry] #发送统计信息,主要是看全球有多少只麦麦
|
||||
enable = true
|
||||
|
||||
[experimental] #实验性功能
|
||||
debug_show_chat_mode = true # 是否在回复后显示当前聊天模式
|
||||
enable_friend_chat = false # 是否启用好友聊天
|
||||
pfc_chatting = false # 是否启用PFC聊天,该功能仅作用于私聊,与回复模式独立,在0.7.0暂时无效
|
||||
|
||||
#下面的模型若使用硅基流动则不需要更改,使用ds官方则改成.env自定义的宏,使用自定义模型则选择定位相似的模型自己填写
|
||||
|
||||
# stream = <true|false> : 用于指定模型是否是使用流式输出
|
||||
@@ -333,5 +320,24 @@ pri_out = 8
|
||||
|
||||
|
||||
|
||||
[maim_message]
|
||||
auth_token = [] # 认证令牌,用于API验证,为空则不启用验证
|
||||
# 以下项目若要使用需要打开use_custom,并单独配置maim_message的服务器
|
||||
use_custom = false # 是否启用自定义的maim_message服务器,注意这需要设置新的端口,不能与.env重复
|
||||
host="127.0.0.1"
|
||||
port=8090
|
||||
mode="ws" # 支持ws和tcp两种模式
|
||||
use_wss = false # 是否使用WSS安全连接,只支持ws模式
|
||||
cert_file = "" # SSL证书文件路径,仅在use_wss=true时有效
|
||||
key_file = "" # SSL密钥文件路径,仅在use_wss=true时有效
|
||||
|
||||
[telemetry] #发送统计信息,主要是看全球有多少只麦麦
|
||||
enable = true
|
||||
|
||||
[experimental] #实验性功能
|
||||
debug_show_chat_mode = true # 是否在回复后显示当前聊天模式
|
||||
enable_friend_chat = false # 是否启用好友聊天
|
||||
pfc_chatting = false # 暂时无效
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user