From a1fbff1d6b7c83c818221ee4295e392a5ba8588a Mon Sep 17 00:00:00 2001 From: Oct-autumn Date: Thu, 8 May 2025 23:56:28 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=83=85?= =?UTF-8?q?=E7=BB=AA=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/do_tool/not_used/change_mood.py | 11 +- src/heart_flow/chat_state_info.py | 6 +- src/heart_flow/mai_state_manager.py | 6 +- src/main.py | 33 +- src/manager/async_task_manager.py | 4 +- src/manager/mood_manager.py | 296 ++++++++++++++++++ src/plugins/__init__.py | 2 - src/plugins/chat/bot.py | 17 +- src/plugins/chat/utils.py | 14 +- src/plugins/heartFC_chat/heartFC_chat.py | 46 +-- .../heartFC_chat/heartflow_prompt_builder.py | 5 +- src/plugins/heartFC_chat/normal_chat.py | 26 +- src/plugins/moods/moods.py | 293 ----------------- .../person_info/relationship_manager.py | 11 +- 14 files changed, 379 insertions(+), 391 deletions(-) create mode 100644 src/manager/mood_manager.py delete mode 100644 src/plugins/moods/moods.py diff --git a/src/do_tool/not_used/change_mood.py b/src/do_tool/not_used/change_mood.py index 5dee6ac98..5d1e7f7a6 100644 --- a/src/do_tool/not_used/change_mood.py +++ b/src/do_tool/not_used/change_mood.py @@ -1,10 +1,10 @@ -from src.do_tool.tool_can_use.base_tool import BaseTool -from src.config.config import global_config -from src.common.logger_manager import get_logger -from src.plugins.moods.moods import MoodManager - from typing import Any +from src.common.logger_manager import get_logger +from src.config.config import global_config +from src.do_tool.tool_can_use.base_tool import BaseTool +from src.manager.mood_manager import mood_manager + logger = get_logger("change_mood_tool") @@ -36,7 +36,6 @@ class ChangeMoodTool(BaseTool): response_set = function_args.get("response_set") _message_processed_plain_text = function_args.get("text") - mood_manager = MoodManager.get_instance() # gpt = ResponseGenerator() if response_set is None: diff --git a/src/heart_flow/chat_state_info.py b/src/heart_flow/chat_state_info.py index 619f372fc..bda5c26c0 100644 --- a/src/heart_flow/chat_state_info.py +++ b/src/heart_flow/chat_state_info.py @@ -1,4 +1,4 @@ -from src.plugins.moods.moods import MoodManager +from src.manager.mood_manager import mood_manager import enum @@ -13,5 +13,5 @@ class ChatStateInfo: self.chat_status: ChatState = ChatState.ABSENT self.current_state_time = 120 - self.mood_manager = MoodManager() - self.mood = self.mood_manager.get_prompt() + self.mood_manager = mood_manager + self.mood = self.mood_manager.get_mood_prompt() diff --git a/src/heart_flow/mai_state_manager.py b/src/heart_flow/mai_state_manager.py index d289a94a1..3c6c19d66 100644 --- a/src/heart_flow/mai_state_manager.py +++ b/src/heart_flow/mai_state_manager.py @@ -3,7 +3,7 @@ import time import random from typing import List, Tuple, Optional from src.common.logger_manager import get_logger -from src.plugins.moods.moods import MoodManager +from src.manager.mood_manager import mood_manager from src.config.config import global_config logger = get_logger("mai_state") @@ -88,7 +88,7 @@ class MaiStateInfo: self.last_min_check_time: float = time.time() # 上次1分钟规则检查时间 # Mood management is now part of MaiStateInfo - self.mood_manager = MoodManager.get_instance() # Use singleton instance + self.mood_manager = mood_manager # Use singleton instance def update_mai_status(self, new_status: MaiState) -> bool: """ @@ -124,7 +124,7 @@ class MaiStateInfo: def get_mood_prompt(self) -> str: """获取当前的心情提示词""" # Delegate to the internal mood manager - return self.mood_manager.get_prompt() + return self.mood_manager.get_mood_prompt() def get_current_state(self) -> MaiState: """获取当前的 MaiState""" diff --git a/src/main.py b/src/main.py index ef0828918..fbb40e3c5 100644 --- a/src/main.py +++ b/src/main.py @@ -1,9 +1,11 @@ import asyncio import time +from maim_message import MessageServer + from .manager.async_task_manager import async_task_manager from .plugins.utils.statistic import OnlineTimeRecordTask, StatisticOutputTask -from .plugins.moods.moods import MoodManager +from src.manager.mood_manager import logger, MoodPrintTask, MoodUpdateTask from .plugins.schedule.schedule_generator import bot_schedule from .plugins.emoji_system.emoji_manager import emoji_manager from .plugins.person_info.person_info import person_info_manager @@ -18,7 +20,7 @@ from .plugins.chat.bot import chat_bot from .common.logger_manager import get_logger from .plugins.remote import heartbeat_thread # noqa: F401 from .individuality.individuality import Individuality -from .common.server import global_server +from .common.server import global_server, Server from rich.traceback import install from .api.main import start_api_server @@ -28,20 +30,15 @@ logger = get_logger("main") class MainSystem: - mood_manager: MoodManager - hippocampus_manager: HippocampusManager - individuality: Individuality - def __init__(self): - self.mood_manager = MoodManager.get_instance() - self.hippocampus_manager = HippocampusManager.get_instance() - self.individuality = Individuality.get_instance() + self.hippocampus_manager: HippocampusManager = HippocampusManager.get_instance() + self.individuality: Individuality = Individuality.get_instance() # 使用消息API替代直接的FastAPI实例 from .plugins.message import global_api - self.app = global_api - self.server = global_server + self.app: MessageServer = global_api + self.server: Server = global_server async def initialize(self): """初始化系统组件""" @@ -69,9 +66,10 @@ class MainSystem: emoji_manager.initialize() logger.success("表情包管理器初始化成功") - # 启动情绪管理器 - self.mood_manager.start_mood_update(update_interval=global_config.mood_update_interval) - logger.success("情绪管理器启动成功") + # 添加情绪衰减任务 + await async_task_manager.add_task(MoodUpdateTask()) + # 添加情绪打印任务 + await async_task_manager.add_task(MoodPrintTask()) # 检查并清除person_info冗余字段,启动个人习惯推断 await person_info_manager.del_all_undefined_field() @@ -136,7 +134,6 @@ class MainSystem: self.build_memory_task(), self.forget_memory_task(), self.consolidate_memory_task(), - self.print_mood_task(), self.remove_recalled_message_task(), emoji_manager.start_periodic_check_register(), self.app.run(), @@ -170,12 +167,6 @@ class MainSystem: await HippocampusManager.get_instance().consolidate_memory() print("\033[1;32m[记忆整合]\033[0m 记忆整合完成") - async def print_mood_task(self): - """打印情绪状态""" - while True: - self.mood_manager.print_mood_status() - await asyncio.sleep(60) - @staticmethod async def remove_recalled_message_task(): """删除撤回消息任务""" diff --git a/src/manager/async_task_manager.py b/src/manager/async_task_manager.py index 6a3f1b813..720e918a9 100644 --- a/src/manager/async_task_manager.py +++ b/src/manager/async_task_manager.py @@ -87,7 +87,7 @@ class AsyncTaskManager: if not issubclass(task.__class__, AsyncTask): raise TypeError(f"task '{task.__class__.__name__}' 必须是继承 AsyncTask 的子类") - with self._lock: # 由于可能需要await等待任务完成,所以需要加异步锁 + async with self._lock: # 由于可能需要await等待任务完成,所以需要加异步锁 if task.task_name in self.tasks: logger.warning(f"已存在名称为 '{task.task_name}' 的任务,正在尝试取消并替换") self.tasks[task.task_name].cancel() # 取消已存在的任务 @@ -120,7 +120,7 @@ class AsyncTaskManager: """ 终止所有任务并等待它们完成(该方法会阻塞其它尝试add_task()的操作) """ - with self._lock: # 由于可能需要await等待任务完成,所以需要加异步锁 + async with self._lock: # 由于可能需要await等待任务完成,所以需要加异步锁 # 设置中止标志 self.abort_flag.set() # 取消所有任务 diff --git a/src/manager/mood_manager.py b/src/manager/mood_manager.py new file mode 100644 index 000000000..42677d4e1 --- /dev/null +++ b/src/manager/mood_manager.py @@ -0,0 +1,296 @@ +import asyncio +import math +import time +from dataclasses import dataclass +from typing import Dict, Tuple + +from ..config.config import global_config +from ..common.logger_manager import get_logger +from ..manager.async_task_manager import AsyncTask +from ..individuality.individuality import Individuality + +logger = get_logger("mood") + + +@dataclass +class MoodState: + valence: float + """愉悦度 (-1.0 到 1.0),-1表示极度负面,1表示极度正面""" + arousal: float + """唤醒度 (-1.0 到 1.0),-1表示抑制,1表示兴奋""" + text: str + """心情的文本描述""" + + +@dataclass +class MoodChangeHistory: + valence_direction_factor: int + """愉悦度变化的系数(正为增益,负为抑制)""" + arousal_direction_factor: int + """唤醒度变化的系数(正为增益,负为抑制)""" + + +class MoodUpdateTask(AsyncTask): + def __init__(self): + super().__init__( + task_name="Mood Update Task", + wait_before_start=global_config.mood_update_interval, + run_interval=global_config.mood_update_interval, + ) + + # 从配置文件获取衰减率 + self.decay_rate_valence: float = 1 - global_config.mood_decay_rate + """愉悦度衰减率""" + self.decay_rate_arousal: float = 1 - global_config.mood_decay_rate + """唤醒度衰减率""" + + self.last_update = time.time() + """上次更新时间""" + + async def run(self): + current_time = time.time() + time_diff = current_time - self.last_update + agreeableness_factor = 1 # 宜人性系数 + agreeableness_bias = 0 # 宜人性偏置 + neuroticism_factor = 0.5 # 神经质系数 + # 获取人格特质 + personality = Individuality.get_instance().personality + if personality: + # 神经质:影响情绪变化速度 + neuroticism_factor = 1 + (personality.neuroticism - 0.5) * 0.4 + agreeableness_factor = 1 + (personality.agreeableness - 0.5) * 0.4 + + # 宜人性:影响情绪基准线 + if personality.agreeableness < 0.2: + agreeableness_bias = (personality.agreeableness - 0.2) * 0.5 + elif personality.agreeableness > 0.8: + agreeableness_bias = (personality.agreeableness - 0.8) * 0.5 + else: + agreeableness_bias = 0 + + # 分别计算正向和负向的衰减率 + if mood_manager.current_mood.valence >= 0: + # 正向情绪衰减 + decay_rate_positive = self.decay_rate_valence * (1 / agreeableness_factor) + valence_target = 0 + agreeableness_bias + new_valence = valence_target + (mood_manager.current_mood.valence - valence_target) * math.exp( + -decay_rate_positive * time_diff * neuroticism_factor + ) + else: + # 负向情绪衰减 + decay_rate_negative = self.decay_rate_valence * agreeableness_factor + valence_target = 0 + agreeableness_bias + new_valence = valence_target + (mood_manager.current_mood.valence - valence_target) * math.exp( + -decay_rate_negative * time_diff * neuroticism_factor + ) + + # Arousal 向中性(0)回归 + arousal_target = 0 + new_arousal = arousal_target + (mood_manager.current_mood.arousal - arousal_target) * math.exp( + -self.decay_rate_arousal * time_diff * neuroticism_factor + ) + + mood_manager.set_current_mood(new_valence, new_arousal) + + self.last_update = current_time + + +class MoodPrintTask(AsyncTask): + def __init__(self): + super().__init__( + task_name="Mood Print Task", + wait_before_start=60, + run_interval=60, + ) + + async def run(self): + # 打印当前心情 + logger.info( + f"愉悦度: {mood_manager.current_mood.valence:.2f}, " + f"唤醒度: {mood_manager.current_mood.arousal:.2f}, " + f"心情: {mood_manager.current_mood.text}" + ) + + +class MoodManager: + # TODO: 改进,使用具有实验支持的新情绪模型 + + EMOTION_FACTOR_MAP: Dict[str, Tuple[float, float]] = { + "开心": (0.21, 0.6), + "害羞": (0.15, 0.2), + "愤怒": (-0.24, 0.8), + "恐惧": (-0.21, 0.7), + "悲伤": (-0.21, 0.3), + "厌恶": (-0.12, 0.4), + "惊讶": (0.06, 0.7), + "困惑": (0.0, 0.6), + "平静": (0.03, 0.5), + } + """ + 情绪词映射表 {mood: (valence, arousal)} + 将情绪描述词映射到愉悦度和唤醒度的元组 + """ + + EMOTION_POINT_MAP: Dict[Tuple[float, float], str] = { + # 第一象限:高唤醒,正愉悦 + (0.5, 0.4): "兴奋", + (0.3, 0.6): "快乐", + (0.2, 0.3): "满足", + # 第二象限:高唤醒,负愉悦 + (-0.5, 0.4): "愤怒", + (-0.3, 0.6): "焦虑", + (-0.2, 0.3): "烦躁", + # 第三象限:低唤醒,负愉悦 + (-0.5, -0.4): "悲伤", + (-0.3, -0.3): "疲倦", + (-0.4, -0.7): "疲倦", + # 第四象限:低唤醒,正愉悦 + (0.2, -0.1): "平静", + (0.3, -0.2): "安宁", + (0.5, -0.4): "放松", + } + """ + 情绪文本映射表 {(valence, arousal): mood} + 将量化的情绪状态元组映射到文本描述 + """ + + def __init__(self): + self.current_mood = MoodState( + valence=0.0, + arousal=0.0, + text="平静", + ) + """当前情绪状态""" + + self.mood_change_history: MoodChangeHistory = MoodChangeHistory( + valence_direction_factor=0, + arousal_direction_factor=0, + ) + """情绪变化历史""" + + self._lock = asyncio.Lock() + """异步锁,用于保护线程安全""" + + def set_current_mood(self, new_valence: float, new_arousal: float): + """ + 设置当前情绪状态 + :param new_valence: 新的愉悦度 + :param new_arousal: 新的唤醒度 + """ + # 限制范围 + self.current_mood.valence = max(-1.0, min(new_valence, 1.0)) + self.current_mood.arousal = max(-1.0, min(new_arousal, 1.0)) + + closest_mood = None + min_distance = float("inf") + + for (v, a), text in self.EMOTION_POINT_MAP.items(): + # 计算当前情绪状态与每个情绪文本的欧氏距离 + distance = math.sqrt((self.current_mood.valence - v) ** 2 + (self.current_mood.arousal - a) ** 2) + if distance < min_distance: + min_distance = distance + closest_mood = text + + if closest_mood: + self.current_mood.text = closest_mood + + def update_current_mood(self, valence_delta: float, arousal_delta: float): + """ + 根据愉悦度和唤醒度变化量更新当前情绪状态 + :param valence_delta: 愉悦度变化量 + :param arousal_delta: 唤醒度变化量 + """ + # 计算连续增益/抑制 + # 规则:多次相同方向的变化会有更大的影响系数,反方向的变化会清零影响系数(系数的正负号由变化方向决定) + if valence_delta * self.mood_change_history.valence_direction_factor > 0: + # 如果方向相同,则根据变化方向改变系数 + if valence_delta > 0: + self.mood_change_history.valence_direction_factor += 1 # 若为正向,则增加 + else: + self.mood_change_history.valence_direction_factor -= 1 # 若为负向,则减少 + else: + # 如果方向不同,则重置计数 + self.mood_change_history.valence_direction_factor = 0 + + if arousal_delta * self.mood_change_history.arousal_direction_factor > 0: + # 如果方向相同,则根据变化方向改变系数 + if arousal_delta > 0: + self.mood_change_history.arousal_direction_factor += 1 # 若为正向,则增加计数 + else: + self.mood_change_history.arousal_direction_factor -= 1 # 若为负向,则减少计数 + else: + # 如果方向不同,则重置计数 + self.mood_change_history.arousal_direction_factor = 0 + + # 计算增益/抑制的结果 + # 规则:如果当前情绪状态与变化方向相同,则增益;否则抑制 + if self.current_mood.valence * self.mood_change_history.valence_direction_factor > 0: + valence_delta = valence_delta * (1.01 ** abs(self.mood_change_history.valence_direction_factor)) + else: + valence_delta = valence_delta * (0.99 ** abs(self.mood_change_history.valence_direction_factor)) + + if self.current_mood.arousal * self.mood_change_history.arousal_direction_factor > 0: + arousal_delta = arousal_delta * (1.01 ** abs(self.mood_change_history.arousal_direction_factor)) + else: + arousal_delta = arousal_delta * (0.99 ** abs(self.mood_change_history.arousal_direction_factor)) + + self.set_current_mood( + new_valence=self.current_mood.valence + valence_delta, + new_arousal=self.current_mood.arousal + arousal_delta, + ) + + def get_mood_prompt(self) -> str: + """ + 根据当前情绪状态生成提示词 + """ + base_prompt = f"当前心情:{self.current_mood.text}。" + + # 根据情绪状态添加额外的提示信息 + if self.current_mood.valence > 0.5: + base_prompt += "你现在心情很好," + elif self.current_mood.valence < -0.5: + base_prompt += "你现在心情不太好," + + if self.current_mood.arousal > 0.4: + base_prompt += "情绪比较激动。" + elif self.current_mood.arousal < -0.4: + base_prompt += "情绪比较平静。" + + return base_prompt + + def get_arousal_multiplier(self) -> float: + """ + 根据当前情绪状态返回唤醒度乘数 + """ + if self.current_mood.arousal > 0.4: + multiplier = 1 + min(0.15, (self.current_mood.arousal - 0.4) / 3) + return multiplier + elif self.current_mood.arousal < -0.4: + multiplier = 1 - min(0.15, ((0 - self.current_mood.arousal) - 0.4) / 3) + return multiplier + return 1.0 + + def update_mood_from_emotion(self, emotion: str, intensity: float = 1.0) -> None: + """ + 根据情绪词更新心情状态 + :param emotion: 情绪词(如'开心', '悲伤'等位于self.EMOTION_FACTOR_MAP中的键) + :param intensity: 情绪强度(0.0-1.0) + """ + if emotion not in self.EMOTION_FACTOR_MAP: + logger.error(f"[情绪更新] 未知情绪词: {emotion}") + return + + valence_change, arousal_change = self.EMOTION_FACTOR_MAP[emotion] + old_valence = self.current_mood.valence + old_arousal = self.current_mood.arousal + old_mood = self.current_mood.text + + self.update_current_mood(valence_change, arousal_change) # 更新当前情绪状态 + + logger.info( + f"[情绪变化] {emotion}(强度:{intensity:.2f}) | 愉悦度:{old_valence:.2f}->{self.current_mood.valence:.2f}, 唤醒度:{old_arousal:.2f}->{self.current_mood.arousal:.2f} | 心情:{old_mood}->{self.current_mood.text}" + ) + + +mood_manager = MoodManager() +"""全局情绪管理器""" diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py index 2e057e6fe..631d9bbb7 100644 --- a/src/plugins/__init__.py +++ b/src/plugins/__init__.py @@ -6,7 +6,6 @@ MaiMBot插件系统 from .chat.chat_stream import chat_manager from .emoji_system.emoji_manager import emoji_manager from .person_info.relationship_manager import relationship_manager -from .moods.moods import MoodManager from .willing.willing_manager import willing_manager from .schedule.schedule_generator import bot_schedule @@ -15,7 +14,6 @@ __all__ = [ "chat_manager", "emoji_manager", "relationship_manager", - "MoodManager", "willing_manager", "bot_schedule", ] diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index 9c4a33581..79e97c4f3 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -1,16 +1,15 @@ +import traceback from typing import Dict, Any -from ..moods.moods import MoodManager # 导入情绪管理器 -from ...config.config import global_config -from .message import MessageRecv -from ..PFC.pfc_manager import PFCManager -from .chat_stream import chat_manager -from .only_message_process import MessageProcessor - from src.common.logger_manager import get_logger +from src.manager.mood_manager import mood_manager # 导入情绪管理器 +from .chat_stream import chat_manager +from .message import MessageRecv +from .only_message_process import MessageProcessor +from ..PFC.pfc_manager import PFCManager from ..heartFC_chat.heartflow_processor import HeartFCProcessor from ..utils.prompt_builder import Prompt, global_prompt_manager -import traceback +from ...config.config import global_config # 定义日志配置 @@ -23,7 +22,7 @@ class ChatBot: def __init__(self): self.bot = None # bot 实例引用 self._started = False - self.mood_manager = MoodManager.get_instance() # 获取情绪管理器单例 + self.mood_manager = mood_manager # 获取情绪管理器单例 self.heartflow_processor = HeartFCProcessor() # 新增 # 创建初始化PFC管理器的任务,会在_ensure_started时执行 diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 53e8f6f6e..c229f0a59 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -1,21 +1,20 @@ import random -import time import re +import time from collections import Counter import jieba import numpy as np -from src.common.logger import get_module_logger +from maim_message import UserInfo from pymongo.errors import PyMongoError +from src.common.logger import get_module_logger +from src.manager.mood_manager import mood_manager +from .message import MessageRecv from ..models.utils_model import LLMRequest from ..utils.typo_generator import ChineseTypoGenerator -from ...config.config import global_config -from .message import MessageRecv -from maim_message import UserInfo -from ..moods.moods import MoodManager from ...common.database import db - +from ...config.config import global_config logger = get_module_logger("chat_utils") @@ -405,7 +404,6 @@ def calculate_typing_time( - 在所有输入结束后,额外加上回车时间0.3秒 - 如果is_emoji为True,将使用固定1秒的输入时间 """ - mood_manager = MoodManager.get_instance() # 将0-1的唤醒度映射到-1到1 mood_arousal = mood_manager.current_mood.arousal # 映射到0.5到2倍的速度系数 diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index b594bf029..83abfbbed 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -1,33 +1,35 @@ import asyncio +import contextlib +import json # <--- 确保导入 json +import random # <--- 添加导入 import time import traceback -import random # <--- 添加导入 -import json # <--- 确保导入 json -from typing import List, Optional, Dict, Any, Deque, Callable, Coroutine from collections import deque +from typing import List, Optional, Dict, Any, Deque, Callable, Coroutine + +from rich.traceback import install + +from src.common.logger_manager import get_logger +from src.config.config import global_config +from src.heart_flow.observation import Observation +from src.heart_flow.sub_mind import SubMind +from src.heart_flow.utils_chat import get_chat_type_and_target_info +from src.manager.mood_manager import mood_manager +from src.plugins.chat.chat_stream import ChatStream +from src.plugins.chat.chat_stream import chat_manager from src.plugins.chat.message import MessageRecv, BaseMessageInfo, MessageThinking, MessageSending from src.plugins.chat.message import Seg # Local import needed after move -from src.plugins.chat.chat_stream import ChatStream from src.plugins.chat.message import UserInfo -from src.plugins.chat.chat_stream import chat_manager -from src.common.logger_manager import get_logger -from src.plugins.models.utils_model import LLMRequest -from src.config.config import global_config -from src.plugins.chat.utils_image import image_path_to_base64 # Local import needed after move -from src.plugins.utils.timer_calculator import Timer # <--- Import Timer -from src.plugins.emoji_system.emoji_manager import emoji_manager -from src.heart_flow.sub_mind import SubMind -from src.heart_flow.observation import Observation -from src.plugins.heartFC_chat.heartflow_prompt_builder import global_prompt_manager, prompt_builder -import contextlib -from src.plugins.utils.chat_message_builder import num_new_messages_since -from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo -from .heartFC_sender import HeartFCSender from src.plugins.chat.utils import process_llm_response +from src.plugins.chat.utils_image import image_path_to_base64 # Local import needed after move +from src.plugins.emoji_system.emoji_manager import emoji_manager +from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo +from src.plugins.heartFC_chat.heartflow_prompt_builder import global_prompt_manager, prompt_builder +from src.plugins.models.utils_model import LLMRequest from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager -from src.plugins.moods.moods import MoodManager -from src.heart_flow.utils_chat import get_chat_type_and_target_info -from rich.traceback import install +from src.plugins.utils.chat_message_builder import num_new_messages_since +from src.plugins.utils.timer_calculator import Timer # <--- Import Timer +from .heartFC_sender import HeartFCSender install(extra_lines=3) @@ -1275,7 +1277,7 @@ class HeartFChatting: """ try: # 1. 获取情绪影响因子并调整模型温度 - arousal_multiplier = MoodManager.get_instance().get_arousal_multiplier() + arousal_multiplier = mood_manager.get_arousal_multiplier() current_temp = global_config.llm_normal["temp"] * arousal_multiplier self.model_normal.temperature = current_temp # 动态调整温度 diff --git a/src/plugins/heartFC_chat/heartflow_prompt_builder.py b/src/plugins/heartFC_chat/heartflow_prompt_builder.py index c59168a7f..c4a137a78 100644 --- a/src/plugins/heartFC_chat/heartflow_prompt_builder.py +++ b/src/plugins/heartFC_chat/heartflow_prompt_builder.py @@ -10,7 +10,7 @@ import time from typing import Union, Optional, Deque, Dict, Any from ...common.database import db from ..chat.utils import get_recent_group_speaker -from ..moods.moods import MoodManager +from src.manager.mood_manager import mood_manager from ..memory_system.Hippocampus import HippocampusManager from ..schedule.schedule_generator import bot_schedule from ..knowledge.knowledge_lib import qa_manager @@ -341,8 +341,7 @@ class PromptBuilder: else: logger.warning(f"Invalid person tuple encountered for relationship prompt: {person}") - mood_manager = MoodManager.get_instance() - mood_prompt = mood_manager.get_prompt() + mood_prompt = mood_manager.get_mood_prompt() reply_styles1 = [ ("然后给出日常且口语化的回复,平淡一些", 0.4), ("给出非常简短的回复", 0.4), diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index be05f4d70..460e881a0 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -1,26 +1,26 @@ -import time import asyncio -import traceback import statistics # 导入 statistics 模块 +import time +import traceback from random import random from typing import List, Optional # 导入 Optional -from ..moods.moods import MoodManager -from ...config.config import global_config -from ..emoji_system.emoji_manager import emoji_manager -from .normal_chat_generator import NormalChatGenerator -from ..chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet -from ..chat.message_sender import message_manager -from ..chat.utils_image import image_path_to_base64 -from ..willing.willing_manager import willing_manager from maim_message import UserInfo, Seg + from src.common.logger_manager import get_logger +from src.heart_flow.utils_chat import get_chat_type_and_target_info +from src.manager.mood_manager import mood_manager from src.plugins.chat.chat_stream import ChatStream, chat_manager from src.plugins.person_info.relationship_manager import relationship_manager from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager from src.plugins.utils.timer_calculator import Timer -from src.heart_flow.utils_chat import get_chat_type_and_target_info - +from .normal_chat_generator import NormalChatGenerator +from ..chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet +from ..chat.message_sender import message_manager +from ..chat.utils_image import image_path_to_base64 +from ..emoji_system.emoji_manager import emoji_manager +from ..willing.willing_manager import willing_manager +from ...config.config import global_config logger = get_logger("chat") @@ -45,7 +45,7 @@ class NormalChat: # Other sync initializations self.gpt = NormalChatGenerator() - self.mood_manager = MoodManager.get_instance() + self.mood_manager = mood_manager self.start_time = time.time() self.last_speak_time = 0 self._chat_task: Optional[asyncio.Task] = None diff --git a/src/plugins/moods/moods.py b/src/plugins/moods/moods.py deleted file mode 100644 index 1c025319f..000000000 --- a/src/plugins/moods/moods.py +++ /dev/null @@ -1,293 +0,0 @@ -import math -import threading -import time -from dataclasses import dataclass - -from ...config.config import global_config -from src.common.logger_manager import get_logger -from ..person_info.relationship_manager import relationship_manager -from src.individuality.individuality import Individuality - - -logger = get_logger("mood") - - -@dataclass -class MoodState: - valence: float # 愉悦度 (-1.0 到 1.0),-1表示极度负面,1表示极度正面 - arousal: float # 唤醒度 (-1.0 到 1.0),-1表示抑制,1表示兴奋 - text: str # 心情文本描述 - - -class MoodManager: - _instance = None - _lock = threading.Lock() - - def __new__(cls): - with cls._lock: - if cls._instance is None: - cls._instance = super().__new__(cls) - cls._instance._initialized = False - return cls._instance - - def __init__(self): - # 确保初始化代码只运行一次 - if self._initialized: - return - - self._initialized = True - - # 初始化心情状态 - self.current_mood = MoodState(valence=0.0, arousal=0.0, text="平静") - - # 从配置文件获取衰减率 - self.decay_rate_valence = 1 - global_config.mood_decay_rate # 愉悦度衰减率 - self.decay_rate_arousal = 1 - global_config.mood_decay_rate # 唤醒度衰减率 - - # 上次更新时间 - self.last_update = time.time() - - # 线程控制 - self._running = False - self._update_thread = None - - # 情绪词映射表 (valence, arousal) - self.emotion_map = { - "开心": (0.21, 0.6), - "害羞": (0.15, 0.2), - "愤怒": (-0.24, 0.8), - "恐惧": (-0.21, 0.7), - "悲伤": (-0.21, 0.3), - "厌恶": (-0.12, 0.4), - "惊讶": (0.06, 0.7), - "困惑": (0.0, 0.6), - "平静": (0.03, 0.5), - } - - # 情绪文本映射表 - self.mood_text_map = { - # 第一象限:高唤醒,正愉悦 - (0.5, 0.4): "兴奋", - (0.3, 0.6): "快乐", - (0.2, 0.3): "满足", - # 第二象限:高唤醒,负愉悦 - (-0.5, 0.4): "愤怒", - (-0.3, 0.6): "焦虑", - (-0.2, 0.3): "烦躁", - # 第三象限:低唤醒,负愉悦 - (-0.5, -0.4): "悲伤", - (-0.3, -0.3): "疲倦", - (-0.4, -0.7): "疲倦", - # 第四象限:低唤醒,正愉悦 - (0.2, -0.1): "平静", - (0.3, -0.2): "安宁", - (0.5, -0.4): "放松", - } - - @classmethod - def get_instance(cls) -> "MoodManager": - """获取MoodManager的单例实例""" - if cls._instance is None: - cls._instance = MoodManager() - return cls._instance - - def start_mood_update(self, update_interval: float = 5.0) -> None: - """ - 启动情绪更新线程 - :param update_interval: 更新间隔(秒) - """ - if self._running: - return - - self._running = True - self._update_thread = threading.Thread( - target=self._continuous_mood_update, args=(update_interval,), daemon=True - ) - self._update_thread.start() - - def stop_mood_update(self) -> None: - """停止情绪更新线程""" - self._running = False - if self._update_thread and self._update_thread.is_alive(): - self._update_thread.join() - - def _continuous_mood_update(self, update_interval: float) -> None: - """ - 持续更新情绪状态的线程函数 - :param update_interval: 更新间隔(秒) - """ - while self._running: - self._apply_decay() - self._update_mood_text() - time.sleep(update_interval) - - def _apply_decay(self) -> None: - """应用情绪衰减,正向和负向情绪分开计算""" - current_time = time.time() - time_diff = current_time - self.last_update - agreeableness_factor = 1 - agreeableness_bias = 0 - neuroticism_factor = 0.5 - - # 获取人格特质 - personality = Individuality.get_instance().personality - if personality: - # 神经质:影响情绪变化速度 - neuroticism_factor = 1 + (personality.neuroticism - 0.5) * 0.4 - agreeableness_factor = 1 + (personality.agreeableness - 0.5) * 0.4 - - # 宜人性:影响情绪基准线 - if personality.agreeableness < 0.2: - agreeableness_bias = (personality.agreeableness - 0.2) * 0.5 - elif personality.agreeableness > 0.8: - agreeableness_bias = (personality.agreeableness - 0.8) * 0.5 - else: - agreeableness_bias = 0 - - # 分别计算正向和负向的衰减率 - if self.current_mood.valence >= 0: - # 正向情绪衰减 - decay_rate_positive = self.decay_rate_valence * (1 / agreeableness_factor) - valence_target = 0 + agreeableness_bias - self.current_mood.valence = valence_target + (self.current_mood.valence - valence_target) * math.exp( - -decay_rate_positive * time_diff * neuroticism_factor - ) - else: - # 负向情绪衰减 - decay_rate_negative = self.decay_rate_valence * agreeableness_factor - valence_target = 0 + agreeableness_bias - self.current_mood.valence = valence_target + (self.current_mood.valence - valence_target) * math.exp( - -decay_rate_negative * time_diff * neuroticism_factor - ) - - # Arousal 向中性(0)回归 - arousal_target = 0 - self.current_mood.arousal = arousal_target + (self.current_mood.arousal - arousal_target) * math.exp( - -self.decay_rate_arousal * time_diff * neuroticism_factor - ) - - # 确保值在合理范围内 - self.current_mood.valence = max(-1.0, min(1.0, self.current_mood.valence)) - self.current_mood.arousal = max(-1.0, min(1.0, self.current_mood.arousal)) - - self.last_update = current_time - - def update_mood_from_text(self, text: str, valence_change: float, arousal_change: float) -> None: - """根据输入文本更新情绪状态""" - - self.current_mood.valence += valence_change - self.current_mood.arousal += arousal_change - - # 限制范围 - self.current_mood.valence = max(-1.0, min(1.0, self.current_mood.valence)) - self.current_mood.arousal = max(-1.0, min(1.0, self.current_mood.arousal)) - - self._update_mood_text() - - def set_mood_text(self, text: str) -> None: - """直接设置心情文本""" - self.current_mood.text = text - - def _update_mood_text(self) -> None: - """根据当前情绪状态更新文本描述""" - closest_mood = None - min_distance = float("inf") - - for (v, a), text in self.mood_text_map.items(): - distance = math.sqrt((self.current_mood.valence - v) ** 2 + (self.current_mood.arousal - a) ** 2) - if distance < min_distance: - min_distance = distance - closest_mood = text - - if closest_mood: - self.current_mood.text = closest_mood - - def update_mood_by_user(self, user_id: str, valence_change: float, arousal_change: float) -> None: - """根据用户ID更新情绪状态""" - - # 这里可以根据用户ID添加特定的权重或规则 - weight = 1.0 # 默认权重 - - self.current_mood.valence += valence_change * weight - self.current_mood.arousal += arousal_change * weight - - # 限制范围 - self.current_mood.valence = max(-1.0, min(1.0, self.current_mood.valence)) - self.current_mood.arousal = max(-1.0, min(1.0, self.current_mood.arousal)) - - self._update_mood_text() - - def get_prompt(self) -> str: - """根据当前情绪状态生成提示词""" - - base_prompt = f"当前心情:{self.current_mood.text}。" - - # 根据情绪状态添加额外的提示信息 - if self.current_mood.valence > 0.5: - base_prompt += "你现在心情很好," - elif self.current_mood.valence < -0.5: - base_prompt += "你现在心情不太好," - - if self.current_mood.arousal > 0.4: - base_prompt += "情绪比较激动。" - elif self.current_mood.arousal < -0.4: - base_prompt += "情绪比较平静。" - - return base_prompt - - def get_arousal_multiplier(self) -> float: - """根据当前情绪状态返回唤醒度乘数""" - if self.current_mood.arousal > 0.4: - multiplier = 1 + min(0.15, (self.current_mood.arousal - 0.4) / 3) - return multiplier - elif self.current_mood.arousal < -0.4: - multiplier = 1 - min(0.15, ((0 - self.current_mood.arousal) - 0.4) / 3) - return multiplier - return 1.0 - - def get_current_mood(self) -> MoodState: - """获取当前情绪状态""" - return self.current_mood - - def print_mood_status(self) -> None: - """打印当前情绪状态""" - logger.info( - f"愉悦度: {self.current_mood.valence:.2f}, " - f"唤醒度: {self.current_mood.arousal:.2f}, " - f"心情: {self.current_mood.text}" - ) - - def update_mood_from_emotion(self, emotion: str, intensity: float = 1.0) -> None: - """ - 根据情绪词更新心情状态 - :param emotion: 情绪词(如'happy', 'sad'等) - :param intensity: 情绪强度(0.0-1.0) - """ - if emotion not in self.emotion_map: - logger.debug(f"[情绪更新] 未知情绪词: {emotion}") - return - - valence_change, arousal_change = self.emotion_map[emotion] - old_valence = self.current_mood.valence - old_arousal = self.current_mood.arousal - old_mood = self.current_mood.text - - valence_change = relationship_manager.feedback_to_mood(valence_change) - - # 应用情绪强度 - valence_change *= intensity - arousal_change *= intensity - - # 更新当前情绪状态 - self.current_mood.valence += valence_change - self.current_mood.arousal += arousal_change - - # 限制范围 - self.current_mood.valence = max(-1.0, min(1.0, self.current_mood.valence)) - self.current_mood.arousal = max(-1.0, min(1.0, self.current_mood.arousal)) - - self._update_mood_text() - - logger.info( - f"[情绪变化] {emotion}(强度:{intensity:.2f}) | 愉悦度:{old_valence:.2f}->{self.current_mood.valence:.2f}, 唤醒度:{old_arousal:.2f}->{self.current_mood.arousal:.2f} | 心情:{old_mood}->{self.current_mood.text}" - ) diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 862f23984..e9dad4b74 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -6,6 +6,9 @@ from .person_info import person_info_manager import time import random from maim_message import UserInfo + +from ...manager.mood_manager import mood_manager + # import re # import traceback @@ -22,9 +25,7 @@ class RelationshipManager: @property def mood_manager(self): if self._mood_manager is None: - from ..moods.moods import MoodManager # 延迟导入 - - self._mood_manager = MoodManager.get_instance() + self._mood_manager = mood_manager return self._mood_manager def positive_feedback_sys(self, label: str, stance: str): @@ -60,9 +61,7 @@ class RelationshipManager: def mood_feedback(self, value): """情绪反馈""" mood_manager = self.mood_manager - mood_gain = mood_manager.get_current_mood().valence ** 2 * math.copysign( - 1, value * mood_manager.get_current_mood().valence - ) + mood_gain = mood_manager.current_mood.valence**2 * math.copysign(1, value * mood_manager.current_mood.valence) value += value * mood_gain logger.info(f"当前relationship增益系数:{mood_gain:.3f}") return value