diff --git a/src/chat/chatter_manager.py b/src/chat/chatter_manager.py index cab8c1b71..c906fd901 100644 --- a/src/chat/chatter_manager.py +++ b/src/chat/chatter_manager.py @@ -99,8 +99,7 @@ class ChatterManager: raise ValueError(f"No chatter registered for chat type {chat_type}") if stream_id not in self.instances: - planner = ActionPlanner(stream_id, self.action_manager) - self.instances[stream_id] = chatter_class(stream_id=stream_id, planner=planner, action_manager=self.action_manager) + self.instances[stream_id] = chatter_class(stream_id=stream_id, action_manager=self.action_manager) logger.info(f"创建新的聊天流实例: {stream_id} 使用 {chatter_class.__name__} (类型: {chat_type.value})") self.stats["streams_processed"] += 1 diff --git a/src/chat/message_manager/message_manager.py b/src/chat/message_manager/message_manager.py index c012691e1..d20c67321 100644 --- a/src/chat/message_manager/message_manager.py +++ b/src/chat/message_manager/message_manager.py @@ -13,6 +13,7 @@ from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.message_manager_data_model import StreamContext, MessageManagerStats, StreamStats from src.chat.chatter_manager import ChatterManager from src.chat.planner_actions.action_manager import ChatterActionManager +from src.plugin_system.base.component_types import ChatMode if TYPE_CHECKING: from src.common.data_models.message_manager_data_model import StreamContext @@ -72,6 +73,7 @@ class MessageManager: self.stats.total_streams += 1 context = self.stream_contexts[stream_id] + context.set_chat_mode(ChatMode.FOCUS) context.add_message(message) logger.debug(f"添加消息到聊天流 {stream_id}: {message.message_id}") diff --git a/src/common/data_models/info_data_model.py b/src/common/data_models/info_data_model.py index 5351ab76a..ba45ab3c4 100644 --- a/src/common/data_models/info_data_model.py +++ b/src/common/data_models/info_data_model.py @@ -1,5 +1,7 @@ from dataclasses import dataclass, field from typing import Optional, Dict, List, TYPE_CHECKING + +from src.plugin_system.base.component_types import ChatType from . import BaseDataModel if TYPE_CHECKING: @@ -46,6 +48,7 @@ class Plan(BaseDataModel): chat_id: str mode: "ChatMode" + chat_type: "ChatType" # Generator 填充 available_actions: Dict[str, "ActionInfo"] = field(default_factory=dict) chat_history: List["DatabaseMessages"] = field(default_factory=list) diff --git a/src/common/data_models/message_manager_data_model.py b/src/common/data_models/message_manager_data_model.py index 5ba8d6c42..5ba25c5ec 100644 --- a/src/common/data_models/message_manager_data_model.py +++ b/src/common/data_models/message_manager_data_model.py @@ -10,7 +10,7 @@ from enum import Enum from typing import List, Optional, TYPE_CHECKING from . import BaseDataModel -from src.plugin_system.base.component_types import ChatType +from src.plugin_system.base.component_types import ChatMode, ChatType if TYPE_CHECKING: from .database_data_model import DatabaseMessages @@ -30,6 +30,7 @@ class StreamContext(BaseDataModel): stream_id: str chat_type: ChatType = ChatType.PRIVATE # 聊天类型,默认为私聊 + chat_mode: ChatMode = ChatMode.NORMAL # 聊天模式,默认为普通模式 unread_messages: List["DatabaseMessages"] = field(default_factory=list) history_messages: List["DatabaseMessages"] = field(default_factory=list) last_check_time: float = field(default_factory=time.time) @@ -60,6 +61,10 @@ class StreamContext(BaseDataModel): """手动更新聊天类型""" self.chat_type = chat_type + def set_chat_mode(self, chat_mode: ChatMode): + """设置聊天模式""" + self.chat_mode = chat_mode + def is_group_chat(self) -> bool: """检查是否为群聊""" return self.chat_type == ChatType.GROUP @@ -89,7 +94,7 @@ class StreamContext(BaseDataModel): self.history_messages.append(msg) self.unread_messages.remove(msg) break - + def get_history_messages(self, limit: int = 20) -> List["DatabaseMessages"]: """获取历史消息""" # 优先返回最近的历史消息和所有未读消息 diff --git a/src/plugin_system/base/base_chatter.py b/src/plugin_system/base/base_chatter.py index a803d15e5..1bdb79c31 100644 --- a/src/plugin_system/base/base_chatter.py +++ b/src/plugin_system/base/base_chatter.py @@ -15,17 +15,15 @@ class BaseChatter(ABC): """Chatter组件的描述""" chat_types: List[ChatType] = [ChatType.PRIVATE, ChatType.GROUP] - def __init__(self, stream_id: str, planner: 'ActionPlanner', action_manager: 'ChatterActionManager'): + def __init__(self, stream_id: str, action_manager: 'ChatterActionManager'): """ 初始化聊天处理器 Args: stream_id: 聊天流ID - planner: 动作规划器 action_manager: 动作管理器 """ self.stream_id = stream_id - self.planner = planner self.action_manager = action_manager @abstractmethod diff --git a/src/plugin_system/base/component_types.py b/src/plugin_system/base/component_types.py index 4d8454da9..3fc943bd5 100644 --- a/src/plugin_system/base/component_types.py +++ b/src/plugin_system/base/component_types.py @@ -40,9 +40,8 @@ class ActionActivationType(Enum): # 聊天模式枚举 class ChatMode(Enum): """聊天模式枚举""" - - GROUP = "group" # 群聊模式 - PRIVATE = "private" # 私聊模式 + + FOCUS = "focus" # 专注模式 NORMAL = "normal" # Normal聊天模式 PROACTIVE = "proactive" # 主动思考模式 PRIORITY = "priority" # 优先级聊天模式 diff --git a/src/plugins/built_in/affinity_flow_chatter/__init__.py b/src/plugins/built_in/affinity_flow_chatter/__init__.py index b41def533..bc8ebb733 100644 --- a/src/plugins/built_in/affinity_flow_chatter/__init__.py +++ b/src/plugins/built_in/affinity_flow_chatter/__init__.py @@ -4,4 +4,4 @@ from .plugin import AffinityChatterPlugin -__all__ = ["AffinityChatterPlugin"] \ No newline at end of file +__all__ = ["AffinityChatterPlugin"] diff --git a/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py b/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py index 45575a033..1e36f0dff 100644 --- a/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py +++ b/src/plugins/built_in/affinity_flow_chatter/affinity_chatter.py @@ -9,9 +9,9 @@ from datetime import datetime from typing import Dict, Any from src.plugin_system.base.base_chatter import BaseChatter -from src.plugin_system.base.component_types import ChatType, ChatMode +from src.plugin_system.base.component_types import ChatType from src.common.data_models.message_manager_data_model import StreamContext -from src.plugins.built_in.affinity_flow_chatter.planner import ChatterActionPlanner as ActionPlanner +from src.plugins.built_in.affinity_flow_chatter.planner import ChatterActionPlanner from src.chat.planner_actions.action_manager import ChatterActionManager from src.common.logger import get_logger @@ -20,11 +20,12 @@ logger = get_logger("affinity_chatter") class AffinityChatter(BaseChatter): """亲和力聊天处理器""" + chatter_name: str = "AffinityChatter" chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型" chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型 - def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ChatterActionManager): + def __init__(self, stream_id: str, action_manager: ChatterActionManager): """ 初始化亲和力聊天处理器 @@ -33,7 +34,8 @@ class AffinityChatter(BaseChatter): planner: 动作规划器 action_manager: 动作管理器 """ - super().__init__(stream_id, planner, action_manager) + super().__init__(stream_id, action_manager) + self.planner = ChatterActionPlanner(stream_id, action_manager) # 处理器统计 self.stats = { @@ -59,7 +61,7 @@ class AffinityChatter(BaseChatter): unread_messages = context.get_unread_messages() # 使用增强版规划器处理消息 - actions, target_message = await self.planner.plan(mode=ChatMode.GROUP, context=context) + actions, target_message = await self.planner.plan(context=context) self.stats["plans_created"] += 1 # 执行动作(如果规划器返回了动作) @@ -203,4 +205,4 @@ class AffinityChatter(BaseChatter): f"messages_processed={self.stats['messages_processed']}, " f"plans_created={self.stats['plans_created']}, " f"last_activity={datetime.fromtimestamp(self.last_activity_time)})" - ) \ No newline at end of file + ) diff --git a/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py b/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py index aab6978ce..221e20b00 100644 --- a/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py +++ b/src/plugins/built_in/affinity_flow_chatter/interest_scoring.py @@ -52,21 +52,16 @@ class ChatterInterestScoringSystem: user_messages = [msg for msg in messages if str(msg.user_info.user_id) != str(global_config.bot.qq_account)] if not user_messages: return [] - logger.info(f"正在为 {len(user_messages)} 条用户消息计算兴趣度...") scores = [] - for i, msg in enumerate(user_messages, 1): - logger.debug(f"[{i}/{len(user_messages)}] 处理消息 ID: {msg.message_id}") + for _, msg in enumerate(user_messages, 1): score = await self._calculate_single_message_score(msg, bot_nickname) scores.append(score) - logger.info(f"为 {len(scores)} 条消息生成了兴趣度评分。") return scores async def _calculate_single_message_score(self, message: DatabaseMessages, bot_nickname: str) -> InterestScore: """计算单条消息的兴趣度评分""" - message_preview = f"\033[96m{message.processed_plain_text[:30].replace('\n', ' ')}...\033[0m" - logger.info(f"计算消息 {message.message_id} 的分数 | 内容: {message_preview}") keywords = self._extract_keywords_from_database(message) interest_match_score = await self._calculate_interest_match_score(message.processed_plain_text, keywords) @@ -86,8 +81,7 @@ class ChatterInterestScoringSystem: } logger.info( - f"消息 {message.message_id} 得分: {total_score:.3f} " - f"(匹配: {interest_match_score:.2f}, 关系: {relationship_score:.2f}, 提及: {mentioned_score:.2f})" + f"消息得分: {total_score:.3f} (匹配: {interest_match_score:.2f}, 关系: {relationship_score:.2f}, 提及: {mentioned_score:.2f})" ) return InterestScore( @@ -109,51 +103,31 @@ class ChatterInterestScoringSystem: return await self._calculate_smart_interest_match(content, keywords) else: # 智能匹配未初始化,返回默认分数 - logger.warning("智能兴趣匹配系统未初始化,返回默认分数") return 0.3 async def _calculate_smart_interest_match(self, content: str, keywords: List[str] = None) -> float: """使用embedding计算智能兴趣匹配""" try: - logger.debug("🧠 开始智能兴趣匹配计算...") - # 如果没有传入关键词,则提取 if not keywords: - logger.debug("🔍 从内容中提取关键词...") keywords = self._extract_keywords_from_content(content) - logger.debug(f"🏷️ 提取到 {len(keywords)} 个关键词") # 使用机器人兴趣管理器计算匹配度 - logger.debug("🤖 调用机器人兴趣管理器计算匹配度...") match_result = await bot_interest_manager.calculate_interest_match(content, keywords) if match_result: - logger.debug("✅ 智能兴趣匹配成功:") - logger.debug(f" 📊 总分: {match_result.overall_score:.3f}") - logger.debug(f" 🏷️ 匹配标签: {match_result.matched_tags}") - logger.debug(f" 🎯 最佳标签: {match_result.top_tag}") - logger.debug(f" 📈 置信度: {match_result.confidence:.3f}") - logger.debug(f" 🔢 匹配详情: {match_result.match_scores}") - # 返回匹配分数,考虑置信度和匹配标签数量 affinity_config = global_config.affinity_flow match_count_bonus = min( len(match_result.matched_tags) * affinity_config.match_count_bonus, affinity_config.max_match_bonus ) final_score = match_result.overall_score * 1.15 * match_result.confidence + match_count_bonus - logger.debug( - f"⚖️ 最终分数计算: 总分({match_result.overall_score:.3f}) × 1.3 × 置信度({match_result.confidence:.3f}) + 标签数量奖励({match_count_bonus:.3f}) = {final_score:.3f}" - ) return final_score else: - logger.warning("⚠️ 智能兴趣匹配未返回结果") return 0.0 except Exception as e: - logger.error(f"❌ 智能兴趣匹配计算失败: {e}") - logger.debug("🔍 错误详情:") - logger.debug(f" 💬 内容长度: {len(content)} 字符") - logger.debug(f" 🏷️ 关键词数量: {len(keywords) if keywords else 0}") + logger.error(f"智能兴趣匹配计算失败: {e}") return 0.0 def _extract_keywords_from_database(self, message: DatabaseMessages) -> List[str]: @@ -225,8 +199,8 @@ class ChatterInterestScoringSystem: # 同时更新内存缓存 self.user_relationships[user_id] = relationship_score return relationship_score - except Exception as e: - logger.warning(f"从关系追踪器获取关系分失败: {e}") + except Exception: + pass else: # 尝试从全局关系追踪器获取 try: @@ -238,8 +212,8 @@ class ChatterInterestScoringSystem: # 同时更新内存缓存 self.user_relationships[user_id] = relationship_score return relationship_score - except Exception as e: - logger.warning(f"从全局关系追踪器获取关系分失败: {e}") + except Exception: + pass # 默认新用户的基础分 return global_config.affinity_flow.base_relationship_score @@ -261,26 +235,20 @@ class ChatterInterestScoringSystem: def should_reply(self, score: InterestScore, message: "DatabaseMessages") -> bool: """判断是否应该回复""" - message_preview = f"\033[96m{(message.processed_plain_text or 'N/A')[:50].replace('\n', ' ')}\033[0m" - logger.info(f"评估消息 {score.message_id} (得分: {score.total_score:.3f}) | 内容: '{message_preview}...'") base_threshold = self.reply_threshold # 如果被提及,降低阈值 if score.mentioned_score >= global_config.affinity_flow.mention_bot_adjustment_threshold: base_threshold = self.mention_threshold - logger.debug(f"机器人被提及, 使用较低阈值: {base_threshold:.3f}") # 计算连续不回复的概率提升 probability_boost = min(self.no_reply_count * self.probability_boost_per_no_reply, 0.8) effective_threshold = base_threshold - probability_boost - logger.debug( - f"基础阈值: {base_threshold:.3f}, 不回复提升: {probability_boost:.3f}, 有效阈值: {effective_threshold:.3f}" - ) # 做出决策 should_reply = score.total_score >= effective_threshold - decision = "✅ 回复" if should_reply else "❌ 不回复" - logger.info(f"回复决策: {decision} (分数: {score.total_score:.3f} {' >=' if should_reply else ' <'} 阈值: {effective_threshold:.3f})") + decision = "回复" if should_reply else "不回复" + logger.info(f"决策: {decision} (分数: {score.total_score:.3f})") return should_reply, score.total_score @@ -296,8 +264,7 @@ class ChatterInterestScoringSystem: # 限制最大计数 self.no_reply_count = min(self.no_reply_count, self.max_no_reply_count) - logger.info(f"记录动作: {action} | 连续不回复次数: {old_count} -> {self.no_reply_count}") - logger.debug(f"📋 最大限制: {self.max_no_reply_count} 次") + logger.info(f"{action} | 不回复次数: {old_count} -> {self.no_reply_count}") def update_user_relationship(self, user_id: str, relationship_change: float): """更新用户关系""" @@ -308,10 +275,7 @@ class ChatterInterestScoringSystem: self.user_relationships[user_id] = new_score - change_direction = "📈" if relationship_change > 0 else "📉" if relationship_change < 0 else "➖" - logger.info(f"{change_direction} 更新用户关系: {user_id}") - logger.info(f"💝 关系分: {old_score:.3f} → {new_score:.3f} (变化: {relationship_change:+.3f})") - logger.debug(f"👥 当前追踪用户数: {len(self.user_relationships)}") + logger.info(f"用户关系: {user_id} | {old_score:.3f} → {new_score:.3f}") def get_user_relationship(self, user_id: str) -> float: """获取用户关系分""" @@ -342,12 +306,7 @@ class ChatterInterestScoringSystem: logger.info("智能兴趣系统初始化完成。") # 显示初始化后的统计信息 - stats = bot_interest_manager.get_interest_stats() - logger.info( - f"兴趣系统统计: 总标签={stats.get('total_tags', 0)}, " - f"缓存大小={stats.get('cache_size', 0)}, " - f"模型='{stats.get('embedding_model', '未知')}'" - ) + bot_interest_manager.get_interest_stats() except Exception as e: logger.error(f"初始化智能兴趣系统失败: {e}") @@ -365,4 +324,4 @@ class ChatterInterestScoringSystem: # 创建全局兴趣评分系统实例 -chatter_interest_scoring_system = ChatterInterestScoringSystem() \ No newline at end of file +chatter_interest_scoring_system = ChatterInterestScoringSystem() diff --git a/src/plugins/built_in/affinity_flow_chatter/plan_executor.py b/src/plugins/built_in/affinity_flow_chatter/plan_executor.py index f42c4dd7f..ede5a8243 100644 --- a/src/plugins/built_in/affinity_flow_chatter/plan_executor.py +++ b/src/plugins/built_in/affinity_flow_chatter/plan_executor.py @@ -4,7 +4,6 @@ PlanExecutor: 接收 Plan 对象并执行其中的所有动作。 """ import asyncio -import re import time from typing import Dict, List @@ -150,7 +149,7 @@ class ChatterPlanExecutor: "reasoning": action_info.reasoning, "action_data": action_info.action_data or {}, } - + logger.debug(f"📬 [PlanExecutor] 准备调用 ActionManager,target_message: {action_info.action_message}") # 通过动作管理器执行回复 @@ -362,4 +361,4 @@ class ChatterPlanExecutor: "timestamp": time.time() - (len(recent_times) - i) * 60, # 估算时间戳 } for i, time_val in enumerate(recent_times) - ] \ No newline at end of file + ] diff --git a/src/plugins/built_in/affinity_flow_chatter/plan_filter.py b/src/plugins/built_in/affinity_flow_chatter/plan_filter.py index 78cc53206..d9e319241 100644 --- a/src/plugins/built_in/affinity_flow_chatter/plan_filter.py +++ b/src/plugins/built_in/affinity_flow_chatter/plan_filter.py @@ -22,7 +22,7 @@ from src.common.logger import get_logger from src.config.config import global_config, model_config from src.llm_models.utils_model import LLMRequest from src.mood.mood_manager import mood_manager -from src.plugin_system.base.component_types import ActionInfo, ChatMode +from src.plugin_system.base.component_types import ActionInfo, ChatMode, ChatType from src.schedule.schedule_manager import schedule_manager logger = get_logger("plan_filter") @@ -41,31 +41,33 @@ class ChatterPlanFilter: """ 执行筛选逻辑,并填充 Plan 对象的 decided_actions 字段。 """ - logger.debug(f"墨墨在这里加了日志 -> filter 入口 plan: {plan}") try: prompt, used_message_id_list = await self._build_prompt(plan) plan.llm_prompt = prompt - logger.debug(f"墨墨在这里加了日志 -> LLM prompt: {prompt}") llm_content, _ = await self.planner_llm.generate_response_async(prompt=prompt) if llm_content: - logger.debug(f"墨墨在这里加了日志 -> LLM a原始返回: {llm_content}") try: parsed_json = orjson.loads(repair_json(llm_content)) except orjson.JSONDecodeError: - parsed_json = {"action": "no_action", "reason": "返回内容无法解析为JSON"} - logger.debug(f"墨墨在这里加了日志 -> 解析后的 JSON: {parsed_json}") + parsed_json = { + "thinking": "", + "actions": {"action_type": "no_action", "reason": "返回内容无法解析为JSON"}, + } if "reply" in plan.available_actions and reply_not_available: # 如果reply动作不可用,但llm返回的仍然有reply,则改为no_reply - if isinstance(parsed_json, dict) and parsed_json.get("action") == "reply": - parsed_json["action"] = "no_reply" + if ( + isinstance(parsed_json, dict) + and parsed_json.get("actions", {}).get("action_type", "") == "reply" + ): + parsed_json["actions"]["action_type"] = "no_reply" elif isinstance(parsed_json, list): for item in parsed_json: - if isinstance(item, dict) and item.get("action") == "reply": - item["action"] = "no_reply" - item["reason"] += " (但由于兴趣度不足,reply动作不可用,已改为no_reply)" + if isinstance(item, dict) and item.get("actions", {}).get("action_type", "") == "reply": + item["actions"]["action_type"] = "no_reply" + item["actions"]["reason"] += " (但由于兴趣度不足,reply动作不可用,已改为no_reply)" if isinstance(parsed_json, dict): parsed_json = [parsed_json] @@ -81,23 +83,40 @@ class ChatterPlanFilter: continue # 预解析 action_type 来进行判断 - action_type = item.get("action", "no_action") + thinking = item.get("thinking", "未提供思考过程") + actions_obj = item.get("actions", {}) + + # 处理actions字段可能是字典或列表的情况 + if isinstance(actions_obj, dict): + action_type = actions_obj.get("action_type", "no_action") + elif isinstance(actions_obj, list) and actions_obj: + # 如果是列表,取第一个元素的action_type + first_action = actions_obj[0] + if isinstance(first_action, dict): + action_type = first_action.get("action_type", "no_action") + else: + action_type = "no_action" + else: + action_type = "no_action" if action_type in reply_action_types: if not reply_action_added: - final_actions.extend(await self._parse_single_action(item, used_message_id_list, plan)) + final_actions.extend( + await self._parse_single_action(item, used_message_id_list, plan) + ) reply_action_added = True else: # 非回复类动作直接添加 final_actions.extend(await self._parse_single_action(item, used_message_id_list, plan)) - - plan.decided_actions = self._filter_no_actions(final_actions) + + if thinking and thinking != "未提供思考过程": + logger.info(f"思考: {thinking}") + plan.decided_actions = self._filter_no_actions(final_actions) except Exception as e: logger.error(f"筛选 Plan 时出错: {e}\n{traceback.format_exc()}") plan.decided_actions = [ActionPlannerInfo(action_type="no_action", reasoning=f"筛选时出错: {e}")] - logger.debug(f"墨墨在这里加了日志 -> filter 出口 decided_actions: {plan.decided_actions}") return plan async def _build_prompt(self, plan: Plan) -> tuple[str, list]: @@ -186,7 +205,7 @@ class ChatterPlanFilter: if global_config.chat.at_bot_inevitable_reply: mentioned_bonus = "\n- 有人提到你,或者at你" - if plan.mode == ChatMode.GROUP: + if plan.mode == ChatMode.FOCUS: no_action_block = """ 动作:no_action 动作描述:不选择任何动作 @@ -204,7 +223,7 @@ class ChatterPlanFilter: "reason":"不回复的原因" }} """ - else: # PRIVATE Mode + else: # normal Mode no_action_block = """重要说明: - 'reply' 表示只进行普通聊天回复,不执行任何额外动作 - 其他action表示在普通回复的基础上,执行相应的额外动作 @@ -214,7 +233,7 @@ class ChatterPlanFilter: "reason":"回复的原因" }}""" - is_group_chat = plan.target_info.platform == "group" if plan.target_info else True + is_group_chat = plan.chat_type == ChatType.GROUP chat_context_description = "你现在正在一个群聊中" if not is_group_chat and plan.target_info: chat_target_name = plan.target_info.person_name or plan.target_info.user_nickname or "对方" @@ -321,7 +340,9 @@ 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.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 # 转换消息格式 @@ -364,13 +385,39 @@ class ChatterPlanFilter: ) -> List[ActionPlannerInfo]: parsed_actions = [] try: - action = action_json.get("action", "no_action") - reasoning = action_json.get("reason", "未提供原因") - action_data = {k: v for k, v in action_json.items() if k not in ["action", "reason"]} + # 从新的actions结构中获取动作信息 + actions_obj = action_json.get("actions", {}) + + # 处理actions字段可能是字典或列表的情况 + if isinstance(actions_obj, dict): + action = actions_obj.get("action_type", "no_action") + reasoning = actions_obj.get("reason", "未提供原因") + # 合并actions_obj中的其他字段作为action_data + action_data = {k: v for k, v in actions_obj.items() if k not in ["action_type", "reason"]} + elif isinstance(actions_obj, list) and actions_obj: + # 如果是列表,取第一个元素 + first_action = actions_obj[0] + if isinstance(first_action, dict): + action = first_action.get("action_type", "no_action") + reasoning = first_action.get("reason", "未提供原因") + action_data = {k: v for k, v in first_action.items() if k not in ["action_type", "reason"]} + else: + action = "no_action" + reasoning = "actions格式错误" + action_data = {} + else: + action = "no_action" + reasoning = "actions格式错误" + action_data = {} + + # 保留原始的thinking字段(如果有) + thinking = action_json.get("thinking") + if thinking: + action_data["thinking"] = thinking target_message_obj = None if action not in ["no_action", "no_reply", "do_nothing", "proactive_reply"]: - if target_message_id := action_json.get("target_message_id"): + if target_message_id := action_data.get("target_message_id"): target_message_dict = self._find_message_by_id(target_message_id, message_id_list) else: # 如果LLM没有指定target_message_id,我们就默认选择最新的一条消息 @@ -388,7 +435,7 @@ class ChatterPlanFilter: # 如果找不到目标消息,对于reply动作来说这是必需的,应该记录警告 if action == "reply": logger.warning( - f"reply动作找不到目标消息,target_message_id: {action_json.get('target_message_id')}" + f"reply动作找不到目标消息,target_message_id: {action_data.get('target_message_id')}" ) # 将reply动作改为no_action,避免后续执行时出错 action = "no_action" @@ -516,4 +563,4 @@ class ChatterPlanFilter: def _get_latest_message(self, message_id_list: list) -> Optional[Dict[str, Any]]: if not message_id_list: return None - return message_id_list[-1].get("message") \ No newline at end of file + return message_id_list[-1].get("message") diff --git a/src/plugins/built_in/affinity_flow_chatter/plan_generator.py b/src/plugins/built_in/affinity_flow_chatter/plan_generator.py index c29116887..bd3f6185d 100644 --- a/src/plugins/built_in/affinity_flow_chatter/plan_generator.py +++ b/src/plugins/built_in/affinity_flow_chatter/plan_generator.py @@ -10,7 +10,7 @@ from src.chat.utils.utils import get_chat_type_and_target_info from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.info_data_model import Plan, TargetPersonInfo from src.config.config import global_config -from src.plugin_system.base.component_types import ActionActivationType, ActionInfo, ChatMode, ChatType, ComponentType +from src.plugin_system.base.component_types import ActionInfo, ChatMode, ChatType from src.plugin_system.core.component_registry import component_registry @@ -66,6 +66,7 @@ class ChatterPlanGenerator: # 构建计划对象 plan = Plan( chat_id=self.chat_id, + chat_type=chat_type, mode=mode, target_info=target_info, available_actions=available_actions, @@ -74,7 +75,7 @@ class ChatterPlanGenerator: return plan - except Exception as e: + except Exception: # 如果生成失败,返回一个基本的空计划 return Plan( chat_id=self.chat_id, @@ -110,7 +111,7 @@ class ChatterPlanGenerator: return filtered_actions - except Exception as e: + except Exception: # 如果获取失败,返回空字典 return {} @@ -124,9 +125,7 @@ class ChatterPlanGenerator: try: # 获取最近的消息记录 raw_messages = get_raw_msg_before_timestamp_with_chat( - chat_id=self.chat_id, - timestamp=time.time(), - limit=global_config.memory.short_memory_length + chat_id=self.chat_id, timestamp=time.time(), limit=global_config.memory.short_memory_length ) # 转换为 DatabaseMessages 对象 @@ -143,13 +142,13 @@ class ChatterPlanGenerator: user_platform=msg.get("user_platform", ""), ) recent_messages.append(db_msg) - except Exception as e: + except Exception: # 跳过格式错误的消息 continue return recent_messages - except Exception as e: + except Exception: # 如果获取失败,返回空列表 return [] @@ -162,6 +161,8 @@ class ChatterPlanGenerator: """ return { "chat_id": self.chat_id, - "action_count": len(self.action_manager._using_actions) if hasattr(self.action_manager, '_using_actions') else 0, - "generation_time": time.time() - } \ No newline at end of file + "action_count": len(self.action_manager._using_actions) + if hasattr(self.action_manager, "_using_actions") + else 0, + "generation_time": time.time(), + } diff --git a/src/plugins/built_in/affinity_flow_chatter/planner.py b/src/plugins/built_in/affinity_flow_chatter/planner.py index c1bd7ab9b..0e0b0b361 100644 --- a/src/plugins/built_in/affinity_flow_chatter/planner.py +++ b/src/plugins/built_in/affinity_flow_chatter/planner.py @@ -6,7 +6,6 @@ from dataclasses import asdict from typing import TYPE_CHECKING, Dict, List, Optional, Tuple -from src.plugin_system.base.component_types import ChatMode 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 @@ -21,7 +20,7 @@ if TYPE_CHECKING: from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.info_data_model import Plan from src.chat.planner_actions.action_manager import ChatterActionManager - + # 导入提示词模块以确保其被初始化 from src.plugins.built_in.affinity_flow_chatter import planner_prompts # noqa @@ -58,7 +57,6 @@ class ChatterActionPlanner: # 创建新的关系追踪器 self.relationship_tracker = ChatterRelationshipTracker(self.interest_scoring) - logger.info("创建新的关系追踪器实例") # 设置执行器的关系追踪器 self.executor.set_relationship_tracker(self.relationship_tracker) @@ -72,14 +70,11 @@ class ChatterActionPlanner: "other_actions_executed": 0, } - async def plan( - self, mode: ChatMode = ChatMode.GROUP, context: "StreamContext" = None - ) -> Tuple[List[Dict], Optional[Dict]]: + async def plan(self, context: "StreamContext" = None) -> Tuple[List[Dict], Optional[Dict]]: """ 执行完整的增强版规划流程。 Args: - mode (ChatMode): 当前的聊天模式,默认为 GROUP。 context (StreamContext): 包含聊天流消息的上下文对象。 Returns: @@ -90,18 +85,18 @@ class ChatterActionPlanner: try: self.planner_stats["total_plans"] += 1 - return await self._enhanced_plan_flow(mode, context) + return await self._enhanced_plan_flow(context) except Exception as e: logger.error(f"规划流程出错: {e}") self.planner_stats["failed_plans"] += 1 return [], None - async def _enhanced_plan_flow(self, mode: ChatMode, context: "StreamContext") -> Tuple[List[Dict], Optional[Dict]]: + async def _enhanced_plan_flow(self, context: "StreamContext") -> Tuple[List[Dict], Optional[Dict]]: """执行增强版规划流程""" try: # 1. 生成初始 Plan - initial_plan = await self.generator.generate(mode) + initial_plan = await self.generator.generate(context.chat_mode) unread_messages = context.get_unread_messages() if context else [] # 2. 兴趣度评分 - 只对未读消息进行评分 @@ -119,16 +114,14 @@ class ChatterActionPlanner: reply_not_available = False if not should_reply and "reply" in initial_plan.available_actions: - logger.info(f"兴趣度不足 ({latest_score.total_score:.2f}),移除'回复'动作。") + logger.info(f"兴趣度不足 ({latest_score.total_score:.2f}),移除回复") reply_not_available = True # 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: - logger.info( - f"兴趣度 {score:.3f} 低于非回复动作阈值 {non_reply_action_interest_threshold:.3f},不执行任何动作。" - ) + logger.info(f"兴趣度 {score:.3f} 低于阈值 {non_reply_action_interest_threshold:.3f},不执行动作") # 直接返回 no_action from src.common.data_models.info_data_model import ActionPlannerInfo @@ -241,4 +234,4 @@ class ChatterActionPlanner: } -# 全局兴趣度评分系统实例 - 在 individuality 模块中创建 \ No newline at end of file +# 全局兴趣度评分系统实例 - 在 individuality 模块中创建 diff --git a/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py b/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py index 15dcb584b..8c068076e 100644 --- a/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py +++ b/src/plugins/built_in/affinity_flow_chatter/planner_prompts.py @@ -49,10 +49,6 @@ def init_prompts(): 6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。 7. 如果用户明确要求了某个动作,请务必优先满足。 -**动作限制:** -- 在私聊中,你只能使用 `reply` 动作。私聊中不允许使用任何其他动作。 -- 在群聊中,你可以自由选择是否使用辅助动作。 - **重要提醒:** - **回复消息时必须遵循对话的流程,不要重复已经说过的话。** - **确保回复与上下文紧密相关,回应要针对用户的消息内容。** @@ -62,7 +58,7 @@ def init_prompts(): 请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段: ```json {{ - "thinking": "你的思考过程,分析当前情况并说明为什么选择这些动作", + "thinking": "你的内心思考,简要描述你选择动作时的心路历程", "actions": [ {{ "action_type": "动作类型(如:reply, emoji等)", @@ -257,4 +253,4 @@ def init_prompts(): # 确保提示词在模块加载时初始化 -init_prompts() \ No newline at end of file +init_prompts() diff --git a/src/plugins/built_in/affinity_flow_chatter/plugin.py b/src/plugins/built_in/affinity_flow_chatter/plugin.py index 201b021f5..7c86d13fe 100644 --- a/src/plugins/built_in/affinity_flow_chatter/plugin.py +++ b/src/plugins/built_in/affinity_flow_chatter/plugin.py @@ -6,7 +6,7 @@ from typing import List, Tuple, Type from src.plugin_system.apis.plugin_register_api import register_plugin from src.plugin_system.base.base_plugin import BasePlugin -from src.plugin_system.base.component_types import ComponentInfo, ChatterInfo, ComponentType, ChatType +from src.plugin_system.base.component_types import ComponentInfo from src.common.logger import get_logger logger = get_logger("affinity_chatter_plugin") diff --git a/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py index 995efeee1..abe6390a9 100644 --- a/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py +++ b/src/plugins/built_in/affinity_flow_chatter/relationship_tracker.py @@ -385,7 +385,9 @@ class ChatterRelationshipTracker: time_diff = reply_timestamp - last_tracked_time if time_diff < 5 * 60: # 5分钟内不重复追踪 - logger.debug(f"⏱️ [RelationshipTracker] 用户 {user_id} 距离上次追踪时间不足5分钟 ({time_diff:.2f}s),跳过") + logger.debug( + f"⏱️ [RelationshipTracker] 用户 {user_id} 距离上次追踪时间不足5分钟 ({time_diff:.2f}s),跳过" + ) return # 获取上次bot回复该用户的消息 @@ -644,9 +646,10 @@ class ChatterRelationshipTracker: """处理与用户的初次交互""" try: logger.info(f"✨ [RelationshipTracker] 正在处理与用户 {user_id} 的初次交互") - + # 获取bot人设信息 from src.individuality.individuality import Individuality + individuality = Individuality() bot_personality = await individuality.get_personality_block() @@ -682,12 +685,19 @@ class ChatterRelationshipTracker: return import json + cleaned_response = self._clean_llm_json_response(llm_response) response_data = json.loads(cleaned_response) new_text = response_data.get("relationship_text", "初次见面") - new_score = max(0.0, min(1.0, float(response_data.get("relationship_score", global_config.affinity_flow.base_relationship_score)))) - + new_score = max( + 0.0, + min( + 1.0, + float(response_data.get("relationship_score", global_config.affinity_flow.base_relationship_score)), + ), + ) + # 更新数据库和缓存 self._update_user_relationship_in_db(user_id, new_text, new_score) self.user_relationship_cache[user_id] = { @@ -702,7 +712,6 @@ class ChatterRelationshipTracker: logger.error(f"处理初次交互失败: {user_id}, 错误: {e}") logger.debug("错误详情:", exc_info=True) - def _clean_llm_json_response(self, response: str) -> str: """ 清理LLM响应,移除可能的JSON格式标记 @@ -746,4 +755,4 @@ class ChatterRelationshipTracker: except Exception as e: logger.warning(f"清理LLM响应失败: {e}") - return response # 清理失败时返回原始响应 \ No newline at end of file + return response # 清理失败时返回原始响应