feat(chat): 实现批量动作存储并优化消息处理流程
新增批量动作记录存储功能,提升数据库写入性能。重构消息预处理逻辑,改进兴趣度计算和同步机制,优化用户信息和群组信息处理。添加配置选项控制批量存储开关,更新相关模板配置。
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"""
|
||||
|
||||
import time
|
||||
import orjson
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from src.chat.interest_system import bot_interest_manager
|
||||
@@ -42,6 +43,9 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
self.reply_threshold = affinity_config.reply_action_interest_threshold # 回复动作兴趣阈值
|
||||
self.mention_threshold = affinity_config.mention_bot_adjustment_threshold # 提及bot后的调整阈值
|
||||
|
||||
# 兴趣匹配系统配置
|
||||
self.use_smart_matching = True
|
||||
|
||||
# 连续不回复概率提升
|
||||
self.no_reply_count = 0
|
||||
self.max_no_reply_count = affinity_config.max_no_reply_count
|
||||
@@ -71,7 +75,11 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
start_time = time.time()
|
||||
message_id = getattr(message, "message_id", "")
|
||||
content = getattr(message, "processed_plain_text", "")
|
||||
user_id = getattr(message, "user_info", {}).user_id if hasattr(message, "user_info") and hasattr(message.user_info, "user_id") else ""
|
||||
user_info = getattr(message, "user_info", None)
|
||||
if user_info and hasattr(user_info, "user_id"):
|
||||
user_id = user_info.user_id
|
||||
else:
|
||||
user_id = ""
|
||||
|
||||
logger.debug(f"[Affinity兴趣计算] 开始处理消息 {message_id}")
|
||||
logger.debug(f"[Affinity兴趣计算] 消息内容: {content[:50]}...")
|
||||
@@ -111,10 +119,18 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
logger.debug(f"[Affinity兴趣计算] 应用不回复提升后: {total_score:.3f} → {adjusted_score:.3f}")
|
||||
|
||||
# 6. 决定是否回复和执行动作
|
||||
should_reply = adjusted_score > self.reply_threshold
|
||||
should_take_action = adjusted_score > (self.reply_threshold + 0.1)
|
||||
logger.debug(f"[Affinity兴趣计算] 阈值判断: {adjusted_score:.3f} > 回复阈值:{self.reply_threshold:.3f}? = {should_reply}")
|
||||
logger.debug(f"[Affinity兴趣计算] 阈值判断: {adjusted_score:.3f} > 动作阈值:{self.reply_threshold + 0.1:.3f}? = {should_take_action}")
|
||||
reply_threshold = self.reply_threshold
|
||||
action_threshold = global_config.affinity_flow.non_reply_action_interest_threshold
|
||||
|
||||
should_reply = adjusted_score >= reply_threshold
|
||||
should_take_action = adjusted_score >= action_threshold
|
||||
|
||||
logger.debug(
|
||||
f"[Affinity兴趣计算] 阈值判断: {adjusted_score:.3f} >= 回复阈值:{reply_threshold:.3f}? = {should_reply}"
|
||||
)
|
||||
logger.debug(
|
||||
f"[Affinity兴趣计算] 阈值判断: {adjusted_score:.3f} >= 动作阈值:{action_threshold:.3f}? = {should_take_action}"
|
||||
)
|
||||
|
||||
calculation_time = time.time() - start_time
|
||||
|
||||
@@ -140,7 +156,7 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
error_message=str(e)
|
||||
)
|
||||
|
||||
async def _calculate_interest_match_score(self, content: str, keywords: list[str] = None) -> float:
|
||||
async def _calculate_interest_match_score(self, content: str, keywords: list[str] | None = None) -> float:
|
||||
"""计算兴趣匹配度(使用智能兴趣匹配系统)"""
|
||||
|
||||
# 调试日志:检查各个条件
|
||||
@@ -158,7 +174,7 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
|
||||
try:
|
||||
# 使用机器人的兴趣标签系统进行智能匹配
|
||||
match_result = await bot_interest_manager.calculate_interest_match(content, keywords)
|
||||
match_result = await bot_interest_manager.calculate_interest_match(content, keywords or [])
|
||||
logger.debug(f"兴趣匹配结果: {match_result}")
|
||||
|
||||
if match_result:
|
||||
@@ -241,7 +257,6 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
key_words = getattr(message, "key_words", "")
|
||||
if key_words:
|
||||
try:
|
||||
import orjson
|
||||
extracted = orjson.loads(key_words)
|
||||
if isinstance(extracted, list):
|
||||
keywords = extracted
|
||||
@@ -253,7 +268,6 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
key_words_lite = getattr(message, "key_words_lite", "")
|
||||
if key_words_lite:
|
||||
try:
|
||||
import orjson
|
||||
extracted = orjson.loads(key_words_lite)
|
||||
if isinstance(extracted, list):
|
||||
keywords = extracted
|
||||
@@ -296,6 +310,3 @@ class AffinityInterestCalculator(BaseInterestCalculator):
|
||||
self.no_reply_count = 0
|
||||
else:
|
||||
self.no_reply_count = min(self.no_reply_count + 1, self.max_no_reply_count)
|
||||
|
||||
# 是否使用智能兴趣匹配(作为类属性)
|
||||
use_smart_matching = True
|
||||
|
||||
@@ -69,6 +69,13 @@ class ChatterPlanExecutor:
|
||||
action_types = [action.action_type for action in plan.decided_actions]
|
||||
logger.info(f"选择动作: {', '.join(action_types) if action_types else '无'}")
|
||||
|
||||
# 根据配置决定是否启用批量存储模式
|
||||
if global_config.database.batch_action_storage_enabled:
|
||||
self.action_manager.enable_batch_storage(plan.chat_id)
|
||||
logger.debug("已启用批量存储模式")
|
||||
else:
|
||||
logger.debug("批量存储功能已禁用,使用立即存储模式")
|
||||
|
||||
execution_results = []
|
||||
reply_actions = []
|
||||
other_actions = []
|
||||
@@ -102,6 +109,9 @@ class ChatterPlanExecutor:
|
||||
f"规划执行完成: 总数={len(plan.decided_actions)}, 成功={successful_count}, 失败={len(execution_results) - successful_count}"
|
||||
)
|
||||
|
||||
# 批量存储所有待处理的动作
|
||||
await self._flush_action_manager_batch_storage(plan)
|
||||
|
||||
return {
|
||||
"executed_count": len(plan.decided_actions),
|
||||
"successful_count": successful_count,
|
||||
@@ -395,6 +405,7 @@ class ChatterPlanExecutor:
|
||||
# 移除执行时间列表以避免返回过大数据
|
||||
stats.pop("execution_times", None)
|
||||
|
||||
|
||||
return stats
|
||||
|
||||
def reset_stats(self):
|
||||
@@ -422,3 +433,26 @@ class ChatterPlanExecutor:
|
||||
}
|
||||
for i, time_val in enumerate(recent_times)
|
||||
]
|
||||
|
||||
|
||||
async def _flush_action_manager_batch_storage(self, plan: Plan):
|
||||
"""使用 action_manager 的批量存储功能存储所有待处理的动作"""
|
||||
try:
|
||||
# 通过 chat_id 获取真实的 chat_stream 对象
|
||||
from src.plugin_system.apis.chat_api import get_chat_manager
|
||||
chat_manager = get_chat_manager()
|
||||
chat_stream = chat_manager.get_stream(plan.chat_id)
|
||||
|
||||
if chat_stream:
|
||||
# 调用 action_manager 的批量存储
|
||||
await self.action_manager.flush_batch_storage(chat_stream)
|
||||
logger.info("批量存储完成:通过 action_manager 存储所有动作记录")
|
||||
|
||||
# 禁用批量存储模式
|
||||
self.action_manager.disable_batch_storage()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"批量存储动作记录时发生错误: {e}")
|
||||
# 确保在出错时也禁用批量存储模式
|
||||
self.action_manager.disable_batch_storage()
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from src.mood.mood_manager import mood_manager
|
||||
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.plugin_system.base.component_types import ChatMode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.chat.planner_actions.action_manager import ChatterActionManager
|
||||
@@ -60,7 +61,7 @@ class ChatterActionPlanner:
|
||||
"other_actions_executed": 0,
|
||||
}
|
||||
|
||||
async def plan(self, context: "StreamContext" = None) -> tuple[list[dict], dict | None]:
|
||||
async def plan(self, context: "StreamContext | None" = None) -> tuple[list[dict[str, Any]], Any | None]:
|
||||
"""
|
||||
执行完整的增强版规划流程。
|
||||
|
||||
@@ -82,7 +83,7 @@ class ChatterActionPlanner:
|
||||
self.planner_stats["failed_plans"] += 1
|
||||
return [], None
|
||||
|
||||
async def _enhanced_plan_flow(self, context: "StreamContext") -> tuple[list[dict], dict | None]:
|
||||
async def _enhanced_plan_flow(self, context: "StreamContext | None") -> tuple[list[dict[str, Any]], Any | None]:
|
||||
"""执行增强版规划流程"""
|
||||
try:
|
||||
# 在规划前,先进行动作修改
|
||||
@@ -92,39 +93,48 @@ class ChatterActionPlanner:
|
||||
await action_modifier.modify_actions()
|
||||
|
||||
# 1. 生成初始 Plan
|
||||
initial_plan = await self.generator.generate(context.chat_mode)
|
||||
chat_mode = context.chat_mode if context else ChatMode.NORMAL
|
||||
initial_plan = await self.generator.generate(chat_mode)
|
||||
|
||||
# 确保Plan中包含所有当前可用的动作
|
||||
initial_plan.available_actions = self.action_manager.get_using_actions()
|
||||
|
||||
unread_messages = context.get_unread_messages() if context else []
|
||||
# 2. 使用新的兴趣度管理系统进行评分
|
||||
message_interest = 0.0
|
||||
reply_not_available = False
|
||||
max_message_interest = 0.0
|
||||
reply_not_available = True
|
||||
interest_updates: list[dict[str, Any]] = []
|
||||
message_should_act = False
|
||||
message_should_reply = False
|
||||
aggregate_should_act = False
|
||||
aggregate_should_reply = False
|
||||
|
||||
if unread_messages:
|
||||
# 直接使用消息中已计算的标志,无需重复计算兴趣值
|
||||
for message in unread_messages:
|
||||
try:
|
||||
message_interest = getattr(message, "interest_value", 0.3)
|
||||
raw_interest = getattr(message, "interest_value", 0.3)
|
||||
if raw_interest is None:
|
||||
raw_interest = 0.0
|
||||
|
||||
message_interest = float(raw_interest)
|
||||
max_message_interest = max(max_message_interest, message_interest)
|
||||
message_should_reply = getattr(message, "should_reply", False)
|
||||
message_should_act = getattr(message, "should_act", False)
|
||||
|
||||
if not message_should_reply:
|
||||
reply_not_available = True
|
||||
|
||||
# 如果should_act为false,强制设为no_action
|
||||
if not message_should_act:
|
||||
reply_not_available = True
|
||||
|
||||
logger.debug(
|
||||
f"消息 {message.message_id} 预计算标志: interest={message_interest:.3f}, "
|
||||
f"should_reply={message_should_reply}, should_act={message_should_act}"
|
||||
)
|
||||
|
||||
if message_should_reply:
|
||||
aggregate_should_reply = True
|
||||
aggregate_should_act = True
|
||||
reply_not_available = False
|
||||
break
|
||||
|
||||
if message_should_act:
|
||||
aggregate_should_act = True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"处理消息 {message.message_id} 失败: {e}")
|
||||
message.interest_value = 0.0
|
||||
@@ -144,14 +154,18 @@ class ChatterActionPlanner:
|
||||
|
||||
# 检查兴趣度是否达到非回复动作阈值
|
||||
non_reply_action_interest_threshold = global_config.affinity_flow.non_reply_action_interest_threshold
|
||||
if not message_should_act:
|
||||
logger.info(f"兴趣度 {message_interest:.3f} 低于阈值 {non_reply_action_interest_threshold:.3f},不执行动作")
|
||||
if not aggregate_should_act:
|
||||
logger.info("所有未读消息低于兴趣度阈值,不执行动作")
|
||||
# 直接返回 no_action
|
||||
from src.common.data_models.info_data_model import ActionPlannerInfo
|
||||
|
||||
no_action = ActionPlannerInfo(
|
||||
action_type="no_action",
|
||||
reasoning=f"兴趣度评分 {message_interest:.3f} 未达阈值 {non_reply_action_interest_threshold:.3f}",
|
||||
reasoning=(
|
||||
"所有未读消息兴趣度未达阈值 "
|
||||
f"{non_reply_action_interest_threshold:.3f}"
|
||||
f"(最高兴趣度 {max_message_interest:.3f})"
|
||||
),
|
||||
action_data={},
|
||||
action_message=None,
|
||||
)
|
||||
@@ -204,7 +218,7 @@ class ChatterActionPlanner:
|
||||
except Exception as e:
|
||||
logger.warning(f"批量更新数据库兴趣度失败: {e}")
|
||||
|
||||
def _update_stats_from_execution_result(self, execution_result: dict[str, any]):
|
||||
def _update_stats_from_execution_result(self, execution_result: dict[str, Any]):
|
||||
"""根据执行结果更新规划器统计"""
|
||||
if not execution_result:
|
||||
return
|
||||
@@ -228,7 +242,7 @@ class ChatterActionPlanner:
|
||||
self.planner_stats["replies_generated"] += reply_count
|
||||
self.planner_stats["other_actions_executed"] += other_count
|
||||
|
||||
def _build_return_result(self, plan: "Plan") -> tuple[list[dict], dict | None]:
|
||||
def _build_return_result(self, plan: "Plan") -> tuple[list[dict[str, Any]], Any | None]:
|
||||
"""构建返回结果"""
|
||||
final_actions = plan.decided_actions or []
|
||||
final_target_message = next((act.action_message for act in final_actions if act.action_message), None)
|
||||
@@ -245,7 +259,7 @@ class ChatterActionPlanner:
|
||||
|
||||
return final_actions_dict, final_target_message_dict
|
||||
|
||||
def get_planner_stats(self) -> dict[str, any]:
|
||||
def get_planner_stats(self) -> dict[str, Any]:
|
||||
"""获取规划器统计"""
|
||||
return self.planner_stats.copy()
|
||||
|
||||
@@ -254,7 +268,7 @@ class ChatterActionPlanner:
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(self.chat_id)
|
||||
return chat_mood.mood_state
|
||||
|
||||
def get_mood_stats(self) -> dict[str, any]:
|
||||
def get_mood_stats(self) -> dict[str, Any]:
|
||||
"""获取情绪状态统计"""
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(self.chat_id)
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user