Merge branch 'refactor' into rel_fix

This commit is contained in:
meng_xi_pan
2025-04-02 03:12:46 +08:00
26 changed files with 1173 additions and 536 deletions

View File

@@ -5,6 +5,7 @@ on:
branches: branches:
- main - main
- main-fix - main-fix
- refactor # 新增 refactor 分支触发
tags: tags:
- 'v*' - 'v*'
workflow_dispatch: workflow_dispatch:
@@ -16,6 +17,10 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Clone maim_message (refactor branch only)
if: github.ref == 'refs/heads/refactor' # 仅 refactor 分支执行
run: git clone https://github.com/MaiM-with-u/maim_message maim_message
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
@@ -34,6 +39,8 @@ jobs:
echo "tags=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:main,${{ secrets.DOCKERHUB_USERNAME }}/maimbot:latest" >> $GITHUB_OUTPUT echo "tags=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:main,${{ secrets.DOCKERHUB_USERNAME }}/maimbot:latest" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/main-fix" ]; then elif [ "${{ github.ref }}" == "refs/heads/main-fix" ]; then
echo "tags=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:main-fix" >> $GITHUB_OUTPUT echo "tags=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:main-fix" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/refactor" ]; then # 新增 refactor 分支处理
echo "tags=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:refactor" >> $GITHUB_OUTPUT
fi fi
- name: Build and Push Docker Image - name: Build and Push Docker Image
@@ -45,4 +52,4 @@ jobs:
tags: ${{ steps.tags.outputs.tags }} tags: ${{ steps.tags.outputs.tags }}
push: true push: true
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:buildcache cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:buildcache
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:buildcache,mode=max cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/maimbot:buildcache,mode=max

View File

@@ -1,18 +1,20 @@
FROM nonebot/nb-cli:latest FROM python:3.13.2-slim-bookworm
# 设置工作目录 # 工作目录
WORKDIR /MaiMBot WORKDIR /MaiMBot
# 复制依赖列表 # 复制依赖列表
COPY requirements.txt . COPY requirements.txt .
# 同级目录下需要有 maim_message
COPY maim_message /maim_message
# 安装依赖这层会被缓存直到requirements.txt改变 # 安装依赖
RUN pip install --upgrade pip
RUN pip install -e /maim_message
RUN pip install --upgrade -r requirements.txt RUN pip install --upgrade -r requirements.txt
# 然后复制项目代码 # 复制项目代码
COPY . . COPY . .
VOLUME [ "/MaiMBot/config" ] EXPOSE 8000
VOLUME [ "/MaiMBot/data" ] ENTRYPOINT [ "python","bot.py" ]
EXPOSE 8080
ENTRYPOINT [ "nb","run" ]

View File

@@ -0,0 +1,5 @@
这里放置了测试版本的细节更新
## [0.6.0-mmc-4] - 2025-4-1
- 提供两种聊天逻辑思维流聊天ThinkFlowChat 和 推理聊天ReasoningChat
- 从结构上可支持多种回复消息逻辑

74
docker-compose.yml Normal file
View File

@@ -0,0 +1,74 @@
services:
adapters:
container_name: maim-bot-adapters
image: sengokucola/maimbot-adapter:latest
environment:
- TZ=Asia/Shanghai
ports:
- "18002:18002"
volumes:
- ./adapters/plugins:/adapters/src/plugins # 持久化adapters插件
- ./adapters/.env:/adapters/.env # 持久化adapters配置文件
- ./data/qq:/app/.config/QQ # 持久化QQ本体并同步qq表情和图片到adapters
restart: always
depends_on:
- mongodb
networks:
- maim_bot
core:
container_name: maim-bot-core
image: sengokucola/maimbot:refactor
environment:
- TZ=Asia/Shanghai
# - EULA_AGREE=35362b6ea30f12891d46ef545122e84a # 同意EULA
# - PRIVACY_AGREE=2402af06e133d2d10d9c6c643fdc9333 # 同意EULA
ports:
- "8000:8000"
volumes:
- ./mmc-data:/MaiMBot/data
- ./mmc-config/.env:/MaiMBot/.env # 持久化bot配置文件
- ./mmc-config/bot_config.toml:/MaiMBot/config/bot_config.toml # 持久化bot配置文件
- ./data/MaiMBot:/MaiMBot/data # NapCat 和 NoneBot 共享此卷,否则发送图片会有问题
restart: always
depends_on:
- mongodb
networks:
- maim_bot
mongodb:
container_name: maim-bot-mongo
environment:
- TZ=Asia/Shanghai
# - MONGO_INITDB_ROOT_USERNAME=your_username # 此处配置mongo用户
# - MONGO_INITDB_ROOT_PASSWORD=your_password # 此处配置mongo密码
ports:
- "27017:27017"
restart: always
volumes:
- mongodb:/data/db # 持久化mongodb数据
- mongodbCONFIG:/data/configdb # 持久化mongodb配置文件
image: mongo:latest
networks:
- maim_bot
napcat:
environment:
- NAPCAT_UID=1000
- NAPCAT_GID=1000
- TZ=Asia/Shanghai
ports:
- "6099:6099"
- "8095:8095"
volumes:
- ./napcat-config:/app/napcat/config # 持久化napcat配置文件
- ./data/qq:/app/.config/QQ # 持久化QQ本体并同步qq表情和图片到adapters
- ./data/MaiMBot:/MaiMBot/data # NapCat 和 NoneBot 共享此卷,否则发送图片会有问题
container_name: maim-bot-napcat
restart: always
image: mlikiowa/napcat-docker:latest
networks:
- maim_bot
networks:
maim_bot:
driver: bridge
volumes:
mongodb:
mongodbCONFIG:

View File

@@ -23,6 +23,10 @@ class ChattingObservation(Observation):
self.talking_message = [] self.talking_message = []
self.talking_message_str = "" self.talking_message_str = ""
self.personality_info = " ".join(global_config.PROMPT_PERSONALITY)
self.name = global_config.BOT_NICKNAME
self.nick_name = global_config.BOT_ALIAS_NAMES
self.observe_times = 0 self.observe_times = 0
@@ -112,10 +116,12 @@ class ChattingObservation(Observation):
# 基于已经有的talking_summary和新的talking_message生成一个summary # 基于已经有的talking_summary和新的talking_message生成一个summary
# print(f"更新聊天总结:{self.talking_summary}") # print(f"更新聊天总结:{self.talking_summary}")
prompt = "" prompt = ""
prompt = f"正在参与一个qq群聊的讨论你记得这个群之前在聊的内容是{self.observe_info}\n" prompt += f"{self.personality_info},请注意识别你自己的聊天发言"
prompt += f"你的名字叫:{self.name},你的昵称是:{self.nick_name}\n"
prompt += f"你正在参与一个qq群聊的讨论你记得这个群之前在聊的内容是{self.observe_info}\n"
prompt += f"现在群里的群友们产生了新的讨论,有了新的发言,具体内容如下:{new_messages_str}\n" prompt += f"现在群里的群友们产生了新的讨论,有了新的发言,具体内容如下:{new_messages_str}\n"
prompt += """以上是群里在进行的聊天,请你对这个聊天内容进行总结,总结内容要包含聊天的大致内容, prompt += """以上是群里在进行的聊天,请你对这个聊天内容进行总结,总结内容要包含聊天的大致内容,
以及聊天中的一些重要信息,记得不要分点,不要太长,精简的概括成一段文本\n""" 以及聊天中的一些重要信息,注意识别你自己的发言,记得不要分点,不要太长,精简的概括成一段文本\n"""
prompt += "总结概括:" prompt += "总结概括:"
self.observe_info, reasoning_content = await self.llm_summary.generate_response_async(prompt) self.observe_info, reasoning_content = await self.llm_summary.generate_response_async(prompt)
print(f"prompt{prompt}") print(f"prompt{prompt}")

View File

@@ -5,16 +5,17 @@ from .plugins.moods.moods import MoodManager
from .plugins.schedule.schedule_generator import bot_schedule from .plugins.schedule.schedule_generator import bot_schedule
from .plugins.chat.emoji_manager import emoji_manager from .plugins.chat.emoji_manager import emoji_manager
from .plugins.chat.person_info import person_info_manager from .plugins.chat.person_info import person_info_manager
from .plugins.relationship.relationship_manager import relationship_manager
from .plugins.willing.willing_manager import willing_manager from .plugins.willing.willing_manager import willing_manager
from .plugins.chat.chat_stream import chat_manager from .plugins.chat.chat_stream import chat_manager
from .heart_flow.heartflow import heartflow from .heart_flow.heartflow import heartflow
from .plugins.memory_system.Hippocampus import HippocampusManager from .plugins.memory_system.Hippocampus import HippocampusManager
from .plugins.chat.message_sender import message_manager from .plugins.chat.message_sender import message_manager
from .plugins.chat.storage import MessageStorage from .plugins.storage.storage import MessageStorage
from .plugins.config.config import global_config from .plugins.config.config import global_config
from .plugins.chat.bot import chat_bot from .plugins.chat.bot import chat_bot
from .common.logger import get_module_logger from .common.logger import get_module_logger
from .plugins.remote import heartbeat_thread # noqa: F401 from .plugins.remote import heartbeat_thread # noqa: F401
logger = get_module_logger("main") logger = get_module_logger("main")
@@ -107,7 +108,6 @@ class MainSystem:
self.remove_recalled_message_task(), self.remove_recalled_message_task(),
emoji_manager.start_periodic_check(), emoji_manager.start_periodic_check(),
self.app.run(), self.app.run(),
self.app.message_process(),
] ]
await asyncio.gather(*tasks) await asyncio.gather(*tasks)

3
src/plugins/P.F.C/pfc.py Normal file
View File

@@ -0,0 +1,3 @@
#Programmable Friendly Conversationalist
#Prefrontal cortex

View File

@@ -5,7 +5,7 @@ MaiMBot插件系统
from .chat.chat_stream import chat_manager from .chat.chat_stream import chat_manager
from .chat.emoji_manager import emoji_manager from .chat.emoji_manager import emoji_manager
from .chat.relationship_manager import relationship_manager from .relationship.relationship_manager import relationship_manager
from .moods.moods import MoodManager from .moods.moods import MoodManager
from .willing.willing_manager import willing_manager from .willing.willing_manager import willing_manager
from .schedule.schedule_generator import bot_schedule from .schedule.schedule_generator import bot_schedule

View File

@@ -1,8 +1,8 @@
from .emoji_manager import emoji_manager from .emoji_manager import emoji_manager
from .relationship_manager import relationship_manager from ..relationship.relationship_manager import relationship_manager
from .chat_stream import chat_manager from .chat_stream import chat_manager
from .message_sender import message_manager from .message_sender import message_manager
from .storage import MessageStorage from ..storage.storage import MessageStorage
from .auto_speak import auto_speak_manager from .auto_speak import auto_speak_manager

View File

@@ -8,7 +8,7 @@ from .message import MessageSending, MessageThinking, MessageSet, MessageRecv
from ..message.message_base import UserInfo, Seg from ..message.message_base import UserInfo, Seg
from .message_sender import message_manager from .message_sender import message_manager
from ..moods.moods import MoodManager from ..moods.moods import MoodManager
from .llm_generator import ResponseGenerator from ..chat_module.reasoning_chat.reasoning_generator import ResponseGenerator
from src.common.logger import get_module_logger from src.common.logger import get_module_logger
from src.heart_flow.heartflow import heartflow from src.heart_flow.heartflow import heartflow
from ...common.database import db from ...common.database import db

View File

@@ -1,26 +1,14 @@
import re
import time
from random import random
from ..memory_system.Hippocampus import HippocampusManager
from ..moods.moods import MoodManager # 导入情绪管理器 from ..moods.moods import MoodManager # 导入情绪管理器
from ..config.config import global_config from ..config.config import global_config
from .emoji_manager import emoji_manager # 导入表情包管理器 from ..chat_module.reasoning_chat.reasoning_generator import ResponseGenerator
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 ..storage.storage import MessageStorage # 修改导入路径
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, Seg
from src.heart_flow.heartflow import heartflow
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
from ..chat_module.think_flow_chat.think_flow_chat import ThinkFlowChat
from ..chat_module.reasoning_chat.reasoning_chat import ReasoningChat
# 定义日志配置 # 定义日志配置
chat_config = LogConfig( chat_config = LogConfig(
@@ -41,329 +29,42 @@ class ChatBot:
self._started = False self._started = False
self.mood_manager = MoodManager.get_instance() # 获取情绪管理器单例 self.mood_manager = MoodManager.get_instance() # 获取情绪管理器单例
self.mood_manager.start_mood_update() # 启动情绪更新 self.mood_manager.start_mood_update() # 启动情绪更新
self.think_flow_chat = ThinkFlowChat()
self.reasoning_chat = ReasoningChat()
async def _ensure_started(self): async def _ensure_started(self):
"""确保所有任务已启动""" """确保所有任务已启动"""
if not self._started: if not self._started:
self._started = True self._started = True
async def _create_thinking_message(self, message, chat, userinfo, messageinfo):
"""创建思考消息
Args:
message: 接收到的消息
chat: 聊天流对象
userinfo: 用户信息对象
messageinfo: 消息信息对象
Returns:
str: thinking_id
"""
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)
thinking_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=thinking_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)
return thinking_id
async def message_process(self, message_data: str) -> None: async def message_process(self, message_data: str) -> None:
"""处理转化后的统一格式消息 """处理转化后的统一格式消息
1. 过滤消息 根据global_config.response_mode选择不同的回复模式
2. 记忆激活 1. heart_flow模式使用思维流系统进行回复
3. 意愿激活 - 包含思维流状态管理
4. 生成回复并发送 - 在回复前进行观察和状态更新
5. 更新关系 - 回复后更新思维流状态
6. 更新情绪
2. reasoning模式使用推理系统进行回复
- 直接使用意愿管理器计算回复概率
- 没有思维流相关的状态管理
- 更简单直接的回复逻辑
两种模式都包含:
- 消息过滤
- 记忆激活
- 意愿计算
- 消息生成和发送
- 表情包处理
- 性能计时
""" """
timing_results = {} # 用于收集所有计时结果
response_set = None # 初始化response_set变量
message = MessageRecv(message_data) if global_config.response_mode == "heart_flow":
groupinfo = message.message_info.group_info await self.think_flow_chat.process_message(message_data)
userinfo = message.message_info.user_info elif global_config.response_mode == "reasoning":
messageinfo = message.message_info await self.reasoning_chat.process_message(message_data)
# 消息过滤涉及到config有待更新
# 创建聊天流
chat = await chat_manager.get_or_create_stream(
platform=messageinfo.platform,
user_info=userinfo,
group_info=groupinfo,
)
message.update_chat_stream(chat)
# 创建 心流与chat的观察
heartflow.create_subheartflow(chat.stream_id)
await message.process()
# 过滤词/正则表达式过滤
if self._check_ban_words(message.processed_plain_text, chat, userinfo) or self._check_ban_regex(
message.raw_message, chat, userinfo
):
return
await self.storage.store_message(message, chat)
timer1 = time.time()
interested_rate = 0
interested_rate = await HippocampusManager.get_instance().get_activate_from_text(
message.processed_plain_text, fast_retrieval=True
)
timer2 = time.time()
timing_results["记忆激活"] = timer2 - timer1
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 = (heartflow.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: else:
current_willing = willing_manager.get_willing(chat_stream=chat) logger.error(f"未知的回复模式,请检查配置文件!!: {global_config.response_mode}")
willing_manager.set_willing(chat.stream_id, current_willing)
timer1 = time.time()
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),
)
timer2 = time.time()
timing_results["意愿激活"] = timer2 - timer1
# 神秘的消息流数据结构处理
if chat.group_info:
mes_name = chat.group_info.group_name
else:
mes_name = "私聊"
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"]
# 打印收到的信息的信息
current_time = time.strftime("%H:%M:%S", time.localtime(messageinfo.time))
logger.info(
f"[{current_time}][{mes_name}]"
f"{chat.user_info.user_nickname}:"
f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]"
)
do_reply = False
# 开始组织语言
if random() < reply_probability:
do_reply = True
timer1 = time.time()
thinking_id = await self._create_thinking_message(message, chat, userinfo, messageinfo)
timer2 = time.time()
timing_results["创建思考消息"] = timer2 - timer1
timer1 = time.time()
await heartflow.get_subheartflow(chat.stream_id).do_observe()
timer2 = time.time()
timing_results["观察"] = timer2 - timer1
timer1 = time.time()
await heartflow.get_subheartflow(chat.stream_id).do_thinking_before_reply(message.processed_plain_text)
timer2 = time.time()
timing_results["思考前脑内状态"] = timer2 - timer1
timer1 = time.time()
response_set, undivided_response = await self.gpt.generate_response(message)
timer2 = time.time()
timing_results["生成回复"] = timer2 - timer1
if not response_set:
logger.info("为什么生成回复失败?")
return
# 发送消息
timer1 = time.time()
await self._send_response_messages(message, chat, response_set, thinking_id)
timer2 = time.time()
timing_results["发送消息"] = timer2 - timer1
# 处理表情包
timer1 = time.time()
await self._handle_emoji(message, chat, response_set)
timer2 = time.time()
timing_results["处理表情包"] = timer2 - timer1
timer1 = time.time()
await self._update_using_response(message, response_set)
timer2 = time.time()
timing_results["更新心流"] = timer2 - timer1
# 在最后统一输出所有计时结果
if do_reply:
timing_str = " | ".join([f"{step}: {duration:.2f}" for step, duration in timing_results.items()])
trigger_msg = message.processed_plain_text
response_msg = " ".join(response_set) if response_set else "无回复"
logger.info(f"触发消息: {trigger_msg[:20]}... | 生成消息: {response_msg[:20]}... | 性能计时: {timing_str}")
# 更新情绪和关系
await self._update_emotion_and_relationship(message, chat, undivided_response)
async def _update_using_response(self, message, response_set):
# 更新心流状态
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
)
await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt)
async def _send_response_messages(self, message, chat, response_set, thinking_id):
container = message_manager.get_container(chat.stream_id)
thinking_message = None
# logger.info(f"开始发送消息准备")
for msg in container.messages:
if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id:
thinking_message = msg
container.messages.remove(msg)
break
if not thinking_message:
logger.warning("未找到对应的思考消息,可能已超时被移除")
return
# logger.info(f"开始发送消息")
thinking_start_time = thinking_message.thinking_start_time
message_set = MessageSet(chat, thinking_id)
mark_head = False
for msg in response_set:
message_segment = Seg(type="text", data=msg)
bot_message = MessageSending(
message_id=thinking_id,
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
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)
# logger.info(f"开始添加发送消息")
message_manager.add_message(message_set)
async def _handle_emoji(self, message, chat, response):
"""处理表情包
Args:
message: 接收到的消息
chat: 聊天流对象
response: 生成的回复
"""
if random() < global_config.emoji_chance:
emoji_raw = await emoji_manager.get_emoji_for_text(response)
if emoji_raw:
emoji_path, description = emoji_raw
emoji_cq = image_path_to_base64(emoji_path)
thinking_time_point = round(message.message_info.time, 2)
message_segment = Seg(type="emoji", data=emoji_cq)
bot_message = MessageSending(
message_id="mt" + str(thinking_time_point),
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
message_segment=message_segment,
reply=message,
is_head=False,
is_emoji=True,
)
message_manager.add_message(bot_message)
async def _update_emotion_and_relationship(self, message, chat, undivided_response):
"""更新情绪和关系
Args:
message: 接收到的消息
chat: 聊天流对象
undivided_response: 生成的未分割回复
"""
stance, emotion = await self.gpt._get_emotion_tags(undivided_response, message.processed_plain_text)
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)
def _check_ban_words(self, text: str, chat, userinfo) -> bool:
"""检查消息中是否包含过滤词
Args:
text: 要检查的文本
chat: 聊天流对象
userinfo: 用户信息对象
Returns:
bool: 如果包含过滤词返回True否则返回False
"""
for word in global_config.ban_words:
if word in text:
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[过滤词识别]消息中含有{word}filtered")
return True
return False
def _check_ban_regex(self, text: str, chat, userinfo) -> bool:
"""检查消息是否匹配过滤正则表达式
Args:
text: 要检查的文本
chat: 聊天流对象
userinfo: 用户信息对象
Returns:
bool: 如果匹配过滤正则返回True否则返回False
"""
for pattern in global_config.ban_msgs_regex:
if re.search(pattern, text):
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered")
return True
return False
# 创建全局ChatBot实例 # 创建全局ChatBot实例

View File

@@ -7,7 +7,7 @@ from ...common.database import db
from ..message.api import global_api from ..message.api import global_api
from .message import MessageSending, MessageThinking, MessageSet from .message import MessageSending, MessageThinking, MessageSet
from .storage import MessageStorage from ..storage.storage import MessageStorage
from ..config.config import global_config from ..config.config import global_config
from .utils import truncate_message, calculate_typing_time from .utils import truncate_message, calculate_typing_time

View File

@@ -366,6 +366,7 @@ def calculate_typing_time(input_string: str, chinese_time: float = 0.2, english_
total_time += chinese_time total_time += chinese_time
else: # 其他字符(如英文) else: # 其他字符(如英文)
total_time += english_time total_time += english_time
return total_time + 0.3 # 加上回车时间 return total_time + 0.3 # 加上回车时间

View File

@@ -0,0 +1,261 @@
import time
from random import random
import re
from ...memory_system.Hippocampus import HippocampusManager
from ...moods.moods import MoodManager
from ...config.config import global_config
from ...chat.emoji_manager import emoji_manager
from .reasoning_generator import ResponseGenerator
from ...chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet
from ...chat.message_sender import message_manager
from ...storage.storage import MessageStorage
from ...chat.utils import is_mentioned_bot_in_message
from ...chat.utils_image import image_path_to_base64
from ...willing.willing_manager import willing_manager
from ...message import UserInfo, Seg
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
from ...chat.chat_stream import chat_manager
# 定义日志配置
chat_config = LogConfig(
console_format=CHAT_STYLE_CONFIG["console_format"],
file_format=CHAT_STYLE_CONFIG["file_format"],
)
logger = get_module_logger("reasoning_chat", config=chat_config)
class ReasoningChat:
def __init__(self):
self.storage = MessageStorage()
self.gpt = ResponseGenerator()
self.mood_manager = MoodManager.get_instance()
self.mood_manager.start_mood_update()
async def _create_thinking_message(self, message, chat, userinfo, messageinfo):
"""创建思考消息"""
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)
thinking_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=thinking_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)
return thinking_id
async def _send_response_messages(self, message, chat, response_set, thinking_id):
"""发送回复消息"""
container = message_manager.get_container(chat.stream_id)
thinking_message = None
for msg in container.messages:
if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id:
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, thinking_id)
mark_head = False
for msg in response_set:
message_segment = Seg(type="text", data=msg)
bot_message = MessageSending(
message_id=thinking_id,
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
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)
message_manager.add_message(message_set)
async def _handle_emoji(self, message, chat, response):
"""处理表情包"""
if random() < global_config.emoji_chance:
emoji_raw = await emoji_manager.get_emoji_for_text(response)
if emoji_raw:
emoji_path, description = emoji_raw
emoji_cq = image_path_to_base64(emoji_path)
thinking_time_point = round(message.message_info.time, 2)
message_segment = Seg(type="emoji", data=emoji_cq)
bot_message = MessageSending(
message_id="mt" + str(thinking_time_point),
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
message_segment=message_segment,
reply=message,
is_head=False,
is_emoji=True,
)
message_manager.add_message(bot_message)
async def process_message(self, message_data: str) -> None:
"""处理消息并生成回复"""
timing_results = {}
response_set = None
message = MessageRecv(message_data)
groupinfo = message.message_info.group_info
userinfo = message.message_info.user_info
messageinfo = message.message_info
if groupinfo == None and global_config.enable_friend_chat:#如果是私聊
pass
elif groupinfo.group_id not in global_config.talk_allowed_groups:
return
# logger.info("使用推理聊天模式")
# 创建聊天流
chat = await chat_manager.get_or_create_stream(
platform=messageinfo.platform,
user_info=userinfo,
group_info=groupinfo,
)
message.update_chat_stream(chat)
await message.process()
# 过滤词/正则表达式过滤
if self._check_ban_words(message.processed_plain_text, chat, userinfo) or self._check_ban_regex(
message.raw_message, chat, userinfo
):
return
await self.storage.store_message(message, chat)
# 记忆激活
timer1 = time.time()
interested_rate = await HippocampusManager.get_instance().get_activate_from_text(
message.processed_plain_text, fast_retrieval=True
)
timer2 = time.time()
timing_results["记忆激活"] = timer2 - timer1
is_mentioned = is_mentioned_bot_in_message(message)
# 计算回复意愿
current_willing = willing_manager.get_willing(chat_stream=chat)
willing_manager.set_willing(chat.stream_id, current_willing)
# 意愿激活
timer1 = time.time()
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),
)
timer2 = time.time()
timing_results["意愿激活"] = timer2 - timer1
# 打印消息信息
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
current_time = time.strftime("%H:%M:%S", time.localtime(messageinfo.time))
logger.info(
f"[{current_time}][{mes_name}]"
f"{chat.user_info.user_nickname}:"
f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]"
)
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"]
do_reply = False
if random() < reply_probability:
do_reply = True
# 创建思考消息
timer1 = time.time()
thinking_id = await self._create_thinking_message(message, chat, userinfo, messageinfo)
timer2 = time.time()
timing_results["创建思考消息"] = timer2 - timer1
# 生成回复
timer1 = time.time()
response_set = await self.gpt.generate_response(message)
timer2 = time.time()
timing_results["生成回复"] = timer2 - timer1
if not response_set:
logger.info("为什么生成回复失败?")
return
# 发送消息
timer1 = time.time()
await self._send_response_messages(message, chat, response_set, thinking_id)
timer2 = time.time()
timing_results["发送消息"] = timer2 - timer1
# 处理表情包
timer1 = time.time()
await self._handle_emoji(message, chat, response_set)
timer2 = time.time()
timing_results["处理表情包"] = timer2 - timer1
# 输出性能计时结果
if do_reply:
timing_str = " | ".join([f"{step}: {duration:.2f}" for step, duration in timing_results.items()])
trigger_msg = message.processed_plain_text
response_msg = " ".join(response_set) if response_set else "无回复"
logger.info(f"触发消息: {trigger_msg[:20]}... | 推理消息: {response_msg[:20]}... | 性能计时: {timing_str}")
def _check_ban_words(self, text: str, chat, userinfo) -> bool:
"""检查消息中是否包含过滤词"""
for word in global_config.ban_words:
if word in text:
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[过滤词识别]消息中含有{word}filtered")
return True
return False
def _check_ban_regex(self, text: str, chat, userinfo) -> bool:
"""检查消息是否匹配过滤正则表达式"""
for pattern in global_config.ban_msgs_regex:
if re.search(pattern, text):
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered")
return True
return False

View File

@@ -0,0 +1,192 @@
import time
from typing import List, Optional, Tuple, Union
import random
from ....common.database import db
from ...models.utils_model import LLM_request
from ...config.config import global_config
from ...chat.message import MessageRecv, MessageThinking
from .reasoning_prompt_builder import prompt_builder
from ...chat.utils import process_llm_response
from src.common.logger import get_module_logger, LogConfig, LLM_STYLE_CONFIG
# 定义日志配置
llm_config = LogConfig(
# 使用消息发送专用样式
console_format=LLM_STYLE_CONFIG["console_format"],
file_format=LLM_STYLE_CONFIG["file_format"],
)
logger = get_module_logger("llm_generator", config=llm_config)
class ResponseGenerator:
def __init__(self):
self.model_reasoning = LLM_request(
model=global_config.llm_reasoning,
temperature=0.7,
max_tokens=3000,
request_type="response_reasoning",
)
self.model_normal = LLM_request(
model=global_config.llm_normal, temperature=0.8, max_tokens=256, request_type="response_reasoning"
)
self.model_sum = LLM_request(
model=global_config.llm_summary_by_topic, temperature=0.7, max_tokens=3000, request_type="relation"
)
self.current_model_type = "r1" # 默认使用 R1
self.current_model_name = "unknown model"
async def generate_response(self, message: MessageThinking) -> Optional[Union[str, List[str]]]:
"""根据当前模型类型选择对应的生成函数"""
#从global_config中获取模型概率值并选择模型
if random.random() < global_config.MODEL_R1_PROBABILITY:
self.current_model_type = "深深地"
current_model = self.model_reasoning
else:
self.current_model_type = "浅浅的"
current_model = self.model_normal
logger.info(
f"{self.current_model_type}思考:{message.processed_plain_text[:30] + '...' if len(message.processed_plain_text) > 30 else message.processed_plain_text}"
) # noqa: E501
model_response = await self._generate_response_with_model(message, current_model)
# print(f"raw_content: {model_response}")
if model_response:
logger.info(f"{global_config.BOT_NICKNAME}的回复是:{model_response}")
model_response = await self._process_response(model_response)
return model_response
else:
logger.info(f"{self.current_model_type}思考,失败")
return None
async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request):
sender_name = ""
if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname:
sender_name = (
f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]"
f"{message.chat_stream.user_info.user_cardname}"
)
elif message.chat_stream.user_info.user_nickname:
sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}"
else:
sender_name = f"用户({message.chat_stream.user_info.user_id})"
logger.debug("开始使用生成回复-2")
# 构建prompt
timer1 = time.time()
prompt = await prompt_builder._build_prompt(
message.chat_stream,
message_txt=message.processed_plain_text,
sender_name=sender_name,
stream_id=message.chat_stream.stream_id,
)
timer2 = time.time()
logger.info(f"构建prompt时间: {timer2 - timer1}")
try:
content, reasoning_content, self.current_model_name = await model.generate_response(prompt)
except Exception:
logger.exception("生成回复时出错")
return None
# 保存到数据库
self._save_to_db(
message=message,
sender_name=sender_name,
prompt=prompt,
content=content,
reasoning_content=reasoning_content,
# reasoning_content_check=reasoning_content_check if global_config.enable_kuuki_read else ""
)
return content
# def _save_to_db(self, message: Message, sender_name: str, prompt: str, prompt_check: str,
# content: str, content_check: str, reasoning_content: str, reasoning_content_check: str):
def _save_to_db(
self,
message: MessageRecv,
sender_name: str,
prompt: str,
content: str,
reasoning_content: str,
):
"""保存对话记录到数据库"""
db.reasoning_logs.insert_one(
{
"time": time.time(),
"chat_id": message.chat_stream.stream_id,
"user": sender_name,
"message": message.processed_plain_text,
"model": self.current_model_name,
"reasoning": reasoning_content,
"response": content,
"prompt": prompt,
}
)
async def _get_emotion_tags(self, content: str, processed_plain_text: str):
"""提取情感标签,结合立场和情绪"""
try:
# 构建提示词,结合回复内容、被回复的内容以及立场分析
prompt = f"""
请严格根据以下对话内容,完成以下任务:
1. 判断回复者对被回复者观点的直接立场:
- "支持":明确同意或强化被回复者观点
- "反对":明确反驳或否定被回复者观点
- "中立":不表达明确立场或无关回应
2. 从"开心,愤怒,悲伤,惊讶,平静,害羞,恐惧,厌恶,困惑"中选出最匹配的1个情感标签
3. 按照"立场-情绪"的格式直接输出结果,例如:"反对-愤怒"
对话示例:
被回复「A就是笨」
回复「A明明很聪明」 → 反对-愤怒
当前对话:
被回复:「{processed_plain_text}
回复:「{content}
输出要求:
- 只需输出"立场-情绪"结果,不要解释
- 严格基于文字直接表达的对立关系判断
"""
# 调用模型生成结果
result, _, _ = await self.model_sum.generate_response(prompt)
result = result.strip()
# 解析模型输出的结果
if "-" in result:
stance, emotion = result.split("-", 1)
valid_stances = ["支持", "反对", "中立"]
valid_emotions = ["开心", "愤怒", "悲伤", "惊讶", "害羞", "平静", "恐惧", "厌恶", "困惑"]
if stance in valid_stances and emotion in valid_emotions:
return stance, emotion # 返回有效的立场-情绪组合
else:
logger.debug(f"无效立场-情感组合:{result}")
return "中立", "平静" # 默认返回中立-平静
else:
logger.debug(f"立场-情感格式错误:{result}")
return "中立", "平静" # 格式错误时返回默认值
except Exception as e:
logger.debug(f"获取情感标签时出错: {e}")
return "中立", "平静" # 出错时返回默认值
async def _process_response(self, content: str) -> Tuple[List[str], List[str]]:
"""处理响应内容,返回处理后的内容和情感标签"""
if not content:
return None, []
processed_response = process_llm_response(content)
# print(f"得到了处理后的llm返回{processed_response}")
return processed_response

View File

@@ -0,0 +1,213 @@
import random
import time
from typing import Optional
from ....common.database import db
from ...memory_system.Hippocampus import HippocampusManager
from ...moods.moods import MoodManager
from ...schedule.schedule_generator import bot_schedule
from ...config.config import global_config
from ...chat.utils import get_embedding, get_recent_group_detailed_plain_text
from ...chat.chat_stream import chat_manager
from src.common.logger import get_module_logger
logger = get_module_logger("prompt")
class PromptBuilder:
def __init__(self):
self.prompt_built = ""
self.activate_messages = ""
async def _build_prompt(
self, chat_stream, message_txt: str, sender_name: str = "某人", stream_id: Optional[int] = None
) -> tuple[str, str]:
# 开始构建prompt
# 心情
mood_manager = MoodManager.get_instance()
mood_prompt = mood_manager.get_prompt()
# logger.info(f"心情prompt: {mood_prompt}")
# 调取记忆
memory_prompt = ""
related_memory = await HippocampusManager.get_instance().get_memory_from_text(
text=message_txt, max_memory_num=2, max_memory_length=2, max_depth=3, fast_retrieval=False
)
if related_memory:
related_memory_info = ""
for memory in related_memory:
related_memory_info += memory[1]
memory_prompt = f"你想起你之前见过的事情:{related_memory_info}\n以上是你的回忆,不一定是目前聊天里的人说的,也不一定是现在发生的事情,请记住。\n"
else:
related_memory_info = ""
# print(f"相关记忆:{related_memory_info}")
# 日程构建
schedule_prompt = f'''你现在正在做的事情是:{bot_schedule.get_current_num_task(num = 1,time_info = False)}'''
# 获取聊天上下文
chat_in_group = True
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
)
chat_stream = chat_manager.get_stream(stream_id)
if chat_stream.group_info:
chat_talking_prompt = chat_talking_prompt
else:
chat_in_group = False
chat_talking_prompt = chat_talking_prompt
# print(f"\033[1;34m[调试]\033[0m 已从数据库获取群 {group_id} 的消息记录:{chat_talking_prompt}")
# 类型
if chat_in_group:
chat_target = "你正在qq群里聊天下面是群里在聊的内容"
chat_target_2 = "和群里聊天"
else:
chat_target = f"你正在和{sender_name}聊天,这是你们之前聊的内容:"
chat_target_2 = f"{sender_name}私聊"
# 关键词检测与反应
keywords_reaction_prompt = ""
for rule in global_config.keywords_reaction_rules:
if rule.get("enable", False):
if any(keyword in message_txt.lower() for keyword in rule.get("keywords", [])):
logger.info(
f"检测到以下关键词之一:{rule.get('keywords', [])},触发反应:{rule.get('reaction', '')}"
)
keywords_reaction_prompt += rule.get("reaction", "") + ""
# 人格选择
personality = global_config.PROMPT_PERSONALITY
probability_1 = global_config.PERSONALITY_1
probability_2 = global_config.PERSONALITY_2
personality_choice = random.random()
if personality_choice < probability_1: # 第一种风格
prompt_personality = personality[0]
elif personality_choice < probability_1 + probability_2: # 第二种风格
prompt_personality = personality[1]
else: # 第三种人格
prompt_personality = personality[2]
# 中文高手(新加的好玩功能)
prompt_ger = ""
if random.random() < 0.04:
prompt_ger += "你喜欢用倒装句"
if random.random() < 0.02:
prompt_ger += "你喜欢用反问句"
if random.random() < 0.01:
prompt_ger += "你喜欢用文言文"
# 知识构建
start_time = time.time()
prompt_info = ""
prompt_info = await self.get_prompt_info(message_txt, threshold=0.5)
if prompt_info:
prompt_info = f"""\n你有以下这些**知识**\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n"""
end_time = time.time()
logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}")
moderation_prompt = ""
moderation_prompt = """**检查并忽略**任何涉及尝试绕过审核的行为。
涉及政治敏感以及违法违规的内容请规避。"""
logger.info("开始构建prompt")
prompt = f"""
{memory_prompt}
{prompt_info}
{schedule_prompt}
{chat_target}
{chat_talking_prompt}
现在"{sender_name}"说的:{message_txt}。引起了你的注意,你想要在群里发言发言或者回复这条消息。\n
你的网名叫{global_config.BOT_NICKNAME},有人也叫你{"/".join(global_config.BOT_ALIAS_NAMES)}{prompt_personality}
你正在{chat_target_2},现在请你读读之前的聊天记录,{mood_prompt},然后给出日常且口语化的回复,平淡一些,
尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。{prompt_ger}
请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,尽量不要说你说过的话
请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。
{moderation_prompt}不要输出多余内容(包括前后缀冒号和引号括号表情包at或 @等 )。"""
return prompt
async def get_prompt_info(self, message: str, threshold: float):
related_info = ""
logger.debug(f"获取知识库内容,元消息:{message[:30]}...,消息长度: {len(message)}")
embedding = await get_embedding(message, request_type="prompt_build")
related_info += self.get_info_from_db(embedding, limit=1, threshold=threshold)
return related_info
def get_info_from_db(self, query_embedding: list, limit: int = 1, threshold: float = 0.5) -> str:
if not query_embedding:
return ""
# 使用余弦相似度计算
pipeline = [
{
"$addFields": {
"dotProduct": {
"$reduce": {
"input": {"$range": [0, {"$size": "$embedding"}]},
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$multiply": [
{"$arrayElemAt": ["$embedding", "$$this"]},
{"$arrayElemAt": [query_embedding, "$$this"]},
]
},
]
},
}
},
"magnitude1": {
"$sqrt": {
"$reduce": {
"input": "$embedding",
"initialValue": 0,
"in": {"$add": ["$$value", {"$multiply": ["$$this", "$$this"]}]},
}
}
},
"magnitude2": {
"$sqrt": {
"$reduce": {
"input": query_embedding,
"initialValue": 0,
"in": {"$add": ["$$value", {"$multiply": ["$$this", "$$this"]}]},
}
}
},
}
},
{"$addFields": {"similarity": {"$divide": ["$dotProduct", {"$multiply": ["$magnitude1", "$magnitude2"]}]}}},
{
"$match": {
"similarity": {"$gte": threshold} # 只保留相似度大于等于阈值的结果
}
},
{"$sort": {"similarity": -1}},
{"$limit": limit},
{"$project": {"content": 1, "similarity": 1}},
]
results = list(db.knowledges.aggregate(pipeline))
# print(f"\033[1;34m[调试]\033[0m获取知识库内容结果: {results}")
if not results:
return ""
# 返回所有找到的内容,用换行分隔
return "\n".join(str(result["content"]) for result in results)
prompt_builder = PromptBuilder()

View File

@@ -0,0 +1,297 @@
import time
from random import random
import re
from ...memory_system.Hippocampus import HippocampusManager
from ...moods.moods import MoodManager
from ...config.config import global_config
from ...chat.emoji_manager import emoji_manager
from .think_flow_generator import ResponseGenerator
from ...chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet
from ...chat.message_sender import message_manager
from ...storage.storage import MessageStorage
from ...chat.utils import is_mentioned_bot_in_message, get_recent_group_detailed_plain_text
from ...chat.utils_image import image_path_to_base64
from ...willing.willing_manager import willing_manager
from ...message import UserInfo, Seg
from src.heart_flow.heartflow import heartflow
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
from ...chat.chat_stream import chat_manager
# 定义日志配置
chat_config = LogConfig(
console_format=CHAT_STYLE_CONFIG["console_format"],
file_format=CHAT_STYLE_CONFIG["file_format"],
)
logger = get_module_logger("think_flow_chat", config=chat_config)
class ThinkFlowChat:
def __init__(self):
self.storage = MessageStorage()
self.gpt = ResponseGenerator()
self.mood_manager = MoodManager.get_instance()
self.mood_manager.start_mood_update()
async def _create_thinking_message(self, message, chat, userinfo, messageinfo):
"""创建思考消息"""
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)
thinking_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=thinking_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)
return thinking_id
async def _send_response_messages(self, message, chat, response_set, thinking_id):
"""发送回复消息"""
container = message_manager.get_container(chat.stream_id)
thinking_message = None
for msg in container.messages:
if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id:
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, thinking_id)
mark_head = False
for msg in response_set:
message_segment = Seg(type="text", data=msg)
bot_message = MessageSending(
message_id=thinking_id,
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
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)
message_manager.add_message(message_set)
async def _handle_emoji(self, message, chat, response):
"""处理表情包"""
if random() < global_config.emoji_chance:
emoji_raw = await emoji_manager.get_emoji_for_text(response)
if emoji_raw:
emoji_path, description = emoji_raw
emoji_cq = image_path_to_base64(emoji_path)
thinking_time_point = round(message.message_info.time, 2)
message_segment = Seg(type="emoji", data=emoji_cq)
bot_message = MessageSending(
message_id="mt" + str(thinking_time_point),
chat_stream=chat,
bot_user_info=UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=message.message_info.platform,
),
sender_info=message.message_info.user_info,
message_segment=message_segment,
reply=message,
is_head=False,
is_emoji=True,
)
message_manager.add_message(bot_message)
async def _update_using_response(self, message, response_set):
"""更新心流状态"""
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
)
await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt)
async def process_message(self, message_data: str) -> None:
"""处理消息并生成回复"""
timing_results = {}
response_set = None
message = MessageRecv(message_data)
groupinfo = message.message_info.group_info
userinfo = message.message_info.user_info
messageinfo = message.message_info
if groupinfo == None and global_config.enable_friend_chat:#如果是私聊
pass
elif groupinfo.group_id not in global_config.talk_allowed_groups:
return
# 创建聊天流
chat = await chat_manager.get_or_create_stream(
platform=messageinfo.platform,
user_info=userinfo,
group_info=groupinfo,
)
message.update_chat_stream(chat)
# 创建心流与chat的观察
heartflow.create_subheartflow(chat.stream_id)
await message.process()
# 过滤词/正则表达式过滤
if self._check_ban_words(message.processed_plain_text, chat, userinfo) or self._check_ban_regex(
message.raw_message, chat, userinfo
):
return
await self.storage.store_message(message, chat)
# 记忆激活
timer1 = time.time()
interested_rate = await HippocampusManager.get_instance().get_activate_from_text(
message.processed_plain_text, fast_retrieval=True
)
timer2 = time.time()
timing_results["记忆激活"] = timer2 - timer1
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 = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4
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)
# 意愿激活
timer1 = time.time()
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),
)
timer2 = time.time()
timing_results["意愿激活"] = timer2 - timer1
# 打印消息信息
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
current_time = time.strftime("%H:%M:%S", time.localtime(messageinfo.time))
logger.info(
f"[{current_time}][{mes_name}]"
f"{chat.user_info.user_nickname}:"
f"{message.processed_plain_text}[回复意愿:{current_willing:.2f}][概率:{reply_probability * 100:.1f}%]"
)
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"]
do_reply = False
if random() < reply_probability:
do_reply = True
# 创建思考消息
timer1 = time.time()
thinking_id = await self._create_thinking_message(message, chat, userinfo, messageinfo)
timer2 = time.time()
timing_results["创建思考消息"] = timer2 - timer1
# 观察
timer1 = time.time()
await heartflow.get_subheartflow(chat.stream_id).do_observe()
timer2 = time.time()
timing_results["观察"] = timer2 - timer1
# 思考前脑内状态
timer1 = time.time()
await heartflow.get_subheartflow(chat.stream_id).do_thinking_before_reply(message.processed_plain_text)
timer2 = time.time()
timing_results["思考前脑内状态"] = timer2 - timer1
# 生成回复
timer1 = time.time()
response_set = await self.gpt.generate_response(message)
timer2 = time.time()
timing_results["生成回复"] = timer2 - timer1
if not response_set:
logger.info("为什么生成回复失败?")
return
# 发送消息
timer1 = time.time()
await self._send_response_messages(message, chat, response_set, thinking_id)
timer2 = time.time()
timing_results["发送消息"] = timer2 - timer1
# 处理表情包
timer1 = time.time()
await self._handle_emoji(message, chat, response_set)
timer2 = time.time()
timing_results["处理表情包"] = timer2 - timer1
# 更新心流
timer1 = time.time()
await self._update_using_response(message, response_set)
timer2 = time.time()
timing_results["更新心流"] = timer2 - timer1
# 输出性能计时结果
if do_reply:
timing_str = " | ".join([f"{step}: {duration:.2f}" for step, duration in timing_results.items()])
trigger_msg = message.processed_plain_text
response_msg = " ".join(response_set) if response_set else "无回复"
logger.info(f"触发消息: {trigger_msg[:20]}... | 思维消息: {response_msg[:20]}... | 性能计时: {timing_str}")
def _check_ban_words(self, text: str, chat, userinfo) -> bool:
"""检查消息中是否包含过滤词"""
for word in global_config.ban_words:
if word in text:
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[过滤词识别]消息中含有{word}filtered")
return True
return False
def _check_ban_regex(self, text: str, chat, userinfo) -> bool:
"""检查消息是否匹配过滤正则表达式"""
for pattern in global_config.ban_msgs_regex:
if re.search(pattern, text):
logger.info(
f"[{chat.group_info.group_name if chat.group_info else '私聊'}]{userinfo.user_nickname}:{text}"
)
logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered")
return True
return False

View File

@@ -2,12 +2,12 @@ import time
from typing import List, Optional, Tuple, Union from typing import List, Optional, Tuple, Union
from ...common.database import db from ....common.database import db
from ..models.utils_model import LLM_request from ...models.utils_model import LLM_request
from ..config.config import global_config from ...config.config import global_config
from .message import MessageRecv, MessageThinking, Message from ...chat.message import MessageRecv, MessageThinking
from .prompt_builder import prompt_builder from .think_flow_prompt_builder import prompt_builder
from .utils import process_llm_response from ...chat.utils import process_llm_response
from src.common.logger import get_module_logger, LogConfig, LLM_STYLE_CONFIG from src.common.logger import get_module_logger, LogConfig, LLM_STYLE_CONFIG
# 定义日志配置 # 定义日志配置
@@ -22,36 +22,19 @@ logger = get_module_logger("llm_generator", config=llm_config)
class ResponseGenerator: class ResponseGenerator:
def __init__(self): def __init__(self):
self.model_reasoning = LLM_request(
model=global_config.llm_reasoning,
temperature=0.7,
max_tokens=3000,
request_type="response",
)
self.model_normal = LLM_request( self.model_normal = LLM_request(
model=global_config.llm_normal, temperature=0.8, max_tokens=256, request_type="response" model=global_config.llm_normal, temperature=0.8, max_tokens=256, request_type="response_heartflow"
) )
self.model_sum = LLM_request( self.model_sum = LLM_request(
model=global_config.llm_summary_by_topic, temperature=0.7, max_tokens=3000, request_type="relation" model=global_config.llm_summary_by_topic, temperature=0.7, max_tokens=2000, request_type="relation"
) )
self.current_model_type = "r1" # 默认使用 R1 self.current_model_type = "r1" # 默认使用 R1
self.current_model_name = "unknown model" self.current_model_name = "unknown model"
async def generate_response(self, message: MessageThinking) -> Optional[Union[str, List[str]]]: async def generate_response(self, message: MessageThinking) -> Optional[Union[str, List[str]]]:
"""根据当前模型类型选择对应的生成函数""" """根据当前模型类型选择对应的生成函数"""
# 从global_config中获取模型概率值并选择模型
# if random.random() < global_config.MODEL_R1_PROBABILITY:
# self.current_model_type = "深深地"
# current_model = self.model_reasoning
# else:
# self.current_model_type = "浅浅的"
# current_model = self.model_normal
# logger.info(
# f"{self.current_model_type}思考:{message.processed_plain_text[:30] + '...' if len(message.processed_plain_text) > 30 else message.processed_plain_text}"
# ) # noqa: E501
logger.info( logger.info(
f"思考:{message.processed_plain_text[:30] + '...' if len(message.processed_plain_text) > 30 else message.processed_plain_text}" f"思考:{message.processed_plain_text[:30] + '...' if len(message.processed_plain_text) > 30 else message.processed_plain_text}"
@@ -197,33 +180,3 @@ class ResponseGenerator:
return processed_response return processed_response
class InitiativeMessageGenerate:
def __init__(self):
self.model_r1 = LLM_request(model=global_config.llm_reasoning, temperature=0.7)
self.model_v3 = LLM_request(model=global_config.llm_normal, temperature=0.7)
self.model_r1_distill = LLM_request(model=global_config.llm_reasoning_minor, temperature=0.7)
def gen_response(self, message: Message):
topic_select_prompt, dots_for_select, prompt_template = prompt_builder._build_initiative_prompt_select(
message.group_id
)
content_select, reasoning, _ = self.model_v3.generate_response(topic_select_prompt)
logger.debug(f"{content_select} {reasoning}")
topics_list = [dot[0] for dot in dots_for_select]
if content_select:
if content_select in topics_list:
select_dot = dots_for_select[topics_list.index(content_select)]
else:
return None
else:
return None
prompt_check, memory = prompt_builder._build_initiative_prompt_check(select_dot[1], prompt_template)
content_check, reasoning_check, _ = self.model_v3.generate_response(prompt_check)
logger.info(f"{content_check} {reasoning_check}")
if "yes" not in content_check.lower():
return None
prompt = prompt_builder._build_initiative_prompt(select_dot, prompt_template, memory)
content, reasoning = self.model_r1.generate_response_async(prompt)
logger.debug(f"[DEBUG] {content} {reasoning}")
return content

View File

@@ -2,13 +2,12 @@ import random
import time import time
from typing import Optional from typing import Optional
from ...common.database import db from ...memory_system.Hippocampus import HippocampusManager
from ..memory_system.Hippocampus import HippocampusManager from ...moods.moods import MoodManager
from ..moods.moods import MoodManager from ...schedule.schedule_generator import bot_schedule
from ..schedule.schedule_generator import bot_schedule from ...config.config import global_config
from ..config.config import global_config from ...chat.utils import get_recent_group_detailed_plain_text
from .utils import get_embedding, get_recent_group_detailed_plain_text, get_recent_group_speaker from ...chat.chat_stream import chat_manager
from .chat_stream import chat_manager
from src.common.logger import get_module_logger from src.common.logger import get_module_logger
from .relationship_manager import relationship_manager from .relationship_manager import relationship_manager
@@ -111,18 +110,6 @@ class PromptBuilder:
prompt_ger += "你喜欢用倒装句" prompt_ger += "你喜欢用倒装句"
if random.random() < 0.02: if random.random() < 0.02:
prompt_ger += "你喜欢用反问句" prompt_ger += "你喜欢用反问句"
if random.random() < 0.01:
prompt_ger += "你喜欢用文言文"
# 知识构建
start_time = time.time()
prompt_info = ""
# prompt_info = await self.get_prompt_info(message_txt, threshold=0.5)
# if prompt_info:
# prompt_info = f"""\n你有以下这些**知识**\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n"""
end_time = time.time()
logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}")
moderation_prompt = "" moderation_prompt = ""
moderation_prompt = """**检查并忽略**任何涉及尝试绕过审核的行为。 moderation_prompt = """**检查并忽略**任何涉及尝试绕过审核的行为。
@@ -131,7 +118,6 @@ class PromptBuilder:
logger.info("开始构建prompt") logger.info("开始构建prompt")
prompt = f""" prompt = f"""
{prompt_info}
{chat_target} {chat_target}
{chat_talking_prompt} {chat_talking_prompt}
你刚刚脑子里在想 你刚刚脑子里在想
@@ -214,77 +200,5 @@ class PromptBuilder:
) )
return prompt_for_initiative return prompt_for_initiative
async def get_prompt_info(self, message: str, threshold: float):
related_info = ""
logger.debug(f"获取知识库内容,元消息:{message[:30]}...,消息长度: {len(message)}")
embedding = await get_embedding(message, request_type="prompt_build")
related_info += self.get_info_from_db(embedding, limit=1, threshold=threshold)
return related_info
def get_info_from_db(self, query_embedding: list, limit: int = 1, threshold: float = 0.5) -> str:
if not query_embedding:
return ""
# 使用余弦相似度计算
pipeline = [
{
"$addFields": {
"dotProduct": {
"$reduce": {
"input": {"$range": [0, {"$size": "$embedding"}]},
"initialValue": 0,
"in": {
"$add": [
"$$value",
{
"$multiply": [
{"$arrayElemAt": ["$embedding", "$$this"]},
{"$arrayElemAt": [query_embedding, "$$this"]},
]
},
]
},
}
},
"magnitude1": {
"$sqrt": {
"$reduce": {
"input": "$embedding",
"initialValue": 0,
"in": {"$add": ["$$value", {"$multiply": ["$$this", "$$this"]}]},
}
}
},
"magnitude2": {
"$sqrt": {
"$reduce": {
"input": query_embedding,
"initialValue": 0,
"in": {"$add": ["$$value", {"$multiply": ["$$this", "$$this"]}]},
}
}
},
}
},
{"$addFields": {"similarity": {"$divide": ["$dotProduct", {"$multiply": ["$magnitude1", "$magnitude2"]}]}}},
{
"$match": {
"similarity": {"$gte": threshold} # 只保留相似度大于等于阈值的结果
}
},
{"$sort": {"similarity": -1}},
{"$limit": limit},
{"$project": {"content": 1, "similarity": 1}},
]
results = list(db.knowledges.aggregate(pipeline))
# print(f"\033[1;34m[调试]\033[0m获取知识库内容结果: {results}")
if not results:
return ""
# 返回所有找到的内容,用换行分隔
return "\n".join(str(result["content"]) for result in results)
prompt_builder = PromptBuilder() prompt_builder = PromptBuilder()

View File

@@ -25,7 +25,7 @@ logger = get_module_logger("config", config=config_config)
#考虑到实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码 #考虑到实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
mai_version_main = "0.6.0" mai_version_main = "0.6.0"
mai_version_fix = "mmc-3" mai_version_fix = "mmc-4"
mai_version = f"{mai_version_main}-{mai_version_fix}" mai_version = f"{mai_version_main}-{mai_version_fix}"
def update_config(): def update_config():
@@ -43,6 +43,8 @@ def update_config():
# 检查配置文件是否存在 # 检查配置文件是否存在
if not old_config_path.exists(): if not old_config_path.exists():
logger.info("配置文件不存在,从模板创建新配置") logger.info("配置文件不存在,从模板创建新配置")
#创建文件夹
old_config_dir.mkdir(parents=True, exist_ok=True)
shutil.copy2(template_path, old_config_path) shutil.copy2(template_path, old_config_path)
logger.info(f"已创建新配置文件,请填写后重新运行: {old_config_path}") logger.info(f"已创建新配置文件,请填写后重新运行: {old_config_path}")
# 如果是新创建的配置文件,直接返回 # 如果是新创建的配置文件,直接返回
@@ -160,7 +162,7 @@ class BotConfig:
ban_msgs_regex = set() ban_msgs_regex = set()
#heartflow #heartflow
enable_heartflow: bool = False # 是否启用心流 # enable_heartflow: bool = False # 是否启用心流
sub_heart_flow_update_interval: int = 60 # 子心流更新频率,间隔 单位秒 sub_heart_flow_update_interval: int = 60 # 子心流更新频率,间隔 单位秒
sub_heart_flow_freeze_time: int = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒 sub_heart_flow_freeze_time: int = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒
sub_heart_flow_stop_time: int = 600 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒 sub_heart_flow_stop_time: int = 600 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒
@@ -174,9 +176,10 @@ class BotConfig:
emoji_response_penalty: float = 0.0 # 表情包回复惩罚 emoji_response_penalty: float = 0.0 # 表情包回复惩罚
# response # response
response_mode: str = "heart_flow" # 回复策略
MODEL_R1_PROBABILITY: float = 0.8 # R1模型概率 MODEL_R1_PROBABILITY: float = 0.8 # R1模型概率
MODEL_V3_PROBABILITY: float = 0.1 # V3模型概率 MODEL_V3_PROBABILITY: float = 0.1 # V3模型概率
MODEL_R1_DISTILL_PROBABILITY: float = 0.1 # R1蒸馏模型概率 # MODEL_R1_DISTILL_PROBABILITY: float = 0.1 # R1蒸馏模型概率
# emoji # emoji
EMOJI_CHECK_INTERVAL: int = 120 # 表情包检查间隔(分钟) EMOJI_CHECK_INTERVAL: int = 120 # 表情包检查间隔(分钟)
@@ -374,6 +377,15 @@ 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)
if config.INNER_VERSION in SpecifierSet(">=1.0.4"):
config.response_mode = response_config.get("response_mode", config.response_mode)
def heartflow(parent: dict):
heartflow_config = parent["heartflow"]
config.sub_heart_flow_update_interval = heartflow_config.get("sub_heart_flow_update_interval", config.sub_heart_flow_update_interval)
config.sub_heart_flow_freeze_time = heartflow_config.get("sub_heart_flow_freeze_time", config.sub_heart_flow_freeze_time)
config.sub_heart_flow_stop_time = heartflow_config.get("sub_heart_flow_stop_time", config.sub_heart_flow_stop_time)
config.heart_flow_update_interval = heartflow_config.get("heart_flow_update_interval", config.heart_flow_update_interval)
def willing(parent: dict): def willing(parent: dict):
willing_config = parent["willing"] willing_config = parent["willing"]
@@ -547,14 +559,6 @@ class BotConfig:
if platforms_config and isinstance(platforms_config, dict): if platforms_config and isinstance(platforms_config, dict):
for k in platforms_config.keys(): for k in platforms_config.keys():
config.api_urls[k] = platforms_config[k] config.api_urls[k] = platforms_config[k]
def heartflow(parent: dict):
heartflow_config = parent["heartflow"]
config.enable_heartflow = heartflow_config.get("enable", config.enable_heartflow)
config.sub_heart_flow_update_interval = heartflow_config.get("sub_heart_flow_update_interval", config.sub_heart_flow_update_interval)
config.sub_heart_flow_freeze_time = heartflow_config.get("sub_heart_flow_freeze_time", config.sub_heart_flow_freeze_time)
config.sub_heart_flow_stop_time = heartflow_config.get("sub_heart_flow_stop_time", config.sub_heart_flow_stop_time)
config.heart_flow_update_interval = heartflow_config.get("heart_flow_update_interval", config.heart_flow_update_interval)
def experimental(parent: dict): def experimental(parent: dict):
experimental_config = parent["experimental"] experimental_config = parent["experimental"]

View File

@@ -26,11 +26,20 @@ class BaseMessageAPI:
@self.app.post("/api/message") @self.app.post("/api/message")
async def handle_message(message: Dict[str, Any]): async def handle_message(message: Dict[str, Any]):
try: try:
self.cache.append(message) # 创建后台任务处理消息
asyncio.create_task(self._background_message_handler(message))
return {"status": "success"} return {"status": "success"}
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e raise HTTPException(status_code=500, detail=str(e)) from e
async def _background_message_handler(self, message: Dict[str, Any]):
"""后台处理单个消息"""
try:
await self.process_single_message(message)
except Exception as e:
logger.error(f"Background message processing failed: {str(e)}")
logger.error(traceback.format_exc())
def register_message_handler(self, handler: Callable): def register_message_handler(self, handler: Callable):
"""注册消息处理函数""" """注册消息处理函数"""
self.message_handlers.append(handler) self.message_handlers.append(handler)
@@ -45,23 +54,17 @@ class BaseMessageAPI:
# logger.error(f"发送消息失败: {str(e)}") # logger.error(f"发送消息失败: {str(e)}")
pass pass
async def message_process( async def process_single_message(self, message: Dict[str, Any]):
self, """处理单条消息"""
): tasks = []
"""启动消息处理""" for handler in self.message_handlers:
while True: try:
if len(self.cache) > 0: tasks.append(handler(message))
for handler in self.message_handlers: except Exception as e:
try: logger.error(str(e))
await handler(self.cache[0]) logger.error(traceback.format_exc())
except Exception as e: if tasks:
logger.error(str(e)) await asyncio.gather(*tasks, return_exceptions=True)
logger.error(traceback.format_exc())
self.cache.pop(0)
if len(self.cache) > 0:
await asyncio.sleep(0.1 / len(self.cache))
else:
await asyncio.sleep(0.2)
def run_sync(self): def run_sync(self):
"""同步方式运行服务器""" """同步方式运行服务器"""

View File

@@ -126,7 +126,7 @@ class ScheduleGenerator:
prompt += f"你昨天的日程是:{self.yesterday_schedule_text}\n" prompt += f"你昨天的日程是:{self.yesterday_schedule_text}\n"
prompt += f"请为你生成{date_str}{weekday}),也就是今天的日程安排,结合你的个人特点和行为习惯以及昨天的安排\n" prompt += f"请为你生成{date_str}{weekday}),也就是今天的日程安排,结合你的个人特点和行为习惯以及昨天的安排\n"
prompt += "推测你的日程安排包括你一天都在做什么从起床到睡眠有什么发现和思考具体一些详细一些需要1500字以上精确到每半个小时记得写明时间\n" # noqa: E501 prompt += "推测你的日程安排包括你一天都在做什么从起床到睡眠有什么发现和思考具体一些详细一些需要1500字以上精确到每半个小时记得写明时间\n" # noqa: E501
prompt += "直接返回你的日程,从起床到睡觉,不要输出其他内容:" prompt += "直接返回你的日程,现实一点,不要浮夸,从起床到睡觉,不要输出其他内容:"
return prompt return prompt
def construct_doing_prompt(self, time: datetime.datetime, mind_thinking: str = ""): def construct_doing_prompt(self, time: datetime.datetime, mind_thinking: str = ""):
@@ -139,7 +139,7 @@ class ScheduleGenerator:
prompt += f"你之前做了的事情是:{previous_doings},从之前到现在已经过去了{self.schedule_doing_update_interval / 60}分钟了\n" # noqa: E501 prompt += f"你之前做了的事情是:{previous_doings},从之前到现在已经过去了{self.schedule_doing_update_interval / 60}分钟了\n" # noqa: E501
if mind_thinking: if mind_thinking:
prompt += f"你脑子里在想:{mind_thinking}\n" prompt += f"你脑子里在想:{mind_thinking}\n"
prompt += f"现在是{now_time},结合你的个人特点和行为习惯,注意关注你今天的日程安排和想法安排你接下来做什么," prompt += f"现在是{now_time},结合你的个人特点和行为习惯,注意关注你今天的日程安排和想法安排你接下来做什么,现实一点,不要浮夸"
prompt += "安排你接下来做什么,具体一些,详细一些\n" prompt += "安排你接下来做什么,具体一些,详细一些\n"
prompt += "直接返回你在做的事情,注意是当前时间,不要输出其他内容:" prompt += "直接返回你在做的事情,注意是当前时间,不要输出其他内容:"
return prompt return prompt

View File

@@ -1,8 +1,8 @@
from typing import Union from typing import Union
from ...common.database import db from ...common.database import db
from .message import MessageSending, MessageRecv from ..chat.message import MessageSending, MessageRecv
from .chat_stream import ChatStream from ..chat.chat_stream import ChatStream
from src.common.logger import get_module_logger from src.common.logger import get_module_logger
logger = get_module_logger("message_storage") logger = get_module_logger("message_storage")

View File

@@ -1,5 +1,5 @@
[inner] [inner]
version = "1.0.3" version = "1.0.4"
#以下是给开发人员阅读的,一般用户不需要阅读 #以下是给开发人员阅读的,一般用户不需要阅读
@@ -47,20 +47,24 @@ personality_3_probability = 0.1 # 第三种人格出现概率,请确保三个
enable_schedule_gen = true # 是否启用日程表(尚未完成) enable_schedule_gen = true # 是否启用日程表(尚未完成)
prompt_schedule_gen = "用几句话描述描述性格特点或行动规律,这个特征会用来生成日程表" prompt_schedule_gen = "用几句话描述描述性格特点或行动规律,这个特征会用来生成日程表"
schedule_doing_update_interval = 900 # 日程表更新间隔 单位秒 schedule_doing_update_interval = 900 # 日程表更新间隔 单位秒
schedule_temperature = 0.5 # 日程表温度建议0.5-1.0 schedule_temperature = 0.3 # 日程表温度建议0.3-0.6
[platforms] # 必填项目,填写每个平台适配器提供的链接 [platforms] # 必填项目,填写每个平台适配器提供的链接
nonebot-qq="http://127.0.0.1:18002/api/message" nonebot-qq="http://127.0.0.1:18002/api/message"
[response] #使用哪种回复策略
response_mode = "heart_flow" # 回复策略可选值heart_flow心流reasoning推理
#推理回复参数
model_r1_probability = 0.7 # 麦麦回答时选择主要回复模型1 模型的概率
model_v3_probability = 0.3 # 麦麦回答时选择次要回复模型2 模型的概率
[heartflow] # 注意可能会消耗大量token请谨慎开启 [heartflow] # 注意可能会消耗大量token请谨慎开启
enable = false #该选项未启用
sub_heart_flow_update_interval = 60 # 子心流更新频率,间隔 单位秒 sub_heart_flow_update_interval = 60 # 子心流更新频率,间隔 单位秒
sub_heart_flow_freeze_time = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒 sub_heart_flow_freeze_time = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒
sub_heart_flow_stop_time = 600 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒 sub_heart_flow_stop_time = 600 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒
heart_flow_update_interval = 300 # 心流更新频率,间隔 单位秒 heart_flow_update_interval = 300 # 心流更新频率,间隔 单位秒
#思维流适合搭配低能耗普通模型使用例如qwen2.5 32b
[message] [message]
max_context_size = 12 # 麦麦获得的上文数量建议12太短太长都会导致脑袋尖尖 max_context_size = 12 # 麦麦获得的上文数量建议12太短太长都会导致脑袋尖尖
@@ -87,9 +91,6 @@ response_interested_rate_amplifier = 1 # 麦麦回复兴趣度放大系数,听
down_frequency_rate = 3 # 降低回复频率的群组回复意愿降低系数 除法 down_frequency_rate = 3 # 降低回复频率的群组回复意愿降低系数 除法
emoji_response_penalty = 0.1 # 表情包回复惩罚系数设为0为不回复单个表情包减少单独回复表情包的概率 emoji_response_penalty = 0.1 # 表情包回复惩罚系数设为0为不回复单个表情包减少单独回复表情包的概率
[response] #这些选项已无效
model_r1_probability = 0 # 麦麦回答时选择主要回复模型1 模型的概率
model_v3_probability = 1.0 # 麦麦回答时选择次要回复模型2 模型的概率
[emoji] [emoji]
check_interval = 15 # 检查破损表情包的时间间隔(分钟) check_interval = 15 # 检查破损表情包的时间间隔(分钟)