fix:修复hfc根本不会被触发的bug

This commit is contained in:
SengokuCola
2025-04-23 23:08:19 +08:00
parent 5782d4425b
commit 7733782929
13 changed files with 621 additions and 472 deletions

View File

@@ -3,7 +3,7 @@ from ...config.config import global_config
from .message import MessageRecv
from ..PFC.pfc_manager import PFCManager
from .chat_stream import chat_manager
from ..chat_module.only_process.only_message_process import MessageProcessor
from .only_message_process import MessageProcessor
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
from ..heartFC_chat.heartflow_processor import HeartFCProcessor

View File

@@ -13,9 +13,7 @@ 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_calculater import Timer # <--- Import Timer
# --- Import necessary dependencies directly ---
from .heartFC_generator import ResponseGenerator # Assuming this is the type for gpt
from src.plugins.heartFC_chat.heartFC_generator import HeartFCGenerator
from src.do_tool.tool_use import ToolUser
from ..chat.message_sender import message_manager # <-- Import the global manager
from src.plugins.chat.emoji_manager import emoji_manager
@@ -77,9 +75,7 @@ class HeartFChatting:
def __init__(
self,
chat_id: str,
gpt_instance: ResponseGenerator, # 文本回复生成器
tool_user_instance: ToolUser, # 工具使用实例
chat_id: str
):
"""
HeartFChatting 初始化函数
@@ -97,13 +93,12 @@ class HeartFChatting:
# 初始化状态控制
self._initialized = False # 是否已初始化标志
self._init_lock = asyncio.Lock() # 初始化锁(确保只初始化一次)
self._processing_lock = asyncio.Lock() # 处理锁(确保单次Plan-Replier-Sender周期)
self._timer_lock = asyncio.Lock() # 计时器锁(安全更新计时器)
# 依赖注入存储
self.gpt_instance = gpt_instance # 文本回复生成器
self.tool_user = tool_user_instance # 工具使用实例
self.gpt_instance = HeartFCGenerator() # 文本回复生成器
self.tool_user = ToolUser() # 工具使用实例
# LLM规划器配置
self.planner_llm = LLMRequest(
@@ -117,7 +112,6 @@ class HeartFChatting:
self._loop_timer: float = 0.0 # 循环剩余时间(秒)
self._loop_active: bool = False # 循环是否正在运行
self._loop_task: Optional[asyncio.Task] = None # 主循环任务
self._trigger_count_this_activation: int = 0 # 当前激活周期内的触发计数
self._initial_duration: float = INITIAL_DURATION # 首次触发增加的时间
self._last_added_duration: float = self._initial_duration # 上次增加的时间
@@ -131,35 +125,34 @@ class HeartFChatting:
懒初始化以使用提供的标识符解析chat_stream和sub_hf。
确保实例已准备好处理触发器。
"""
async with self._init_lock:
if self._initialized:
return True
log_prefix = self._get_log_prefix() # 获取前缀
try:
self.chat_stream = chat_manager.get_stream(self.stream_id)
if self._initialized:
return True
log_prefix = self._get_log_prefix() # 获取前缀
try:
self.chat_stream = chat_manager.get_stream(self.stream_id)
if not self.chat_stream:
logger.error(f"{log_prefix} 获取ChatStream失败。")
return False
# <-- 在这里导入 heartflow 实例
from src.heart_flow.heartflow import heartflow
self.sub_hf = heartflow.get_subheartflow(self.stream_id)
if not self.sub_hf:
logger.warning(f"{log_prefix} 获取SubHeartflow失败。一些功能可能受限。")
self._initialized = True
logger.info(f"麦麦感觉到了激发了HeartFChatting{log_prefix} 初始化成功。")
return True
except Exception as e:
logger.error(f"{log_prefix} 初始化失败: {e}")
logger.error(traceback.format_exc())
if not self.chat_stream:
logger.error(f"{log_prefix} 获取ChatStream失败。")
return False
# <-- 在这里导入 heartflow 实例
from src.heart_flow.heartflow import heartflow
self.sub_hf = heartflow.get_subheartflow(self.stream_id)
if not self.sub_hf:
logger.warning(f"{log_prefix} 获取SubHeartflow失败。一些功能可能受限。")
self._initialized = True
logger.info(f"麦麦感觉到了激发了HeartFChatting{log_prefix} 初始化成功。")
return True
except Exception as e:
logger.error(f"{log_prefix} 初始化失败: {e}")
logger.error(traceback.format_exc())
return False
async def add_time(self):
"""
为麦麦添加时间,麦麦有兴趣时,时间增加。
为麦麦添加时间,麦麦有兴趣时,固定增加15秒
"""
log_prefix = self._get_log_prefix()
if not self._initialized:
@@ -168,45 +161,61 @@ class HeartFChatting:
return
async with self._timer_lock:
duration_to_add: float = 0.0
duration_to_add: float = 15.0 # 固定增加15秒
if not self._loop_active: # 首次触发
logger.info(f"{log_prefix} 麦麦有兴趣! 打算聊15s.")
else: # 循环已激活
logger.info(f"{log_prefix} 麦麦想继续聊15s, 还能聊: {self._loop_timer:.1f}s.")
if not self._loop_active: # First trigger for this activation cycle
duration_to_add = self._initial_duration # 使用初始值
self._last_added_duration = duration_to_add # 更新上次增加的值
self._trigger_count_this_activation = 1 # Start counting
logger.info(
f"{log_prefix} 麦麦有兴趣! #{self._trigger_count_this_activation}. 麦麦打算聊: {duration_to_add:.2f}s."
)
else: # Loop is already active, apply 50% reduction
self._trigger_count_this_activation += 1
duration_to_add = self._last_added_duration * 0.5
if duration_to_add < 1.5:
duration_to_add = 1.5
# Update _last_added_duration only if it's >= 0.5 to prevent it from becoming too small
self._last_added_duration = duration_to_add
logger.info(
f"{log_prefix} 麦麦兴趣增加! #{self._trigger_count_this_activation}. 想继续聊: {duration_to_add:.2f}s, 麦麦还能聊: {self._loop_timer:.1f}s."
)
# 添加计算出的时间
# 添加固定时间
new_timer_value = self._loop_timer + duration_to_add
# Add max timer duration limit? e.g., max(0, min(new_timer_value, 300))
self._loop_timer = max(0, new_timer_value)
# Log less frequently, e.g., every 10 seconds or significant change?
# if self._trigger_count_this_activation % 5 == 0:
# logger.info(f"{log_prefix} 麦麦现在想聊{self._loop_timer:.1f}秒")
# Start the loop if it wasn't active and timer is positive
# 添加时间后,检查是否需要启动循环
await self._start_loop_if_needed()
async def start(self):
"""
显式尝试启动 HeartFChatting 的主循环。
如果循环未激活且计时器 > 0则启动循环。
"""
log_prefix = self._get_log_prefix()
if not self._initialized:
if not await self._initialize():
logger.error(f"{log_prefix} 无法启动循环: 初始化失败。")
return
logger.info(f"{log_prefix} 尝试显式启动循环...")
await self._start_loop_if_needed()
async def _start_loop_if_needed(self):
"""检查是否需要启动主循环如果未激活且计时器大于0则启动。"""
log_prefix = self._get_log_prefix()
should_start_loop = False
async with self._timer_lock:
# 检查是否满足启动条件:未激活且计时器有时间
if not self._loop_active and self._loop_timer > 0:
self._loop_active = True
if self._loop_task and not self._loop_task.done():
logger.warning(f"{log_prefix} 发现意外的循环任务正在进行。取消它。")
self._loop_task.cancel()
should_start_loop = True
self._loop_active = True # 在锁内标记为活动,防止重复启动
self._loop_task = asyncio.create_task(self._run_pf_loop())
self._loop_task.add_done_callback(self._handle_loop_completion)
elif self._loop_active:
logger.trace(f"{log_prefix} 循环已经激活。计时器延长")
if should_start_loop:
# 检查是否已有任务在运行(理论上不应该,因为 _loop_active=False
if self._loop_task and not self._loop_task.done():
logger.warning(f"{log_prefix} 发现之前的循环任务仍在运行(不符合预期)。取消旧任务")
self._loop_task.cancel()
try:
# 等待旧任务确实被取消
await asyncio.wait_for(self._loop_task, timeout=0.5)
except (asyncio.CancelledError, asyncio.TimeoutError):
pass # 忽略取消或超时错误
self._loop_task = None # 清理旧任务引用
logger.info(f"{log_prefix} 计时器 > 0 且循环未激活,启动主循环...")
# 创建新的循环任务
self._loop_task = asyncio.create_task(self._run_pf_loop())
# 添加完成回调
self._loop_task.add_done_callback(self._handle_loop_completion)
# else:
# logger.trace(f"{log_prefix} 不需要启动循环已激活或计时器为0") # 可以取消注释以进行调试
def _handle_loop_completion(self, task: asyncio.Task):
"""当 _run_pf_loop 任务完成时执行的回调。"""
@@ -228,8 +237,6 @@ class HeartFChatting:
if self._processing_lock.locked():
logger.warning(f"{log_prefix} HeartFChatting: 处理锁在循环结束时仍被锁定,强制释放。")
self._processing_lock.release()
# Instance removal is now handled by SubHeartflow
# asyncio.create_task(self.heartfc_controller._remove_heartFC_chat_instance(self.stream_id)) # Removed
async def _run_pf_loop(self):
"""

View File

@@ -22,7 +22,7 @@ llm_config = LogConfig(
logger = get_module_logger("llm_generator", config=llm_config)
class ResponseGenerator:
class HeartFCGenerator:
def __init__(self):
self.model_normal = LLMRequest(
model=global_config.llm_normal,

View File

@@ -67,11 +67,8 @@ class HeartFCProcessor:
group_info=groupinfo,
)
# --- 确保 SubHeartflow 存在 ---
subheartflow = await heartflow.create_subheartflow(chat.stream_id)
if not subheartflow:
logger.error(f"无法为 stream_id {chat.stream_id} 创建或获取 SubHeartflow中止处理")
return
message.update_chat_stream(chat)
@@ -137,33 +134,16 @@ class HeartFCProcessor:
# --- 修改:兴趣度更新逻辑 --- #
if is_mentioned:
interest_increase_on_mention = 2
interest_increase_on_mention = 1
mentioned_boost = interest_increase_on_mention # 从配置获取提及增加值
interested_rate += mentioned_boost
logger.trace(f"消息提及机器人,额外增加兴趣 {mentioned_boost:.2f}")
# 更新兴趣度 (调用 SubHeartflow 的方法)
current_interest = 0.0 # 初始化
try:
# 获取当前时间,传递给 increase_interest
current_time = time.time()
await subheartflow.interest_chatting.increase_interest(current_time, value=interested_rate)
current_interest = await subheartflow.get_interest_level() # 获取更新后的值
current_time = time.time()
await subheartflow.interest_chatting.increase_interest(current_time, value=interested_rate)
logger.trace(
f"使用激活率 {interested_rate:.2f} 更新后 (通过缓冲后),当前兴趣度: {current_interest:.2f} (Stream: {chat.stream_id})"
)
# 添加到 SubHeartflow 的 interest_dict
await subheartflow.add_interest_dict_entry(message, interested_rate, is_mentioned)
logger.trace(
f"Message {message.message_info.message_id} added to interest dict for stream {chat.stream_id}"
)
except Exception as e:
logger.error(f"更新兴趣度失败 (Stream: {chat.stream_id}): {e}")
logger.error(traceback.format_exc())
# --- 结束修改 --- #
# 添加到 SubHeartflow 的 interest_dict给normal_chat处理
await subheartflow.add_interest_dict_entry(message, interested_rate, is_mentioned)
# 打印消息接收和处理信息
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
@@ -172,7 +152,7 @@ class HeartFCProcessor:
f"[{current_time}][{mes_name}]"
f"{chat.user_info.user_nickname}:"
f"{message.processed_plain_text}"
f"兴趣度: {current_interest:.2f}"
f"[兴趣度: {interested_rate:.2f}]"
)
try:

View File

@@ -7,7 +7,7 @@ from typing import List, Optional # 导入 Optional
from ..moods.moods import MoodManager
from ...config.config import global_config
from ..chat.emoji_manager import emoji_manager
from .normal_chat_generator import ResponseGenerator
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
@@ -43,12 +43,10 @@ class NormalChat:
self.interest_dict = interest_dict
logger.info(f"[{self.stream_name}] 正在初始化 NormalChat 实例...")
self.gpt = ResponseGenerator()
self.gpt = NormalChatGenerator()
self.mood_manager = MoodManager.get_instance() # MoodManager 保持单例
# 存储此实例的兴趣监控任务
self._interest_monitoring_task: Optional[asyncio.Task] = None
self._chat_task: Optional[asyncio.Task] = None
logger.info(f"[{self.stream_name}] NormalChat 实例初始化完成。")
# 改为实例方法
@@ -73,7 +71,6 @@ class NormalChat:
)
await message_manager.add_message(thinking_message)
return thinking_id
# 改为实例方法
@@ -176,7 +173,7 @@ class NormalChat:
await asyncio.sleep(1) # 每秒检查一次
# 检查任务是否已被取消
if self._interest_monitoring_task is None or self._interest_monitoring_task.cancelled():
if self._chat_task is None or self._chat_task.cancelled():
logger.info(f"[{self.stream_name}] 兴趣监控任务被取消或置空,退出")
break
@@ -352,19 +349,21 @@ class NormalChat:
return False
# 改为实例方法, 移除 chat 参数
async def start_monitoring_interest(self):
"""为此 NormalChat 实例关联的 ChatStream 启动兴趣消息监控任务(如果尚未运行)。"""
if self._interest_monitoring_task is None or self._interest_monitoring_task.done():
logger.info(f"[{self.stream_name}] 启动兴趣消息监控任务...")
async def start_chat(self):
"""为此 NormalChat 实例关联的 ChatStream 启动聊天任务(如果尚未运行)。"""
if self._chat_task is None or self._chat_task.done():
logger.info(f"[{self.stream_name}] 启动聊天任务...")
task = asyncio.create_task(self._find_interested_message())
task.add_done_callback(lambda t: self._handle_task_completion(t)) # 回调现在是实例方法
self._interest_monitoring_task = task
self._chat_task = task
# 改为实例方法, 移除 stream_id 参数
def _handle_task_completion(self, task: asyncio.Task):
"""兴趣监控任务完成时的回调函数。"""
# 检查完成的任务是否是当前实例的任务
if task is not self._interest_monitoring_task:
if task is not self._chat_task:
logger.warning(f"[{self.stream_name}] 收到一个未知或过时任务的完成回调。")
return
@@ -382,27 +381,26 @@ class NormalChat:
logger.error(f"[{self.stream_name}] 处理任务完成回调时出错: {e}")
finally:
# 标记任务已完成/移除
if self._interest_monitoring_task is task: # 再次确认是当前任务
self._interest_monitoring_task = None
logger.debug(f"[{self.stream_name}] 兴趣监控任务已被标记为完成/移除。")
if self._chat_task is task: # 再次确认是当前任务
self._chat_task = None
logger.debug(f"[{self.stream_name}] 聊天任务已被标记为完成/移除。")
# 改为实例方法, 移除 stream_id 参数
async def stop_monitoring_interest(self):
async def stop_chat(self):
"""停止当前实例的兴趣监控任务。"""
if self._interest_monitoring_task and not self._interest_monitoring_task.done():
task = self._interest_monitoring_task
logger.info(f"[{self.stream_name}] 尝试取消兴趣监控任务。")
if self._chat_task and not self._chat_task.done():
task = self._chat_task
logger.info(f"[{self.stream_name}] 尝试取消聊天任务。")
task.cancel()
try:
await task # 等待任务响应取消
except asyncio.CancelledError:
logger.info(f"[{self.stream_name}] 兴趣监控任务已成功取消。")
logger.info(f"[{self.stream_name}] 聊天任务已成功取消。")
except Exception as e:
# 回调函数 _handle_task_completion 会处理异常日志
logger.warning(f"[{self.stream_name}] 等待监控任务取消时捕获到异常 (可能已在回调中记录): {e}")
finally:
# 确保任务状态更新,即使等待出错 (回调函数也会尝试更新)
if self._interest_monitoring_task is task:
self._interest_monitoring_task = None
# else:
# logger.debug(f"[{self.stream_name}] 没有正在运行的兴趣监控任务可停止。")
if self._chat_task is task:
self._chat_task = None

View File

@@ -19,7 +19,7 @@ llm_config = LogConfig(
logger = get_module_logger("llm_generator", config=llm_config)
class ResponseGenerator:
class NormalChatGenerator:
def __init__(self):
self.model_reasoning = LLMRequest(
model=global_config.llm_reasoning,
@@ -77,8 +77,6 @@ class ResponseGenerator:
sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}"
else:
sender_name = f"用户({message.chat_stream.user_info.user_id})"
logger.debug("开始使用生成回复-2")
# 构建prompt
with Timer() as t_build_prompt:
prompt = await prompt_builder.build_prompt(