refactor(chat): 迁移数据库操作为异步模式并修复相关调用

将同步数据库操作全面迁移为异步模式,主要涉及:
- 将 `with get_db_session()` 改为 `async with get_db_session()`
- 修复相关异步调用链,确保 await 正确传递
- 优化消息管理器、上下文管理器等核心组件的异步处理
- 移除同步的 person_id 获取方法,避免协程对象传递问题

修复 deepcopy 在 StreamContext 中的序列化问题,跳过不可序列化的 asyncio.Task 对象

删除无用的测试文件和废弃的插件清单文件
This commit is contained in:
Windpicker-owo
2025-09-28 20:40:46 +08:00
parent 9836d317b8
commit c31fd02daf
28 changed files with 526 additions and 604 deletions

View File

@@ -261,7 +261,7 @@ class AntiPromptInjector:
logger.warning("无法删除消息缺少message_id")
return
with get_db_session() as session:
async with get_db_session() as session:
# 删除对应的消息记录
stmt = delete(Messages).where(Messages.message_id == message_id)
result = session.execute(stmt)
@@ -287,7 +287,7 @@ class AntiPromptInjector:
logger.warning("无法更新消息缺少message_id")
return
with get_db_session() as session:
async with get_db_session() as session:
# 更新消息内容
stmt = (
update(Messages)

View File

@@ -42,7 +42,7 @@ class SingleStreamContextManager:
self._update_access_stats()
return self.context
def add_message(self, message: DatabaseMessages, skip_energy_update: bool = False) -> bool:
async def add_message(self, message: DatabaseMessages, skip_energy_update: bool = False) -> bool:
"""添加消息到上下文
Args:
@@ -53,30 +53,21 @@ class SingleStreamContextManager:
bool: 是否成功添加
"""
try:
# 添加消息到上下文
self.context.add_message(message)
# 计算消息兴趣度
interest_value = self._calculate_message_interest(message)
interest_value = await self._calculate_message_interest(message)
message.interest_value = interest_value
# 更新统计
self.total_messages += 1
self.last_access_time = time.time()
# 更新能量和分发
if not skip_energy_update:
self._update_stream_energy()
await self._update_stream_energy()
distribution_manager.add_stream_message(self.stream_id, 1)
logger.debug(f"添加消息到单流上下文: {self.stream_id} (兴趣度: {interest_value:.3f})")
return True
except Exception as e:
logger.error(f"添加消息到单流上下文失败 {self.stream_id}: {e}", exc_info=True)
return False
def update_message(self, message_id: str, updates: Dict[str, Any]) -> bool:
async def update_message(self, message_id: str, updates: Dict[str, Any]) -> bool:
"""更新上下文中的消息
Args:
@@ -87,16 +78,11 @@ class SingleStreamContextManager:
bool: 是否成功更新
"""
try:
# 更新消息信息
self.context.update_message_info(message_id, **updates)
# 如果更新了兴趣度,重新计算能量
if "interest_value" in updates:
self._update_stream_energy()
await self._update_stream_energy()
logger.debug(f"更新单流上下文消息: {self.stream_id}/{message_id}")
return True
except Exception as e:
logger.error(f"更新单流上下文消息失败 {self.stream_id}/{message_id}: {e}", exc_info=True)
return False
@@ -164,16 +150,13 @@ class SingleStreamContextManager:
logger.error(f"标记消息已读失败 {self.stream_id}: {e}", exc_info=True)
return False
def clear_context(self) -> bool:
async def clear_context(self) -> bool:
"""清空上下文"""
try:
# 清空消息
if hasattr(self.context, "unread_messages"):
self.context.unread_messages.clear()
if hasattr(self.context, "history_messages"):
self.context.history_messages.clear()
# 重置状态
reset_attrs = ["interruption_count", "afc_threshold_adjustment", "last_check_time"]
for attr in reset_attrs:
if hasattr(self.context, attr):
@@ -181,13 +164,9 @@ class SingleStreamContextManager:
setattr(self.context, attr, 0)
else:
setattr(self.context, attr, time.time())
# 重新计算能量
self._update_stream_energy()
await self._update_stream_energy()
logger.info(f"清空单流上下文: {self.stream_id}")
return True
except Exception as e:
logger.error(f"清空单流上下文失败 {self.stream_id}: {e}", exc_info=True)
return False
@@ -249,39 +228,115 @@ class SingleStreamContextManager:
self.last_access_time = time.time()
self.access_count += 1
def _calculate_message_interest(self, message: DatabaseMessages) -> float:
"""计算消息兴趣度"""
async def _calculate_message_interest(self, message: DatabaseMessages) -> float:
"""异步实现:使用插件的异步评分器正确 await 计算兴趣度并返回分数。"""
try:
# 使用插件内部的兴趣度评分系统
try:
from src.plugins.built_in.affinity_flow_chatter.interest_scoring import chatter_interest_scoring_system
# 使用插件内部的兴趣度评分系统计算(同步方式)
from src.plugins.built_in.affinity_flow_chatter.interest_scoring import (
chatter_interest_scoring_system,
)
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
interest_score = loop.run_until_complete(
chatter_interest_scoring_system._calculate_single_message_score(
interest_score = await chatter_interest_scoring_system._calculate_single_message_score(
message=message, bot_nickname=global_config.bot.nickname
)
)
interest_value = interest_score.total_score
interest_value = interest_score.total_score
logger.debug(f"使用插件内部系统计算兴趣度: {interest_value:.3f}")
return interest_value
except Exception as e:
logger.warning(f"插件内部兴趣度计算失败: {e}")
return 0.5
except Exception as e:
logger.warning(f"插件内部兴趣度计算加载失败,使用默认值: {e}")
return 0.5
except Exception as e:
logger.error(f"计算消息兴趣度失败: {e}")
return 0.5
logger.debug(f"使用插件内部系统计算兴趣度: {interest_value:.3f}")
async def _calculate_message_interest_async(self, message: DatabaseMessages) -> float:
"""异步实现:使用插件的异步评分器正确 await 计算兴趣度并返回分数。"""
try:
try:
from src.plugins.built_in.affinity_flow_chatter.interest_scoring import (
chatter_interest_scoring_system,
)
# 直接 await 插件的异步方法
try:
interest_score = await chatter_interest_scoring_system._calculate_single_message_score(
message=message, bot_nickname=global_config.bot.nickname
)
interest_value = interest_score.total_score
logger.debug(f"使用插件内部系统计算兴趣度: {interest_value:.3f}")
return interest_value
except Exception as e:
logger.warning(f"插件内部兴趣度计算失败: {e}")
return 0.5
except Exception as e:
logger.warning(f"插件内部兴趣度计算失败,使用默认值: {e}")
interest_value = 0.5 # 默认中等兴趣度
return interest_value
logger.warning(f"插件内部兴趣度计算加载失败,使用默认值: {e}")
return 0.5
except Exception as e:
logger.error(f"计算消息兴趣度失败: {e}")
return 0.5
async def add_message_async(self, message: DatabaseMessages, skip_energy_update: bool = False) -> bool:
"""异步实现的 add_message将消息添加到 context并 await 能量更新与分发。"""
try:
self.context.add_message(message)
interest_value = await self._calculate_message_interest_async(message)
message.interest_value = interest_value
self.total_messages += 1
self.last_access_time = time.time()
if not skip_energy_update:
await self._update_stream_energy()
distribution_manager.add_stream_message(self.stream_id, 1)
logger.debug(f"添加消息到单流上下文(异步): {self.stream_id} (兴趣度: {interest_value:.3f})")
return True
except Exception as e:
logger.error(f"添加消息到单流上下文失败 (async) {self.stream_id}: {e}", exc_info=True)
return False
async def update_message_async(self, message_id: str, updates: Dict[str, Any]) -> bool:
"""异步实现的 update_message更新消息并在需要时 await 能量更新。"""
try:
self.context.update_message_info(message_id, **updates)
if "interest_value" in updates:
await self._update_stream_energy()
logger.debug(f"更新单流上下文消息(异步): {self.stream_id}/{message_id}")
return True
except Exception as e:
logger.error(f"更新单流上下文消息失败 (async) {self.stream_id}/{message_id}: {e}", exc_info=True)
return False
async def clear_context_async(self) -> bool:
"""异步实现的 clear_context清空消息并 await 能量重算。"""
try:
if hasattr(self.context, "unread_messages"):
self.context.unread_messages.clear()
if hasattr(self.context, "history_messages"):
self.context.history_messages.clear()
reset_attrs = ["interruption_count", "afc_threshold_adjustment", "last_check_time"]
for attr in reset_attrs:
if hasattr(self.context, attr):
if attr in ["interruption_count", "afc_threshold_adjustment"]:
setattr(self.context, attr, 0)
else:
setattr(self.context, attr, time.time())
await self._update_stream_energy()
logger.info(f"清空单流上下文(异步): {self.stream_id}")
return True
except Exception as e:
logger.error(f"清空单流上下文失败 (async) {self.stream_id}: {e}", exc_info=True)
return False
async def _update_stream_energy(self):
"""更新流能量"""
try:
@@ -305,4 +360,4 @@ class SingleStreamContextManager:
distribution_manager.update_stream_energy(self.stream_id, energy)
except Exception as e:
logger.error(f"更新单流能量失败 {self.stream_id}: {e}")
logger.error(f"更新单流能量失败 {self.stream_id}: {e}")

View File

@@ -75,29 +75,23 @@ class MessageManager:
logger.info("消息管理器已停止")
def add_message(self, stream_id: str, message: DatabaseMessages):
async def add_message(self, stream_id: str, message: DatabaseMessages):
"""添加消息到指定聊天流"""
try:
# 通过 ChatManager 获取 ChatStream
chat_manager = get_chat_manager()
chat_stream = chat_manager.get_stream(stream_id)
if not chat_stream:
logger.warning(f"MessageManager.add_message: 聊天流 {stream_id} 不存在")
return
# 使用 ChatStream 的 context_manager 添加消息
success = chat_stream.context_manager.add_message(message)
success = await chat_stream.context_manager.add_message(message)
if success:
logger.debug(f"添加消息到聊天流 {stream_id}: {message.message_id}")
else:
logger.warning(f"添加消息到聊天流 {stream_id} 失败")
except Exception as e:
logger.error(f"添加消息到聊天流 {stream_id} 时发生错误: {e}")
def update_message(
async def update_message(
self,
stream_id: str,
message_id: str,
@@ -107,15 +101,11 @@ class MessageManager:
):
"""更新消息信息"""
try:
# 通过 ChatManager 获取 ChatStream
chat_manager = get_chat_manager()
chat_stream = chat_manager.get_stream(stream_id)
if not chat_stream:
logger.warning(f"MessageManager.update_message: 聊天流 {stream_id} 不存在")
return
# 构建更新字典
updates = {}
if interest_value is not None:
updates["interest_value"] = interest_value
@@ -123,41 +113,30 @@ class MessageManager:
updates["actions"] = actions
if should_reply is not None:
updates["should_reply"] = should_reply
# 使用 ChatStream 的 context_manager 更新消息
if updates:
success = chat_stream.context_manager.update_message(message_id, updates)
success = await chat_stream.context_manager.update_message(message_id, updates)
if success:
logger.debug(f"更新消息 {message_id} 成功")
else:
logger.warning(f"更新消息 {message_id} 失败")
except Exception as e:
logger.error(f"更新消息 {message_id} 时发生错误: {e}")
def add_action(self, stream_id: str, message_id: str, action: str):
async def add_action(self, stream_id: str, message_id: str, action: str):
"""添加动作到消息"""
try:
# 通过 ChatManager 获取 ChatStream
chat_manager = get_chat_manager()
chat_stream = chat_manager.get_stream(stream_id)
if not chat_stream:
logger.warning(f"MessageManager.add_action: 聊天流 {stream_id} 不存在")
return
# 使用 ChatStream 的 context_manager 添加动作
# 注意:这里需要根据实际的 API 调整
# 假设我们可以通过 update_message 来添加动作
success = chat_stream.context_manager.update_message(
success = await chat_stream.context_manager.update_message(
message_id, {"actions": [action]}
)
if success:
logger.debug(f"为消息 {message_id} 添加动作 {action} 成功")
else:
logger.warning(f"为消息 {message_id} 添加动作 {action} 失败")
except Exception as e:
logger.error(f"为消息 {message_id} 添加动作时发生错误: {e}")
@@ -382,36 +361,27 @@ class MessageManager:
"start_time": self.stats.start_time,
}
def cleanup_inactive_streams(self, max_inactive_hours: int = 24):
async def cleanup_inactive_streams(self, max_inactive_hours: int = 24):
"""清理不活跃的聊天流"""
try:
# 通过 ChatManager 清理不活跃的流
chat_manager = get_chat_manager()
current_time = time.time()
max_inactive_seconds = max_inactive_hours * 3600
inactive_streams = []
for stream_id, chat_stream in chat_manager.streams.items():
# 检查最后活跃时间
if current_time - chat_stream.last_active_time > max_inactive_seconds:
inactive_streams.append(stream_id)
# 清理不活跃的流
for stream_id in inactive_streams:
try:
# 清理流的内容
chat_stream.context_manager.clear_context()
# 从 ChatManager 中移除
await chat_stream.context_manager.clear_context()
del chat_manager.streams[stream_id]
logger.info(f"清理不活跃聊天流: {stream_id}")
except Exception as e:
logger.error(f"清理聊天流 {stream_id} 失败: {e}")
if inactive_streams:
logger.info(f"已清理 {len(inactive_streams)} 个不活跃聊天流")
else:
logger.debug("没有需要清理的不活跃聊天流")
except Exception as e:
logger.error(f"清理不活跃聊天流时发生错误: {e}")

View File

@@ -518,7 +518,7 @@ class ChatBot:
db_message.chat_info_group_platform = message.chat_stream.group_info.platform
# 添加消息到消息管理器
message_manager.add_message(message.chat_stream.stream_id, db_message)
await message_manager.add_message(message.chat_stream.stream_id, db_message)
logger.debug(f"消息已添加到消息管理器: {message.chat_stream.stream_id}")
if template_group_name:

View File

@@ -389,94 +389,105 @@ class ChatStream:
from sqlalchemy import select, desc
import asyncio
async def _load_messages():
def _db_query():
with get_db_session() as session:
# 查询该stream_id的最近20条消息
async def _load_history_messages_async():
"""异步加载并转换历史消息到 stream_context在事件循环中运行"""
try:
async with get_db_session() as session:
stmt = (
select(Messages)
.where(Messages.chat_info_stream_id == self.stream_id)
.order_by(desc(Messages.time))
.limit(global_config.chat.max_context_size)
)
result = session.execute(stmt)
results = result.scalars().all()
return results
result = await session.execute(stmt)
db_messages = result.scalars().all()
# 在线程中执行数据库查询
db_messages = await asyncio.to_thread(_db_query)
# 转换为DatabaseMessages对象并添加到StreamContext
for db_msg in db_messages:
try:
import orjson
# 转换为DatabaseMessages对象并添加到StreamContext
for db_msg in db_messages:
actions = None
if db_msg.actions:
try:
actions = orjson.loads(db_msg.actions)
except (orjson.JSONDecodeError, TypeError):
actions = None
db_message = DatabaseMessages(
message_id=db_msg.message_id,
time=db_msg.time,
chat_id=db_msg.chat_id,
reply_to=db_msg.reply_to,
interest_value=db_msg.interest_value,
key_words=db_msg.key_words,
key_words_lite=db_msg.key_words_lite,
is_mentioned=db_msg.is_mentioned,
processed_plain_text=db_msg.processed_plain_text,
display_message=db_msg.display_message,
priority_mode=db_msg.priority_mode,
priority_info=db_msg.priority_info,
additional_config=db_msg.additional_config,
is_emoji=db_msg.is_emoji,
is_picid=db_msg.is_picid,
is_command=db_msg.is_command,
is_notify=db_msg.is_notify,
user_id=db_msg.user_id,
user_nickname=db_msg.user_nickname,
user_cardname=db_msg.user_cardname,
user_platform=db_msg.user_platform,
chat_info_group_id=db_msg.chat_info_group_id,
chat_info_group_name=db_msg.chat_info_group_name,
chat_info_group_platform=db_msg.chat_info_group_platform,
chat_info_user_id=db_msg.chat_info_user_id,
chat_info_user_nickname=db_msg.chat_info_user_nickname,
chat_info_user_cardname=db_msg.chat_info_user_cardname,
chat_info_user_platform=db_msg.chat_info_user_platform,
chat_info_stream_id=db_msg.chat_info_stream_id,
chat_info_platform=db_msg.chat_info_platform,
chat_info_create_time=db_msg.chat_info_create_time,
chat_info_last_active_time=db_msg.chat_info_last_active_time,
actions=actions,
should_reply=getattr(db_msg, "should_reply", False) or False,
)
logger.debug(
f"加载历史消息 {db_message.message_id} - interest_value: {db_message.interest_value}"
)
db_message.is_read = True
self.stream_context.history_messages.append(db_message)
except Exception as e:
logger.warning(f"转换消息 {getattr(db_msg, 'message_id', '<unknown>')} 失败: {e}")
continue
if self.stream_context.history_messages:
logger.info(
f"已从数据库加载 {len(self.stream_context.history_messages)} 条历史消息到聊天流 {self.stream_id}"
)
except Exception as e:
logger.warning(f"异步加载历史消息失败: {e}")
# 在已有事件循环中,避免调用 asyncio.run()
try:
loop = asyncio.get_running_loop()
except RuntimeError:
# 没有运行的事件循环,安全地运行并等待完成
asyncio.run(_load_history_messages_async())
else:
# 如果事件循环正在运行,在后台创建任务
if loop.is_running():
try:
# 从SQLAlchemy模型转换为DatabaseMessages数据模型
import orjson
# 解析actions字段JSON格式
actions = None
if db_msg.actions:
try:
actions = orjson.loads(db_msg.actions)
except (orjson.JSONDecodeError, TypeError):
actions = None
db_message = DatabaseMessages(
message_id=db_msg.message_id,
time=db_msg.time,
chat_id=db_msg.chat_id,
reply_to=db_msg.reply_to,
interest_value=db_msg.interest_value,
key_words=db_msg.key_words,
key_words_lite=db_msg.key_words_lite,
is_mentioned=db_msg.is_mentioned,
processed_plain_text=db_msg.processed_plain_text,
display_message=db_msg.display_message,
priority_mode=db_msg.priority_mode,
priority_info=db_msg.priority_info,
additional_config=db_msg.additional_config,
is_emoji=db_msg.is_emoji,
is_picid=db_msg.is_picid,
is_command=db_msg.is_command,
is_notify=db_msg.is_notify,
user_id=db_msg.user_id,
user_nickname=db_msg.user_nickname,
user_cardname=db_msg.user_cardname,
user_platform=db_msg.user_platform,
chat_info_group_id=db_msg.chat_info_group_id,
chat_info_group_name=db_msg.chat_info_group_name,
chat_info_group_platform=db_msg.chat_info_group_platform,
chat_info_user_id=db_msg.chat_info_user_id,
chat_info_user_nickname=db_msg.chat_info_user_nickname,
chat_info_user_cardname=db_msg.chat_info_user_cardname,
chat_info_user_platform=db_msg.chat_info_user_platform,
chat_info_stream_id=db_msg.chat_info_stream_id,
chat_info_platform=db_msg.chat_info_platform,
chat_info_create_time=db_msg.chat_info_create_time,
chat_info_last_active_time=db_msg.chat_info_last_active_time,
actions=actions,
should_reply=getattr(db_msg, "should_reply", False) or False,
)
# 添加调试日志检查从数据库加载的interest_value
logger.debug(
f"加载历史消息 {db_message.message_id} - interest_value: {db_message.interest_value}"
)
# 标记为已读并添加到历史消息
db_message.is_read = True
self.stream_context.history_messages.append(db_message)
asyncio.create_task(_load_history_messages_async())
except Exception as e:
logger.warning(f"转换消息 {db_msg.message_id} 失败: {e}")
continue
if self.stream_context.history_messages:
logger.info(
f"已从数据库加载 {len(self.stream_context.history_messages)} 条历史消息到聊天流 {self.stream_id}"
)
# 创建任务来加载历史消息
asyncio.create_task(_load_messages())
# 如果无法创建任务,退回到阻塞运行
logger.warning(f"无法在事件循环中创建后台任务,尝试阻塞运行: {e}")
asyncio.run(_load_history_messages_async())
else:
# loop 存在但未运行,使用 asyncio.run
asyncio.run(_load_history_messages_async())
except Exception as e:
logger.error(f"加载历史消息失败: {e}")
@@ -498,7 +509,7 @@ class ChatManager:
self.streams: Dict[str, ChatStream] = {} # stream_id -> ChatStream
self.last_messages: Dict[str, "MessageRecv"] = {} # stream_id -> last_message
# try:
# with get_db_session() as session:
# async with get_db_session() as session:
# db.connect(reuse_if_open=True)
# # 确保 ChatStreams 表存在
# session.execute(text("CREATE TABLE IF NOT EXISTS chat_streams (stream_id TEXT PRIMARY KEY, platform TEXT, create_time REAL, last_active_time REAL, user_platform TEXT, user_id TEXT, user_nickname TEXT, user_cardname TEXT, group_platform TEXT, group_id TEXT, group_name TEXT)"))

View File

@@ -212,7 +212,7 @@ class MessageStorage:
return match.group(0)
@staticmethod
def update_message_interest_value(message_id: str, interest_value: float) -> None:
async def update_message_interest_value(message_id: str, interest_value: float) -> None:
"""
更新数据库中消息的interest_value字段
@@ -221,11 +221,11 @@ class MessageStorage:
interest_value: 兴趣度值
"""
try:
with get_db_session() as session:
async with get_db_session() as session:
# 更新消息的interest_value字段
stmt = update(Messages).where(Messages.message_id == message_id).values(interest_value=interest_value)
result = session.execute(stmt)
session.commit()
result = await session.execute(stmt)
await session.commit()
if result.rowcount > 0:
logger.debug(f"成功更新消息 {message_id} 的interest_value为 {interest_value}")
@@ -237,7 +237,7 @@ class MessageStorage:
raise
@staticmethod
def fix_zero_interest_values(chat_id: str, since_time: float) -> int:
async def fix_zero_interest_values(chat_id: str, since_time: float) -> int:
"""
修复指定聊天中interest_value为0或null的历史消息记录
@@ -249,7 +249,7 @@ class MessageStorage:
修复的记录数量
"""
try:
with get_db_session() as session:
async with get_db_session() as session:
from sqlalchemy import select, update
from src.common.database.sqlalchemy_models import Messages
@@ -264,7 +264,7 @@ class MessageStorage:
)
).limit(50) # 限制每次修复的数量,避免性能问题
result = session.execute(query)
result = await session.execute(query)
messages_to_fix = result.scalars().all()
fixed_count = 0
@@ -290,12 +290,12 @@ class MessageStorage:
Messages.message_id == msg.message_id
).values(interest_value=default_interest)
result = session.execute(update_stmt)
result = await session.execute(update_stmt)
if result.rowcount > 0:
fixed_count += 1
logger.debug(f"修复消息 {msg.message_id} 的interest_value为 {default_interest}")
session.commit()
await session.commit()
logger.info(f"共修复了 {fixed_count} 条历史消息的interest_value值")
return fixed_count

View File

@@ -297,15 +297,12 @@ class ChatterActionManager:
return
# 通过message_manager更新消息的动作记录并刷新focus_energy
if chat_stream.stream_id in message_manager.stream_contexts:
message_manager.add_action(
stream_id=chat_stream.stream_id,
message_id=target_message_id,
action=action_name
)
logger.debug(f"已记录动作 {action_name} 到消息 {target_message_id} 并更新focus_energy")
else:
logger.debug(f"未找到stream_context: {chat_stream.stream_id}")
await message_manager.add_action(
stream_id=chat_stream.stream_id,
message_id=target_message_id,
action=action_name
)
logger.debug(f"已记录动作 {action_name} 到消息 {target_message_id} 并更新focus_energy")
except Exception as e:
logger.error(f"记录动作到消息失败: {e}")
@@ -315,8 +312,11 @@ class ChatterActionManager:
"""在动作执行成功后重置打断计数"""
from src.chat.message_manager.message_manager import message_manager
try:
if stream_id in message_manager.stream_contexts:
context = message_manager.stream_contexts[stream_id]
from src.plugin_system.apis.chat_api import get_chat_manager
chat_manager = get_chat_manager()
chat_stream = chat_manager.get_stream(stream_id)
if chat_stream:
context = chat_stream.context_manager
if context.interruption_count > 0:
old_count = context.interruption_count
old_afc_adjustment = context.get_afc_threshold_adjustment()

View File

@@ -73,7 +73,7 @@ class ActionModifier:
from src.chat.utils.utils import get_chat_type_and_target_info
# 获取聊天类型
is_group_chat, _ = await get_chat_type_and_target_info(self.chat_id)
is_group_chat, _ = get_chat_type_and_target_info(self.chat_id)
all_registered_actions = component_registry.get_components_by_type(ComponentType.ACTION)
chat_type_removals = []

View File

@@ -706,8 +706,11 @@ class DefaultReplyer:
from src.chat.message_manager.message_manager import message_manager
# 获取聊天流的上下文
stream_context = message_manager.stream_contexts.get(chat_id)
if stream_context:
from src.plugin_system.apis.chat_api import get_chat_manager
chat_manager = get_chat_manager()
chat_stream = chat_manager.get_stream(chat_id)
if chat_stream:
stream_context = chat_stream.context_manager
# 使用真正的已读和未读消息
read_messages = stream_context.history_messages # 已读消息
unread_messages = stream_context.get_unread_messages() # 未读消息
@@ -715,7 +718,7 @@ class DefaultReplyer:
# 构建已读历史消息 prompt
read_history_prompt = ""
if read_messages:
read_content = build_readable_messages(
read_content = await build_readable_messages(
[msg.flatten() for msg in read_messages[-50:]], # 限制数量
replace_bot_name=True,
timestamp_mode="normal_no_YMD",
@@ -738,7 +741,7 @@ class DefaultReplyer:
]
if filtered_fallback_messages:
read_content = build_readable_messages(
read_content = await build_readable_messages(
filtered_fallback_messages,
replace_bot_name=True,
timestamp_mode="normal_no_YMD",
@@ -776,7 +779,7 @@ class DefaultReplyer:
if platform and user_id:
person_id = PersonInfoManager.get_person_id(platform, user_id)
person_info_manager = get_person_info_manager()
sender_name = person_info_manager.get_value_sync(person_id, "person_name") or "未知用户"
sender_name = person_info_manager.get_value(person_id, "person_name") or "未知用户"
else:
sender_name = "未知用户"
@@ -841,7 +844,7 @@ class DefaultReplyer:
# 构建已读历史消息 prompt
read_history_prompt = ""
if read_messages:
read_content = build_readable_messages(
read_content = await build_readable_messages(
read_messages[-50:],
replace_bot_name=True,
timestamp_mode="normal_no_YMD",
@@ -875,7 +878,7 @@ class DefaultReplyer:
if platform and user_id:
person_id = PersonInfoManager.get_person_id(platform, user_id)
person_info_manager = get_person_info_manager()
sender_name = person_info_manager.get_value_sync(person_id, "person_name") or "未知用户"
sender_name = person_info_manager.get_value(person_id, "person_name") or "未知用户"
else:
sender_name = "未知用户"
@@ -1087,7 +1090,7 @@ class DefaultReplyer:
# 检查是否是bot自己的名字如果是则替换为"(你)"
bot_user_id = str(global_config.bot.qq_account)
current_user_id = person_info_manager.get_value_sync(person_id, "user_id")
current_user_id = person_info_manager.get_value(person_id, "user_id")
current_platform = reply_message.get("chat_info_platform")
if current_user_id == bot_user_id and current_platform == global_config.bot.platform:
@@ -1125,7 +1128,7 @@ class DefaultReplyer:
target = "(无消息内容)"
person_info_manager = get_person_info_manager()
person_id = person_info_manager.get_person_id(platform, reply_message.get("user_id")) if reply_message else None
person_id = await person_info_manager.get_person_id_by_person_name(sender)
platform = chat_stream.platform
target = replace_user_references_sync(target, chat_stream.platform, replace_bot_name=True)

View File

@@ -45,7 +45,7 @@ def replace_user_references_sync(
return f"{global_config.bot.nickname}(你)"
person_id = PersonInfoManager.get_person_id(platform, user_id)
return person_info_manager.get_value(person_id, "person_name") or user_id # type: ignore
name_resolver = default_resolver
# 处理回复<aaa:bbb>格式
@@ -272,20 +272,19 @@ async def get_actions_by_timestamp_with_chat(
async with get_db_session() as session:
if limit > 0:
if limit_mode == "latest":
query = await session.execute(
result = await session.execute(
select(ActionRecords)
.where(
and_(
ActionRecords.chat_id == chat_id,
ActionRecords.time > timestamp_start,
ActionRecords.time < timestamp_end,
ActionRecords.time >= timestamp_start,
ActionRecords.time <= timestamp_end,
)
)
.order_by(ActionRecords.time.desc())
.limit(limit)
)
actions = list(query.scalars())
actions = list(result.scalars())
actions_result = []
for action in reversed(actions):
action_dict = {
@@ -302,38 +301,39 @@ async def get_actions_by_timestamp_with_chat(
"chat_info_platform": action.chat_info_platform,
}
actions_result.append(action_dict)
else: # earliest
query = await session.execute(
select(ActionRecords)
.where(
and_(
ActionRecords.chat_id == chat_id,
ActionRecords.time > timestamp_start,
ActionRecords.time < timestamp_end,
)
)
.order_by(ActionRecords.time.asc())
.limit(limit)
)
actions = list(query.scalars())
actions_result = []
for action in actions:
action_dict = {
"id": action.id,
"action_id": action.action_id,
"time": action.time,
"action_name": action.action_name,
"action_data": action.action_data,
"action_done": action.action_done,
"action_build_into_prompt": action.action_build_into_prompt,
"action_prompt_display": action.action_prompt_display,
"chat_id": action.chat_id,
"chat_info_stream_id": action.chat_info_stream_id,
"chat_info_platform": action.chat_info_platform,
}
actions_result.append(action_dict)
else: # earliest
result = await session.execute(
select(ActionRecords)
.where(
and_(
ActionRecords.chat_id == chat_id,
ActionRecords.time > timestamp_start,
ActionRecords.time < timestamp_end,
)
)
.order_by(ActionRecords.time.asc())
.limit(limit)
)
actions = list(result.scalars())
actions_result = []
for action in actions:
action_dict = {
"id": action.id,
"action_id": action.action_id,
"time": action.time,
"action_name": action.action_name,
"action_data": action.action_data,
"action_done": action.action_done,
"action_build_into_prompt": action.action_build_into_prompt,
"action_prompt_display": action.action_prompt_display,
"chat_id": action.chat_id,
"chat_info_stream_id": action.chat_info_stream_id,
"chat_info_platform": action.chat_info_platform,
}
actions_result.append(action_dict)
else:
query = await session.execute(
result = await session.execute(
select(ActionRecords)
.where(
and_(
@@ -344,7 +344,7 @@ async def get_actions_by_timestamp_with_chat(
)
.order_by(ActionRecords.time.asc())
)
actions = list(query.scalars())
actions = list(result.scalars())
actions_result = []
for action in actions:
action_dict = {
@@ -371,7 +371,7 @@ async def get_actions_by_timestamp_with_chat_inclusive(
async with get_db_session() as session:
if limit > 0:
if limit_mode == "latest":
query = await session.execute(
result = await session.execute(
select(ActionRecords)
.where(
and_(
@@ -383,10 +383,10 @@ async def get_actions_by_timestamp_with_chat_inclusive(
.order_by(ActionRecords.time.desc())
.limit(limit)
)
actions = list(query.scalars())
actions = list(result.scalars())
return [action.__dict__ for action in reversed(actions)]
else: # earliest
query = await session.execute(
result = await session.execute(
select(ActionRecords)
.where(
and_(
@@ -626,8 +626,7 @@ async def _build_readable_messages_internal(
if replace_bot_name and user_id == global_config.bot.qq_account:
person_name = f"{global_config.bot.nickname}(你)"
else:
person_info = await person_info_manager.get_values(person_id, ["person_name"])
person_name = person_info.get("person_name") # type: ignore
person_name = await person_info_manager.get_value(person_id, "person_name") # type: ignore
# 如果 person_name 未设置,则使用消息中的 nickname 或默认名称
if not person_name:
@@ -828,8 +827,8 @@ async def build_pic_mapping_info(pic_id_mapping: Dict[str, str]) -> str:
# 从数据库中获取图片描述
description = "[图片内容未知]" # 默认描述
try:
with get_db_session() as session:
result = session.execute(select(Images).where(Images.image_id == pic_id))
async with get_db_session() as session:
result = await session.execute(select(Images).where(Images.image_id == pic_id))
image = result.scalar_one_or_none()
if image and image.description: # type: ignore
description = image.description
@@ -965,6 +964,12 @@ async def build_readable_messages_with_id(
message_id_list=message_id_list,
)
# 如果存在图片映射信息,附加之
if pic_mapping_info := await build_pic_mapping_info({}):
# 如果当前没有图片映射则不附加
if pic_mapping_info:
formatted_string = f"{pic_mapping_info}\n\n{formatted_string}"
return formatted_string, message_id_list
@@ -1011,27 +1016,24 @@ async def build_readable_messages(
async with get_db_session() as session:
# 获取这个时间范围内的动作记录并匹配chat_id
actions_in_range = (
await session.execute(
select(ActionRecords)
.where(
and_(
ActionRecords.time >= min_time, ActionRecords.time <= max_time, ActionRecords.chat_id == chat_id
)
actions_in_range = (await session.execute(
select(ActionRecords)
.where(
and_(
ActionRecords.time >= min_time, ActionRecords.time <= max_time, ActionRecords.chat_id == chat_id
)
.order_by(ActionRecords.time)
)
).scalars()
.order_by(ActionRecords.time)
)).scalars()
# 获取最新消息之后的第一个动作记录
action_after_latest = (
await session.execute(
select(ActionRecords)
.where(and_(ActionRecords.time > max_time, ActionRecords.chat_id == chat_id))
.order_by(ActionRecords.time)
.limit(1)
)
).scalars()
action_after_latest = (await session.execute(
select(ActionRecords)
.where(and_(ActionRecords.time > max_time, ActionRecords.chat_id == chat_id))
.order_by(ActionRecords.time)
.limit(1)
)).scalars()
# 合并两部分动作记录,并转为 dict避免 DetachedInstanceError
actions = [

View File

@@ -498,7 +498,7 @@ class Prompt:
chat_history = ""
if self.parameters.message_list_before_now_long:
recent_messages = self.parameters.message_list_before_now_long[-10:]
chat_history = build_readable_messages(
chat_history = await build_readable_messages(
recent_messages, replace_bot_name=True, timestamp_mode="normal", truncate=True
)
@@ -539,7 +539,7 @@ class Prompt:
chat_history = ""
if self.parameters.message_list_before_now_long:
recent_messages = self.parameters.message_list_before_now_long[-20:]
chat_history = build_readable_messages(
chat_history = await build_readable_messages(
recent_messages, replace_bot_name=True, timestamp_mode="normal", truncate=True
)
@@ -593,7 +593,7 @@ class Prompt:
chat_history = ""
if self.parameters.message_list_before_now_long:
recent_messages = self.parameters.message_list_before_now_long[-15:]
chat_history = build_readable_messages(
chat_history = await build_readable_messages(
recent_messages, replace_bot_name=True, timestamp_mode="normal", truncate=True
)
@@ -867,7 +867,7 @@ class Prompt:
# 获取用户ID
person_info_manager = get_person_info_manager()
person_id = person_info_manager.get_person_id_by_person_name(sender)
person_id = await person_info_manager.get_person_id_by_person_name(sender)
if not person_id:
logger.warning(f"未找到用户 {sender} 的ID跳过信息提取")
return f"你完全不认识{sender}不理解ta的相关信息。"
@@ -908,7 +908,7 @@ class Prompt:
return ""
@staticmethod
def parse_reply_target_id(reply_to: str) -> str:
async def parse_reply_target_id(reply_to: str) -> str:
"""
解析回复目标中的用户ID
@@ -928,7 +928,7 @@ class Prompt:
# 获取用户ID
person_info_manager = get_person_info_manager()
person_id = person_info_manager.get_person_id_by_person_name(sender)
person_id = await person_info_manager.get_person_id_by_person_name(sender)
if person_id:
user_id = person_info_manager.get_value(person_id, "user_id")
return str(user_id) if user_id else ""

View File

@@ -1,3 +1,4 @@
import asyncio
import random
import re
import string
@@ -667,10 +668,32 @@ async def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Di
person_id = person.person_id
person_name = None
if person_id:
# get_value is async, so await it directly
person_info_manager = get_person_info_manager()
person_data = await person_info_manager.get_values(person_id, ["person_name"])
person_name = person_data.get("person_name")
try:
# 如果没有运行的事件循环,直接 asyncio.run
loop = asyncio.get_event_loop()
if loop.is_running():
# 如果事件循环在运行,从其他线程提交并等待结果
try:
from concurrent.futures import TimeoutError
fut = asyncio.run_coroutine_threadsafe(
person_info_manager.get_value(person_id, "person_name"), loop
)
person_name = fut.result(timeout=2)
except Exception as e:
# 无法在运行循环上安全等待,退回为 None
logger.debug(f"无法通过运行的事件循环获取 person_name: {e}")
person_name = None
else:
person_name = asyncio.run(person_info_manager.get_value(person_id, "person_name"))
except RuntimeError:
# get_event_loop 在某些上下文可能抛出 RuntimeError退回到 asyncio.run
try:
person_name = asyncio.run(person_info_manager.get_value(person_id, "person_name"))
except Exception as e:
logger.debug(f"获取 person_name 失败: {e}")
person_name = None
target_info["person_id"] = person_id
target_info["person_name"] = person_name