Files
Mofox-Core/src/plugins/chat/bot.py

300 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
import time
from random import random
import json
from ..memory_system.Hippocampus import HippocampusManager
from ..moods.moods import MoodManager # 导入情绪管理器
from ..config.config import global_config
from .emoji_manager import emoji_manager # 导入表情包管理器
from .llm_generator import ResponseGenerator
from .message import MessageSending, MessageRecv, MessageThinking, MessageSet
from .chat_stream import chat_manager
from .message_sender import message_manager # 导入新的消息管理器
from .relationship_manager import relationship_manager
from .storage import MessageStorage
from .utils import is_mentioned_bot_in_message, get_recent_group_detailed_plain_text
from .utils_image import image_path_to_base64
from ..willing.willing_manager import willing_manager # 导入意愿管理器
from ..message import UserInfo, GroupInfo, Seg
from src.think_flow_demo.heartflow import subheartflow_manager
from src.think_flow_demo.outer_world import outer_world
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
# 定义日志配置
chat_config = LogConfig(
# 使用消息发送专用样式
console_format=CHAT_STYLE_CONFIG["console_format"],
file_format=CHAT_STYLE_CONFIG["file_format"],
)
# 配置主程序日志格式
logger = get_module_logger("chat_bot", config=chat_config)
class ChatBot:
def __init__(self):
self.storage = MessageStorage()
self.gpt = ResponseGenerator()
self.bot = None # bot 实例引用
self._started = False
self.mood_manager = MoodManager.get_instance() # 获取情绪管理器单例
self.mood_manager.start_mood_update() # 启动情绪更新
async def _ensure_started(self):
"""确保所有任务已启动"""
if not self._started:
self._started = True
async def message_process(self, message_data: str) -> None:
"""处理转化后的统一格式消息
1. 过滤消息
2. 记忆激活
3. 意愿激活
4. 生成回复并发送
5. 更新关系
6. 更新情绪
"""
# message_json = json.loads(message_data)
# 哦我嘞个json
# 进入maimbot
message = MessageRecv(message_data)
groupinfo = message.message_info.group_info
userinfo = message.message_info.user_info
messageinfo = message.message_info
# 消息过滤涉及到config有待更新
# 创建聊天流
chat = await chat_manager.get_or_create_stream(
platform=messageinfo.platform,
user_info=userinfo,
group_info=groupinfo, # 我嘞个gourp_info
)
message.update_chat_stream(chat)
# 创建 心流 观察
if global_config.enable_think_flow:
await outer_world.check_and_add_new_observe()
subheartflow_manager.create_subheartflow(chat.stream_id)
await relationship_manager.update_relationship(
chat_stream=chat,
)
await relationship_manager.update_relationship_value(chat_stream=chat, relationship_value=0)
await message.process()
# 过滤词
for word in global_config.ban_words:
if word in message.processed_plain_text:
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]"
f"{userinfo.user_nickname}:{message.processed_plain_text}"
)
logger.info(f"[过滤词识别]消息中含有{word}filtered")
return
# 正则表达式过滤
for pattern in global_config.ban_msgs_regex:
if re.search(pattern, message.raw_message):
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]"
f"{userinfo.user_nickname}:{message.raw_message}"
)
logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered")
return
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(messageinfo.time))
# 根据话题计算激活度
topic = ""
await self.storage.store_message(message, chat, topic[0] if topic else None)
interested_rate = 0
interested_rate = await HippocampusManager.get_instance().get_activate_from_text(
message.processed_plain_text, fast_retrieval=True
)
is_mentioned = is_mentioned_bot_in_message(message)
if global_config.enable_think_flow:
current_willing_old = willing_manager.get_willing(chat_stream=chat)
current_willing_new = (subheartflow_manager.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4
print(f"旧回复意愿:{current_willing_old},新回复意愿:{current_willing_new}")
current_willing = (current_willing_old + current_willing_new) / 2
else:
current_willing = willing_manager.get_willing(chat_stream=chat)
willing_manager.set_willing(chat.stream_id, current_willing)
reply_probability = await willing_manager.change_reply_willing_received(
chat_stream=chat,
is_mentioned_bot=is_mentioned,
config=global_config,
is_emoji=message.is_emoji,
interested_rate=interested_rate,
sender_id=str(message.message_info.user_info.user_id),
)
logger.info(
f"[{current_time}][{chat.group_info.group_name if chat.group_info else '私聊'}]"
f"{chat.user_info.user_nickname}:"
f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]"
)
response = None
if message.message_info.additional_config:
if "maimcore_reply_probability_gain" in message.message_info.additional_config.keys():
reply_probability += message.message_info.additional_config["maimcore_reply_probability_gain"]
# 开始组织语言
if random() < reply_probability:
bot_user_info = UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=messageinfo.platform,
)
# 开始思考的时间点
thinking_time_point = round(time.time(), 2)
# logger.debug(f"开始思考的时间点: {thinking_time_point}")
think_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=think_id,
chat_stream=chat,
bot_user_info=bot_user_info,
reply=message,
thinking_start_time=thinking_time_point,
)
message_manager.add_message(thinking_message)
willing_manager.change_reply_willing_sent(chat)
response, raw_content = await self.gpt.generate_response(message)
else:
# 决定不回复时,也更新回复意愿
willing_manager.change_reply_willing_not_sent(chat)
# print(f"response: {response}")
if response:
stream_id = message.chat_stream.stream_id
chat_talking_prompt = ""
if stream_id:
chat_talking_prompt = get_recent_group_detailed_plain_text(
stream_id, limit=global_config.MAX_CONTEXT_SIZE, combine=True
)
if subheartflow_manager.get_subheartflow(stream_id):
await subheartflow_manager.get_subheartflow(stream_id).do_after_reply(response, chat_talking_prompt)
else:
await subheartflow_manager.create_subheartflow(stream_id).do_after_reply(response, chat_talking_prompt)
# print(f"有response: {response}")
container = message_manager.get_container(chat.stream_id)
thinking_message = None
# 找到message,删除
# print(f"开始找思考消息")
for msg in container.messages:
if isinstance(msg, MessageThinking) and msg.message_info.message_id == think_id:
# print(f"找到思考消息: {msg}")
thinking_message = msg
container.messages.remove(msg)
break
# 如果找不到思考消息,直接返回
if not thinking_message:
logger.warning("未找到对应的思考消息,可能已超时被移除")
return
# 记录开始思考的时间,避免从思考到回复的时间太久
thinking_start_time = thinking_message.thinking_start_time
message_set = MessageSet(chat, think_id)
# 计算打字时间1是为了模拟打字2是避免多条回复乱序
# accu_typing_time = 0
mark_head = False
for msg in response:
# print(f"\033[1;32m[回复内容]\033[0m {msg}")
# 通过时间改变时间戳
# typing_time = calculate_typing_time(msg)
# logger.debug(f"typing_time: {typing_time}")
# accu_typing_time += typing_time
# timepoint = thinking_time_point + accu_typing_time
message_segment = Seg(type="text", data=msg)
# logger.debug(f"message_segment: {message_segment}")
bot_message = MessageSending(
message_id=think_id,
chat_stream=chat,
bot_user_info=bot_user_info,
sender_info=userinfo,
message_segment=message_segment,
reply=message,
is_head=not mark_head,
is_emoji=False,
thinking_start_time=thinking_start_time,
)
if not mark_head:
mark_head = True
message_set.add_message(bot_message)
if len(str(bot_message)) < 1000:
logger.debug(f"bot_message: {bot_message}")
logger.debug(f"添加消息到message_set: {bot_message}")
else:
logger.debug(f"bot_message: {str(bot_message)[:1000]}...{str(bot_message)[-10:]}")
logger.debug(f"添加消息到message_set: {str(bot_message)[:1000]}...{str(bot_message)[-10:]}")
# message_set 可以直接加入 message_manager
# print(f"\033[1;32m[回复]\033[0m 将回复载入发送容器")
logger.debug("添加message_set到message_manager")
message_manager.add_message(message_set)
bot_response_time = thinking_time_point
if random() < global_config.emoji_chance:
emoji_raw = await emoji_manager.get_emoji_for_text(response)
# 检查是否 <没有找到> emoji
if emoji_raw != None:
emoji_path, description = emoji_raw
emoji_cq = image_path_to_base64(emoji_path)
if random() < 0.5:
bot_response_time = thinking_time_point - 1
else:
bot_response_time = bot_response_time + 1
message_segment = Seg(type="emoji", data=emoji_cq)
bot_message = MessageSending(
message_id=think_id,
chat_stream=chat,
bot_user_info=bot_user_info,
sender_info=userinfo,
message_segment=message_segment,
reply=message,
is_head=False,
is_emoji=True,
)
message_manager.add_message(bot_message)
# 获取立场和情感标签,更新关系值
stance, emotion = await self.gpt._get_emotion_tags(raw_content, message.processed_plain_text)
logger.debug(f"'{response}' 立场为:{stance} 获取到的情感标签为:{emotion}")
await relationship_manager.calculate_update_relationship_value(
chat_stream=chat, label=emotion, stance=stance
)
# 使用情绪管理器更新情绪
self.mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor)
# willing_manager.change_reply_willing_after_sent(
# chat_stream=chat
# )
# 创建全局ChatBot实例
chat_bot = ChatBot()