调参仙人有福了,添加了willing_manager的自选功能

This commit is contained in:
SengokuCola
2025-03-14 21:34:52 +08:00
parent ccc6d9e48c
commit c0f9298517
11 changed files with 286 additions and 30 deletions

View File

@@ -15,7 +15,7 @@ from .bot import chat_bot
from .config import global_config from .config import global_config
from .emoji_manager import emoji_manager from .emoji_manager import emoji_manager
from .relationship_manager import relationship_manager from .relationship_manager import relationship_manager
from .willing_manager import willing_manager from ..willing.willing_manager import willing_manager
from .chat_stream import chat_manager from .chat_stream import chat_manager
from ..memory_system.memory import hippocampus, memory_graph from ..memory_system.memory import hippocampus, memory_graph
from .bot import ChatBot from .bot import ChatBot

View File

@@ -29,7 +29,7 @@ from .storage import MessageStorage
from .utils import calculate_typing_time, is_mentioned_bot_in_message from .utils import calculate_typing_time, is_mentioned_bot_in_message
from .utils_image import image_path_to_base64 from .utils_image import image_path_to_base64
from .utils_user import get_user_nickname, get_user_cardname, get_groupname from .utils_user import get_user_nickname, get_user_cardname, get_groupname
from .willing_manager import willing_manager # 导入意愿管理器 from ..willing.willing_manager import willing_manager # 导入意愿管理器
from .message_base import UserInfo, GroupInfo, Seg from .message_base import UserInfo, GroupInfo, Seg
from ..utils.logger_config import LogClassification, LogModule from ..utils.logger_config import LogClassification, LogModule
@@ -113,6 +113,8 @@ class ChatBot:
logger.debug(f"跳过处理回复来自被ban用户 {event.reply.sender.user_id} 的消息") logger.debug(f"跳过处理回复来自被ban用户 {event.reply.sender.user_id} 的消息")
return return
# 处理私聊消息 # 处理私聊消息
if isinstance(event, PrivateMessageEvent): if isinstance(event, PrivateMessageEvent):
if not global_config.enable_friend_chat: # 私聊过滤 if not global_config.enable_friend_chat: # 私聊过滤
return return
@@ -161,6 +163,7 @@ class ChatBot:
) )
await message_cq.initialize() await message_cq.initialize()
message_json = message_cq.to_dict() message_json = message_cq.to_dict()
# 哦我嘞个json
# 进入maimbot # 进入maimbot
message = MessageRecv(message_json) message = MessageRecv(message_json)
@@ -170,8 +173,9 @@ class ChatBot:
# 消息过滤涉及到config有待更新 # 消息过滤涉及到config有待更新
# 创建聊天流
chat = await chat_manager.get_or_create_stream( chat = await chat_manager.get_or_create_stream(
platform=messageinfo.platform, user_info=userinfo, group_info=groupinfo platform=messageinfo.platform, user_info=userinfo, group_info=groupinfo #我嘞个gourp_info
) )
message.update_chat_stream(chat) message.update_chat_stream(chat)
await relationship_manager.update_relationship( await relationship_manager.update_relationship(
@@ -180,6 +184,7 @@ class ChatBot:
await relationship_manager.update_relationship_value(chat_stream=chat, relationship_value=0.5) await relationship_manager.update_relationship_value(chat_stream=chat, relationship_value=0.5)
await message.process() await message.process()
# 过滤词 # 过滤词
for word in global_config.ban_words: for word in global_config.ban_words:
if word in message.processed_plain_text: if word in message.processed_plain_text:
@@ -200,8 +205,7 @@ class ChatBot:
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(messageinfo.time)) current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(messageinfo.time))
# topic=await topic_identifier.identify_topic_llm(message.processed_plain_text) #根据话题计算激活度
topic = "" topic = ""
interested_rate = await hippocampus.memory_activate_value(message.processed_plain_text) / 100 interested_rate = await hippocampus.memory_activate_value(message.processed_plain_text) / 100
logger.debug(f"{message.processed_plain_text}的激活度:{interested_rate}") logger.debug(f"{message.processed_plain_text}的激活度:{interested_rate}")

View File

@@ -73,6 +73,8 @@ class BotConfig:
mood_update_interval: float = 1.0 # 情绪更新间隔 单位秒 mood_update_interval: float = 1.0 # 情绪更新间隔 单位秒
mood_decay_rate: float = 0.95 # 情绪衰减率 mood_decay_rate: float = 0.95 # 情绪衰减率
mood_intensity_factor: float = 0.7 # 情绪强度因子 mood_intensity_factor: float = 0.7 # 情绪强度因子
willing_mode: str = "classical" # 意愿模式
keywords_reaction_rules = [] # 关键词回复规则 keywords_reaction_rules = [] # 关键词回复规则
@@ -212,6 +214,10 @@ class BotConfig:
"model_r1_distill_probability", config.MODEL_R1_DISTILL_PROBABILITY "model_r1_distill_probability", config.MODEL_R1_DISTILL_PROBABILITY
) )
config.max_response_length = response_config.get("max_response_length", config.max_response_length) config.max_response_length = response_config.get("max_response_length", config.max_response_length)
def willing(parent: dict):
willing_config = parent["willing"]
config.willing_mode = willing_config.get("willing_mode", config.willing_mode)
def model(parent: dict): def model(parent: dict):
# 加载模型配置 # 加载模型配置
@@ -353,6 +359,7 @@ class BotConfig:
"cq_code": {"func": cq_code, "support": ">=0.0.0"}, "cq_code": {"func": cq_code, "support": ">=0.0.0"},
"bot": {"func": bot, "support": ">=0.0.0"}, "bot": {"func": bot, "support": ">=0.0.0"},
"response": {"func": response, "support": ">=0.0.0"}, "response": {"func": response, "support": ">=0.0.0"},
"willing": {"func": willing, "support": ">=0.0.9", "necessary": False},
"model": {"func": model, "support": ">=0.0.0"}, "model": {"func": model, "support": ">=0.0.0"},
"message": {"func": message, "support": ">=0.0.0"}, "message": {"func": message, "support": ">=0.0.0"},
"memory": {"func": memory, "support": ">=0.0.0", "necessary": False}, "memory": {"func": memory, "support": ">=0.0.0", "necessary": False},

View File

@@ -1,7 +1,6 @@
import random import random
import time import time
from typing import Optional from typing import Optional
from loguru import logger
from ...common.database import db from ...common.database import db
from ..memory_system.memory import hippocampus, memory_graph from ..memory_system.memory import hippocampus, memory_graph
@@ -11,6 +10,13 @@ from .config import global_config
from .utils import get_embedding, get_recent_group_detailed_plain_text from .utils import get_embedding, get_recent_group_detailed_plain_text
from .chat_stream import chat_manager from .chat_stream import chat_manager
from ..utils.logger_config import LogClassification, LogModule
log_module = LogModule()
logger = log_module.setup_logger(LogClassification.PBUILDER)
logger.info("初始化Prompt系统")
class PromptBuilder: class PromptBuilder:
def __init__(self): def __init__(self):
@@ -163,7 +169,7 @@ class PromptBuilder:
prompt_ger += "你喜欢用文言文" prompt_ger += "你喜欢用文言文"
# 额外信息要求 # 额外信息要求
extra_info = """但是记得回复平淡一些,简短一些,尤其注意在没明确提到时不要过多提及自身的背景, 不要直接回复别人发的表情包,记住不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只需要输出回复内容就好,不要输出其他任何内容""" extra_info = """但是记得回复平淡一些,简短一些,尤其注意在没明确提到时不要过多提及自身的背景, 不要直接回复别人发的表情包,记住不要输出多余内容(包括前后缀,冒号和引号,括号,表情,@,等),只需要输出回复内容就好,不要输出其他任何内容"""
# 合并prompt # 合并prompt
prompt = "" prompt = ""
@@ -239,7 +245,7 @@ class PromptBuilder:
return prompt_for_check, memory return prompt_for_check, memory
def _build_initiative_prompt(self, selected_node, prompt_regular, memory): def _build_initiative_prompt(self, selected_node, prompt_regular, memory):
prompt_for_initiative = f"{prompt_regular}你现在想在群里发言,回忆了一下,想到一个话题,是{selected_node['concept']},关于这个话题的记忆有\n{memory}\n,请在把握群里的聊天内容的基础上,综合群内的氛围,以日常且口语化的口吻,简短且随意一点进行发言,不要说的太有条理,可以有个性。记住不要输出多余内容(包括前后缀,冒号和引号,括号,表情等)" prompt_for_initiative = f"{prompt_regular}你现在想在群里发言,回忆了一下,想到一个话题,是{selected_node['concept']},关于这个话题的记忆有\n{memory}\n,请在把握群里的聊天内容的基础上,综合群内的氛围,以日常且口语化的口吻,简短且随意一点进行发言,不要说的太有条理,可以有个性。记住不要输出多余内容(包括前后缀,冒号和引号,括号,表情,@等)"
return prompt_for_initiative return prompt_for_initiative
async def get_prompt_info(self, message: str, threshold: float): async def get_prompt_info(self, message: str, threshold: float):

View File

@@ -1,14 +0,0 @@
#Broca's Area
# 功能:语言产生、语法处理和言语运动控制。
# 损伤后果:布洛卡失语症(表达困难,但理解保留)。
import time
class Thinking_Idea:
def __init__(self, message_id: str):
self.messages = [] # 消息列表集合
self.current_thoughts = [] # 当前思考内容列表
self.time = time.time() # 创建时间
self.id = str(int(time.time() * 1000)) # 使用时间戳生成唯一标识ID

View File

@@ -7,6 +7,7 @@ class LogClassification(Enum):
MEMORY = "memory" MEMORY = "memory"
EMOJI = "emoji" EMOJI = "emoji"
CHAT = "chat" CHAT = "chat"
PBUILDER = "promptbuilder"
class LogModule: class LogModule:
logger = loguru.logger.opt() logger = loguru.logger.opt()
@@ -32,6 +33,10 @@ class LogModule:
# 表情包系统日志格式 # 表情包系统日志格式
emoji_format = "<green>{time:HH:mm}</green> | <level>{level: <8}</level> | <yellow>表情包</yellow> | <cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>" emoji_format = "<green>{time:HH:mm}</green> | <level>{level: <8}</level> | <yellow>表情包</yellow> | <cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
promptbuilder_format = "<green>{time:HH:mm}</green> | <level>{level: <8}</level> | <yellow>Prompt</yellow> | <cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
# 根据日志类型选择日志格式和输出 # 根据日志类型选择日志格式和输出
if log_type == LogClassification.CHAT: if log_type == LogClassification.CHAT:
self.logger.add( self.logger.add(
@@ -39,6 +44,12 @@ class LogModule:
format=chat_format, format=chat_format,
# level="INFO" # level="INFO"
) )
elif log_type == LogClassification.PBUILDER:
self.logger.add(
sys.stderr,
format=promptbuilder_format,
# level="INFO"
)
elif log_type == LogClassification.MEMORY: elif log_type == LogClassification.MEMORY:
# 同时输出到控制台和文件 # 同时输出到控制台和文件

View File

@@ -0,0 +1,102 @@
import asyncio
from typing import Dict
from ..chat.chat_stream import ChatStream
class WillingManager:
def __init__(self):
self.chat_reply_willing: Dict[str, float] = {} # 存储每个聊天流的回复意愿
self._decay_task = None
self._started = False
async def _decay_reply_willing(self):
"""定期衰减回复意愿"""
while True:
await asyncio.sleep(3)
for chat_id in self.chat_reply_willing:
# 每分钟衰减10%的回复意愿
self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
def get_willing(self, chat_stream: ChatStream) -> float:
"""获取指定聊天流的回复意愿"""
if chat_stream:
return self.chat_reply_willing.get(chat_stream.stream_id, 0)
return 0
def set_willing(self, chat_id: str, willing: float):
"""设置指定聊天流的回复意愿"""
self.chat_reply_willing[chat_id] = willing
async def change_reply_willing_received(self,
chat_stream: ChatStream,
topic: str = None,
is_mentioned_bot: bool = False,
config = None,
is_emoji: bool = False,
interested_rate: float = 0,
sender_id: str = None) -> float:
"""改变指定聊天流的回复意愿并返回回复概率"""
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
if topic and current_willing < 1:
current_willing += 0.2
elif topic:
current_willing += 0.05
if is_mentioned_bot and current_willing < 1.0:
current_willing += 0.9
elif is_mentioned_bot:
current_willing += 0.05
if is_emoji:
current_willing *= 0.2
self.chat_reply_willing[chat_id] = min(current_willing, 3.0)
reply_probability = (current_willing - 0.5) * 2
# 检查群组权限(如果是群聊)
if chat_stream.group_info and config:
if chat_stream.group_info.group_id not in config.talk_allowed_groups:
current_willing = 0
reply_probability = 0
if chat_stream.group_info.group_id in config.talk_frequency_down_groups:
reply_probability = reply_probability / 3.5
if is_mentioned_bot and sender_id == "1026294844":
reply_probability = 1
return reply_probability
def change_reply_willing_sent(self, chat_stream: ChatStream):
"""发送消息后降低聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
self.chat_reply_willing[chat_id] = max(0, current_willing - 1.8)
def change_reply_willing_not_sent(self, chat_stream: ChatStream):
"""未发送消息后降低聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
self.chat_reply_willing[chat_id] = max(0, current_willing - 0)
def change_reply_willing_after_sent(self, chat_stream: ChatStream):
"""发送消息后提高聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
if current_willing < 1:
self.chat_reply_willing[chat_id] = min(1, current_willing + 0.4)
async def ensure_started(self):
"""确保衰减任务已启动"""
if not self._started:
if self._decay_task is None:
self._decay_task = asyncio.create_task(self._decay_reply_willing())
self._started = True
# 创建全局实例
willing_manager = WillingManager()

View File

@@ -0,0 +1,102 @@
import asyncio
from typing import Dict
from ..chat.chat_stream import ChatStream
class WillingManager:
def __init__(self):
self.chat_reply_willing: Dict[str, float] = {} # 存储每个聊天流的回复意愿
self._decay_task = None
self._started = False
async def _decay_reply_willing(self):
"""定期衰减回复意愿"""
while True:
await asyncio.sleep(3)
for chat_id in self.chat_reply_willing:
# 每分钟衰减10%的回复意愿
self.chat_reply_willing[chat_id] = max(0, self.chat_reply_willing[chat_id] * 0.6)
def get_willing(self, chat_stream: ChatStream) -> float:
"""获取指定聊天流的回复意愿"""
if chat_stream:
return self.chat_reply_willing.get(chat_stream.stream_id, 0)
return 0
def set_willing(self, chat_id: str, willing: float):
"""设置指定聊天流的回复意愿"""
self.chat_reply_willing[chat_id] = willing
async def change_reply_willing_received(self,
chat_stream: ChatStream,
topic: str = None,
is_mentioned_bot: bool = False,
config = None,
is_emoji: bool = False,
interested_rate: float = 0,
sender_id: str = None) -> float:
"""改变指定聊天流的回复意愿并返回回复概率"""
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
if topic and current_willing < 1:
current_willing += 0.2
elif topic:
current_willing += 0.05
if is_mentioned_bot and current_willing < 1.0:
current_willing += 0.9
elif is_mentioned_bot:
current_willing += 0.05
if is_emoji:
current_willing *= 0.2
self.chat_reply_willing[chat_id] = min(current_willing, 3.0)
reply_probability = (current_willing - 0.5) * 2
# 检查群组权限(如果是群聊)
if chat_stream.group_info and config:
if chat_stream.group_info.group_id not in config.talk_allowed_groups:
current_willing = 0
reply_probability = 0
if chat_stream.group_info.group_id in config.talk_frequency_down_groups:
reply_probability = reply_probability / 3.5
if is_mentioned_bot and sender_id == "1026294844":
reply_probability = 1
return reply_probability
def change_reply_willing_sent(self, chat_stream: ChatStream):
"""发送消息后降低聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
self.chat_reply_willing[chat_id] = max(0, current_willing - 1.8)
def change_reply_willing_not_sent(self, chat_stream: ChatStream):
"""未发送消息后降低聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
self.chat_reply_willing[chat_id] = max(0, current_willing - 0)
def change_reply_willing_after_sent(self, chat_stream: ChatStream):
"""发送消息后提高聊天流的回复意愿"""
if chat_stream:
chat_id = chat_stream.stream_id
current_willing = self.chat_reply_willing.get(chat_id, 0)
if current_willing < 1:
self.chat_reply_willing[chat_id] = min(1, current_willing + 0.4)
async def ensure_started(self):
"""确保衰减任务已启动"""
if not self._started:
if self._decay_task is None:
self._decay_task = asyncio.create_task(self._decay_reply_willing())
self._started = True
# 创建全局实例
willing_manager = WillingManager()

View File

@@ -5,9 +5,8 @@ from typing import Dict
from loguru import logger from loguru import logger
from .config import global_config from ..chat.config import global_config
from .chat_stream import ChatStream from ..chat.chat_stream import ChatStream
class WillingManager: class WillingManager:
def __init__(self): def __init__(self):

View File

@@ -0,0 +1,32 @@
from typing import Optional
from loguru import logger
from ..chat.config import global_config
from .mode_classical import WillingManager as ClassicalWillingManager
from .mode_dynamic import WillingManager as DynamicWillingManager
from .mode_custom import WillingManager as CustomWillingManager
def init_willing_manager() -> Optional[object]:
"""
根据配置初始化并返回对应的WillingManager实例
Returns:
对应mode的WillingManager实例
"""
mode = global_config.willing_mode.lower()
if mode == "classical":
logger.info("使用经典回复意愿管理器")
return ClassicalWillingManager()
elif mode == "dynamic":
logger.info("使用动态回复意愿管理器")
return DynamicWillingManager()
elif mode == "custom":
logger.warning(f"自定义的回复意愿管理器模式: {mode}")
return CustomWillingManager()
else:
logger.warning(f"未知的回复意愿管理器模式: {mode}, 将使用经典模式")
return ClassicalWillingManager()
# 全局willing_manager对象
willing_manager = init_willing_manager()

View File

@@ -1,6 +1,7 @@
[inner] [inner]
version = "0.0.8" version = "0.0.9"
#以下是给开发人员阅读的,一般用户不需要阅读
#如果你想要修改配置文件请在修改后将version的值进行变更 #如果你想要修改配置文件请在修改后将version的值进行变更
#如果新增项目请在BotConfig类下新增相应的变量 #如果新增项目请在BotConfig类下新增相应的变量
#1.如果你修改的是[]层级项目,例如你新增了 [memory],那么请在config.py的 load_config函数中的include_configs字典中新增"内容":{ #1.如果你修改的是[]层级项目,例如你新增了 [memory],那么请在config.py的 load_config函数中的include_configs字典中新增"内容":{
@@ -64,11 +65,16 @@ model_v3_probability = 0.1 # 麦麦回答时选择次要回复模型2 模型的
model_r1_distill_probability = 0.1 # 麦麦回答时选择次要回复模型3 模型的概率 model_r1_distill_probability = 0.1 # 麦麦回答时选择次要回复模型3 模型的概率
max_response_length = 1024 # 麦麦回答的最大token数 max_response_length = 1024 # 麦麦回答的最大token数
[willing]
willing_mode = "classical"
# willing_mode = "dynamic"
# willing_mode = "custom"
[memory] [memory]
build_memory_interval = 600 # 记忆构建间隔 单位秒 间隔越低,麦麦学习越多,但是冗余信息也会增多 build_memory_interval = 2000 # 记忆构建间隔 单位秒 间隔越低,麦麦学习越多,但是冗余信息也会增多
memory_compress_rate = 0.1 # 记忆压缩率 控制记忆精简程度 建议保持默认,调高可以获得更多信息,但是冗余信息也会增多 memory_compress_rate = 0.1 # 记忆压缩率 控制记忆精简程度 建议保持默认,调高可以获得更多信息,但是冗余信息也会增多
forget_memory_interval = 600 # 记忆遗忘间隔 单位秒 间隔越低,麦麦遗忘越频繁,记忆更精简,但更难学习 forget_memory_interval = 1000 # 记忆遗忘间隔 单位秒 间隔越低,麦麦遗忘越频繁,记忆更精简,但更难学习
memory_forget_time = 24 #多长时间后的记忆会被遗忘 单位小时 memory_forget_time = 24 #多长时间后的记忆会被遗忘 单位小时
memory_forget_percentage = 0.01 # 记忆遗忘比例 控制记忆遗忘程度 越大遗忘越多 建议保持默认 memory_forget_percentage = 0.01 # 记忆遗忘比例 控制记忆遗忘程度 越大遗忘越多 建议保持默认
@@ -116,6 +122,9 @@ talk_allowed = [
talk_frequency_down = [] #降低回复频率的群 talk_frequency_down = [] #降低回复频率的群
ban_user_id = [] #禁止回复消息的QQ号 ban_user_id = [] #禁止回复消息的QQ号
[remote] #测试功能,发送统计信息,主要是看全球有多少只麦麦
enable = false #默认关闭
#V3 #V3
#name = "deepseek-chat" #name = "deepseek-chat"
@@ -178,8 +187,6 @@ pri_out = 0
name = "Pro/Qwen/Qwen2-VL-7B-Instruct" name = "Pro/Qwen/Qwen2-VL-7B-Instruct"
provider = "SILICONFLOW" provider = "SILICONFLOW"
#嵌入模型 #嵌入模型
[model.embedding] #嵌入 [model.embedding] #嵌入