Merge remote-tracking branch 'upstream/main-fix' into main-fix
This commit is contained in:
@@ -20,7 +20,7 @@ from .chat_stream import chat_manager
|
||||
from ..memory_system.memory import hippocampus, memory_graph
|
||||
from .bot import ChatBot
|
||||
from .message_sender import message_manager, message_sender
|
||||
|
||||
from .storage import MessageStorage
|
||||
|
||||
# 创建LLM统计实例
|
||||
llm_stats = LLMStatistics("llm_statistics.txt")
|
||||
@@ -148,3 +148,13 @@ async def generate_schedule_task():
|
||||
await bot_schedule.initialize()
|
||||
if not bot_schedule.enable_output:
|
||||
bot_schedule.print_schedule()
|
||||
|
||||
@scheduler.scheduled_job("interval", seconds=3600, id="remove_recalled_message")
|
||||
|
||||
async def remove_recalled_message() -> None:
|
||||
"""删除撤回消息"""
|
||||
try:
|
||||
storage = MessageStorage()
|
||||
await storage.remove_recalled_message(time.time())
|
||||
except Exception:
|
||||
logger.exception("删除撤回消息失败")
|
||||
@@ -1,7 +1,6 @@
|
||||
import re
|
||||
import time
|
||||
from random import random
|
||||
from loguru import logger
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupMessageEvent,
|
||||
@@ -9,6 +8,8 @@ from nonebot.adapters.onebot.v11 import (
|
||||
PrivateMessageEvent,
|
||||
NoticeEvent,
|
||||
PokeNotifyEvent,
|
||||
GroupRecallNoticeEvent,
|
||||
FriendRecallNoticeEvent,
|
||||
)
|
||||
|
||||
from ..memory_system.memory import hippocampus
|
||||
@@ -30,6 +31,10 @@ from .utils_image import image_path_to_base64
|
||||
from .utils_user import get_user_nickname, get_user_cardname, get_groupname
|
||||
from .willing_manager import willing_manager # 导入意愿管理器
|
||||
from .message_base import UserInfo, GroupInfo, Seg
|
||||
from ..utils.logger_config import setup_logger, LogModule
|
||||
|
||||
# 配置日志
|
||||
logger = setup_logger(LogModule.CHAT)
|
||||
|
||||
|
||||
class ChatBot:
|
||||
@@ -53,65 +58,41 @@ class ChatBot:
|
||||
"""处理收到的通知"""
|
||||
# 戳一戳通知
|
||||
if isinstance(event, PokeNotifyEvent):
|
||||
# 不处理其他人的戳戳
|
||||
if not event.is_tome():
|
||||
return
|
||||
|
||||
# 用户屏蔽,不区分私聊/群聊
|
||||
if event.user_id in global_config.ban_user_id:
|
||||
return
|
||||
reply_poke_probability = 1 # 回复戳一戳的概率
|
||||
|
||||
reply_poke_probability = 1.0 # 回复戳一戳的概率,如果要改可以在这里改,暂不提取到配置文件
|
||||
|
||||
if random() < reply_poke_probability:
|
||||
user_info = UserInfo(
|
||||
user_id=event.user_id,
|
||||
user_nickname=get_user_nickname(event.user_id) or None,
|
||||
user_cardname=get_user_cardname(event.user_id) or None,
|
||||
platform="qq",
|
||||
)
|
||||
group_info = GroupInfo(group_id=event.group_id, group_name=None, platform="qq")
|
||||
message_cq = MessageRecvCQ(
|
||||
message_id=None,
|
||||
user_info=user_info,
|
||||
raw_message=str("[戳了戳]你"),
|
||||
group_info=group_info,
|
||||
reply_message=None,
|
||||
platform="qq",
|
||||
)
|
||||
await message_cq.initialize()
|
||||
message_json = message_cq.to_dict()
|
||||
raw_message = "[戳了戳]你" # 默认类型
|
||||
if info := event.raw_info:
|
||||
poke_type = info[2].get("txt", "戳了戳") # 戳戳类型,例如“拍一拍”、“揉一揉”、“捏一捏”
|
||||
custom_poke_message = info[4].get("txt", "") # 自定义戳戳消息,若不存在会为空字符串
|
||||
raw_message = f"[{poke_type}]你{custom_poke_message}"
|
||||
|
||||
# 进入maimbot
|
||||
message = MessageRecv(message_json)
|
||||
groupinfo = message.message_info.group_info
|
||||
userinfo = message.message_info.user_info
|
||||
messageinfo = message.message_info
|
||||
raw_message += "(这是一个类似摸摸头的友善行为,而不是恶意行为,请不要作出攻击发言)"
|
||||
await self.directly_reply(raw_message, event.user_id, event.group_id)
|
||||
|
||||
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 isinstance(event, GroupRecallNoticeEvent) or isinstance(event, FriendRecallNoticeEvent):
|
||||
user_info = UserInfo(
|
||||
user_id=event.user_id,
|
||||
user_nickname=get_user_nickname(event.user_id) or None,
|
||||
user_cardname=get_user_cardname(event.user_id) or None,
|
||||
platform="qq",
|
||||
)
|
||||
|
||||
bot_user_info = UserInfo(
|
||||
user_id=global_config.BOT_QQ,
|
||||
user_nickname=global_config.BOT_NICKNAME,
|
||||
platform=messageinfo.platform,
|
||||
)
|
||||
group_info = GroupInfo(group_id=event.group_id, group_name=None, platform="qq")
|
||||
|
||||
response, raw_content = await self.gpt.generate_response(message)
|
||||
chat = await chat_manager.get_or_create_stream(
|
||||
platform=user_info.platform, user_info=user_info, group_info=group_info
|
||||
)
|
||||
|
||||
if response:
|
||||
for msg in response:
|
||||
message_segment = Seg(type="text", data=msg)
|
||||
|
||||
bot_message = MessageSending(
|
||||
message_id=None,
|
||||
chat_stream=chat,
|
||||
bot_user_info=bot_user_info,
|
||||
sender_info=userinfo,
|
||||
message_segment=message_segment,
|
||||
reply=None,
|
||||
is_head=False,
|
||||
is_emoji=False,
|
||||
)
|
||||
message_manager.add_message(bot_message)
|
||||
await self.storage.store_recalled_message(event.message_id, time.time(), chat)
|
||||
|
||||
async def handle_message(self, event: MessageEvent, bot: Bot) -> None:
|
||||
"""处理收到的消息"""
|
||||
@@ -378,6 +359,72 @@ class ChatBot:
|
||||
# chat_stream=chat
|
||||
# )
|
||||
|
||||
async def directly_reply(self, raw_message: str, user_id: int, group_id: int):
|
||||
"""
|
||||
直接回复发来的消息,不经过意愿管理器
|
||||
"""
|
||||
|
||||
# 构造用户信息和群组信息
|
||||
user_info = UserInfo(
|
||||
user_id=user_id,
|
||||
user_nickname=get_user_nickname(user_id) or None,
|
||||
user_cardname=get_user_cardname(user_id) or None,
|
||||
platform="qq",
|
||||
)
|
||||
group_info = GroupInfo(group_id=group_id, group_name=None, platform="qq")
|
||||
|
||||
message_cq = MessageRecvCQ(
|
||||
message_id=None,
|
||||
user_info=user_info,
|
||||
raw_message=raw_message,
|
||||
group_info=group_info,
|
||||
reply_message=None,
|
||||
platform="qq",
|
||||
)
|
||||
message_json = message_cq.to_dict()
|
||||
|
||||
message = MessageRecv(message_json)
|
||||
groupinfo = message.message_info.group_info
|
||||
userinfo = message.message_info.user_info
|
||||
messageinfo = message.message_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()
|
||||
|
||||
bot_user_info = UserInfo(
|
||||
user_id=global_config.BOT_QQ,
|
||||
user_nickname=global_config.BOT_NICKNAME,
|
||||
platform=messageinfo.platform,
|
||||
)
|
||||
|
||||
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(messageinfo.time))
|
||||
logger.info(
|
||||
f"[{current_time}][{chat.group_info.group_name if chat.group_info else '私聊'}]{chat.user_info.user_nickname}:"
|
||||
f"{message.processed_plain_text}"
|
||||
)
|
||||
|
||||
# 使用大模型生成回复
|
||||
response, raw_content = await self.gpt.generate_response(message)
|
||||
|
||||
if response:
|
||||
for msg in response:
|
||||
message_segment = Seg(type="text", data=msg)
|
||||
|
||||
bot_message = MessageSending(
|
||||
message_id=None,
|
||||
chat_stream=chat,
|
||||
bot_user_info=bot_user_info,
|
||||
sender_info=userinfo,
|
||||
message_segment=message_segment,
|
||||
reply=None,
|
||||
is_head=False,
|
||||
is_emoji=False,
|
||||
)
|
||||
message_manager.add_message(bot_message)
|
||||
|
||||
|
||||
# 创建全局ChatBot实例
|
||||
chat_bot = ChatBot()
|
||||
|
||||
@@ -18,11 +18,17 @@ from ..chat.utils import get_embedding
|
||||
from ..chat.utils_image import ImageManager, image_path_to_base64
|
||||
from ..models.utils_model import LLM_request
|
||||
|
||||
from ..utils.logger_config import setup_logger, LogModule
|
||||
|
||||
# 配置日志
|
||||
logger = setup_logger(LogModule.EMOJI)
|
||||
|
||||
driver = get_driver()
|
||||
config = driver.config
|
||||
image_manager = ImageManager()
|
||||
|
||||
|
||||
|
||||
class EmojiManager:
|
||||
_instance = None
|
||||
EMOJI_DIR = os.path.join("data", "emoji") # 表情包存储目录
|
||||
@@ -154,20 +160,20 @@ class EmojiManager:
|
||||
# 更新使用次数
|
||||
db.emoji.update_one({"_id": selected_emoji["_id"]}, {"$inc": {"usage_count": 1}})
|
||||
|
||||
logger.success(
|
||||
f"找到匹配的表情包: {selected_emoji.get('description', '无描述')} (相似度: {similarity:.4f})"
|
||||
logger.info(
|
||||
f"[匹配] 找到表情包: {selected_emoji.get('description', '无描述')} (相似度: {similarity:.4f})"
|
||||
)
|
||||
# 稍微改一下文本描述,不然容易产生幻觉,描述已经包含 表情包 了
|
||||
return selected_emoji["path"], "[ %s ]" % selected_emoji.get("description", "无描述")
|
||||
|
||||
except Exception as search_error:
|
||||
logger.error(f"搜索表情包失败: {str(search_error)}")
|
||||
logger.error(f"[错误] 搜索表情包失败: {str(search_error)}")
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取表情包失败: {str(e)}")
|
||||
logger.error(f"[错误] 获取表情包失败: {str(e)}")
|
||||
return None
|
||||
|
||||
async def _get_emoji_discription(self, image_base64: str) -> str:
|
||||
@@ -181,7 +187,7 @@ class EmojiManager:
|
||||
return description
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取标签失败: {str(e)}")
|
||||
logger.error(f"[错误] 获取表情包描述失败: {str(e)}")
|
||||
return None
|
||||
|
||||
async def _check_emoji(self, image_base64: str, image_format: str) -> str:
|
||||
@@ -189,11 +195,11 @@ class EmojiManager:
|
||||
prompt = f'这是一个表情包,请回答这个表情包是否满足"{global_config.EMOJI_CHECK_PROMPT}"的要求,是则回答是,否则回答否,不要出现任何其他内容'
|
||||
|
||||
content, _ = await self.vlm.generate_response_for_image(prompt, image_base64, image_format)
|
||||
logger.debug(f"输出描述: {content}")
|
||||
logger.debug(f"[检查] 表情包检查结果: {content}")
|
||||
return content
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取标签失败: {str(e)}")
|
||||
logger.error(f"[错误] 表情包检查失败: {str(e)}")
|
||||
return None
|
||||
|
||||
async def _get_kimoji_for_text(self, text: str):
|
||||
@@ -201,11 +207,11 @@ class EmojiManager:
|
||||
prompt = f'这是{global_config.BOT_NICKNAME}将要发送的消息内容:\n{text}\n若要为其配上表情包,请你输出这个表情包应该表达怎样的情感,应该给人什么样的感觉,不要太简洁也不要太长,注意不要输出任何对消息内容的分析内容,只输出"一种什么样的感觉"中间的形容词部分。'
|
||||
|
||||
content, _ = await self.llm_emotion_judge.generate_response_async(prompt, temperature=1.5)
|
||||
logger.info(f"输出描述: {content}")
|
||||
logger.info(f"[情感] 表情包情感描述: {content}")
|
||||
return content
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取标签失败: {str(e)}")
|
||||
logger.error(f"[错误] 获取表情包情感失败: {str(e)}")
|
||||
return None
|
||||
|
||||
async def scan_new_emojis(self):
|
||||
@@ -252,7 +258,7 @@ class EmojiManager:
|
||||
db.images.update_one({"hash": image_hash}, {"$set": image_doc}, upsert=True)
|
||||
# 保存描述到image_descriptions集合
|
||||
image_manager._save_description_to_db(image_hash, description, "emoji")
|
||||
logger.success(f"同步已存在的表情包到images集合: {filename}")
|
||||
logger.success(f"[同步] 已同步表情包到images集合: {filename}")
|
||||
continue
|
||||
|
||||
# 检查是否在images集合中已有描述
|
||||
@@ -268,15 +274,10 @@ class EmojiManager:
|
||||
check = await self._check_emoji(image_base64, image_format)
|
||||
if "是" not in check:
|
||||
os.remove(image_path)
|
||||
logger.info(f"描述: {description}")
|
||||
|
||||
logger.info(f"描述: {description}")
|
||||
logger.info(f"其不满足过滤规则,被剔除 {check}")
|
||||
logger.info(f"[过滤] 表情包描述: {description}")
|
||||
logger.info(f"[过滤] 表情包不满足规则,已移除: {check}")
|
||||
continue
|
||||
logger.info(f"check通过 {check}")
|
||||
|
||||
if description is not None:
|
||||
embedding = await get_embedding(description)
|
||||
logger.info(f"[检查] 表情包检查通过: {check}")
|
||||
|
||||
# 准备数据库记录
|
||||
emoji_record = {
|
||||
@@ -290,8 +291,8 @@ class EmojiManager:
|
||||
|
||||
# 保存到emoji数据库
|
||||
db["emoji"].insert_one(emoji_record)
|
||||
logger.success(f"注册新表情包: {filename}")
|
||||
logger.info(f"描述: {description}")
|
||||
logger.success(f"[注册] 新表情包: {filename}")
|
||||
logger.info(f"[描述] {description}")
|
||||
|
||||
# 保存到images数据库
|
||||
image_doc = {
|
||||
@@ -304,17 +305,17 @@ class EmojiManager:
|
||||
db.images.update_one({"hash": image_hash}, {"$set": image_doc}, upsert=True)
|
||||
# 保存描述到image_descriptions集合
|
||||
image_manager._save_description_to_db(image_hash, description, "emoji")
|
||||
logger.success(f"同步保存到images集合: {filename}")
|
||||
logger.success(f"[同步] 已保存到images集合: {filename}")
|
||||
else:
|
||||
logger.warning(f"跳过表情包: {filename}")
|
||||
logger.warning(f"[跳过] 表情包: {filename}")
|
||||
|
||||
except Exception:
|
||||
logger.exception("扫描表情包失败")
|
||||
logger.exception("[错误] 扫描表情包失败")
|
||||
|
||||
async def _periodic_scan(self, interval_MINS: int = 10):
|
||||
"""定期扫描新表情包"""
|
||||
while True:
|
||||
logger.info("开始扫描新表情包...")
|
||||
logger.info("[扫描] 开始扫描新表情包...")
|
||||
await self.scan_new_emojis()
|
||||
await asyncio.sleep(interval_MINS * 60) # 每600秒扫描一次
|
||||
|
||||
@@ -332,48 +333,48 @@ class EmojiManager:
|
||||
for emoji in all_emojis:
|
||||
try:
|
||||
if "path" not in emoji:
|
||||
logger.warning(f"发现无效记录(缺少path字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
logger.warning(f"[检查] 发现无效记录(缺少path字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
db.emoji.delete_one({"_id": emoji["_id"]})
|
||||
removed_count += 1
|
||||
continue
|
||||
|
||||
if "embedding" not in emoji:
|
||||
logger.warning(f"发现过时记录(缺少embedding字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
logger.warning(f"[检查] 发现过时记录(缺少embedding字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
db.emoji.delete_one({"_id": emoji["_id"]})
|
||||
removed_count += 1
|
||||
continue
|
||||
|
||||
# 检查文件是否存在
|
||||
if not os.path.exists(emoji["path"]):
|
||||
logger.warning(f"表情包文件已被删除: {emoji['path']}")
|
||||
logger.warning(f"[检查] 表情包文件已被删除: {emoji['path']}")
|
||||
# 从数据库中删除记录
|
||||
result = db.emoji.delete_one({"_id": emoji["_id"]})
|
||||
if result.deleted_count > 0:
|
||||
logger.debug(f"成功删除数据库记录: {emoji['_id']}")
|
||||
logger.debug(f"[清理] 成功删除数据库记录: {emoji['_id']}")
|
||||
removed_count += 1
|
||||
else:
|
||||
logger.error(f"删除数据库记录失败: {emoji['_id']}")
|
||||
logger.error(f"[错误] 删除数据库记录失败: {emoji['_id']}")
|
||||
continue
|
||||
|
||||
if "hash" not in emoji:
|
||||
logger.warning(f"发现缺失记录(缺少hash字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
logger.warning(f"[检查] 发现缺失记录(缺少hash字段),ID: {emoji.get('_id', 'unknown')}")
|
||||
hash = hashlib.md5(open(emoji["path"], "rb").read()).hexdigest()
|
||||
db.emoji.update_one({"_id": emoji["_id"]}, {"$set": {"hash": hash}})
|
||||
|
||||
except Exception as item_error:
|
||||
logger.error(f"处理表情包记录时出错: {str(item_error)}")
|
||||
logger.error(f"[错误] 处理表情包记录时出错: {str(item_error)}")
|
||||
continue
|
||||
|
||||
# 验证清理结果
|
||||
remaining_count = db.emoji.count_documents({})
|
||||
if removed_count > 0:
|
||||
logger.success(f"已清理 {removed_count} 个失效的表情包记录")
|
||||
logger.info(f"清理前总数: {total_count} | 清理后总数: {remaining_count}")
|
||||
logger.success(f"[清理] 已清理 {removed_count} 个失效的表情包记录")
|
||||
logger.info(f"[统计] 清理前: {total_count} | 清理后: {remaining_count}")
|
||||
else:
|
||||
logger.info(f"已检查 {total_count} 个表情包记录")
|
||||
logger.info(f"[检查] 已检查 {total_count} 个表情包记录")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"检查表情包完整性失败: {str(e)}")
|
||||
logger.error(f"[错误] 检查表情包完整性失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
async def start_periodic_check(self, interval_MINS: int = 120):
|
||||
|
||||
@@ -27,6 +27,7 @@ class Message(MessageBase):
|
||||
reply: Optional["Message"] = None
|
||||
detailed_plain_text: str = ""
|
||||
processed_plain_text: str = ""
|
||||
memorized_times: int = 0
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Union
|
||||
|
||||
from loguru import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
|
||||
from ...common.database import db
|
||||
from .message_cq import MessageSendCQ
|
||||
from .message import MessageSending, MessageThinking, MessageRecv, MessageSet
|
||||
|
||||
@@ -24,6 +24,14 @@ class Message_Sender:
|
||||
def set_bot(self, bot: Bot):
|
||||
"""设置当前bot实例"""
|
||||
self._current_bot = bot
|
||||
|
||||
def get_recalled_messages(self, stream_id: str) -> list:
|
||||
"""获取所有撤回的消息"""
|
||||
recalled_messages = []
|
||||
|
||||
recalled_messages = list(db.recalled_messages.find({"stream_id": stream_id}, {"message_id": 1}))
|
||||
# 按thinking_start_time排序,时间早的在前面
|
||||
return recalled_messages
|
||||
|
||||
async def send_message(
|
||||
self,
|
||||
@@ -32,36 +40,41 @@ class Message_Sender:
|
||||
"""发送消息"""
|
||||
|
||||
if isinstance(message, MessageSending):
|
||||
message_json = message.to_dict()
|
||||
message_send = MessageSendCQ(data=message_json)
|
||||
# logger.debug(message_send.message_info,message_send.raw_message)
|
||||
message_preview = truncate_message(message.processed_plain_text)
|
||||
if (
|
||||
message_send.message_info.group_info
|
||||
and message_send.message_info.group_info.group_id
|
||||
):
|
||||
try:
|
||||
await self._current_bot.send_group_msg(
|
||||
group_id=message.message_info.group_info.group_id,
|
||||
message=message_send.raw_message,
|
||||
auto_escape=False,
|
||||
)
|
||||
logger.success(f"[调试] 发送消息“{message_preview}”成功")
|
||||
except Exception as e:
|
||||
logger.error(f"[调试] 发生错误 {e}")
|
||||
logger.error(f"[调试] 发送消息“{message_preview}”失败")
|
||||
else:
|
||||
try:
|
||||
logger.debug(message.message_info.user_info)
|
||||
await self._current_bot.send_private_msg(
|
||||
user_id=message.sender_info.user_id,
|
||||
message=message_send.raw_message,
|
||||
auto_escape=False,
|
||||
)
|
||||
logger.success(f"[调试] 发送消息“{message_preview}”成功")
|
||||
except Exception as e:
|
||||
logger.error(f"[调试] 发生错误 {e}")
|
||||
logger.error(f"[调试] 发送消息“{message_preview}”失败")
|
||||
recalled_messages = self.get_recalled_messages(message.chat_stream.stream_id)
|
||||
is_recalled = False
|
||||
for recalled_message in recalled_messages:
|
||||
if message.reply_to_message_id == recalled_message["message_id"]:
|
||||
is_recalled = True
|
||||
logger.warning(f"消息“{message.processed_plain_text}”已被撤回,不发送")
|
||||
break
|
||||
if not is_recalled:
|
||||
message_json = message.to_dict()
|
||||
message_send = MessageSendCQ(data=message_json)
|
||||
# logger.debug(message_send.message_info,message_send.raw_message)
|
||||
message_preview = truncate_message(message.processed_plain_text)
|
||||
if message_send.message_info.group_info and message_send.message_info.group_info.group_id:
|
||||
try:
|
||||
await self._current_bot.send_group_msg(
|
||||
group_id=message.message_info.group_info.group_id,
|
||||
message=message_send.raw_message,
|
||||
auto_escape=False,
|
||||
)
|
||||
logger.success(f"[调试] 发送消息“{message_preview}”成功")
|
||||
except Exception as e:
|
||||
logger.error(f"[调试] 发生错误 {e}")
|
||||
logger.error(f"[调试] 发送消息“{message_preview}”失败")
|
||||
else:
|
||||
try:
|
||||
logger.debug(message.message_info.user_info)
|
||||
await self._current_bot.send_private_msg(
|
||||
user_id=message.sender_info.user_id,
|
||||
message=message_send.raw_message,
|
||||
auto_escape=False,
|
||||
)
|
||||
logger.success(f"[调试] 发送消息“{message_preview}”成功")
|
||||
except Exception as e:
|
||||
logger.error(f"[调试] 发生错误 {e}")
|
||||
logger.error(f"[调试] 发送消息“{message_preview}”失败")
|
||||
|
||||
|
||||
class MessageContainer:
|
||||
@@ -144,9 +157,7 @@ class MessageManager:
|
||||
self.containers[chat_id] = MessageContainer(chat_id)
|
||||
return self.containers[chat_id]
|
||||
|
||||
def add_message(
|
||||
self, message: Union[MessageThinking, MessageSending, MessageSet]
|
||||
) -> None:
|
||||
def add_message(self, message: Union[MessageThinking, MessageSending, MessageSet]) -> None:
|
||||
chat_stream = message.chat_stream
|
||||
if not chat_stream:
|
||||
raise ValueError("无法找到对应的聊天流")
|
||||
@@ -173,25 +184,22 @@ class MessageManager:
|
||||
if thinking_time > global_config.thinking_timeout:
|
||||
logger.warning(f"消息思考超时({thinking_time}秒),移除该消息")
|
||||
container.remove_message(message_earliest)
|
||||
else:
|
||||
|
||||
else:
|
||||
if (
|
||||
message_earliest.is_head
|
||||
and message_earliest.update_thinking_time() > 30
|
||||
and not message_earliest.is_private_message() # 避免在私聊时插入reply
|
||||
):
|
||||
await message_sender.send_message(message_earliest.set_reply())
|
||||
else:
|
||||
await message_sender.send_message(message_earliest)
|
||||
message_earliest.set_reply()
|
||||
await message_sender.send_message(message_earliest)
|
||||
await message_earliest.process()
|
||||
|
||||
print(
|
||||
f"\033[1;34m[调试]\033[0m 消息“{truncate_message(message_earliest.processed_plain_text)}”正在发送中"
|
||||
)
|
||||
|
||||
await self.storage.store_message(
|
||||
message_earliest, message_earliest.chat_stream, None
|
||||
)
|
||||
await self.storage.store_message(message_earliest, message_earliest.chat_stream, None)
|
||||
|
||||
container.remove_message(message_earliest)
|
||||
|
||||
@@ -208,9 +216,8 @@ class MessageManager:
|
||||
and msg.update_thinking_time() > 30
|
||||
and not message_earliest.is_private_message() # 避免在私聊时插入reply
|
||||
):
|
||||
await message_sender.send_message(msg.set_reply())
|
||||
else:
|
||||
await message_sender.send_message(msg)
|
||||
msg.set_reply()
|
||||
await message_sender.send_message(msg)
|
||||
|
||||
# if msg.is_emoji:
|
||||
# msg.processed_plain_text = "[表情包]"
|
||||
|
||||
@@ -19,9 +19,31 @@ class MessageStorage:
|
||||
"processed_plain_text": message.processed_plain_text,
|
||||
"detailed_plain_text": message.detailed_plain_text,
|
||||
"topic": topic,
|
||||
"memorized_times": message.memorized_times,
|
||||
}
|
||||
db.messages.insert_one(message_data)
|
||||
except Exception:
|
||||
logger.exception("存储消息失败")
|
||||
|
||||
async def store_recalled_message(self, message_id: str, time: str, chat_stream:ChatStream) -> None:
|
||||
"""存储撤回消息到数据库"""
|
||||
if "recalled_messages" not in db.list_collection_names():
|
||||
db.create_collection("recalled_messages")
|
||||
else:
|
||||
try:
|
||||
message_data = {
|
||||
"message_id": message_id,
|
||||
"time": time,
|
||||
"stream_id":chat_stream.stream_id,
|
||||
}
|
||||
db.recalled_messages.insert_one(message_data)
|
||||
except Exception:
|
||||
logger.exception("存储撤回消息失败")
|
||||
|
||||
async def remove_recalled_message(self, time: str) -> None:
|
||||
"""删除撤回消息"""
|
||||
try:
|
||||
db.recalled_messages.delete_many({"time": {"$lt": time-300}})
|
||||
except Exception:
|
||||
logger.exception("删除撤回消息失败")
|
||||
# 如果需要其他存储相关的函数,可以在这里添加
|
||||
|
||||
@@ -104,10 +104,13 @@ def get_closest_chat_from_db(length: int, timestamp: str):
|
||||
# 转换记录格式
|
||||
formatted_records = []
|
||||
for record in chat_records:
|
||||
# 兼容行为,前向兼容老数据
|
||||
formatted_records.append({
|
||||
'_id': record["_id"],
|
||||
'time': record["time"],
|
||||
'chat_id': record["chat_id"],
|
||||
'detailed_plain_text': record.get("detailed_plain_text", "") # 添加文本内容
|
||||
'detailed_plain_text': record.get("detailed_plain_text", ""), # 添加文本内容
|
||||
'memorized_times': record.get("memorized_times", 0) # 添加记忆次数
|
||||
})
|
||||
|
||||
return formatted_records
|
||||
|
||||
Reference in New Issue
Block a user