feat(chat): 实现可配置的主动思考范围并优化逻辑
- 将主动思考的prompt移至代码内部,并区分私聊和群聊场景。 - 增加`The_scope_that_proactive_thinking_can_trigger`配置项,允许用户将主动思考限制在“全部”、“私聊”或“群聊”范围。 - 删除了旧的`proactive_thinking_prompt_template`配置。 - 优化了主动思考的触发条件,现在会根据新的范围配置进行检查。 - 清理了代码中多余的空行和未使用的导入。
This commit is contained in:
@@ -139,6 +139,22 @@ class HeartFChatting:
|
|||||||
self.last_message_time = time.time() # 最后一条消息的时间
|
self.last_message_time = time.time() # 最后一条消息的时间
|
||||||
self._proactive_thinking_task: Optional[asyncio.Task] = None # 主动思考任务
|
self._proactive_thinking_task: Optional[asyncio.Task] = None # 主动思考任务
|
||||||
|
|
||||||
|
self.proactive_thinking_prompts = {
|
||||||
|
"private": """现在你和你朋友的私聊里面已经隔了{time}没有发送消息了,请你结合上下文以及你和你朋友之前聊过的话题和你的人设来决定要不要主动发送消息,你可以选择:
|
||||||
|
|
||||||
|
1. 继续保持沉默(当{time}以前已经结束了一个话题并且你不想挑起新话题时)
|
||||||
|
2. 选择回复(当{time}以前你发送了一条消息且没有人回复你时、你想主动挑起一个话题时)
|
||||||
|
|
||||||
|
请根据当前情况做出选择。如果选择回复,请直接发送你想说的内容;如果选择保持沉默,请只回复"沉默"(注意:这个词不会被发送到群聊中)。""",
|
||||||
|
"group": """现在群里面已经隔了{time}没有人发送消息了,请你结合上下文以及群聊里面之前聊过的话题和你的人设来决定要不要主动发送消息,你可以选择:
|
||||||
|
|
||||||
|
1. 继续保持沉默(当{time}以前已经结束了一个话题并且你不想挑起新话题时)
|
||||||
|
2. 选择回复(当{time}以前你发送了一条消息且没有人回复你时、你想主动挑起一个话题时)
|
||||||
|
|
||||||
|
请根据当前情况做出选择。如果选择回复,请直接发送你想说的内容;如果选择保持沉默,请只回复"沉默"(注意:这个词不会被发送到群聊中)。""",
|
||||||
|
}
|
||||||
|
self.proactive_thinking_chat_scope = global_config.chat.The_scope_that_proactive_thinking_can_trigger
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
"""检查是否需要启动主循环,如果未激活则启动。"""
|
"""检查是否需要启动主循环,如果未激活则启动。"""
|
||||||
|
|
||||||
@@ -154,9 +170,8 @@ class HeartFChatting:
|
|||||||
self._energy_task = asyncio.create_task(self._energy_loop())
|
self._energy_task = asyncio.create_task(self._energy_loop())
|
||||||
self._energy_task.add_done_callback(self._handle_energy_completion)
|
self._energy_task.add_done_callback(self._handle_energy_completion)
|
||||||
|
|
||||||
# 启动主动思考任务(仅在群聊且启用的情况下)
|
# 启动主动思考任务
|
||||||
if (global_config.chat.enable_proactive_thinking and
|
if global_config.chat.enable_proactive_thinking:
|
||||||
self.chat_stream.group_info is not None):
|
|
||||||
self._proactive_thinking_task = asyncio.create_task(self._proactive_thinking_loop())
|
self._proactive_thinking_task = asyncio.create_task(self._proactive_thinking_loop())
|
||||||
self._proactive_thinking_task.add_done_callback(self._handle_proactive_thinking_completion)
|
self._proactive_thinking_task.add_done_callback(self._handle_proactive_thinking_completion)
|
||||||
|
|
||||||
@@ -274,6 +289,11 @@ class HeartFChatting:
|
|||||||
# 只在focus模式下进行主动思考
|
# 只在focus模式下进行主动思考
|
||||||
if self.loop_mode != ChatMode.FOCUS:
|
if self.loop_mode != ChatMode.FOCUS:
|
||||||
continue
|
continue
|
||||||
|
if self.proactive_thinking_chat_scope == "group" and self.chat_stream.group_info is None:
|
||||||
|
continue
|
||||||
|
if self.proactive_thinking_chat_scope == "private" and self.chat_stream.group_info is not None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
silence_duration = current_time - self.last_message_time
|
silence_duration = current_time - self.last_message_time
|
||||||
@@ -310,17 +330,12 @@ class HeartFChatting:
|
|||||||
logger.info(f"{self.log_prefix} 触发主动思考,已沉默{formatted_time}")
|
logger.info(f"{self.log_prefix} 触发主动思考,已沉默{formatted_time}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 构建主动思考的prompt
|
# 根据聊天类型选择prompt
|
||||||
proactive_prompt = global_config.chat.proactive_thinking_prompt_template.format(
|
chat_type = "group" if self.chat_stream.group_info else "private"
|
||||||
time=formatted_time
|
prompt_template = self.proactive_thinking_prompts.get(chat_type, self.proactive_thinking_prompts["group"])
|
||||||
)
|
proactive_prompt = prompt_template.format(time=formatted_time)
|
||||||
|
|
||||||
# 创建一个虚拟的消息数据用于主动思考
|
# 创建一个虚拟的消息数据用于主动思考
|
||||||
"""
|
|
||||||
因为主动思考是在没有用户消息的情况下触发的
|
|
||||||
但规划器仍然需要一个"消息"作为输入来工作
|
|
||||||
所以需要"伪造"一个消息来触发思考流程,本质上是系统与自己的对话,让AI能够主动思考和决策。
|
|
||||||
"""
|
|
||||||
thinking_message = {
|
thinking_message = {
|
||||||
"processed_plain_text": proactive_prompt,
|
"processed_plain_text": proactive_prompt,
|
||||||
"user_id": "system_proactive_thinking",
|
"user_id": "system_proactive_thinking",
|
||||||
@@ -329,11 +344,10 @@ class HeartFChatting:
|
|||||||
"message_type": "proactive_thinking",
|
"message_type": "proactive_thinking",
|
||||||
"user_nickname": "系统主动思考",
|
"user_nickname": "系统主动思考",
|
||||||
"chat_info_platform": "system",
|
"chat_info_platform": "system",
|
||||||
"message_id": f"proactive_{int(time.time())}"
|
"message_id": f"proactive_{int(time.time())}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# 使用现有的_observe方法来处理主动思考
|
# 使用现有的_observe方法来处理主动思考
|
||||||
# 这样可以复用现有的完整思考流程
|
|
||||||
logger.info(f"{self.log_prefix} 开始主动思考...")
|
logger.info(f"{self.log_prefix} 开始主动思考...")
|
||||||
await self._observe(message_data=thinking_message)
|
await self._observe(message_data=thinking_message)
|
||||||
logger.info(f"{self.log_prefix} 主动思考完成")
|
logger.info(f"{self.log_prefix} 主动思考完成")
|
||||||
@@ -356,13 +370,12 @@ class HeartFChatting:
|
|||||||
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _loopbody(self):
|
async def _loopbody(self):
|
||||||
recent_messages_dict = message_api.get_messages_by_time_in_chat(
|
recent_messages_dict = message_api.get_messages_by_time_in_chat(
|
||||||
chat_id=self.stream_id,
|
chat_id=self.stream_id,
|
||||||
start_time=self.last_read_time,
|
start_time=self.last_read_time,
|
||||||
end_time=time.time(),
|
end_time=time.time(),
|
||||||
limit = 10,
|
limit=10,
|
||||||
limit_mode="latest",
|
limit_mode="latest",
|
||||||
filter_mai=True,
|
filter_mai=True,
|
||||||
filter_command=True,
|
filter_command=True,
|
||||||
@@ -374,7 +387,6 @@ class HeartFChatting:
|
|||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
self.last_message_time = current_time
|
self.last_message_time = current_time
|
||||||
|
|
||||||
|
|
||||||
if self.loop_mode == ChatMode.FOCUS:
|
if self.loop_mode == ChatMode.FOCUS:
|
||||||
# focus模式下,在有新消息时进行观察思考
|
# focus模式下,在有新消息时进行观察思考
|
||||||
# 主动思考由独立的 _proactive_thinking_loop 处理
|
# 主动思考由独立的 _proactive_thinking_loop 处理
|
||||||
@@ -426,9 +438,7 @@ class HeartFChatting:
|
|||||||
elif global_config.chat.focus_value != 0:
|
elif global_config.chat.focus_value != 0:
|
||||||
if new_message_count > 3 / pow(global_config.chat.focus_value, 0.5):
|
if new_message_count > 3 / pow(global_config.chat.focus_value, 0.5):
|
||||||
self.loop_mode = ChatMode.FOCUS
|
self.loop_mode = ChatMode.FOCUS
|
||||||
self.energy_value = (
|
self.energy_value = 10 + (new_message_count / (3 / pow(global_config.chat.focus_value, 0.5))) * 10
|
||||||
10 + (new_message_count / (3 / pow(global_config.chat.focus_value, 0.5))) * 10
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.energy_value >= 30:
|
if self.energy_value >= 30:
|
||||||
@@ -466,7 +476,9 @@ class HeartFChatting:
|
|||||||
person_info_manager = get_person_info_manager()
|
person_info_manager = get_person_info_manager()
|
||||||
|
|
||||||
# 获取平台信息,优先使用chat_info_platform,如果为None则使用user_platform
|
# 获取平台信息,优先使用chat_info_platform,如果为None则使用user_platform
|
||||||
platform = message_data.get("chat_info_platform") or message_data.get("user_platform") or self.chat_stream.platform
|
platform = (
|
||||||
|
message_data.get("chat_info_platform") or message_data.get("user_platform") or self.chat_stream.platform
|
||||||
|
)
|
||||||
user_id = message_data.get("user_id")
|
user_id = message_data.get("user_id")
|
||||||
|
|
||||||
person_id = person_info_manager.get_person_id(platform, user_id)
|
person_id = person_info_manager.get_person_id(platform, user_id)
|
||||||
@@ -490,7 +502,9 @@ class HeartFChatting:
|
|||||||
person_info_manager = get_person_info_manager()
|
person_info_manager = get_person_info_manager()
|
||||||
|
|
||||||
# 获取平台信息,优先使用chat_info_platform,如果为空则使用user_platform
|
# 获取平台信息,优先使用chat_info_platform,如果为空则使用user_platform
|
||||||
platform = action_message.get("chat_info_platform") or action_message.get("user_platform") or self.chat_stream.platform
|
platform = (
|
||||||
|
action_message.get("chat_info_platform") or action_message.get("user_platform") or self.chat_stream.platform
|
||||||
|
)
|
||||||
user_id = action_message.get("user_id", "")
|
user_id = action_message.get("user_id", "")
|
||||||
|
|
||||||
person_id = person_info_manager.get_person_id(platform, user_id)
|
person_id = person_info_manager.get_person_id(platform, user_id)
|
||||||
@@ -555,12 +569,15 @@ class HeartFChatting:
|
|||||||
|
|
||||||
# 在focus模式下如果你的bot被@/提到了,那么就移除no_reply动作
|
# 在focus模式下如果你的bot被@/提到了,那么就移除no_reply动作
|
||||||
is_mentioned_bot = message_data.get("is_mentioned", False)
|
is_mentioned_bot = message_data.get("is_mentioned", False)
|
||||||
at_bot_mentioned = (global_config.chat.mentioned_bot_inevitable_reply and is_mentioned_bot) or \
|
at_bot_mentioned = (global_config.chat.mentioned_bot_inevitable_reply and is_mentioned_bot) or (
|
||||||
(global_config.chat.at_bot_inevitable_reply and is_mentioned_bot)
|
global_config.chat.at_bot_inevitable_reply and is_mentioned_bot
|
||||||
|
)
|
||||||
|
|
||||||
if self.loop_mode == ChatMode.FOCUS and at_bot_mentioned and "no_reply" in available_actions:
|
if self.loop_mode == ChatMode.FOCUS and at_bot_mentioned and "no_reply" in available_actions:
|
||||||
logger.info(f"{self.log_prefix} Focus模式下检测到@或提及bot,移除no_reply动作以确保回复")
|
logger.info(f"{self.log_prefix} Focus模式下检测到@或提及bot,移除no_reply动作以确保回复")
|
||||||
available_actions = {k: v for k, v in available_actions.items() if k != "no_reply"} # 用一个循环来移除no_reply
|
available_actions = {
|
||||||
|
k: v for k, v in available_actions.items() if k != "no_reply"
|
||||||
|
} # 用一个循环来移除no_reply
|
||||||
|
|
||||||
# 检查是否在normal模式下没有可用动作(除了reply相关动作)
|
# 检查是否在normal模式下没有可用动作(除了reply相关动作)
|
||||||
skip_planner = False
|
skip_planner = False
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from rich.progress import (
|
|||||||
SpinnerColumn,
|
SpinnerColumn,
|
||||||
TextColumn,
|
TextColumn,
|
||||||
)
|
)
|
||||||
from src.chat.utils.utils import get_embedding
|
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
import json
|
from typing import List, Dict, Any
|
||||||
import hashlib
|
|
||||||
from typing import List, Optional, Tuple, Dict, Any
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import chromadb
|
import chromadb
|
||||||
from chromadb.config import Settings
|
from chromadb.config import Settings
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.chat.utils.utils import get_embedding
|
from src.chat.utils.utils import get_embedding
|
||||||
from src.config.config import global_config
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("vector_instant_memory_v2")
|
logger = get_logger("vector_instant_memory_v2")
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class ChatConfig(ValidatedConfigBase):
|
|||||||
timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field(default="normal_no_YMD", description="时间戳显示模式")
|
timestamp_display_mode: Literal["normal", "normal_no_YMD", "relative"] = Field(default="normal_no_YMD", description="时间戳显示模式")
|
||||||
enable_proactive_thinking: bool = Field(default=False, description="启用主动思考")
|
enable_proactive_thinking: bool = Field(default=False, description="启用主动思考")
|
||||||
proactive_thinking_interval: int = Field(default=1500, description="主动思考间隔")
|
proactive_thinking_interval: int = Field(default=1500, description="主动思考间隔")
|
||||||
proactive_thinking_prompt_template: str = Field(default="", description="主动思考提示模板")
|
The_scope_that_proactive_thinking_can_trigger: str = Field(default="all", description="主动思考可以触发的范围")
|
||||||
|
|
||||||
def get_current_talk_frequency(self, chat_stream_id: Optional[str] = None) -> float:
|
def get_current_talk_frequency(self, chat_stream_id: Optional[str] = None) -> float:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -122,13 +122,8 @@ talk_frequency_adjust = [
|
|||||||
# 主动思考功能配置(仅在focus模式下生效)
|
# 主动思考功能配置(仅在focus模式下生效)
|
||||||
enable_proactive_thinking = false # 是否启用主动思考功能
|
enable_proactive_thinking = false # 是否启用主动思考功能
|
||||||
proactive_thinking_interval = 1500 # 主动思考触发间隔时间(秒),默认1500秒(25分钟)
|
proactive_thinking_interval = 1500 # 主动思考触发间隔时间(秒),默认1500秒(25分钟)
|
||||||
# 主动思考prompt模板,{time}会被替换为实际的沉默时间(如"2小时30分15秒")
|
The_scope_that_proactive_thinking_can_trigger = "all" #主动思考可以触发的范围(all - 所有,private - 私聊,group - 群聊)
|
||||||
proactive_thinking_prompt_template = """现在群里面已经隔了{time}没有人发送消息了,请你结合上下文以及群聊里面之前聊过的话题和你的人设来决定要不要主动发送消息,你可以选择:
|
|
||||||
|
|
||||||
1. 继续保持沉默(当{time}以前已经结束了一个话题并且你不想挑起新话题时)
|
|
||||||
2. 选择回复(当{time}以前你发送了一条消息且没有人回复你时、你想主动挑起一个话题时)
|
|
||||||
|
|
||||||
请根据当前情况做出选择。如果选择回复,请直接发送你想说的内容;如果选择保持沉默,请只回复"沉默"(注意:这个词不会被发送到群聊中)。"""
|
|
||||||
|
|
||||||
# 特定聊天流配置示例:
|
# 特定聊天流配置示例:
|
||||||
# [
|
# [
|
||||||
@@ -306,7 +301,7 @@ library_log_levels = { "aiohttp" = "WARNING"} # 设置特定库的日志级别
|
|||||||
|
|
||||||
[dependency_management] # 插件Python依赖管理配置
|
[dependency_management] # 插件Python依赖管理配置
|
||||||
# 是否启用自动安装Python依赖包(主开关)
|
# 是否启用自动安装Python依赖包(主开关)
|
||||||
auto_install = false #暂时关闭一下因为还用不了
|
auto_install = true #暂时关闭一下因为还用不了
|
||||||
# 安装超时时间(秒)
|
# 安装超时时间(秒)
|
||||||
auto_install_timeout = 300
|
auto_install_timeout = 300
|
||||||
# 是否使用PyPI镜像源(推荐,可加速下载)
|
# 是否使用PyPI镜像源(推荐,可加速下载)
|
||||||
|
|||||||
Reference in New Issue
Block a user