mirror of https://github.com/Mai-with-u/MaiBot.git
before merge commit
parent
ce74df51db
commit
5427e2448c
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
from typing import List, Optional, Dict, Any, Tuple
|
from typing import List, Optional, Dict, Any, Tuple
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
|
|
@ -8,6 +9,7 @@ from collections import deque
|
||||||
|
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
|
from src.common.data_models.database_data_model import DatabaseMessages
|
||||||
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
||||||
from src.chat.utils.prompt_builder import global_prompt_manager
|
from src.chat.utils.prompt_builder import global_prompt_manager
|
||||||
from src.chat.utils.timer_calculator import Timer
|
from src.chat.utils.timer_calculator import Timer
|
||||||
|
|
@ -15,21 +17,19 @@ 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.planner_actions.action_manager import ActionManager
|
from src.chat.planner_actions.action_manager import ActionManager
|
||||||
from src.chat.chat_loop.hfc_utils import CycleDetail
|
from src.chat.chat_loop.hfc_utils import CycleDetail
|
||||||
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
from src.chat.chat_loop.hfc_utils import send_typing, stop_typing
|
||||||
|
from src.chat.memory_system.Hippocampus import hippocampus_manager
|
||||||
|
from src.chat.frequency_control.talk_frequency_control import talk_frequency_control
|
||||||
|
from src.chat.frequency_control.focus_value_control import focus_value_control
|
||||||
from src.chat.express.expression_learner import expression_learner_manager
|
from src.chat.express.expression_learner import expression_learner_manager
|
||||||
|
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
||||||
from src.person_info.person_info import Person
|
from src.person_info.person_info import Person
|
||||||
from src.plugin_system.base.component_types import ChatMode, EventType
|
from src.plugin_system.base.component_types import ChatMode, EventType
|
||||||
from src.plugin_system.core import events_manager
|
from src.plugin_system.core import events_manager
|
||||||
from src.plugin_system.apis import generator_api, send_api, message_api, database_api
|
from src.plugin_system.apis import generator_api, send_api, message_api, database_api
|
||||||
from src.mais4u.mai_think import mai_thinking_manager
|
from src.mais4u.mai_think import mai_thinking_manager
|
||||||
import math
|
|
||||||
from src.mais4u.s4u_config import s4u_config
|
from src.mais4u.s4u_config import s4u_config
|
||||||
# no_action逻辑已集成到heartFC_chat.py中,不再需要导入
|
|
||||||
from src.chat.chat_loop.hfc_utils import send_typing, stop_typing
|
|
||||||
# 导入记忆系统
|
|
||||||
from src.chat.memory_system.Hippocampus import hippocampus_manager
|
|
||||||
from src.chat.frequency_control.talk_frequency_control import talk_frequency_control
|
|
||||||
from src.chat.frequency_control.focus_value_control import focus_value_control
|
|
||||||
|
|
||||||
ERROR_LOOP_INFO = {
|
ERROR_LOOP_INFO = {
|
||||||
"loop_plan_info": {
|
"loop_plan_info": {
|
||||||
|
|
@ -62,10 +62,7 @@ class HeartFChatting:
|
||||||
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
其生命周期现在由其关联的 SubHeartflow 的 FOCUSED 状态控制。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, chat_id: str):
|
||||||
self,
|
|
||||||
chat_id: str,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
HeartFChatting 初始化函数
|
HeartFChatting 初始化函数
|
||||||
|
|
||||||
|
|
@ -166,25 +163,24 @@ class HeartFChatting:
|
||||||
|
|
||||||
# 获取动作类型,兼容新旧格式
|
# 获取动作类型,兼容新旧格式
|
||||||
action_type = "未知动作"
|
action_type = "未知动作"
|
||||||
if hasattr(self, '_current_cycle_detail') and self._current_cycle_detail:
|
if hasattr(self, "_current_cycle_detail") and self._current_cycle_detail:
|
||||||
loop_plan_info = self._current_cycle_detail.loop_plan_info
|
loop_plan_info = self._current_cycle_detail.loop_plan_info
|
||||||
if isinstance(loop_plan_info, dict):
|
if isinstance(loop_plan_info, dict):
|
||||||
action_result = loop_plan_info.get('action_result', {})
|
action_result = loop_plan_info.get("action_result", {})
|
||||||
if isinstance(action_result, dict):
|
if isinstance(action_result, dict):
|
||||||
# 旧格式:action_result是字典
|
# 旧格式:action_result是字典
|
||||||
action_type = action_result.get('action_type', '未知动作')
|
action_type = action_result.get("action_type", "未知动作")
|
||||||
elif isinstance(action_result, list) and action_result:
|
elif isinstance(action_result, list) and action_result:
|
||||||
# 新格式:action_result是actions列表
|
# 新格式:action_result是actions列表
|
||||||
action_type = action_result[0].get('action_type', '未知动作')
|
action_type = action_result[0].get("action_type", "未知动作")
|
||||||
elif isinstance(loop_plan_info, list) and loop_plan_info:
|
elif isinstance(loop_plan_info, list) and loop_plan_info:
|
||||||
# 直接是actions列表的情况
|
# 直接是actions列表的情况
|
||||||
action_type = loop_plan_info[0].get('action_type', '未知动作')
|
action_type = loop_plan_info[0].get("action_type", "未知动作")
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{self.log_prefix} 第{self._current_cycle_detail.cycle_id}次思考,"
|
f"{self.log_prefix} 第{self._current_cycle_detail.cycle_id}次思考,"
|
||||||
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, " # type: ignore
|
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, " # type: ignore
|
||||||
f"选择动作: {action_type}"
|
f"选择动作: {action_type}" + (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||||
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _determine_form_type(self) -> None:
|
def _determine_form_type(self) -> None:
|
||||||
|
|
@ -199,7 +195,9 @@ class HeartFChatting:
|
||||||
# 计算调整后的阈值
|
# 计算调整后的阈值
|
||||||
adjusted_threshold = 1 / self.talk_frequency_control.get_current_talk_frequency()
|
adjusted_threshold = 1 / self.talk_frequency_control.get_current_talk_frequency()
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix} 最近三次兴趣度总和: {total_recent_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}")
|
logger.info(
|
||||||
|
f"{self.log_prefix} 最近三次兴趣度总和: {total_recent_interest:.2f}, 调整后阈值: {adjusted_threshold:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
# 如果兴趣度总和小于阈值,进入breaking形式
|
# 如果兴趣度总和小于阈值,进入breaking形式
|
||||||
if total_recent_interest < adjusted_threshold:
|
if total_recent_interest < adjusted_threshold:
|
||||||
|
|
@ -209,7 +207,7 @@ class HeartFChatting:
|
||||||
logger.info(f"{self.log_prefix} 兴趣度充足,等待新消息")
|
logger.info(f"{self.log_prefix} 兴趣度充足,等待新消息")
|
||||||
self.focus_energy = 1
|
self.focus_energy = 1
|
||||||
|
|
||||||
async def _should_process_messages(self, new_message: List[Dict[str, Any]]) -> tuple[bool,float]:
|
async def _should_process_messages(self, new_message: List[DatabaseMessages]) -> tuple[bool, float]:
|
||||||
"""
|
"""
|
||||||
判断是否应该处理消息
|
判断是否应该处理消息
|
||||||
|
|
||||||
|
|
@ -226,9 +224,9 @@ class HeartFChatting:
|
||||||
modified_exit_count_threshold = self.focus_energy * 0.5 / talk_frequency
|
modified_exit_count_threshold = self.focus_energy * 0.5 / talk_frequency
|
||||||
modified_exit_interest_threshold = 1.5 / talk_frequency
|
modified_exit_interest_threshold = 1.5 / talk_frequency
|
||||||
total_interest = 0.0
|
total_interest = 0.0
|
||||||
for msg_dict in new_message:
|
for msg in new_message:
|
||||||
interest_value = msg_dict.get("interest_value")
|
interest_value = msg.interest_value
|
||||||
if interest_value is not None and msg_dict.get("processed_plain_text", ""):
|
if interest_value is not None and msg.processed_plain_text:
|
||||||
total_interest += float(interest_value)
|
total_interest += float(interest_value)
|
||||||
|
|
||||||
if new_message_count >= modified_exit_count_threshold:
|
if new_message_count >= modified_exit_count_threshold:
|
||||||
|
|
@ -244,7 +242,9 @@ class HeartFChatting:
|
||||||
if new_message_count > 0:
|
if new_message_count > 0:
|
||||||
# 只在兴趣值变化时输出log
|
# 只在兴趣值变化时输出log
|
||||||
if not hasattr(self, "_last_accumulated_interest") or total_interest != self._last_accumulated_interest:
|
if not hasattr(self, "_last_accumulated_interest") or total_interest != self._last_accumulated_interest:
|
||||||
logger.info(f"{self.log_prefix} 休息中,新消息:{new_message_count}条,累计兴趣值: {total_interest:.2f}, 活跃度: {talk_frequency:.1f}")
|
logger.info(
|
||||||
|
f"{self.log_prefix} 休息中,新消息:{new_message_count}条,累计兴趣值: {total_interest:.2f}, 活跃度: {talk_frequency:.1f}"
|
||||||
|
)
|
||||||
self._last_accumulated_interest = total_interest
|
self._last_accumulated_interest = total_interest
|
||||||
|
|
||||||
if total_interest >= modified_exit_interest_threshold:
|
if total_interest >= modified_exit_interest_threshold:
|
||||||
|
|
@ -262,28 +262,24 @@ class HeartFChatting:
|
||||||
)
|
)
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
return False,0.0
|
return False, 0.0
|
||||||
|
|
||||||
|
|
||||||
async def _loopbody(self):
|
async def _loopbody(self):
|
||||||
recent_messages_dict = message_api.get_messages_by_time_in_chat(
|
recent_messages_dict = message_api.get_messages_by_time_in_chat(
|
||||||
chat_id=self.stream_id,
|
chat_id=self.stream_id,
|
||||||
start_time=self.last_read_time,
|
start_time=self.last_read_time,
|
||||||
end_time=time.time(),
|
end_time=time.time(),
|
||||||
limit = 10,
|
limit=10,
|
||||||
limit_mode="latest",
|
limit_mode="latest",
|
||||||
filter_mai=True,
|
filter_mai=True,
|
||||||
filter_command=True,
|
filter_command=True,
|
||||||
)
|
)
|
||||||
# TODO: 修复!
|
|
||||||
from src.common.data_models import temporarily_transform_class_to_dict
|
|
||||||
temp_recent_messages_dict = [temporarily_transform_class_to_dict(msg) for msg in recent_messages_dict]
|
|
||||||
# 统一的消息处理逻辑
|
# 统一的消息处理逻辑
|
||||||
should_process,interest_value = await self._should_process_messages(temp_recent_messages_dict)
|
should_process, interest_value = await self._should_process_messages(recent_messages_dict)
|
||||||
|
|
||||||
if should_process:
|
if should_process:
|
||||||
self.last_read_time = time.time()
|
self.last_read_time = time.time()
|
||||||
await self._observe(interest_value = interest_value)
|
await self._observe(interest_value=interest_value)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Normal模式:消息数量不足,等待
|
# Normal模式:消息数量不足,等待
|
||||||
|
|
@ -298,9 +294,8 @@ class HeartFChatting:
|
||||||
cycle_timers: Dict[str, float],
|
cycle_timers: Dict[str, float],
|
||||||
thinking_id,
|
thinking_id,
|
||||||
actions,
|
actions,
|
||||||
selected_expressions:List[int] = None,
|
selected_expressions: List[int] = None,
|
||||||
) -> Tuple[Dict[str, Any], str, Dict[str, float]]:
|
) -> Tuple[Dict[str, Any], str, Dict[str, float]]:
|
||||||
|
|
||||||
with Timer("回复发送", cycle_timers):
|
with Timer("回复发送", cycle_timers):
|
||||||
reply_text = await self._send_response(
|
reply_text = await self._send_response(
|
||||||
reply_set=response_set,
|
reply_set=response_set,
|
||||||
|
|
@ -313,7 +308,7 @@ class HeartFChatting:
|
||||||
if platform is None:
|
if platform is None:
|
||||||
platform = getattr(self.chat_stream, "platform", "unknown")
|
platform = getattr(self.chat_stream, "platform", "unknown")
|
||||||
|
|
||||||
person = Person(platform = platform ,user_id = action_message.get("user_id", ""))
|
person = Person(platform=platform, user_id=action_message.get("user_id", ""))
|
||||||
person_name = person.person_name
|
person_name = person.person_name
|
||||||
action_prompt_display = f"你对{person_name}进行了回复:{reply_text}"
|
action_prompt_display = f"你对{person_name}进行了回复:{reply_text}"
|
||||||
|
|
||||||
|
|
@ -342,12 +337,10 @@ class HeartFChatting:
|
||||||
|
|
||||||
return loop_info, reply_text, cycle_timers
|
return loop_info, reply_text, cycle_timers
|
||||||
|
|
||||||
async def _observe(self,interest_value:float = 0.0) -> bool:
|
async def _observe(self, interest_value: float = 0.0) -> bool:
|
||||||
|
|
||||||
action_type = "no_action"
|
action_type = "no_action"
|
||||||
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
reply_text = "" # 初始化reply_text变量,避免UnboundLocalError
|
||||||
|
|
||||||
|
|
||||||
# 使用sigmoid函数将interest_value转换为概率
|
# 使用sigmoid函数将interest_value转换为概率
|
||||||
# 当interest_value为0时,概率接近0(使用Focus模式)
|
# 当interest_value为0时,概率接近0(使用Focus模式)
|
||||||
# 当interest_value很高时,概率接近1(使用Normal模式)
|
# 当interest_value很高时,概率接近1(使用Normal模式)
|
||||||
|
|
@ -361,12 +354,18 @@ class HeartFChatting:
|
||||||
x0 = 1.0 # 控制曲线中心点
|
x0 = 1.0 # 控制曲线中心点
|
||||||
return 1.0 / (1.0 + math.exp(-k * (interest_val - x0)))
|
return 1.0 / (1.0 + math.exp(-k * (interest_val - x0)))
|
||||||
|
|
||||||
normal_mode_probability = calculate_normal_mode_probability(interest_value) * 0.5 / self.talk_frequency_control.get_current_talk_frequency()
|
normal_mode_probability = (
|
||||||
|
calculate_normal_mode_probability(interest_value)
|
||||||
|
* 0.5
|
||||||
|
/ self.talk_frequency_control.get_current_talk_frequency()
|
||||||
|
)
|
||||||
|
|
||||||
# 根据概率决定使用哪种模式
|
# 根据概率决定使用哪种模式
|
||||||
if random.random() < normal_mode_probability:
|
if random.random() < normal_mode_probability:
|
||||||
mode = ChatMode.NORMAL
|
mode = ChatMode.NORMAL
|
||||||
logger.info(f"{self.log_prefix} 有兴趣({interest_value:.2f}),在{normal_mode_probability*100:.0f}%概率下选择回复")
|
logger.info(
|
||||||
|
f"{self.log_prefix} 有兴趣({interest_value:.2f}),在{normal_mode_probability * 100:.0f}%概率下选择回复"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
mode = ChatMode.FOCUS
|
mode = ChatMode.FOCUS
|
||||||
|
|
||||||
|
|
@ -388,9 +387,8 @@ class HeartFChatting:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} 记忆构建失败: {e}")
|
logger.error(f"{self.log_prefix} 记忆构建失败: {e}")
|
||||||
|
|
||||||
|
|
||||||
if random.random() > self.focus_value_control.get_current_focus_value() and mode == ChatMode.FOCUS:
|
if random.random() > self.focus_value_control.get_current_focus_value() and mode == ChatMode.FOCUS:
|
||||||
#如果激活度没有激活,并且聊天活跃度低,有可能不进行plan,相当于不在电脑前,不进行认真思考
|
# 如果激活度没有激活,并且聊天活跃度低,有可能不进行plan,相当于不在电脑前,不进行认真思考
|
||||||
actions = [
|
actions = [
|
||||||
{
|
{
|
||||||
"action_type": "no_action",
|
"action_type": "no_action",
|
||||||
|
|
@ -420,16 +418,14 @@ class HeartFChatting:
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
with Timer("规划器", cycle_timers):
|
with Timer("规划器", cycle_timers):
|
||||||
actions, _= await self.action_planner.plan(
|
actions, _ = await self.action_planner.plan(
|
||||||
mode=mode,
|
mode=mode,
|
||||||
loop_start_time=self.last_read_time,
|
loop_start_time=self.last_read_time,
|
||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 3. 并行执行所有动作
|
# 3. 并行执行所有动作
|
||||||
async def execute_action(action_info,actions):
|
async def execute_action(action_info, actions):
|
||||||
"""执行单个动作的通用函数"""
|
"""执行单个动作的通用函数"""
|
||||||
try:
|
try:
|
||||||
if action_info["action_type"] == "no_action":
|
if action_info["action_type"] == "no_action":
|
||||||
|
|
@ -448,12 +444,7 @@ class HeartFChatting:
|
||||||
action_name="no_action",
|
action_name="no_action",
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {"action_type": "no_action", "success": True, "reply_text": "", "command": ""}
|
||||||
"action_type": "no_action",
|
|
||||||
"success": True,
|
|
||||||
"reply_text": "",
|
|
||||||
"command": ""
|
|
||||||
}
|
|
||||||
elif action_info["action_type"] != "reply":
|
elif action_info["action_type"] != "reply":
|
||||||
# 执行普通动作
|
# 执行普通动作
|
||||||
with Timer("动作执行", cycle_timers):
|
with Timer("动作执行", cycle_timers):
|
||||||
|
|
@ -463,20 +454,19 @@ class HeartFChatting:
|
||||||
action_info["action_data"],
|
action_info["action_data"],
|
||||||
cycle_timers,
|
cycle_timers,
|
||||||
thinking_id,
|
thinking_id,
|
||||||
action_info["action_message"]
|
action_info["action_message"],
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"action_type": action_info["action_type"],
|
"action_type": action_info["action_type"],
|
||||||
"success": success,
|
"success": success,
|
||||||
"reply_text": reply_text,
|
"reply_text": reply_text,
|
||||||
"command": command
|
"command": command,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success, response_set, prompt_selected_expressions = await generator_api.generate_reply(
|
success, response_set, prompt_selected_expressions = await generator_api.generate_reply(
|
||||||
chat_stream=self.chat_stream,
|
chat_stream=self.chat_stream,
|
||||||
reply_message = action_info["action_message"],
|
reply_message=action_info["action_message"],
|
||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
choosen_actions=actions,
|
choosen_actions=actions,
|
||||||
reply_reason=action_info.get("reasoning", ""),
|
reply_reason=action_info.get("reasoning", ""),
|
||||||
|
|
@ -487,27 +477,19 @@ class HeartFChatting:
|
||||||
)
|
)
|
||||||
|
|
||||||
if prompt_selected_expressions and len(prompt_selected_expressions) > 1:
|
if prompt_selected_expressions and len(prompt_selected_expressions) > 1:
|
||||||
_,selected_expressions = prompt_selected_expressions
|
_, selected_expressions = prompt_selected_expressions
|
||||||
else:
|
else:
|
||||||
selected_expressions = []
|
selected_expressions = []
|
||||||
|
|
||||||
if not success or not response_set:
|
if not success or not response_set:
|
||||||
logger.info(f"对 {action_info['action_message'].get('processed_plain_text')} 的回复生成失败")
|
logger.info(
|
||||||
return {
|
f"对 {action_info['action_message'].get('processed_plain_text')} 的回复生成失败"
|
||||||
"action_type": "reply",
|
)
|
||||||
"success": False,
|
return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None}
|
||||||
"reply_text": "",
|
|
||||||
"loop_info": None
|
|
||||||
}
|
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
logger.debug(f"{self.log_prefix} 并行执行:回复生成任务已被取消")
|
logger.debug(f"{self.log_prefix} 并行执行:回复生成任务已被取消")
|
||||||
return {
|
return {"action_type": "reply", "success": False, "reply_text": "", "loop_info": None}
|
||||||
"action_type": "reply",
|
|
||||||
"success": False,
|
|
||||||
"reply_text": "",
|
|
||||||
"loop_info": None
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(
|
loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(
|
||||||
response_set=response_set,
|
response_set=response_set,
|
||||||
|
|
@ -521,7 +503,7 @@ class HeartFChatting:
|
||||||
"action_type": "reply",
|
"action_type": "reply",
|
||||||
"success": True,
|
"success": True,
|
||||||
"reply_text": reply_text,
|
"reply_text": reply_text,
|
||||||
"loop_info": loop_info
|
"loop_info": loop_info,
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{self.log_prefix} 执行动作时出错: {e}")
|
logger.error(f"{self.log_prefix} 执行动作时出错: {e}")
|
||||||
|
|
@ -531,10 +513,10 @@ class HeartFChatting:
|
||||||
"success": False,
|
"success": False,
|
||||||
"reply_text": "",
|
"reply_text": "",
|
||||||
"loop_info": None,
|
"loop_info": None,
|
||||||
"error": str(e)
|
"error": str(e),
|
||||||
}
|
}
|
||||||
|
|
||||||
action_tasks = [asyncio.create_task(execute_action(action,actions)) for action in actions]
|
action_tasks = [asyncio.create_task(execute_action(action, actions)) for action in actions]
|
||||||
|
|
||||||
# 并行执行所有任务
|
# 并行执行所有任务
|
||||||
results = await asyncio.gather(*action_tasks, return_exceptions=True)
|
results = await asyncio.gather(*action_tasks, return_exceptions=True)
|
||||||
|
|
@ -591,7 +573,6 @@ class HeartFChatting:
|
||||||
}
|
}
|
||||||
reply_text = action_reply_text
|
reply_text = action_reply_text
|
||||||
|
|
||||||
|
|
||||||
if s4u_config.enable_s4u:
|
if s4u_config.enable_s4u:
|
||||||
await stop_typing()
|
await stop_typing()
|
||||||
await mai_thinking_manager.get_mai_think(self.stream_id).do_think_after_response(reply_text)
|
await mai_thinking_manager.get_mai_think(self.stream_id).do_think_after_response(reply_text)
|
||||||
|
|
@ -692,11 +673,12 @@ class HeartFChatting:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False, "", ""
|
return False, "", ""
|
||||||
|
|
||||||
async def _send_response(self,
|
async def _send_response(
|
||||||
reply_set,
|
self,
|
||||||
message_data,
|
reply_set,
|
||||||
selected_expressions:List[int] = None,
|
message_data,
|
||||||
) -> str:
|
selected_expressions: List[int] = None,
|
||||||
|
) -> str:
|
||||||
new_message_count = message_api.count_new_messages(
|
new_message_count = message_api.count_new_messages(
|
||||||
chat_id=self.chat_stream.stream_id, start_time=self.last_read_time, end_time=time.time()
|
chat_id=self.chat_stream.stream_id, start_time=self.last_read_time, end_time=time.time()
|
||||||
)
|
)
|
||||||
|
|
@ -714,7 +696,7 @@ class HeartFChatting:
|
||||||
await send_api.text_to_stream(
|
await send_api.text_to_stream(
|
||||||
text=data,
|
text=data,
|
||||||
stream_id=self.chat_stream.stream_id,
|
stream_id=self.chat_stream.stream_id,
|
||||||
reply_message = message_data,
|
reply_message=message_data,
|
||||||
set_reply=need_reply,
|
set_reply=need_reply,
|
||||||
typing=False,
|
typing=False,
|
||||||
selected_expressions=selected_expressions,
|
selected_expressions=selected_expressions,
|
||||||
|
|
@ -724,7 +706,7 @@ class HeartFChatting:
|
||||||
await send_api.text_to_stream(
|
await send_api.text_to_stream(
|
||||||
text=data,
|
text=data,
|
||||||
stream_id=self.chat_stream.stream_id,
|
stream_id=self.chat_stream.stream_id,
|
||||||
reply_message = message_data,
|
reply_message=message_data,
|
||||||
set_reply=False,
|
set_reply=False,
|
||||||
typing=True,
|
typing=True,
|
||||||
selected_expressions=selected_expressions,
|
selected_expressions=selected_expressions,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from typing import List, Dict, Optional, Any, Tuple
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.common.database.database_model import Expression
|
from src.common.database.database_model import Expression
|
||||||
|
from src.common.data_models.database_data_model import DatabaseMessages
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.config.config import model_config, global_config
|
from src.config.config import model_config, global_config
|
||||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat_inclusive, build_anonymous_messages
|
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat_inclusive, build_anonymous_messages
|
||||||
|
|
@ -346,21 +347,17 @@ class ExpressionLearner:
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
|
|
||||||
# 获取上次学习时间
|
# 获取上次学习时间
|
||||||
random_msg_temp = get_raw_msg_by_timestamp_with_chat_inclusive(
|
random_msg = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||||
chat_id=self.chat_id,
|
chat_id=self.chat_id,
|
||||||
timestamp_start=self.last_learning_time,
|
timestamp_start=self.last_learning_time,
|
||||||
timestamp_end=current_time,
|
timestamp_end=current_time,
|
||||||
limit=num,
|
limit=num,
|
||||||
)
|
)
|
||||||
# TODO: 修复!
|
|
||||||
from src.common.data_models import temporarily_transform_class_to_dict
|
|
||||||
random_msg: Optional[List[Dict[str, Any]]] = [temporarily_transform_class_to_dict(msg) for msg in random_msg_temp] if random_msg_temp else None
|
|
||||||
|
|
||||||
# print(random_msg)
|
# print(random_msg)
|
||||||
if not random_msg or random_msg == []:
|
if not random_msg or random_msg == []:
|
||||||
return None
|
return None
|
||||||
# 转化成str
|
# 转化成str
|
||||||
chat_id: str = random_msg[0]["chat_id"]
|
chat_id: str = random_msg[0].chat_id
|
||||||
# random_msg_str: str = build_readable_messages(random_msg, timestamp_mode="normal")
|
# random_msg_str: str = build_readable_messages(random_msg, timestamp_mode="normal")
|
||||||
random_msg_str: str = await build_anonymous_messages(random_msg)
|
random_msg_str: str = await build_anonymous_messages(random_msg)
|
||||||
# print(f"random_msg_str:{random_msg_str}")
|
# print(f"random_msg_str:{random_msg_str}")
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,9 @@ class ActionModifier:
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
limit=min(int(global_config.chat.max_context_size * 0.33), 10),
|
limit=min(int(global_config.chat.max_context_size * 0.33), 10),
|
||||||
)
|
)
|
||||||
# TODO: 修复!
|
|
||||||
from src.common.data_models import temporarily_transform_class_to_dict
|
|
||||||
temp_msg_list_before_now_half = [temporarily_transform_class_to_dict(msg) for msg in message_list_before_now_half]
|
|
||||||
chat_content = build_readable_messages(
|
chat_content = build_readable_messages(
|
||||||
temp_msg_list_before_now_half,
|
message_list_before_now_half,
|
||||||
replace_bot_name=True,
|
replace_bot_name=True,
|
||||||
merge_messages=False,
|
merge_messages=False,
|
||||||
timestamp_mode="relative",
|
timestamp_mode="relative",
|
||||||
|
|
|
||||||
|
|
@ -280,11 +280,8 @@ class ActionPlanner:
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
limit=int(global_config.chat.max_context_size * 0.6),
|
limit=int(global_config.chat.max_context_size * 0.6),
|
||||||
)
|
)
|
||||||
# TODO: 修复!
|
|
||||||
from src.common.data_models import temporarily_transform_class_to_dict
|
|
||||||
temp_msg_list_before_now = [temporarily_transform_class_to_dict(msg) for msg in message_list_before_now]
|
|
||||||
chat_content_block, message_id_list = build_readable_messages_with_id(
|
chat_content_block, message_id_list = build_readable_messages_with_id(
|
||||||
messages=temp_msg_list_before_now,
|
messages=message_list_before_now,
|
||||||
timestamp_mode="normal_no_YMD",
|
timestamp_mode="normal_no_YMD",
|
||||||
read_mark=self.last_obs_time_mark,
|
read_mark=self.last_obs_time_mark,
|
||||||
truncate=True,
|
truncate=True,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from typing import List, Dict, Any, Tuple, Optional, Callable
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
|
|
||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
|
from src.common.logger import get_logger
|
||||||
from src.common.message_repository import find_messages, count_messages
|
from src.common.message_repository import find_messages, count_messages
|
||||||
from src.common.data_models.database_data_model import DatabaseMessages
|
from src.common.data_models.database_data_model import DatabaseMessages
|
||||||
from src.common.database.database_model import ActionRecords
|
from src.common.database.database_model import ActionRecords
|
||||||
|
|
@ -14,6 +15,7 @@ from src.person_info.person_info import Person, get_person_id
|
||||||
from src.chat.utils.utils import translate_timestamp_to_human_readable, assign_message_ids
|
from src.chat.utils.utils import translate_timestamp_to_human_readable, assign_message_ids
|
||||||
|
|
||||||
install(extra_lines=3)
|
install(extra_lines=3)
|
||||||
|
logger = get_logger("chat_message_builder")
|
||||||
|
|
||||||
|
|
||||||
def replace_user_references_sync(
|
def replace_user_references_sync(
|
||||||
|
|
@ -349,7 +351,9 @@ def get_raw_msg_before_timestamp_with_chat(chat_id: str, timestamp: float, limit
|
||||||
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit)
|
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
def get_raw_msg_before_timestamp_with_users(timestamp: float, person_ids: list, limit: int = 0) -> List[DatabaseMessages]:
|
def get_raw_msg_before_timestamp_with_users(
|
||||||
|
timestamp: float, person_ids: list, limit: int = 0
|
||||||
|
) -> List[DatabaseMessages]:
|
||||||
"""获取指定时间戳之前的消息,按时间升序排序,返回消息列表
|
"""获取指定时间戳之前的消息,按时间升序排序,返回消息列表
|
||||||
limit: 限制返回的消息数量,0为不限制
|
limit: 限制返回的消息数量,0为不限制
|
||||||
"""
|
"""
|
||||||
|
|
@ -776,7 +780,7 @@ async def build_readable_messages_with_list(
|
||||||
|
|
||||||
|
|
||||||
def build_readable_messages_with_id(
|
def build_readable_messages_with_id(
|
||||||
messages: List[Dict[str, Any]],
|
messages: List[DatabaseMessages],
|
||||||
replace_bot_name: bool = True,
|
replace_bot_name: bool = True,
|
||||||
merge_messages: bool = False,
|
merge_messages: bool = False,
|
||||||
timestamp_mode: str = "relative",
|
timestamp_mode: str = "relative",
|
||||||
|
|
@ -807,7 +811,7 @@ def build_readable_messages_with_id(
|
||||||
|
|
||||||
|
|
||||||
def build_readable_messages(
|
def build_readable_messages(
|
||||||
messages: List[Dict[str, Any]],
|
messages: List[DatabaseMessages],
|
||||||
replace_bot_name: bool = True,
|
replace_bot_name: bool = True,
|
||||||
merge_messages: bool = False,
|
merge_messages: bool = False,
|
||||||
timestamp_mode: str = "relative",
|
timestamp_mode: str = "relative",
|
||||||
|
|
@ -835,15 +839,15 @@ def build_readable_messages(
|
||||||
if not messages:
|
if not messages:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
copy_messages = [msg.copy() for msg in messages]
|
copy_messages = list(messages)
|
||||||
|
|
||||||
if show_actions and copy_messages:
|
if show_actions and copy_messages:
|
||||||
# 获取所有消息的时间范围
|
# 获取所有消息的时间范围
|
||||||
min_time = min(msg.get("time", 0) for msg in copy_messages)
|
min_time = min(msg.time or 0 for msg in copy_messages)
|
||||||
max_time = max(msg.get("time", 0) for msg in copy_messages)
|
max_time = max(msg.time or 0 for msg in copy_messages)
|
||||||
|
|
||||||
# 从第一条消息中获取chat_id
|
# 从第一条消息中获取chat_id
|
||||||
chat_id = copy_messages[0].get("chat_id") if copy_messages else None
|
chat_id = copy_messages[0].chat_id if copy_messages else None
|
||||||
|
|
||||||
# 获取这个时间范围内的动作记录,并匹配chat_id
|
# 获取这个时间范围内的动作记录,并匹配chat_id
|
||||||
actions_in_range = (
|
actions_in_range = (
|
||||||
|
|
@ -883,7 +887,7 @@ def build_readable_messages(
|
||||||
copy_messages.append(action_msg)
|
copy_messages.append(action_msg)
|
||||||
|
|
||||||
# 重新按时间排序
|
# 重新按时间排序
|
||||||
copy_messages.sort(key=lambda x: x.get("time", 0))
|
copy_messages.sort(key=lambda x: x.time or 0)
|
||||||
|
|
||||||
if read_mark <= 0:
|
if read_mark <= 0:
|
||||||
# 没有有效的 read_mark,直接格式化所有消息
|
# 没有有效的 read_mark,直接格式化所有消息
|
||||||
|
|
@ -905,8 +909,8 @@ def build_readable_messages(
|
||||||
return formatted_string
|
return formatted_string
|
||||||
else:
|
else:
|
||||||
# 按 read_mark 分割消息
|
# 按 read_mark 分割消息
|
||||||
messages_before_mark = [msg for msg in copy_messages if msg.get("time", 0) <= read_mark]
|
messages_before_mark = [msg for msg in copy_messages if (msg.time or 0) <= read_mark]
|
||||||
messages_after_mark = [msg for msg in copy_messages if msg.get("time", 0) > read_mark]
|
messages_after_mark = [msg for msg in copy_messages if (msg.time or 0) > read_mark]
|
||||||
|
|
||||||
# 共享的图片映射字典和计数器
|
# 共享的图片映射字典和计数器
|
||||||
pic_id_mapping = {}
|
pic_id_mapping = {}
|
||||||
|
|
@ -960,13 +964,13 @@ def build_readable_messages(
|
||||||
return "".join(result_parts)
|
return "".join(result_parts)
|
||||||
|
|
||||||
|
|
||||||
async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
|
async def build_anonymous_messages(messages: List[DatabaseMessages]) -> str:
|
||||||
"""
|
"""
|
||||||
构建匿名可读消息,将不同人的名称转为唯一占位符(A、B、C...),bot自己用SELF。
|
构建匿名可读消息,将不同人的名称转为唯一占位符(A、B、C...),bot自己用SELF。
|
||||||
处理 回复<aaa:bbb> 和 @<aaa:bbb> 字段,将bbb映射为匿名占位符。
|
处理 回复<aaa:bbb> 和 @<aaa:bbb> 字段,将bbb映射为匿名占位符。
|
||||||
"""
|
"""
|
||||||
if not messages:
|
if not messages:
|
||||||
print("111111111111没有消息,无法构建匿名消息")
|
logger.warning("没有消息,无法构建匿名消息")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
person_map = {}
|
person_map = {}
|
||||||
|
|
@ -1017,14 +1021,9 @@ async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
|
||||||
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
try:
|
try:
|
||||||
platform: str = msg.get("chat_info_platform") # type: ignore
|
platform = msg.chat_info.platform
|
||||||
user_id = msg.get("user_id")
|
user_id = msg.user_info.user_id
|
||||||
_timestamp = msg.get("time")
|
content = msg.display_message or msg.processed_plain_text or ""
|
||||||
content: str = ""
|
|
||||||
if msg.get("display_message"):
|
|
||||||
content = msg.get("display_message", "")
|
|
||||||
else:
|
|
||||||
content = msg.get("processed_plain_text", "")
|
|
||||||
|
|
||||||
if "ᶠ" in content:
|
if "ᶠ" in content:
|
||||||
content = content.replace("ᶠ", "")
|
content = content.replace("ᶠ", "")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue