Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox_Bot into dev
This commit is contained in:
@@ -277,6 +277,11 @@ class ChatterActionManager:
|
|||||||
logger.debug(f"{log_prefix} 并行执行:回复生成任务已被取消")
|
logger.debug(f"{log_prefix} 并行执行:回复生成任务已被取消")
|
||||||
return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None}
|
return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None}
|
||||||
|
|
||||||
|
# 从action_data中提取should_quote_reply参数
|
||||||
|
should_quote_reply = None
|
||||||
|
if action_data and isinstance(action_data, dict):
|
||||||
|
should_quote_reply = action_data.get("should_quote_reply", None)
|
||||||
|
|
||||||
# 发送并存储回复
|
# 发送并存储回复
|
||||||
loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(
|
loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(
|
||||||
chat_stream,
|
chat_stream,
|
||||||
@@ -286,6 +291,7 @@ class ChatterActionManager:
|
|||||||
{}, # cycle_timers
|
{}, # cycle_timers
|
||||||
thinking_id,
|
thinking_id,
|
||||||
[], # actions
|
[], # actions
|
||||||
|
should_quote_reply, # 传递should_quote_reply参数
|
||||||
)
|
)
|
||||||
|
|
||||||
# 记录回复动作到目标消息
|
# 记录回复动作到目标消息
|
||||||
@@ -474,6 +480,7 @@ class ChatterActionManager:
|
|||||||
cycle_timers: dict[str, float],
|
cycle_timers: dict[str, float],
|
||||||
thinking_id,
|
thinking_id,
|
||||||
actions,
|
actions,
|
||||||
|
should_quote_reply: bool | None = None,
|
||||||
) -> tuple[dict[str, Any], str, dict[str, float]]:
|
) -> tuple[dict[str, Any], str, dict[str, float]]:
|
||||||
"""
|
"""
|
||||||
发送并存储回复信息
|
发送并存储回复信息
|
||||||
@@ -486,13 +493,16 @@ class ChatterActionManager:
|
|||||||
cycle_timers: 循环计时器
|
cycle_timers: 循环计时器
|
||||||
thinking_id: 思考ID
|
thinking_id: 思考ID
|
||||||
actions: 动作列表
|
actions: 动作列表
|
||||||
|
should_quote_reply: 是否应该引用回复原消息,None表示自动决定
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[Dict[str, Any], str, Dict[str, float]]: 循环信息, 回复文本, 循环计时器
|
Tuple[Dict[str, Any], str, Dict[str, float]]: 循环信息, 回复文本, 循环计时器
|
||||||
"""
|
"""
|
||||||
# 发送回复
|
# 发送回复
|
||||||
with Timer("回复发送", cycle_timers):
|
with Timer("回复发送", cycle_timers):
|
||||||
reply_text = await self.send_response(chat_stream, response_set, loop_start_time, action_message)
|
reply_text = await self.send_response(
|
||||||
|
chat_stream, response_set, loop_start_time, action_message, should_quote_reply
|
||||||
|
)
|
||||||
|
|
||||||
# 存储reply action信息
|
# 存储reply action信息
|
||||||
person_info_manager = get_person_info_manager()
|
person_info_manager = get_person_info_manager()
|
||||||
@@ -551,16 +561,18 @@ class ChatterActionManager:
|
|||||||
|
|
||||||
return loop_info, reply_text, cycle_timers
|
return loop_info, reply_text, cycle_timers
|
||||||
|
|
||||||
async def send_response(self, chat_stream, reply_set, thinking_start_time, message_data) -> str:
|
async def send_response(
|
||||||
|
self, chat_stream, reply_set, thinking_start_time, message_data, should_quote_reply: bool | None = None
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
发送回复内容的具体实现
|
发送回复内容的具体实现
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_stream: ChatStream实例
|
chat_stream: ChatStream实例
|
||||||
reply_set: 回复内容集合,包含多个回复段
|
reply_set: 回复内容集合,包含多个回复段
|
||||||
reply_to: 回复目标
|
|
||||||
thinking_start_time: 思考开始时间
|
thinking_start_time: 思考开始时间
|
||||||
message_data: 消息数据
|
message_data: 消息数据
|
||||||
|
should_quote_reply: 是否应该引用回复原消息,None表示自动决定
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 完整的回复文本
|
str: 完整的回复文本
|
||||||
@@ -614,12 +626,24 @@ class ChatterActionManager:
|
|||||||
|
|
||||||
# 发送第一段回复
|
# 发送第一段回复
|
||||||
if not first_replied:
|
if not first_replied:
|
||||||
# 私聊场景不使用引用回复(因为只有两个人对话,引用是多余的)
|
# 决定是否引用回复
|
||||||
# 群聊场景使用引用回复(帮助定位回复的目标消息)
|
|
||||||
is_private_chat = not bool(chat_stream.group_info)
|
is_private_chat = not bool(chat_stream.group_info)
|
||||||
set_reply_flag = bool(message_data) and not is_private_chat
|
|
||||||
|
# 如果明确指定了should_quote_reply,则使用指定值
|
||||||
|
if should_quote_reply is not None:
|
||||||
|
set_reply_flag = should_quote_reply and bool(message_data)
|
||||||
|
logger.debug(
|
||||||
|
f"📤 [ActionManager] 使用planner指定的引用设置: should_quote_reply={should_quote_reply}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# 否则使用默认逻辑:默认不引用,让对话更流畅自然
|
||||||
|
set_reply_flag = False
|
||||||
|
logger.debug(
|
||||||
|
f"📤 [ActionManager] 使用默认引用逻辑: 默认不引用(is_private={is_private_chat})"
|
||||||
|
)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"📤 [ActionManager] 准备发送第一段回复。message_data: {message_data}, is_private: {is_private_chat}, set_reply: {set_reply_flag}"
|
f"📤 [ActionManager] 准备发送第一段回复。message_data: {message_data}, set_reply: {set_reply_flag}"
|
||||||
)
|
)
|
||||||
await send_api.text_to_stream(
|
await send_api.text_to_stream(
|
||||||
text=data,
|
text=data,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class ActionPlannerInfo(BaseDataModel):
|
|||||||
action_data: dict | None = None
|
action_data: dict | None = None
|
||||||
action_message: Optional["DatabaseMessages"] = None
|
action_message: Optional["DatabaseMessages"] = None
|
||||||
available_actions: dict[str, "ActionInfo"] | None = None
|
available_actions: dict[str, "ActionInfo"] | None = None
|
||||||
|
should_quote_reply: bool | None = None # 是否应该引用回复原消息,None表示由系统自动决定
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from src.config.official_configs import (
|
|||||||
MemoryConfig,
|
MemoryConfig,
|
||||||
MessageReceiveConfig,
|
MessageReceiveConfig,
|
||||||
MoodConfig,
|
MoodConfig,
|
||||||
NormalChatConfig,
|
|
||||||
NoticeConfig,
|
NoticeConfig,
|
||||||
PermissionConfig,
|
PermissionConfig,
|
||||||
PersonalityConfig,
|
PersonalityConfig,
|
||||||
@@ -379,7 +378,6 @@ class Config(ValidatedConfigBase):
|
|||||||
chat: ChatConfig = Field(..., description="聊天配置")
|
chat: ChatConfig = Field(..., description="聊天配置")
|
||||||
message_receive: MessageReceiveConfig = Field(..., description="消息接收配置")
|
message_receive: MessageReceiveConfig = Field(..., description="消息接收配置")
|
||||||
notice: NoticeConfig = Field(..., description="Notice消息配置")
|
notice: NoticeConfig = Field(..., description="Notice消息配置")
|
||||||
normal_chat: NormalChatConfig = Field(..., description="普通聊天配置")
|
|
||||||
emoji: EmojiConfig = Field(..., description="表情配置")
|
emoji: EmojiConfig = Field(..., description="表情配置")
|
||||||
expression: ExpressionConfig = Field(..., description="表达配置")
|
expression: ExpressionConfig = Field(..., description="表达配置")
|
||||||
memory: MemoryConfig = Field(..., description="记忆配置")
|
memory: MemoryConfig = Field(..., description="记忆配置")
|
||||||
|
|||||||
@@ -103,19 +103,10 @@ class ChatConfig(ValidatedConfigBase):
|
|||||||
"""聊天配置类"""
|
"""聊天配置类"""
|
||||||
|
|
||||||
max_context_size: int = Field(default=18, description="最大上下文大小")
|
max_context_size: int = Field(default=18, description="最大上下文大小")
|
||||||
replyer_random_probability: float = Field(default=0.5, description="回复者随机概率")
|
|
||||||
thinking_timeout: int = Field(default=40, description="思考超时时间")
|
thinking_timeout: int = Field(default=40, description="思考超时时间")
|
||||||
talk_frequency: float = Field(default=1.0, description="聊天频率")
|
|
||||||
mentioned_bot_inevitable_reply: bool = Field(default=False, description="提到机器人的必然回复")
|
mentioned_bot_inevitable_reply: bool = Field(default=False, description="提到机器人的必然回复")
|
||||||
at_bot_inevitable_reply: bool = Field(default=False, description="@机器人的必然回复")
|
at_bot_inevitable_reply: bool = Field(default=False, description="@机器人的必然回复")
|
||||||
allow_reply_self: bool = Field(default=False, description="是否允许回复自己说的话")
|
allow_reply_self: bool = Field(default=False, description="是否允许回复自己说的话")
|
||||||
focus_value: float = Field(default=1.0, description="专注值")
|
|
||||||
focus_mode_quiet_groups: list[str] = Field(
|
|
||||||
default_factory=list,
|
|
||||||
description='专注模式下需要保持安静的群组列表, 格式: ["platform:group_id1", "platform:group_id2"]',
|
|
||||||
)
|
|
||||||
force_reply_private: bool = Field(default=False, description="强制回复私聊")
|
|
||||||
group_chat_mode: Literal["auto", "normal", "focus"] = Field(default="auto", description="群聊模式")
|
|
||||||
timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field(
|
timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field(
|
||||||
default="normal_no_YMD", description="时间戳显示模式"
|
default="normal_no_YMD", description="时间戳显示模式"
|
||||||
)
|
)
|
||||||
@@ -129,13 +120,6 @@ class ChatConfig(ValidatedConfigBase):
|
|||||||
default=0.1, ge=0.0, le=1.0, description="最低打断概率(即使达到较高打断次数,也保证有此概率的打断机会)"
|
default=0.1, ge=0.0, le=1.0, description="最低打断概率(即使达到较高打断次数,也保证有此概率的打断机会)"
|
||||||
)
|
)
|
||||||
|
|
||||||
# DEPRECATED: interruption_probability_factor (已废弃的配置项)
|
|
||||||
# 新的线性概率模型不再需要复杂的概率因子
|
|
||||||
# 保留此字段是为了向后兼容,现有配置文件不会报错
|
|
||||||
interruption_probability_factor: float = Field(
|
|
||||||
default=0.8, ge=0.0, le=1.0, description="[已废弃] 打断概率因子,新线性概率模型不再使用此参数"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 动态消息分发系统配置
|
# 动态消息分发系统配置
|
||||||
dynamic_distribution_enabled: bool = Field(default=True, description="是否启用动态消息分发周期调整")
|
dynamic_distribution_enabled: bool = Field(default=True, description="是否启用动态消息分发周期调整")
|
||||||
dynamic_distribution_base_interval: float = Field(default=5.0, ge=1.0, le=60.0, description="基础分发间隔(秒)")
|
dynamic_distribution_base_interval: float = Field(default=5.0, ge=1.0, le=60.0, description="基础分发间隔(秒)")
|
||||||
@@ -170,10 +154,6 @@ class NoticeConfig(ValidatedConfigBase):
|
|||||||
notice_retention_time: int = Field(default=86400, ge=3600, le=604800, description="notice保留时间(秒)")
|
notice_retention_time: int = Field(default=86400, ge=3600, le=604800, description="notice保留时间(秒)")
|
||||||
|
|
||||||
|
|
||||||
class NormalChatConfig(ValidatedConfigBase):
|
|
||||||
"""普通聊天配置类"""
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionRule(ValidatedConfigBase):
|
class ExpressionRule(ValidatedConfigBase):
|
||||||
"""表达学习规则"""
|
"""表达学习规则"""
|
||||||
|
|
||||||
@@ -736,33 +716,7 @@ class ProactiveThinkingConfig(ValidatedConfigBase):
|
|||||||
# --- 总开关 ---
|
# --- 总开关 ---
|
||||||
enable: bool = Field(default=False, description="是否启用主动发起对话功能")
|
enable: bool = Field(default=False, description="是否启用主动发起对话功能")
|
||||||
|
|
||||||
# --- 触发时机 ---
|
# --- 间隔配置 ---
|
||||||
interval: int = Field(default=1500, description="基础触发间隔(秒),AI会围绕这个时间点主动发起对话")
|
|
||||||
interval_sigma: int = Field(
|
|
||||||
default=120, description="间隔随机化标准差(秒),让触发时间更自然。设为0则为固定间隔。"
|
|
||||||
)
|
|
||||||
talk_frequency_adjust: list[list[str]] = Field(
|
|
||||||
default_factory=lambda: [["", "8:00,1", "12:00,1.2", "18:00,1.5", "01:00,0.6"]],
|
|
||||||
description='每日活跃度调整,格式:[["", "HH:MM,factor", ...], ["stream_id", ...]]',
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- 作用范围 ---
|
|
||||||
enable_in_private: bool = Field(default=True, description="是否允许在私聊中主动发起对话")
|
|
||||||
enable_in_group: bool = Field(default=True, description="是否允许在群聊中主动发起对话")
|
|
||||||
enabled_private_chats: list[str] = Field(
|
|
||||||
default_factory=list, description='私聊白名单,为空则对所有私聊生效。格式: ["platform:user_id", ...]'
|
|
||||||
)
|
|
||||||
enabled_group_chats: list[str] = Field(
|
|
||||||
default_factory=list, description='群聊白名单,为空则对所有群聊生效。格式: ["platform:group_id", ...]'
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- 冷启动配置 (针对私聊) ---
|
|
||||||
enable_cold_start: bool = Field(default=True, description='对于白名单中不活跃的私聊,是否允许进行一次"冷启动"问候')
|
|
||||||
cold_start_cooldown: int = Field(
|
|
||||||
default=86400, description="冷启动后,该私聊的下一次主动思考需要等待的最小时间(秒)"
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- 新增:间隔配置 ---
|
|
||||||
base_interval: int = Field(default=1800, ge=60, description="基础触发间隔(秒),默认30分钟")
|
base_interval: int = Field(default=1800, ge=60, description="基础触发间隔(秒),默认30分钟")
|
||||||
min_interval: int = Field(default=600, ge=60, description="最小触发间隔(秒),默认10分钟。兴趣分数高时会接近此值")
|
min_interval: int = Field(default=600, ge=60, description="最小触发间隔(秒),默认10分钟。兴趣分数高时会接近此值")
|
||||||
max_interval: int = Field(default=7200, ge=60, description="最大触发间隔(秒),默认2小时。兴趣分数低时会接近此值")
|
max_interval: int = Field(default=7200, ge=60, description="最大触发间隔(秒),默认2小时。兴趣分数低时会接近此值")
|
||||||
|
|||||||
@@ -185,15 +185,24 @@ class ChatterPlanExecutor:
|
|||||||
"reply_content": "",
|
"reply_content": "",
|
||||||
}
|
}
|
||||||
# 构建回复动作参数
|
# 构建回复动作参数
|
||||||
|
action_data = action_info.action_data or {}
|
||||||
|
|
||||||
|
# 如果action_info中有should_quote_reply且action_data中没有,则添加到action_data中
|
||||||
|
if action_info.should_quote_reply is not None and "should_quote_reply" not in action_data:
|
||||||
|
action_data["should_quote_reply"] = action_info.should_quote_reply
|
||||||
|
|
||||||
action_params = {
|
action_params = {
|
||||||
"chat_id": plan.chat_id,
|
"chat_id": plan.chat_id,
|
||||||
"target_message": action_info.action_message,
|
"target_message": action_info.action_message,
|
||||||
"reasoning": action_info.reasoning,
|
"reasoning": action_info.reasoning,
|
||||||
"action_data": action_info.action_data or {},
|
"action_data": action_data,
|
||||||
"clear_unread_messages": clear_unread,
|
"clear_unread_messages": clear_unread,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f"📬 [PlanExecutor] 准备调用 ActionManager,target_message: {action_info.action_message}")
|
logger.debug(
|
||||||
|
f"📬 [PlanExecutor] 准备调用 ActionManager,target_message: {action_info.action_message}, "
|
||||||
|
f"should_quote_reply: {action_info.should_quote_reply}"
|
||||||
|
)
|
||||||
|
|
||||||
# 通过动作管理器执行回复
|
# 通过动作管理器执行回复
|
||||||
execution_result = await self.action_manager.execute_action(
|
execution_result = await self.action_manager.execute_action(
|
||||||
|
|||||||
@@ -601,6 +601,14 @@ class ChatterPlanFilter:
|
|||||||
reasoning = f"LLM 返回了当前不可用的动作 '{action}'。原始理由: {reasoning}"
|
reasoning = f"LLM 返回了当前不可用的动作 '{action}'。原始理由: {reasoning}"
|
||||||
action = "no_action"
|
action = "no_action"
|
||||||
|
|
||||||
|
# 从action_data中提取should_quote_reply参数
|
||||||
|
should_quote_reply = action_data.get("should_quote_reply", None)
|
||||||
|
# 将should_quote_reply转换为布尔值(如果是字符串的话)
|
||||||
|
if isinstance(should_quote_reply, str):
|
||||||
|
should_quote_reply = should_quote_reply.lower() in ["true", "1", "yes"]
|
||||||
|
elif not isinstance(should_quote_reply, bool):
|
||||||
|
should_quote_reply = None
|
||||||
|
|
||||||
parsed_actions.append(
|
parsed_actions.append(
|
||||||
ActionPlannerInfo(
|
ActionPlannerInfo(
|
||||||
action_type=action,
|
action_type=action,
|
||||||
@@ -608,6 +616,7 @@ class ChatterPlanFilter:
|
|||||||
action_data=action_data,
|
action_data=action_data,
|
||||||
action_message=action_message_obj, # 使用转换后的 DatabaseMessages 对象
|
action_message=action_message_obj, # 使用转换后的 DatabaseMessages 对象
|
||||||
available_actions=plan.available_actions,
|
available_actions=plan.available_actions,
|
||||||
|
should_quote_reply=should_quote_reply, # 传递should_quote_reply参数
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -318,6 +318,7 @@ class ChatterActionPlanner:
|
|||||||
reasoning="Normal模式: 兴趣度达到阈值,直接回复",
|
reasoning="Normal模式: 兴趣度达到阈值,直接回复",
|
||||||
action_data={"target_message_id": target_message.message_id},
|
action_data={"target_message_id": target_message.message_id},
|
||||||
action_message=target_message,
|
action_message=target_message,
|
||||||
|
should_quote_reply=False, # Normal模式默认不引用回复,保持对话流畅
|
||||||
)
|
)
|
||||||
|
|
||||||
# Normal模式下直接构建最小化的Plan,跳过generator和action_modifier
|
# Normal模式下直接构建最小化的Plan,跳过generator和action_modifier
|
||||||
|
|||||||
@@ -81,38 +81,56 @@ def init_prompts():
|
|||||||
"reasoning": "选择该动作的理由",
|
"reasoning": "选择该动作的理由",
|
||||||
"action_data": {{
|
"action_data": {{
|
||||||
"target_message_id": "m123",
|
"target_message_id": "m123",
|
||||||
"content": "你的回复内容"
|
"content": "你的回复内容",
|
||||||
|
"should_quote_reply": false
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
示例(多重回复,并行):
|
示例(多重回复,并行 - 需要区分回复对象时才引用):
|
||||||
```json
|
```json
|
||||||
{{
|
{{
|
||||||
"thinking": "在这里写下你的思绪流...",
|
"thinking": "在这里写下你的思绪流...",
|
||||||
"actions": [
|
"actions": [
|
||||||
{{
|
{{
|
||||||
"action_type": "reply",
|
"action_type": "reply",
|
||||||
"reasoning": "理由A",
|
"reasoning": "理由A - 这个消息较早且需要明确回复对象",
|
||||||
"action_data": {{
|
"action_data": {{
|
||||||
"target_message_id": "m124",
|
"target_message_id": "m124",
|
||||||
"content": "对A的回复"
|
"content": "对A的回复",
|
||||||
|
"should_quote_reply": true
|
||||||
}}
|
}}
|
||||||
}},
|
}},
|
||||||
{{
|
{{
|
||||||
"action_type": "reply",
|
"action_type": "reply",
|
||||||
"reasoning": "理由B",
|
"reasoning": "理由B - 这是对最新消息的自然接续",
|
||||||
"action_data": {{
|
"action_data": {{
|
||||||
"target_message_id": "m125",
|
"target_message_id": "m125",
|
||||||
"content": "对B的回复"
|
"content": "对B的回复",
|
||||||
|
"should_quote_reply": false
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# 引用回复控制(should_quote_reply)
|
||||||
|
在群聊中回复消息时,你可以通过 `should_quote_reply` 参数控制是否引用原消息:
|
||||||
|
- **true**: 明确引用原消息(适用于需要明确指向特定消息时,如回答问题、回应多人之一、回复较早的消息)
|
||||||
|
- **false**: 不引用原消息(适用于自然对话流、接续最新话题、轻松闲聊等场景)
|
||||||
|
- **不填写**: 系统将自动决定(默认不引用,让对话更流畅)
|
||||||
|
|
||||||
|
**【重要】默认策略:大多数情况下应该使用 `false` 以保持对话自然流畅**
|
||||||
|
|
||||||
|
**使用建议**:
|
||||||
|
- 当对话自然流畅、你的回复是接续最新话题时,**建议明确设为 `false`** 以避免打断对话节奏
|
||||||
|
- 当需要明确回复某个特定用户或特定问题时,设为 `true` 以帮助定位
|
||||||
|
- 当群聊中多人同时发言,你要回复其中一个较早的消息(非最新消息)时,设为 `true`
|
||||||
|
- 当有人直接@你或明确向你提问时,可以考虑设为 `true` 表明你在回复他
|
||||||
|
- 私聊场景**必须**设为 `false` 或不填(因为只有两个人,引用是多余的)
|
||||||
|
|
||||||
# 强制规则
|
# 强制规则
|
||||||
- 需要目标消息的动作(reply/poke_user/set_emoji_like 等),必须提供准确的 target_message_id(来自未读历史里的 <m...> 标签)。
|
- 需要目标消息的动作(reply/poke_user/set_emoji_like 等),必须提供准确的 target_message_id(来自未读历史里的 <m...> 标签)。
|
||||||
- 当动作需要额外参数时,必须在 action_data 中补全。
|
- 当动作需要额外参数时,必须在 action_data 中补全。
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from typing import Any, Literal
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
|
||||||
from src.chat.express.expression_selector import expression_selector
|
from src.chat.express.expression_selector import expression_selector
|
||||||
|
from src.chat.utils.prompt import Prompt
|
||||||
from src.common.database.sqlalchemy_database_api import get_db_session
|
from src.common.database.sqlalchemy_database_api import get_db_session
|
||||||
from src.common.database.sqlalchemy_models import ChatStreams
|
from src.common.database.sqlalchemy_models import ChatStreams
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
@@ -20,6 +21,133 @@ from src.plugin_system.apis import message_api, send_api
|
|||||||
|
|
||||||
logger = get_logger("proactive_thinking_executor")
|
logger = get_logger("proactive_thinking_executor")
|
||||||
|
|
||||||
|
# ==================================================================================================
|
||||||
|
# == Prompt Templates
|
||||||
|
# ==================================================================================================
|
||||||
|
|
||||||
|
# 决策 Prompt
|
||||||
|
decision_prompt_template = Prompt(
|
||||||
|
"""你的人设是:
|
||||||
|
{bot_personality}
|
||||||
|
|
||||||
|
现在是 {current_time},你正在考虑是否要在与 "{stream_name}" 的对话中主动说些什么。
|
||||||
|
|
||||||
|
【你当前的心情】
|
||||||
|
{current_mood}
|
||||||
|
|
||||||
|
【聊天环境信息】
|
||||||
|
- 整体印象: {stream_impression}
|
||||||
|
- 聊天风格: {chat_style}
|
||||||
|
- 常见话题: {topic_keywords}
|
||||||
|
- 你的兴趣程度: {interest_score:.2f}/1.0
|
||||||
|
{last_decision_text}
|
||||||
|
|
||||||
|
【最近的聊天记录】
|
||||||
|
{recent_chat_history}
|
||||||
|
|
||||||
|
请根据以上信息,决定你现在应该做什么:
|
||||||
|
|
||||||
|
**选项1:什么都不做 (do_nothing)**
|
||||||
|
- 适用场景:气氛不适合说话、最近对话很活跃、没什么特别想说的、或者此时说话会显得突兀。
|
||||||
|
- 心情影响:如果心情不好(如生气、难过),可能更倾向于保持沉默。
|
||||||
|
|
||||||
|
**选项2:简单冒个泡 (simple_bubble)**
|
||||||
|
- 适用场景:对话有些冷清,你想缓和气氛或开启新的互动。
|
||||||
|
- 方式:说一句轻松随意的话,旨在建立或维持连接。
|
||||||
|
- 心情影响:心情会影响你冒泡的方式和内容。
|
||||||
|
|
||||||
|
**选项3:发起一次有目的的互动 (throw_topic)**
|
||||||
|
- 适用场景:你想延续对话、表达关心、或深入讨论某个具体话题。
|
||||||
|
- **【互动类型1:延续约定或提醒】(最高优先级)**:检查最近的聊天记录,是否存在可以延续的互动。例如,如果昨晚的最后一条消息是“晚安”,现在是早上,一个“早安”的回应是绝佳的选择。如果之前提到过某个约定(如“待会聊”),现在可以主动跟进。
|
||||||
|
- **【互动类型2:展现真诚的关心】(次高优先级)**:如果不存在可延续的约定,请仔细阅读聊天记录,寻找对方提及的个人状况(如天气、出行、身体、情绪、工作学习等),并主动表达关心。
|
||||||
|
- **【互动类型3:开启新话题】**:当以上两点都不适用时,可以考虑开启一个你感兴趣的新话题。
|
||||||
|
- 心情影响:心情会影响你想发起互动的方式和内容。
|
||||||
|
|
||||||
|
请以JSON格式回复你的决策:
|
||||||
|
{{
|
||||||
|
"action": "do_nothing" | "simple_bubble" | "throw_topic",
|
||||||
|
"reasoning": "你的决策理由(请结合你的心情、聊天环境和对话历史进行分析)",
|
||||||
|
"topic": "(仅当action=throw_topic时填写)你的互动意图(如:回应晚安并说早安、关心对方的考试情况、讨论新游戏)"
|
||||||
|
}}
|
||||||
|
|
||||||
|
注意:
|
||||||
|
1. 兴趣度较低(<0.4)时或者最近聊天很活跃(不到1小时),倾向于 `do_nothing` 或 `simple_bubble`。
|
||||||
|
2. 你的心情会影响你的行动倾向和表达方式。
|
||||||
|
3. 参考上次决策,避免重复,并可根据上次的互动效果调整策略。
|
||||||
|
4. 只有在真的有感而发时才选择 `throw_topic`。
|
||||||
|
5. 保持你的人设,确保行为一致性。
|
||||||
|
""",
|
||||||
|
name="proactive_thinking_decision",
|
||||||
|
)
|
||||||
|
|
||||||
|
# 冒泡回复 Prompt
|
||||||
|
simple_bubble_reply_prompt_template = Prompt(
|
||||||
|
"""你的人设是:
|
||||||
|
{bot_personality}
|
||||||
|
|
||||||
|
距离上次对话已经有一段时间了,你决定主动说些什么,轻松地开启新的互动。
|
||||||
|
|
||||||
|
【你当前的心情】
|
||||||
|
{current_mood}
|
||||||
|
|
||||||
|
【聊天环境】
|
||||||
|
- 整体印象: {stream_impression}
|
||||||
|
- 聊天风格: {chat_style}
|
||||||
|
|
||||||
|
【最近的聊天记录】
|
||||||
|
{recent_chat_history}
|
||||||
|
{expression_habits}
|
||||||
|
请生成一条简短的消息,用于水群。
|
||||||
|
【要求】
|
||||||
|
1. 风格简短随意(5-20字)
|
||||||
|
2. 不要提出明确的话题或问题,可以是问候、表达心情或一句随口的话。
|
||||||
|
3. 符合你的人设和当前聊天风格。
|
||||||
|
4. **你的心情应该影响消息的内容和语气**。
|
||||||
|
5. 如果有表达方式参考,在合适时自然使用。
|
||||||
|
6. 合理参考历史记录。
|
||||||
|
直接输出消息内容,不要解释:""",
|
||||||
|
name="proactive_thinking_simple_bubble",
|
||||||
|
)
|
||||||
|
|
||||||
|
# 抛出话题回复 Prompt
|
||||||
|
throw_topic_reply_prompt_template = Prompt(
|
||||||
|
"""你的人设是:
|
||||||
|
{bot_personality}
|
||||||
|
|
||||||
|
现在是 {current_time},你决定在与 "{stream_name}" 的对话中主动发起一次互动。
|
||||||
|
|
||||||
|
【你当前的心情】
|
||||||
|
{current_mood}
|
||||||
|
|
||||||
|
【聊天环境】
|
||||||
|
- 整体印象: {stream_impression}
|
||||||
|
- 聊天风格: {chat_style}
|
||||||
|
- 常见话题: {topic_keywords}
|
||||||
|
|
||||||
|
【最近的聊天记录】
|
||||||
|
{recent_chat_history}
|
||||||
|
|
||||||
|
【你的互动意图】
|
||||||
|
{topic}
|
||||||
|
{expression_habits}
|
||||||
|
【构思指南】
|
||||||
|
请根据你的互动意图,生成一条有温度的消息。
|
||||||
|
- 如果意图是**延续约定**(如回应“晚安”),请直接生成对应的问候。
|
||||||
|
- 如果意图是**表达关心**(如跟进对方提到的事),请生成自然、真诚的关心话语。
|
||||||
|
- 如果意图是**开启新话题**,请自然地引入话题。
|
||||||
|
|
||||||
|
请根据这个意图,生成一条消息,要求:
|
||||||
|
1. 自然地引入话题或表达关心。
|
||||||
|
2. 长度适中(20-50字)。
|
||||||
|
3. 可以结合最近的聊天记录,使对话更连贯。
|
||||||
|
4. 符合你的人设和当前聊天风格。
|
||||||
|
5. **你的心情会影响你的表达方式**。
|
||||||
|
6. 如果有表达方式参考,在合适时自然使用。
|
||||||
|
|
||||||
|
直接输出消息内容,不要解释:""",
|
||||||
|
name="proactive_thinking_throw_topic",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProactiveThinkingPlanner:
|
class ProactiveThinkingPlanner:
|
||||||
"""主动思考规划器
|
"""主动思考规划器
|
||||||
@@ -167,7 +295,35 @@ class ProactiveThinkingPlanner:
|
|||||||
|
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
decision_prompt = self._build_decision_prompt(context)
|
# 构建上次决策信息
|
||||||
|
last_decision_text = ""
|
||||||
|
if context.get("last_decision"):
|
||||||
|
last_dec = context["last_decision"]
|
||||||
|
last_action = last_dec.get("action", "未知")
|
||||||
|
last_reasoning = last_dec.get("reasoning", "无")
|
||||||
|
last_topic = last_dec.get("topic")
|
||||||
|
last_time = last_dec.get("timestamp", "未知")
|
||||||
|
|
||||||
|
last_decision_text = f"""
|
||||||
|
【上次主动思考的决策】
|
||||||
|
- 时间: {last_time}
|
||||||
|
- 决策: {last_action}
|
||||||
|
- 理由: {last_reasoning}"""
|
||||||
|
if last_topic:
|
||||||
|
last_decision_text += f"\n- 话题: {last_topic}"
|
||||||
|
|
||||||
|
decision_prompt = decision_prompt_template.format(
|
||||||
|
bot_personality=context["bot_personality"],
|
||||||
|
current_time=context["current_time"],
|
||||||
|
stream_name=context["stream_name"],
|
||||||
|
current_mood=context.get("current_mood", "感觉很平静"),
|
||||||
|
stream_impression=context["stream_impression"],
|
||||||
|
chat_style=context["chat_style"],
|
||||||
|
topic_keywords=context["topic_keywords"] or "暂无",
|
||||||
|
interest_score=context["interest_score"],
|
||||||
|
last_decision_text=last_decision_text,
|
||||||
|
recent_chat_history=context["recent_chat_history"],
|
||||||
|
)
|
||||||
|
|
||||||
if global_config.debug.show_prompt:
|
if global_config.debug.show_prompt:
|
||||||
logger.info(f"决策提示词:\n{decision_prompt}")
|
logger.info(f"决策提示词:\n{decision_prompt}")
|
||||||
@@ -195,76 +351,6 @@ class ProactiveThinkingPlanner:
|
|||||||
logger.error(f"决策过程失败: {e}", exc_info=True)
|
logger.error(f"决策过程失败: {e}", exc_info=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _build_decision_prompt(self, context: dict[str, Any]) -> str:
|
|
||||||
"""构建决策提示词"""
|
|
||||||
# 构建上次决策信息
|
|
||||||
last_decision_text = ""
|
|
||||||
if context.get("last_decision"):
|
|
||||||
last_dec = context["last_decision"]
|
|
||||||
last_action = last_dec.get("action", "未知")
|
|
||||||
last_reasoning = last_dec.get("reasoning", "无")
|
|
||||||
last_topic = last_dec.get("topic")
|
|
||||||
last_time = last_dec.get("timestamp", "未知")
|
|
||||||
|
|
||||||
last_decision_text = f"""
|
|
||||||
【上次主动思考的决策】
|
|
||||||
- 时间: {last_time}
|
|
||||||
- 决策: {last_action}
|
|
||||||
- 理由: {last_reasoning}"""
|
|
||||||
if last_topic:
|
|
||||||
last_decision_text += f"\n- 话题: {last_topic}"
|
|
||||||
|
|
||||||
return f"""你的人设是:
|
|
||||||
{context['bot_personality']}
|
|
||||||
|
|
||||||
现在是 {context['current_time']},你正在考虑是否要在与 "{context['stream_name']}" 的对话中主动说些什么。
|
|
||||||
|
|
||||||
【你当前的心情】
|
|
||||||
{context.get("current_mood", "感觉很平静")}
|
|
||||||
|
|
||||||
【聊天环境信息】
|
|
||||||
- 整体印象: {context["stream_impression"]}
|
|
||||||
- 聊天风格: {context["chat_style"]}
|
|
||||||
- 常见话题: {context["topic_keywords"] or "暂无"}
|
|
||||||
- 你的兴趣程度: {context["interest_score"]:.2f}/1.0
|
|
||||||
{last_decision_text}
|
|
||||||
|
|
||||||
【最近的聊天记录】
|
|
||||||
{context["recent_chat_history"]}
|
|
||||||
|
|
||||||
请根据以上信息,决定你现在应该做什么:
|
|
||||||
|
|
||||||
**选项1:什么都不做 (do_nothing)**
|
|
||||||
- 适用场景:气氛不适合说话、最近对话很活跃、没什么特别想说的、或者此时说话会显得突兀。
|
|
||||||
- 心情影响:如果心情不好(如生气、难过),可能更倾向于保持沉默。
|
|
||||||
|
|
||||||
**选项2:简单冒个泡 (simple_bubble)**
|
|
||||||
- 适用场景:对话有些冷清,你想缓和气氛或开启新的互动。
|
|
||||||
- 方式:说一句轻松随意的话,旨在建立或维持连接。
|
|
||||||
- 心情影响:心情会影响你冒泡的方式和内容。
|
|
||||||
|
|
||||||
**选项3:发起一次有目的的互动 (throw_topic)**
|
|
||||||
- 适用场景:你想延续对话、表达关心、或深入讨论某个具体话题。
|
|
||||||
- **【互动类型1:延续约定或提醒】(最高优先级)**:检查最近的聊天记录,是否存在可以延续的互动。例如,如果昨晚的最后一条消息是“晚安”,现在是早上,一个“早安”的回应是绝佳的选择。如果之前提到过某个约定(如“待会聊”),现在可以主动跟进。
|
|
||||||
- **【互动类型2:展现真诚的关心】(次高优先级)**:如果不存在可延续的约定,请仔细阅读聊天记录,寻找对方提及的个人状况(如天气、出行、身体、情绪、工作学习等),并主动表达关心。
|
|
||||||
- **【互动类型3:开启新话题】**:当以上两点都不适用时,可以考虑开启一个你感兴趣的新话题。
|
|
||||||
- 心情影响:心情会影响你想发起互动的方式和内容。
|
|
||||||
|
|
||||||
请以JSON格式回复你的决策:
|
|
||||||
{{
|
|
||||||
"action": "do_nothing" | "simple_bubble" | "throw_topic",
|
|
||||||
"reasoning": "你的决策理由(请结合你的心情、聊天环境和对话历史进行分析)",
|
|
||||||
"topic": "(仅当action=throw_topic时填写)你的互动意图(如:回应晚安并说早安、关心对方的考试情况、讨论新游戏)"
|
|
||||||
}}
|
|
||||||
|
|
||||||
注意:
|
|
||||||
1. 兴趣度较低(<0.4)时或者最近聊天很活跃(不到1小时),倾向于 `do_nothing` 或 `simple_bubble`。
|
|
||||||
2. 你的心情会影响你的行动倾向和表达方式。
|
|
||||||
3. 参考上次决策,避免重复,并可根据上次的互动效果调整策略。
|
|
||||||
4. 只有在真的有感而发时才选择 `throw_topic`。
|
|
||||||
5. 保持你的人设,确保行为一致性。
|
|
||||||
"""
|
|
||||||
|
|
||||||
async def generate_reply(
|
async def generate_reply(
|
||||||
self, context: dict[str, Any], action: Literal["simple_bubble", "throw_topic"], topic: str | None = None
|
self, context: dict[str, Any], action: Literal["simple_bubble", "throw_topic"], topic: str | None = None
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
@@ -283,7 +369,34 @@ class ProactiveThinkingPlanner:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reply_prompt = await self._build_reply_prompt(context, action, topic)
|
# 获取表达方式参考
|
||||||
|
expression_habits = await self._get_expression_habits(
|
||||||
|
stream_id=context.get("stream_id", ""), chat_history=context.get("recent_chat_history", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
if action == "simple_bubble":
|
||||||
|
reply_prompt = simple_bubble_reply_prompt_template.format(
|
||||||
|
bot_personality=context["bot_personality"],
|
||||||
|
current_mood=context.get("current_mood", "感觉很平静"),
|
||||||
|
stream_impression=context["stream_impression"],
|
||||||
|
chat_style=context["chat_style"],
|
||||||
|
recent_chat_history=context["recent_chat_history"],
|
||||||
|
expression_habits=expression_habits,
|
||||||
|
)
|
||||||
|
else: # throw_topic
|
||||||
|
reply_prompt = throw_topic_reply_prompt_template.format(
|
||||||
|
bot_personality=context["bot_personality"],
|
||||||
|
current_time=context["current_time"],
|
||||||
|
stream_name=context["stream_name"],
|
||||||
|
current_mood=context.get("current_mood", "感觉很平静"),
|
||||||
|
stream_impression=context["stream_impression"],
|
||||||
|
chat_style=context["chat_style"],
|
||||||
|
topic_keywords=context["topic_keywords"] or "暂无",
|
||||||
|
recent_chat_history=context["recent_chat_history"],
|
||||||
|
topic=topic,
|
||||||
|
expression_habits=expression_habits,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if global_config.debug.show_prompt:
|
if global_config.debug.show_prompt:
|
||||||
logger.info(f"回复提示词:\n{reply_prompt}")
|
logger.info(f"回复提示词:\n{reply_prompt}")
|
||||||
@@ -350,77 +463,6 @@ class ProactiveThinkingPlanner:
|
|||||||
logger.warning(f"获取表达方式失败: {e}")
|
logger.warning(f"获取表达方式失败: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
async def _build_reply_prompt(
|
|
||||||
self, context: dict[str, Any], action: Literal["simple_bubble", "throw_topic"], topic: str | None
|
|
||||||
) -> str:
|
|
||||||
"""构建回复提示词"""
|
|
||||||
# 获取表达方式参考
|
|
||||||
expression_habits = await self._get_expression_habits(
|
|
||||||
stream_id=context.get("stream_id", ""), chat_history=context.get("recent_chat_history", "")
|
|
||||||
)
|
|
||||||
|
|
||||||
if action == "simple_bubble":
|
|
||||||
return f"""你的人设是:
|
|
||||||
{context['bot_personality']}
|
|
||||||
|
|
||||||
距离上次对话已经有一段时间了,你决定主动说些什么,轻松地开启新的互动。
|
|
||||||
|
|
||||||
【你当前的心情】
|
|
||||||
{context.get("current_mood", "感觉很平静")}
|
|
||||||
|
|
||||||
【聊天环境】
|
|
||||||
- 整体印象: {context["stream_impression"]}
|
|
||||||
- 聊天风格: {context["chat_style"]}
|
|
||||||
|
|
||||||
【最近的聊天记录】
|
|
||||||
{context["recent_chat_history"]}
|
|
||||||
{expression_habits}
|
|
||||||
请生成一条简短的消息,用于水群。
|
|
||||||
【要求】
|
|
||||||
1. 风格简短随意(5-20字)
|
|
||||||
2. 不要提出明确的话题或问题,可以是问候、表达心情或一句随口的话。
|
|
||||||
3. 符合你的人设和当前聊天风格。
|
|
||||||
4. **你的心情应该影响消息的内容和语气**。
|
|
||||||
5. 如果有表达方式参考,在合适时自然使用。
|
|
||||||
6. 合理参考历史记录。
|
|
||||||
直接输出消息内容,不要解释:"""
|
|
||||||
|
|
||||||
else: # throw_topic
|
|
||||||
return f"""你的人设是:
|
|
||||||
{context['bot_personality']}
|
|
||||||
|
|
||||||
现在是 {context['current_time']},你决定在与 "{context['stream_name']}" 的对话中主动发起一次互动。
|
|
||||||
|
|
||||||
【你当前的心情】
|
|
||||||
{context.get("current_mood", "感觉很平静")}
|
|
||||||
|
|
||||||
【聊天环境】
|
|
||||||
- 整体印象: {context["stream_impression"]}
|
|
||||||
- 聊天风格: {context["chat_style"]}
|
|
||||||
- 常见话题: {context["topic_keywords"] or "暂无"}
|
|
||||||
|
|
||||||
【最近的聊天记录】
|
|
||||||
{context["recent_chat_history"]}
|
|
||||||
|
|
||||||
【你的互动意图】
|
|
||||||
{topic}
|
|
||||||
{expression_habits}
|
|
||||||
【构思指南】
|
|
||||||
请根据你的互动意图,生成一条有温度的消息。
|
|
||||||
- 如果意图是**延续约定**(如回应“晚安”),请直接生成对应的问候。
|
|
||||||
- 如果意图是**表达关心**(如跟进对方提到的事),请生成自然、真诚的关心话语。
|
|
||||||
- 如果意图是**开启新话题**,请自然地引入话题。
|
|
||||||
|
|
||||||
请根据这个意图,生成一条消息,要求:
|
|
||||||
1. 自然地引入话题或表达关心。
|
|
||||||
2. 长度适中(20-50字)。
|
|
||||||
3. 可以结合最近的聊天记录,使对话更连贯。
|
|
||||||
4. 符合你的人设和当前聊天风格。
|
|
||||||
5. **你的心情会影响你的表达方式**。
|
|
||||||
6. 如果有表达方式参考,在合适时自然使用。
|
|
||||||
|
|
||||||
直接输出消息内容,不要解释:"""
|
|
||||||
|
|
||||||
def _clean_json_response(self, response: str) -> str:
|
def _clean_json_response(self, response: str) -> str:
|
||||||
"""清理LLM响应中的JSON格式标记"""
|
"""清理LLM响应中的JSON格式标记"""
|
||||||
import re
|
import re
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "7.5.3"
|
version = "7.5.4"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
||||||
#如果你想要修改配置文件,请递增version的值
|
#如果你想要修改配置文件,请递增version的值
|
||||||
@@ -195,9 +195,6 @@ auto_ban_duration_hours = 2 # 封禁持续时间(小时)
|
|||||||
shield_prefix = "🛡️ " # 加盾消息前缀
|
shield_prefix = "🛡️ " # 加盾消息前缀
|
||||||
shield_suffix = " 🛡️" # 加盾消息后缀
|
shield_suffix = " 🛡️" # 加盾消息后缀
|
||||||
|
|
||||||
[normal_chat] #普通聊天
|
|
||||||
willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical,mxp模式:mxp,自定义模式:custom(需要你自己实现)
|
|
||||||
|
|
||||||
[tool]
|
[tool]
|
||||||
enable_tool = true # 是否在普通聊天中启用工具
|
enable_tool = true # 是否在普通聊天中启用工具
|
||||||
|
|
||||||
@@ -622,13 +619,4 @@ throw_topic_weight = 0.3 # throw_topic动作的基础权重
|
|||||||
|
|
||||||
# --- 调试与监控 ---
|
# --- 调试与监控 ---
|
||||||
enable_statistics = true # 是否启用统计功能(记录触发次数、决策分布等)
|
enable_statistics = true # 是否启用统计功能(记录触发次数、决策分布等)
|
||||||
log_decisions = false # 是否记录每次决策的详细日志(用于调试)
|
log_decisions = false # 是否记录每次决策的详细日志(用于调试)
|
||||||
|
|
||||||
# --- 兼容旧配置(已废弃,建议删除) ---
|
|
||||||
interval = 1800 # [已废弃] 请使用 base_interval
|
|
||||||
interval_sigma = 120 # [已废弃] 随机化功能已移除
|
|
||||||
talk_frequency_adjust = [] # [已废弃] 请使用 enable_time_strategy 和相关配置
|
|
||||||
enabled_private_chats = [] # [已废弃] 请使用 whitelist_private
|
|
||||||
enabled_group_chats = [] # [已废弃] 请使用 whitelist_group
|
|
||||||
enable_cold_start = false # [已废弃] 冷启动功能已移除
|
|
||||||
cold_start_cooldown = 86400 # [已废弃] 冷启动功能已移除
|
|
||||||
Reference in New Issue
Block a user