refactor(chat): 重构消息管理器以使用集中式上下文管理和能量系统

- 将流上下文管理从MessageManager迁移到专门的ContextManager
- 使用统一的能量系统计算focus_energy和分发间隔
- 重构ChatStream的消息数据转换逻辑,支持更完整的数据字段
- 更新数据库模型,移除interest_degree字段,统一使用interest_value
- 集成新的兴趣度管理系统替代原有的评分系统
- 添加消息存储的interest_value修复功能
This commit is contained in:
Windpicker-owo
2025-09-27 14:23:48 +08:00
parent 5962b44294
commit 1177b81285
15 changed files with 3520 additions and 506 deletions

View File

@@ -368,41 +368,30 @@ class ChatterPlanFilter:
interest_scores = {}
try:
from src.plugins.built_in.affinity_flow_chatter.interest_scoring import (
chatter_interest_scoring_system as interest_scoring_system,
)
from src.common.data_models.database_data_model import DatabaseMessages
from src.chat.interest_system import interest_manager
# 转换消息格式
db_messages = []
# 使用新的兴趣度管理系统计算评分
for msg_dict in messages:
try:
db_msg = DatabaseMessages(
message_id=msg_dict.get("message_id", ""),
time=msg_dict.get("time", time.time()),
chat_id=msg_dict.get("chat_id", ""),
processed_plain_text=msg_dict.get("processed_plain_text", ""),
user_id=msg_dict.get("user_id", ""),
user_nickname=msg_dict.get("user_nickname", ""),
user_platform=msg_dict.get("platform", "qq"),
chat_info_group_id=msg_dict.get("group_id", ""),
chat_info_group_name=msg_dict.get("group_name", ""),
chat_info_group_platform=msg_dict.get("platform", "qq"),
# 构建计算上下文
calc_context = {
"stream_id": msg_dict.get("chat_id", ""),
"user_id": msg_dict.get("user_id"),
}
# 计算消息兴趣度
interest_score = interest_manager.calculate_message_interest(
message=msg_dict,
context=calc_context
)
db_messages.append(db_msg)
# 构建兴趣度字典
interest_scores[msg_dict.get("message_id", "")] = interest_score
except Exception as e:
logger.warning(f"转换消息格式失败: {e}")
logger.warning(f"计算消息兴趣度失败: {e}")
continue
# 计算兴趣度评分
if db_messages:
bot_nickname = global_config.bot.nickname or "麦麦"
scores = await interest_scoring_system.calculate_interest_scores(db_messages, bot_nickname)
# 构建兴趣度字典
for score in scores:
interest_scores[score.message_id] = score.total_score
except Exception as e:
logger.warning(f"获取兴趣度评分失败: {e}")

View File

@@ -4,13 +4,13 @@
"""
from dataclasses import asdict
import time
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
from src.plugins.built_in.affinity_flow_chatter.plan_executor import ChatterPlanExecutor
from src.plugins.built_in.affinity_flow_chatter.plan_filter import ChatterPlanFilter
from src.plugins.built_in.affinity_flow_chatter.plan_generator import ChatterPlanGenerator
from src.plugins.built_in.affinity_flow_chatter.interest_scoring import ChatterInterestScoringSystem
from src.plugins.built_in.affinity_flow_chatter.relationship_tracker import ChatterRelationshipTracker
from src.chat.interest_system import interest_manager
from src.mood.mood_manager import mood_manager
@@ -52,14 +52,7 @@ class ChatterActionPlanner:
self.generator = ChatterPlanGenerator(chat_id)
self.executor = ChatterPlanExecutor(action_manager)
# 初始化兴趣度评分系统
self.interest_scoring = ChatterInterestScoringSystem()
# 创建新的关系追踪器
self.relationship_tracker = ChatterRelationshipTracker(self.interest_scoring)
# 设置执行器的关系追踪器
self.executor.set_relationship_tracker(self.relationship_tracker)
# 使用新的统一兴趣度管理系统
# 规划器统计
self.planner_stats = {
@@ -107,51 +100,39 @@ class ChatterActionPlanner:
initial_plan.available_actions = self.action_manager.get_using_actions()
unread_messages = context.get_unread_messages() if context else []
# 2. 兴趣度评分 - 只对未读消息进行评分
# 2. 使用新的兴趣度管理系统进行评分
score = 0.0
should_reply = False
reply_not_available = False
if unread_messages:
bot_nickname = global_config.bot.nickname
interest_scores = await self.interest_scoring.calculate_interest_scores(unread_messages, bot_nickname)
# 获取用户ID
user_id = None
if unread_messages[0].user_id:
user_id = unread_messages[0].user_id
# 3. 根据兴趣度调整可用动作
if interest_scores:
latest_score = max(interest_scores, key=lambda s: s.total_score)
latest_message = next(
(msg for msg in unread_messages if msg.message_id == latest_score.message_id), None
)
should_reply, score = self.interest_scoring.should_reply(latest_score, latest_message)
# 构建计算上下文
calc_context = {
"stream_id": self.chat_id,
"user_id": user_id,
}
reply_not_available = False
if not should_reply and "reply" in initial_plan.available_actions:
logger.info(f"兴趣度不足 ({latest_score.total_score:.2f}),移除回复")
reply_not_available = True
# 更新ChatStream的兴趣度数据
from src.plugin_system.apis.chat_api import get_chat_manager
chat_stream = get_chat_manager().get_stream(self.chat_id)
logger.debug(f"已更新聊天 {self.chat_id} 的ChatStream兴趣度分数: {score:.3f}")
# 更新情绪状态和ChatStream兴趣度数据
if latest_message and score > 0:
chat_mood = mood_manager.get_mood_by_chat_id(self.chat_id)
await chat_mood.update_mood_by_message(latest_message, score)
logger.debug(f"已更新聊天 {self.chat_id} 的情绪状态,兴趣度: {score:.3f}")
elif latest_message:
# 即使不更新情绪状态也要更新ChatStream的兴趣度数据
chat_mood = mood_manager.get_mood_by_chat_id(self.chat_id)
if hasattr(chat_mood, 'chat_stream') and chat_mood.chat_stream:
chat_mood.chat_stream.add_message_interest(score)
# 在这里同步更新 focus_energy
chat_mood.chat_stream.update_focus_energy()
logger.debug(f"已更新聊天 {self.chat_id} 的ChatStream兴趣度和Focus Energy分数: {score:.3f}")
# 为所有未读消息记录兴趣度信息
# 为每条消息计算兴趣度
for message in unread_messages:
# 查找对应的兴趣度评分
message_score = next((s for s in interest_scores if s.message_id == message.message_id), None)
if message_score:
message.interest_degree = message_score.total_score
message.should_reply = self.interest_scoring.should_reply(message_score, message)[0]
logger.debug(f"已记录消息 {message.message_id} - 兴趣度: {message_score.total_score:.3f}, 应回复: {message.should_reply}")
try:
# 使用新的兴趣度管理器计算
message_interest = interest_manager.calculate_message_interest(
message=message.__dict__,
context=calc_context
)
# 更新消息的兴趣度
message.interest_value = message_interest
# 简单的回复决策逻辑:兴趣度超过阈值则回复
message.should_reply = message_interest > global_config.affinity_flow.non_reply_action_interest_threshold
logger.debug(f"消息 {message.message_id} 兴趣度: {message_interest:.3f}, 应回复: {message.should_reply}")
# 更新StreamContext中的消息信息并刷新focus_energy
if context:
@@ -159,25 +140,35 @@ class ChatterActionPlanner:
message_manager.update_message_and_refresh_energy(
stream_id=self.chat_id,
message_id=message.message_id,
interest_degree=message_score.total_score,
interest_value=message_interest,
should_reply=message.should_reply
)
else:
# 如果没有找到评分,设置默认值
message.interest_degree = 0.0
# 更新数据库中的消息记录
try:
from src.chat.message_receive.storage import MessageStorage
MessageStorage.update_message_interest_value(message.message_id, message_interest)
logger.debug(f"已更新数据库中消息 {message.message_id} 的兴趣度为: {message_interest:.3f}")
except Exception as e:
logger.warning(f"更新数据库消息兴趣度失败: {e}")
# 更新话题兴趣度
interest_manager.update_topic_interest(message.__dict__, message_interest)
# 记录最高分
if message_interest > score:
score = message_interest
if message.should_reply:
should_reply = True
else:
reply_not_available = True
except Exception as e:
logger.warning(f"计算消息 {message.message_id} 兴趣度失败: {e}")
# 设置默认值
message.interest_value = 0.0
message.should_reply = False
# 更新StreamContext中的消息信息并刷新focus_energy
if context:
from src.chat.message_manager.message_manager import message_manager
message_manager.update_message_and_refresh_energy(
stream_id=self.chat_id,
message_id=message.message_id,
interest_degree=0.0,
should_reply=False
)
# base_threshold = self.interest_scoring.reply_threshold
# 检查兴趣度是否达到非回复动作阈值
non_reply_action_interest_threshold = global_config.affinity_flow.non_reply_action_interest_threshold
if score < non_reply_action_interest_threshold:
@@ -199,26 +190,16 @@ class ChatterActionPlanner:
plan_filter = ChatterPlanFilter(self.chat_id, available_actions)
filtered_plan = await plan_filter.filter(reply_not_available, initial_plan)
# 检查filtered_plan是否有reply动作以便记录reply action
has_reply_action = False
for decision in filtered_plan.decided_actions:
if decision.action_type == "reply":
has_reply_action = True
self.interest_scoring.record_reply_action(has_reply_action)
# 检查filtered_plan是否有reply动作用于统计
has_reply_action = any(decision.action_type == "reply" for decision in filtered_plan.decided_actions)
# 5. 使用 PlanExecutor 执行 Plan
execution_result = await self.executor.execute(filtered_plan)
# 6. 动作记录现在由ChatterActionManager统一处理
# 动作记录逻辑已移至ChatterActionManager.execute_action方法中
# 7. 根据执行结果更新统计信息
# 6. 根据执行结果更新统计信息
self._update_stats_from_execution_result(execution_result)
# 8. 检查关系更新
await self.relationship_tracker.check_and_update_relationships()
# 8. 返回结果
# 7. 返回结果
return self._build_return_result(filtered_plan)
except Exception as e:
@@ -267,37 +248,10 @@ class ChatterActionPlanner:
return final_actions_dict, final_target_message_dict
def get_user_relationship(self, user_id: str) -> float:
"""获取用户关系分"""
return self.interest_scoring.get_user_relationship(user_id)
def update_interest_keywords(self, new_keywords: Dict[str, List[str]]):
"""更新兴趣关键词(已弃用,仅保留用于兼容性)"""
logger.info("传统关键词匹配已移除,此方法仅保留用于兼容性")
# 此方法已弃用因为现在完全使用embedding匹配
def get_planner_stats(self) -> Dict[str, any]:
"""获取规划器统计"""
return self.planner_stats.copy()
def get_interest_scoring_stats(self) -> Dict[str, any]:
"""获取兴趣度评分统计"""
return {
"no_reply_count": self.interest_scoring.no_reply_count,
"max_no_reply_count": self.interest_scoring.max_no_reply_count,
"reply_threshold": self.interest_scoring.reply_threshold,
"mention_threshold": self.interest_scoring.mention_threshold,
"user_relationships": len(self.interest_scoring.user_relationships),
}
def get_relationship_stats(self) -> Dict[str, any]:
"""获取用户关系统计"""
return {
"tracking_users": len(self.relationship_tracker.tracking_users),
"relationship_history": len(self.relationship_tracker.relationship_history),
"max_tracking_users": self.relationship_tracker.max_tracking_users,
}
def get_current_mood_state(self) -> str:
"""获取当前聊天的情绪状态"""
chat_mood = mood_manager.get_mood_by_chat_id(self.chat_id)