feat:修复no_reply起始时间,移除normal消息管理器,不再并行生成回复,为focus提供退出方法
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import asyncio
|
||||
import time
|
||||
import traceback
|
||||
from collections import deque
|
||||
from typing import Optional, Deque, List
|
||||
from typing import Optional, List
|
||||
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
from rich.traceback import install
|
||||
@@ -16,9 +15,9 @@ from src.config.config import global_config
|
||||
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
||||
from src.chat.focus_chat.hfc_utils import CycleDetail
|
||||
from random import random
|
||||
from src.chat.focus_chat.hfc_utils import create_thinking_message_from_dict, add_messages_to_manager,get_recent_message_stats,cleanup_thinking_message_by_id
|
||||
from src.chat.focus_chat.hfc_utils import get_recent_message_stats
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
from src.plugin_system.apis import generator_api
|
||||
from src.plugin_system.apis import generator_api,send_api,message_api
|
||||
from src.chat.willing.willing_manager import get_willing_manager
|
||||
from .priority_manager import PriorityManager
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat
|
||||
@@ -201,14 +200,22 @@ class HeartFChatting:
|
||||
|
||||
async def _loopbody(self):
|
||||
if self.loop_mode == "focus":
|
||||
|
||||
self.energy_value -= 5 * (1/global_config.chat.exit_focus_threshold)
|
||||
if self.energy_value <= 0:
|
||||
self.loop_mode = "normal"
|
||||
return True
|
||||
|
||||
|
||||
return await self._observe()
|
||||
elif self.loop_mode == "normal":
|
||||
new_messages_data = get_raw_msg_by_timestamp_with_chat(
|
||||
chat_id=self.stream_id, timestamp_start=self.last_read_time, timestamp_end=time.time(),limit=10,limit_mode="earliest",fliter_bot=True
|
||||
)
|
||||
|
||||
if len(new_messages_data) > 5:
|
||||
if len(new_messages_data) > 4 * global_config.chat.auto_focus_threshold:
|
||||
self.loop_mode = "focus"
|
||||
self.energy_value = 100
|
||||
return True
|
||||
|
||||
if new_messages_data:
|
||||
@@ -228,10 +235,8 @@ class HeartFChatting:
|
||||
# 创建新的循环信息
|
||||
cycle_timers, thinking_id = self.start_cycle()
|
||||
|
||||
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考")
|
||||
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考[模式:{self.loop_mode}]")
|
||||
|
||||
if message_data:
|
||||
await create_thinking_message_from_dict(message_data,self.chat_stream,thinking_id)
|
||||
|
||||
async with global_prompt_manager.async_message_scope(
|
||||
self.chat_stream.context.get_template_name()
|
||||
@@ -257,7 +262,14 @@ class HeartFChatting:
|
||||
|
||||
#如果normal,开始一个回复生成进程,先准备好回复(其实是和planer同时进行的)
|
||||
if self.loop_mode == "normal":
|
||||
gen_task = asyncio.create_task(self._generate_normal_response(message_data, available_actions))
|
||||
person_info_manager = get_person_info_manager()
|
||||
person_id = person_info_manager.get_person_id(
|
||||
message_data.get("chat_info_platform"), message_data.get("user_id")
|
||||
)
|
||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
||||
reply_to_str = f"{person_name}:{message_data.get('processed_plain_text')}"
|
||||
|
||||
gen_task = asyncio.create_task(self._generate_response(message_data, available_actions,reply_to_str))
|
||||
|
||||
|
||||
with Timer("规划器", cycle_timers):
|
||||
@@ -299,6 +311,7 @@ class HeartFChatting:
|
||||
|
||||
|
||||
if action_type == "no_action":
|
||||
# 等待回复生成完毕
|
||||
gather_timeout = global_config.chat.thinking_timeout
|
||||
try:
|
||||
response_set = await asyncio.wait_for(gen_task, timeout=gather_timeout)
|
||||
@@ -308,7 +321,7 @@ class HeartFChatting:
|
||||
if response_set:
|
||||
content = " ".join([item[1] for item in response_set if item[0] == "text"])
|
||||
|
||||
|
||||
# 模型炸了,没有回复内容生成
|
||||
if not response_set or (
|
||||
action_type not in ["no_action"] and not is_parallel
|
||||
):
|
||||
@@ -318,25 +331,15 @@ class HeartFChatting:
|
||||
logger.info(
|
||||
f"[{self.log_prefix}] {global_config.bot.nickname} 原本想要回复:{content},但选择执行{action_type},不发表回复"
|
||||
)
|
||||
# 如果模型未生成回复,移除思考消息
|
||||
await cleanup_thinking_message_by_id(self.chat_stream.stream_id,thinking_id,self.log_prefix)
|
||||
return False
|
||||
|
||||
logger.info(f"[{self.log_prefix}] {global_config.bot.nickname} 决定的回复内容: {content}")
|
||||
|
||||
# 提取回复文本
|
||||
reply_texts = [item[1] for item in response_set if item[0] == "text"]
|
||||
if not reply_texts:
|
||||
logger.info(f"[{self.log_prefix}] 回复内容中没有文本,不发送消息")
|
||||
await cleanup_thinking_message_by_id(self.chat_stream.stream_id,thinking_id,self.log_prefix)
|
||||
return False
|
||||
|
||||
# 发送回复 (不再需要传入 chat)
|
||||
await add_messages_to_manager(message_data, reply_texts, thinking_id,self.chat_stream.stream_id)
|
||||
|
||||
return response_set if response_set else False
|
||||
|
||||
await self._send_response(response_set, reply_to_str, loop_start_time)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -465,7 +468,7 @@ class HeartFChatting:
|
||||
# 新增:消息计数和疲惫检查
|
||||
if action == "reply" and success:
|
||||
self._message_count += 1
|
||||
current_threshold = self._get_current_fatigue_threshold()
|
||||
current_threshold = max(10, int(30 / global_config.chat.exit_focus_threshold))
|
||||
logger.info(
|
||||
f"{self.log_prefix} 已发送第 {self._message_count} 条消息(动态阈值: {current_threshold}, exit_focus_threshold: {global_config.chat.exit_focus_threshold})"
|
||||
)
|
||||
@@ -486,14 +489,6 @@ class HeartFChatting:
|
||||
return command
|
||||
return ""
|
||||
|
||||
def _get_current_fatigue_threshold(self) -> int:
|
||||
"""动态获取当前的疲惫阈值,基于exit_focus_threshold配置
|
||||
|
||||
Returns:
|
||||
int: 当前的疲惫阈值
|
||||
"""
|
||||
return max(10, int(30 / global_config.chat.exit_focus_threshold))
|
||||
|
||||
|
||||
async def shutdown(self):
|
||||
"""优雅关闭HeartFChatting实例,取消活动循环任务"""
|
||||
@@ -653,21 +648,14 @@ class HeartFChatting:
|
||||
return True
|
||||
|
||||
|
||||
async def _generate_normal_response(
|
||||
self, message_data: dict, available_actions: Optional[list]
|
||||
async def _generate_response(
|
||||
self, message_data: dict, available_actions: Optional[list],reply_to:str
|
||||
) -> Optional[list]:
|
||||
"""生成普通回复"""
|
||||
try:
|
||||
person_info_manager = get_person_info_manager()
|
||||
person_id = person_info_manager.get_person_id(
|
||||
message_data.get("chat_info_platform"), message_data.get("user_id")
|
||||
)
|
||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
||||
reply_to_str = f"{person_name}:{message_data.get('processed_plain_text')}"
|
||||
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
reply_to=reply_to_str,
|
||||
reply_to=reply_to,
|
||||
available_actions=available_actions,
|
||||
enable_tool=global_config.tool.enable_in_normal_chat,
|
||||
request_type="normal.replyer",
|
||||
@@ -682,3 +670,37 @@ class HeartFChatting:
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.log_prefix}] 回复生成出现错误:{str(e)} {traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
|
||||
async def _send_response(
|
||||
self, reply_set, reply_to, thinking_start_time
|
||||
):
|
||||
current_time = time.time()
|
||||
new_message_count = message_api.count_new_messages(
|
||||
chat_id=self.chat_stream.stream_id, start_time=thinking_start_time, end_time=current_time
|
||||
)
|
||||
|
||||
need_reply = new_message_count >= random.randint(2, 4)
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}引用回复"
|
||||
)
|
||||
|
||||
reply_text = ""
|
||||
first_replyed = False
|
||||
for reply_seg in reply_set:
|
||||
data = reply_seg[1]
|
||||
if not first_replyed:
|
||||
if need_reply:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, reply_to=reply_to, typing=False)
|
||||
first_replyed = True
|
||||
else:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, typing=False)
|
||||
first_replyed = True
|
||||
else:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, typing=True)
|
||||
reply_text += data
|
||||
|
||||
return reply_text
|
||||
|
||||
|
||||
@@ -7,11 +7,7 @@ from typing import Dict, Any
|
||||
from src.config.config import global_config
|
||||
from src.chat.message_receive.message import MessageThinking
|
||||
from src.chat.message_receive.normal_message_sender import message_manager
|
||||
from typing import List
|
||||
from maim_message import Seg
|
||||
from src.common.message_repository import count_messages
|
||||
from ..message_receive.message import MessageSending, MessageSet, message_from_db_dict
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
|
||||
|
||||
|
||||
@@ -125,71 +121,6 @@ async def cleanup_thinking_message_by_id(chat_id: str, thinking_id: str, log_pre
|
||||
|
||||
|
||||
|
||||
async def add_messages_to_manager(
|
||||
message_data: dict, response_set: List[str], thinking_id, chat_id
|
||||
) -> Optional[MessageSending]:
|
||||
"""发送回复消息"""
|
||||
|
||||
chat_stream = get_chat_manager().get_stream(chat_id)
|
||||
|
||||
container = await message_manager.get_container(chat_id) # 使用 self.stream_id
|
||||
thinking_message = None
|
||||
|
||||
for msg in container.messages[:]:
|
||||
# print(msg)
|
||||
if isinstance(msg, MessageThinking) and msg.message_info.message_id == thinking_id:
|
||||
thinking_message = msg
|
||||
container.messages.remove(msg)
|
||||
break
|
||||
|
||||
if not thinking_message:
|
||||
logger.warning(f"[{chat_id}] 未找到对应的思考消息 {thinking_id},可能已超时被移除")
|
||||
return None
|
||||
|
||||
thinking_start_time = thinking_message.thinking_start_time
|
||||
message_set = MessageSet(chat_stream, thinking_id) # 使用 self.chat_stream
|
||||
|
||||
sender_info = UserInfo(
|
||||
user_id=message_data.get("user_id"),
|
||||
user_nickname=message_data.get("user_nickname"),
|
||||
platform=message_data.get("chat_info_platform"),
|
||||
)
|
||||
|
||||
reply = message_from_db_dict(message_data)
|
||||
|
||||
|
||||
mark_head = False
|
||||
first_bot_msg = None
|
||||
for msg in response_set:
|
||||
if global_config.debug.debug_show_chat_mode:
|
||||
msg += "ⁿ"
|
||||
message_segment = Seg(type="text", data=msg)
|
||||
bot_message = MessageSending(
|
||||
message_id=thinking_id,
|
||||
chat_stream=chat_stream, # 使用 self.chat_stream
|
||||
bot_user_info=UserInfo(
|
||||
user_id=global_config.bot.qq_account,
|
||||
user_nickname=global_config.bot.nickname,
|
||||
platform=message_data.get("chat_info_platform"),
|
||||
),
|
||||
sender_info=sender_info,
|
||||
message_segment=message_segment,
|
||||
reply=reply,
|
||||
is_head=not mark_head,
|
||||
is_emoji=False,
|
||||
thinking_start_time=thinking_start_time,
|
||||
apply_set_reply_logic=True,
|
||||
)
|
||||
if not mark_head:
|
||||
mark_head = True
|
||||
first_bot_msg = bot_message
|
||||
message_set.add_message(bot_message)
|
||||
|
||||
await message_manager.add_message(message_set)
|
||||
|
||||
return first_bot_msg
|
||||
|
||||
|
||||
def get_recent_message_stats(minutes: int = 30, chat_id: str = None) -> dict:
|
||||
"""
|
||||
Args:
|
||||
|
||||
@@ -280,17 +280,12 @@ class NormalChatConfig(ConfigBase):
|
||||
at_bot_inevitable_reply: bool = False
|
||||
"""@bot 必然回复"""
|
||||
|
||||
enable_planner: bool = False
|
||||
"""是否启用动作规划器"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class FocusChatConfig(ConfigBase):
|
||||
"""专注聊天配置类"""
|
||||
|
||||
think_interval: float = 1
|
||||
"""思考间隔(秒)"""
|
||||
|
||||
consecutive_replies: float = 1
|
||||
"""连续回复能力,值越高,麦麦连续回复的概率越高"""
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ class NoReplyAction(BaseAction):
|
||||
count = NoReplyAction._consecutive_count
|
||||
|
||||
reason = self.action_data.get("reason", "")
|
||||
start_time = time.time()
|
||||
check_interval = 1.0 # 每秒检查一次
|
||||
start_time = self.action_data.get("loop_start_time", time.time())
|
||||
check_interval = 0.6 # 每秒检查一次
|
||||
|
||||
# 随机生成本次等待需要的新消息数量阈值
|
||||
exit_message_count_threshold = random.randint(self._min_exit_message_count, self._max_exit_message_count)
|
||||
|
||||
@@ -98,7 +98,7 @@ class ReplyAction(BaseAction):
|
||||
)
|
||||
|
||||
# 根据新消息数量决定是否使用reply_to
|
||||
need_reply = new_message_count >= random.randint(2, 5)
|
||||
need_reply = new_message_count >= random.randint(2, 4)
|
||||
logger.info(
|
||||
f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}引用回复"
|
||||
)
|
||||
|
||||
@@ -119,10 +119,8 @@ willing_mode = "classical" # 回复意愿模式 —— 经典模式:classical
|
||||
response_interested_rate_amplifier = 1 # 麦麦回复兴趣度放大系数
|
||||
mentioned_bot_inevitable_reply = true # 提及 bot 必然回复
|
||||
at_bot_inevitable_reply = true # @bot 必然回复(包含提及)
|
||||
enable_planner = true # 是否启用动作规划器(与focus_chat共享actions)
|
||||
|
||||
[focus_chat] #专注聊天
|
||||
think_interval = 3 # 思考间隔 单位秒,可以有效减少消耗
|
||||
consecutive_replies = 1 # 连续回复能力,值越高,麦麦连续回复的概率越高
|
||||
|
||||
[tool]
|
||||
|
||||
Reference in New Issue
Block a user