feat;新的情绪系统
This commit is contained in:
82
bot.py
82
bot.py
@@ -236,67 +236,6 @@ def raw_main():
|
|||||||
return MainSystem()
|
return MainSystem()
|
||||||
|
|
||||||
|
|
||||||
async def _create_console_message_dict(text: str) -> dict:
|
|
||||||
"""使用配置创建消息字典"""
|
|
||||||
timestamp = time.time()
|
|
||||||
|
|
||||||
# --- User & Group Info (hardcoded for console) ---
|
|
||||||
user_info = UserInfo(
|
|
||||||
platform="console",
|
|
||||||
user_id="console_user",
|
|
||||||
user_nickname="ConsoleUser",
|
|
||||||
user_cardname="",
|
|
||||||
)
|
|
||||||
# Console input is private chat
|
|
||||||
group_info = None
|
|
||||||
|
|
||||||
# --- Base Message Info ---
|
|
||||||
message_info = BaseMessageInfo(
|
|
||||||
platform="console",
|
|
||||||
message_id=f"console_{int(timestamp * 1000)}_{hash(text) % 10000}",
|
|
||||||
time=timestamp,
|
|
||||||
user_info=user_info,
|
|
||||||
group_info=group_info,
|
|
||||||
# Other infos can be added here if needed, e.g., FormatInfo
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Message Segment ---
|
|
||||||
message_segment = Seg(type="text", data=text)
|
|
||||||
|
|
||||||
# --- Final MessageBase object to convert to dict ---
|
|
||||||
message = MessageBase(message_info=message_info, message_segment=message_segment, raw_message=text)
|
|
||||||
|
|
||||||
return message.to_dict()
|
|
||||||
|
|
||||||
|
|
||||||
async def console_input_loop(main_system: MainSystem):
|
|
||||||
"""异步循环以读取控制台输入并模拟接收消息"""
|
|
||||||
logger.info("控制台输入已准备就绪 (模拟接收消息)。输入 'exit()' 来停止。")
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
line = await loop.run_in_executor(None, sys.stdin.readline)
|
|
||||||
text = line.strip()
|
|
||||||
|
|
||||||
if not text:
|
|
||||||
continue
|
|
||||||
if text.lower() == "exit()":
|
|
||||||
logger.info("收到 'exit()' 命令,正在停止...")
|
|
||||||
break
|
|
||||||
|
|
||||||
# Create message dict and pass to the processor
|
|
||||||
message_dict = await _create_console_message_dict(text)
|
|
||||||
await chat_bot.message_process(message_dict)
|
|
||||||
logger.info(f"已将控制台消息 '{text}' 作为接收消息处理。")
|
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
logger.info("控制台输入循环被取消。")
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"控制台输入循环出错: {e}", exc_info=True)
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
logger.info("控制台输入循环结束。")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
exit_code = 0 # 用于记录程序最终的退出状态
|
exit_code = 0 # 用于记录程序最终的退出状态
|
||||||
@@ -314,17 +253,7 @@ if __name__ == "__main__":
|
|||||||
# Schedule tasks returns a future that runs forever.
|
# Schedule tasks returns a future that runs forever.
|
||||||
# We can run console_input_loop concurrently.
|
# We can run console_input_loop concurrently.
|
||||||
main_tasks = loop.create_task(main_system.schedule_tasks())
|
main_tasks = loop.create_task(main_system.schedule_tasks())
|
||||||
|
loop.run_until_complete(main_tasks)
|
||||||
# 仅在 TTY 中启用 console_input_loop
|
|
||||||
if sys.stdin.isatty():
|
|
||||||
logger.info("检测到终端环境,启用控制台输入循环")
|
|
||||||
console_task = loop.create_task(console_input_loop(main_system))
|
|
||||||
# Wait for all tasks to complete (which they won't, normally)
|
|
||||||
loop.run_until_complete(asyncio.gather(main_tasks, console_task))
|
|
||||||
else:
|
|
||||||
logger.info("非终端环境,跳过控制台输入循环")
|
|
||||||
# Wait for all tasks to complete (which they won't, normally)
|
|
||||||
loop.run_until_complete(main_tasks)
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
# loop.run_until_complete(get_global_api().stop())
|
# loop.run_until_complete(get_global_api().stop())
|
||||||
@@ -336,15 +265,6 @@ if __name__ == "__main__":
|
|||||||
logger.error(f"优雅关闭时发生错误: {ge}")
|
logger.error(f"优雅关闭时发生错误: {ge}")
|
||||||
# 新增:检测外部请求关闭
|
# 新增:检测外部请求关闭
|
||||||
|
|
||||||
# except Exception as e: # 将主异常捕获移到外层 try...except
|
|
||||||
# logger.error(f"事件循环内发生错误: {str(e)} {str(traceback.format_exc())}")
|
|
||||||
# exit_code = 1
|
|
||||||
# finally: # finally 块移到最外层,确保 loop 关闭和暂停总是执行
|
|
||||||
# if loop and not loop.is_closed():
|
|
||||||
# loop.close()
|
|
||||||
# # 在这里添加 input() 来暂停
|
|
||||||
# input("按 Enter 键退出...") # <--- 添加这行
|
|
||||||
# sys.exit(exit_code) # <--- 使用记录的退出码
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"主程序发生异常: {str(e)} {str(traceback.format_exc())}")
|
logger.error(f"主程序发生异常: {str(e)} {str(traceback.format_exc())}")
|
||||||
|
|||||||
46
interested_rates.txt
Normal file
46
interested_rates.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
0.02388322700338219
|
||||||
|
0.02789637960584667
|
||||||
|
6.1002656551513885
|
||||||
|
6.1002656551513885
|
||||||
|
6.1171064375469255
|
||||||
|
6.106626351535966
|
||||||
|
6.112541462320276
|
||||||
|
0.04230527065567247
|
||||||
|
9.04004621778353
|
||||||
|
6.104278807753853
|
||||||
|
6.106626351535966
|
||||||
|
6.198517524266092
|
||||||
|
0.020373848987042205
|
||||||
|
6.106626351535966
|
||||||
|
6.104278807753853
|
||||||
|
0.03203964454588806
|
||||||
|
6.104278807753853
|
||||||
|
6.104278807753853
|
||||||
|
6.104278807753853
|
||||||
|
6.104278807753853
|
||||||
|
6.1002656551513885
|
||||||
|
6.1002656551513885
|
||||||
|
6.1002656551513885
|
||||||
|
0.02605261040985793
|
||||||
|
1.0273445569816615
|
||||||
|
0.02203945780739345
|
||||||
|
0.03203964454588806
|
||||||
|
0.014013152602464482
|
||||||
|
0.03203964454588806
|
||||||
|
1.018026305204929
|
||||||
|
4.183876948487736
|
||||||
|
0.020373848987042205
|
||||||
|
0.19241219083184483
|
||||||
|
6.103223210543543
|
||||||
|
6.1002656551513885
|
||||||
|
6.103223210543543
|
||||||
|
6.103223210543543
|
||||||
|
1.021266343711497
|
||||||
|
6.103223210543543
|
||||||
|
0.018026305204928966
|
||||||
|
0.020373848987042205
|
||||||
|
6.106626351535966
|
||||||
|
6.089034714923968
|
||||||
|
0.03203964454588806
|
||||||
|
6.089034714923968
|
||||||
|
0.027344556981661584
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from src.manager.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
|
|
||||||
@@ -12,6 +12,3 @@ class ChatStateInfo:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.chat_status: ChatState = ChatState.NORMAL
|
self.chat_status: ChatState = ChatState.NORMAL
|
||||||
self.current_state_time = 120
|
self.current_state_time = 120
|
||||||
|
|
||||||
self.mood_manager = mood_manager
|
|
||||||
self.mood = self.mood_manager.get_mood_prompt()
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from src.chat.memory_system.Hippocampus import hippocampus_manager
|
from src.chat.memory_system.Hippocampus import hippocampus_manager
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
|
import asyncio
|
||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
from src.chat.message_receive.storage import MessageStorage
|
from src.chat.message_receive.storage import MessageStorage
|
||||||
from src.chat.heart_flow.heartflow import heartflow
|
from src.chat.heart_flow.heartflow import heartflow
|
||||||
@@ -13,6 +14,7 @@ import traceback
|
|||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from src.person_info.relationship_manager import get_relationship_manager
|
from src.person_info.relationship_manager import get_relationship_manager
|
||||||
|
from src.mood.mood_manager import mood_manager
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("chat")
|
logger = get_logger("chat")
|
||||||
@@ -114,6 +116,12 @@ class HeartFCMessageReceiver:
|
|||||||
interested_rate, is_mentioned = await _calculate_interest(message)
|
interested_rate, is_mentioned = await _calculate_interest(message)
|
||||||
subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
||||||
|
|
||||||
|
chat_mood = mood_manager.get_mood_by_chat_id(subheartflow.chat_id)
|
||||||
|
asyncio.create_task(chat_mood.update_mood_by_message(message, interested_rate))
|
||||||
|
|
||||||
|
with open("interested_rates.txt", "a", encoding="utf-8") as f:
|
||||||
|
f.write(f"{interested_rate}\n")
|
||||||
|
|
||||||
# 7. 日志记录
|
# 7. 日志记录
|
||||||
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
|
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||||
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ class SubHeartflow:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
subheartflow_id: 子心流唯一标识符
|
subheartflow_id: 子心流唯一标识符
|
||||||
mai_states: 麦麦状态信息实例
|
|
||||||
hfc_no_reply_callback: HFChatting 连续不回复时触发的回调
|
|
||||||
"""
|
"""
|
||||||
# 基础属性,两个值是一样的
|
# 基础属性,两个值是一样的
|
||||||
self.subheartflow_id = subheartflow_id
|
self.subheartflow_id = subheartflow_id
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.manager.mood_manager import mood_manager # 导入情绪管理器
|
from src.mood.mood_manager import mood_manager # 导入情绪管理器
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
from src.experimental.only_message_process import MessageProcessor
|
from src.experimental.only_message_process import MessageProcessor
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from src.chat.planner_actions.planner import ActionPlanner
|
|||||||
from src.chat.planner_actions.action_modifier import ActionModifier
|
from src.chat.planner_actions.action_modifier import ActionModifier
|
||||||
|
|
||||||
from src.chat.utils.utils import get_chat_type_and_target_info
|
from src.chat.utils.utils import get_chat_type_and_target_info
|
||||||
from src.manager.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
|
|
||||||
willing_manager = get_willing_manager()
|
willing_manager = get_willing_manager()
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from src.chat.utils.chat_message_builder import build_readable_messages, get_raw
|
|||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
from src.chat.express.expression_selector import expression_selector
|
from src.chat.express.expression_selector import expression_selector
|
||||||
from src.manager.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
||||||
import random
|
import random
|
||||||
import ast
|
import ast
|
||||||
@@ -55,9 +55,9 @@ def init_prompt():
|
|||||||
{identity}
|
{identity}
|
||||||
|
|
||||||
{action_descriptions}
|
{action_descriptions}
|
||||||
你正在{chat_target_2},现在请你读读之前的聊天记录,{mood_prompt},请你给出回复
|
你正在{chat_target_2},你现在的心情是:{mood_state}
|
||||||
{config_expression_style}。
|
现在请你读读之前的聊天记录,并给出回复
|
||||||
请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,注意不要复读你说过的话。
|
{config_expression_style}。注意不要复读你说过的话
|
||||||
{keywords_reaction_prompt}
|
{keywords_reaction_prompt}
|
||||||
请注意不要输出多余内容(包括前后缀,冒号和引号,at或 @等 )。只输出回复内容。
|
请注意不要输出多余内容(包括前后缀,冒号和引号,at或 @等 )。只输出回复内容。
|
||||||
{moderation_prompt}
|
{moderation_prompt}
|
||||||
@@ -504,6 +504,9 @@ class DefaultReplyer:
|
|||||||
reply_to = reply_data.get("reply_to", "none")
|
reply_to = reply_data.get("reply_to", "none")
|
||||||
extra_info_block = reply_data.get("extra_info", "") or reply_data.get("extra_info_block", "")
|
extra_info_block = reply_data.get("extra_info", "") or reply_data.get("extra_info_block", "")
|
||||||
|
|
||||||
|
chat_mood = mood_manager.get_mood_by_chat_id(chat_id)
|
||||||
|
mood_prompt = chat_mood.mood_state
|
||||||
|
|
||||||
sender, target = self._parse_reply_target(reply_to)
|
sender, target = self._parse_reply_target(reply_to)
|
||||||
|
|
||||||
# 构建action描述 (如果启用planner)
|
# 构建action描述 (如果启用planner)
|
||||||
@@ -639,8 +642,6 @@ class DefaultReplyer:
|
|||||||
else:
|
else:
|
||||||
reply_target_block = ""
|
reply_target_block = ""
|
||||||
|
|
||||||
mood_prompt = mood_manager.get_mood_prompt()
|
|
||||||
|
|
||||||
prompt_info = await get_prompt_info(target, threshold=0.38)
|
prompt_info = await get_prompt_info(target, threshold=0.38)
|
||||||
if prompt_info:
|
if prompt_info:
|
||||||
prompt_info = await global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info)
|
prompt_info = await global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info)
|
||||||
@@ -682,7 +683,7 @@ class DefaultReplyer:
|
|||||||
config_expression_style=global_config.expression.expression_style,
|
config_expression_style=global_config.expression.expression_style,
|
||||||
action_descriptions=action_descriptions,
|
action_descriptions=action_descriptions,
|
||||||
chat_target_2=chat_target_2,
|
chat_target_2=chat_target_2,
|
||||||
mood_prompt=mood_prompt,
|
mood_state=mood_prompt,
|
||||||
)
|
)
|
||||||
|
|
||||||
return prompt
|
return prompt
|
||||||
@@ -774,8 +775,6 @@ class DefaultReplyer:
|
|||||||
else:
|
else:
|
||||||
reply_target_block = ""
|
reply_target_block = ""
|
||||||
|
|
||||||
mood_manager.get_mood_prompt()
|
|
||||||
|
|
||||||
if is_group_chat:
|
if is_group_chat:
|
||||||
chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1")
|
chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1")
|
||||||
chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2")
|
chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import numpy as np
|
|||||||
from maim_message import UserInfo
|
from maim_message import UserInfo
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.manager.mood_manager import mood_manager
|
# from src.mood.mood_manager import mood_manager
|
||||||
from ..message_receive.message import MessageRecv
|
from ..message_receive.message import MessageRecv
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from .typo_generator import ChineseTypoGenerator
|
from .typo_generator import ChineseTypoGenerator
|
||||||
@@ -412,12 +412,12 @@ def calculate_typing_time(
|
|||||||
- 在所有输入结束后,额外加上回车时间0.3秒
|
- 在所有输入结束后,额外加上回车时间0.3秒
|
||||||
- 如果is_emoji为True,将使用固定1秒的输入时间
|
- 如果is_emoji为True,将使用固定1秒的输入时间
|
||||||
"""
|
"""
|
||||||
# 将0-1的唤醒度映射到-1到1
|
# # 将0-1的唤醒度映射到-1到1
|
||||||
mood_arousal = mood_manager.current_mood.arousal
|
# mood_arousal = mood_manager.current_mood.arousal
|
||||||
# 映射到0.5到2倍的速度系数
|
# # 映射到0.5到2倍的速度系数
|
||||||
typing_speed_multiplier = 1.5**mood_arousal # 唤醒度为1时速度翻倍,为-1时速度减半
|
# typing_speed_multiplier = 1.5**mood_arousal # 唤醒度为1时速度翻倍,为-1时速度减半
|
||||||
chinese_time *= 1 / typing_speed_multiplier
|
# chinese_time *= 1 / typing_speed_multiplier
|
||||||
english_time *= 1 / typing_speed_multiplier
|
# english_time *= 1 / typing_speed_multiplier
|
||||||
# 计算中文字符数
|
# 计算中文字符数
|
||||||
chinese_chars = sum(1 for char in input_string if "\u4e00" <= char <= "\u9fff")
|
chinese_chars = sum(1 for char in input_string if "\u4e00" <= char <= "\u9fff")
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from src.chat.express.exprssion_learner import get_expression_learner
|
|||||||
from src.common.remote import TelemetryHeartBeatTask
|
from src.common.remote import TelemetryHeartBeatTask
|
||||||
from src.manager.async_task_manager import async_task_manager
|
from src.manager.async_task_manager import async_task_manager
|
||||||
from src.chat.utils.statistic import OnlineTimeRecordTask, StatisticOutputTask
|
from src.chat.utils.statistic import OnlineTimeRecordTask, StatisticOutputTask
|
||||||
from src.manager.mood_manager import MoodPrintTask, MoodUpdateTask
|
|
||||||
from src.chat.emoji_system.emoji_manager import get_emoji_manager
|
from src.chat.emoji_system.emoji_manager import get_emoji_manager
|
||||||
from src.chat.normal_chat.willing.willing_manager import get_willing_manager
|
from src.chat.normal_chat.willing.willing_manager import get_willing_manager
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
@@ -95,13 +94,6 @@ class MainSystem:
|
|||||||
get_emoji_manager().initialize()
|
get_emoji_manager().initialize()
|
||||||
logger.info("表情包管理器初始化成功")
|
logger.info("表情包管理器初始化成功")
|
||||||
|
|
||||||
# 添加情绪衰减任务
|
|
||||||
await async_task_manager.add_task(MoodUpdateTask())
|
|
||||||
# 添加情绪打印任务
|
|
||||||
await async_task_manager.add_task(MoodPrintTask())
|
|
||||||
|
|
||||||
logger.info("情绪管理器初始化成功")
|
|
||||||
|
|
||||||
# 启动愿望管理器
|
# 启动愿望管理器
|
||||||
await willing_manager.async_task_starter()
|
await willing_manager.async_task_starter()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
from src.mais4u.openai_client import AsyncOpenAIClient
|
from src.mais4u.openai_client import AsyncOpenAIClient
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
|
|||||||
@@ -1,296 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import math
|
|
||||||
import time
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Dict, Tuple
|
|
||||||
|
|
||||||
from ..config.config import global_config
|
|
||||||
from ..common.logger import get_logger
|
|
||||||
from ..manager.async_task_manager import AsyncTask
|
|
||||||
from ..individuality.individuality import get_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.mood_update_interval,
|
|
||||||
run_interval=global_config.mood.mood_update_interval,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 从配置文件获取衰减率
|
|
||||||
self.decay_rate_valence: float = 1 - global_config.mood.mood_decay_rate
|
|
||||||
"""愉悦度衰减率"""
|
|
||||||
self.decay_rate_arousal: float = 1 - global_config.mood.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 = get_individuality().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()
|
|
||||||
"""全局情绪管理器"""
|
|
||||||
135
src/mood/mood_manager.py
Normal file
135
src/mood/mood_manager.py
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
from src.chat.message_receive.message import MessageRecv
|
||||||
|
from src.llm_models.utils_model import LLMRequest
|
||||||
|
from ..common.logger import get_logger
|
||||||
|
from src.chat.utils.chat_message_builder import build_readable_messages, get_raw_msg_by_timestamp_with_chat_inclusive
|
||||||
|
from src.config.config import global_config
|
||||||
|
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
||||||
|
logger = get_logger("mood")
|
||||||
|
|
||||||
|
def init_prompt():
|
||||||
|
Prompt(
|
||||||
|
"""
|
||||||
|
{chat_talking_prompt}
|
||||||
|
以上是群里正在进行的聊天记录
|
||||||
|
|
||||||
|
{indentify_block}
|
||||||
|
你刚刚的情绪状态是:{mood_state}
|
||||||
|
|
||||||
|
现在,发送了消息,引起了你的注意,你对其进行了阅读和思考,请你输出一句话描述你新的情绪状态
|
||||||
|
请只输出情绪状态,不要输出其他内容:
|
||||||
|
""",
|
||||||
|
"change_mood_prompt",
|
||||||
|
)
|
||||||
|
|
||||||
|
class ChatMood:
|
||||||
|
def __init__(self,chat_id:str):
|
||||||
|
self.chat_id:str = chat_id
|
||||||
|
self.mood_state:str = "感觉很平静"
|
||||||
|
|
||||||
|
|
||||||
|
self.mood_model = LLMRequest(
|
||||||
|
model=global_config.model.utils,
|
||||||
|
temperature=0.7,
|
||||||
|
request_type="mood",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.last_change_time = 0
|
||||||
|
|
||||||
|
async def update_mood_by_message(self,message:MessageRecv,interested_rate:float):
|
||||||
|
|
||||||
|
during_last_time = message.message_info.time - self.last_change_time
|
||||||
|
|
||||||
|
base_probability = 0.05
|
||||||
|
time_multiplier = 4 * (1 - math.exp(-0.01 * during_last_time))
|
||||||
|
|
||||||
|
if interested_rate <= 0:
|
||||||
|
interest_multiplier = 0
|
||||||
|
else:
|
||||||
|
interest_multiplier = 3 * math.pow(interested_rate, 0.25)
|
||||||
|
|
||||||
|
logger.info(f"base_probability: {base_probability}, time_multiplier: {time_multiplier}, interest_multiplier: {interest_multiplier}")
|
||||||
|
update_probability = min(1.0, base_probability * time_multiplier * interest_multiplier)
|
||||||
|
|
||||||
|
if random.random() > update_probability:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
message_time = message.message_info.time
|
||||||
|
message_list_before_now = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||||
|
chat_id=self.chat_id,
|
||||||
|
timestamp_start=self.last_change_time,
|
||||||
|
timestamp_end=message_time,
|
||||||
|
limit=15,
|
||||||
|
limit_mode="last",
|
||||||
|
)
|
||||||
|
chat_talking_prompt = build_readable_messages(
|
||||||
|
message_list_before_now,
|
||||||
|
replace_bot_name=True,
|
||||||
|
merge_messages=False,
|
||||||
|
timestamp_mode="normal_no_YMD",
|
||||||
|
read_mark=0.0,
|
||||||
|
truncate=True,
|
||||||
|
show_actions=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
bot_name = global_config.bot.nickname
|
||||||
|
if global_config.bot.alias_names:
|
||||||
|
bot_nickname = f",也有人叫你{','.join(global_config.bot.alias_names)}"
|
||||||
|
else:
|
||||||
|
bot_nickname = ""
|
||||||
|
|
||||||
|
prompt_personality = global_config.personality.personality_core
|
||||||
|
indentify_block = f"你的名字是{bot_name}{bot_nickname},你{prompt_personality}:"
|
||||||
|
|
||||||
|
prompt = await global_prompt_manager.format_prompt(
|
||||||
|
"change_mood_prompt",
|
||||||
|
chat_talking_prompt=chat_talking_prompt,
|
||||||
|
indentify_block=indentify_block,
|
||||||
|
mood_state=self.mood_state,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f"prompt: {prompt}")
|
||||||
|
response, (reasoning_content, model_name) = await self.mood_model.generate_response_async(prompt=prompt)
|
||||||
|
logger.info(f"response: {response}")
|
||||||
|
logger.info(f"reasoning_content: {reasoning_content}")
|
||||||
|
|
||||||
|
|
||||||
|
self.mood_state = response
|
||||||
|
|
||||||
|
|
||||||
|
self.last_change_time = message_time
|
||||||
|
|
||||||
|
|
||||||
|
class MoodManager:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.mood_list:list[ChatMood] = []
|
||||||
|
"""当前情绪状态"""
|
||||||
|
|
||||||
|
def get_mood_by_chat_id(self, chat_id:str) -> ChatMood:
|
||||||
|
for mood in self.mood_list:
|
||||||
|
if mood.chat_id == chat_id:
|
||||||
|
return mood
|
||||||
|
|
||||||
|
new_mood = ChatMood(chat_id)
|
||||||
|
self.mood_list.append(new_mood)
|
||||||
|
return new_mood
|
||||||
|
|
||||||
|
def reset_mood_by_chat_id(self, chat_id:str):
|
||||||
|
for mood in self.mood_list:
|
||||||
|
if mood.chat_id == chat_id:
|
||||||
|
mood.mood_state = "感觉很平静"
|
||||||
|
return
|
||||||
|
self.mood_list.append(ChatMood(chat_id))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
init_prompt()
|
||||||
|
|
||||||
|
mood_manager = MoodManager()
|
||||||
|
"""全局情绪管理器"""
|
||||||
@@ -426,7 +426,7 @@ class RelationshipBuilder:
|
|||||||
if not segments_to_process and segments:
|
if not segments_to_process and segments:
|
||||||
segments.sort(key=lambda x: x["end_time"], reverse=True)
|
segments.sort(key=lambda x: x["end_time"], reverse=True)
|
||||||
segments_to_process.append(segments[0])
|
segments_to_process.append(segments[0])
|
||||||
logger.debug(f"随机丢弃了所有消息段,强制保留最新的一个以进行处理。")
|
logger.debug("随机丢弃了所有消息段,强制保留最新的一个以进行处理。")
|
||||||
|
|
||||||
dropped_count = original_segment_count - len(segments_to_process)
|
dropped_count = original_segment_count - len(segments_to_process)
|
||||||
if dropped_count > 0:
|
if dropped_count > 0:
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
import math
|
|
||||||
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
|
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.chat.utils.chat_message_builder import build_readable_messages
|
from src.chat.utils.chat_message_builder import build_readable_messages
|
||||||
from src.manager.mood_manager import mood_manager
|
|
||||||
import json
|
import json
|
||||||
from json_repair import repair_json
|
from json_repair import repair_json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ compress_indentity = true # 是否压缩身份,压缩后会精简身份信息
|
|||||||
[expression]
|
[expression]
|
||||||
# 表达方式
|
# 表达方式
|
||||||
enable_expression = true # 是否启用表达方式
|
enable_expression = true # 是否启用表达方式
|
||||||
expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。)"
|
# 描述麦麦说话的表达风格,表达习惯,例如:(请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。)
|
||||||
|
expression_style = "请回复的平淡一些,简短一些,说中文,可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,不要刻意突出自身学科背景。"
|
||||||
enable_expression_learning = false # 是否启用表达学习,麦麦会学习不同群里人类说话风格(群之间不互通)
|
enable_expression_learning = false # 是否启用表达学习,麦麦会学习不同群里人类说话风格(群之间不互通)
|
||||||
learning_interval = 600 # 学习间隔 单位秒
|
learning_interval = 600 # 学习间隔 单位秒
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user