This commit is contained in:
SengokuCola
2025-04-21 18:45:39 +08:00
17 changed files with 412 additions and 806 deletions

View File

@@ -2,6 +2,7 @@ import traceback
from typing import Optional, Dict
import asyncio
from asyncio import Lock
import threading # 导入 threading
from ...moods.moods import MoodManager
from ...chat.emoji_manager import emoji_manager
from .heartFC_generator import ResponseGenerator
@@ -13,7 +14,7 @@ from src.do_tool.tool_use import ToolUser
from .interest import InterestManager
from src.plugins.chat.chat_stream import chat_manager
from .pf_chatting import PFChatting
import threading # 导入 threading
# 定义日志配置
chat_config = LogConfig(
@@ -21,51 +22,73 @@ chat_config = LogConfig(
file_format=CHAT_STYLE_CONFIG["file_format"],
)
logger = get_module_logger("HeartFC_Controller", config=chat_config)
logger = get_module_logger("HeartFCController", config=chat_config)
# 检测群聊兴趣的间隔时间
INTEREST_MONITOR_INTERVAL_SECONDS = 1
class HeartFC_Controller:
# 合并后的版本:使用 __new__ + threading.Lock 实现线程安全单例,类名为 HeartFCController
class HeartFCController:
_instance = None
_lock = threading.Lock() # 使用 threading.Lock 替代 asyncio.Lock 以兼容 __new__
_lock = threading.Lock() # 使用 threading.Lock 保证 __new__ 线程安全
_initialized = False
def __new__(cls, *args, **kwargs):
if cls._instance is None:
with cls._lock:
# Double-checked locking
if cls._instance is None:
logger.debug("创建 HeartFCController 单例实例...")
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
# 使用 _initialized 标志确保 __init__ 只执行一次
if self._initialized:
return
with self.__class__._lock: # 使用类锁确保初始化线程安全
if self._initialized:
# 虽然 __new__ 保证了只有一个实例,但为了防止意外重入或多线程下的初始化竞争,
# 再次使用类锁保护初始化过程是更严谨的做法。
# 如果确定 __init__ 逻辑本身是幂等的或非关键的,可以省略这里的锁。
# 但为了保持原始逻辑的意图(防止重复初始化),这里保留检查。
with self.__class__._lock: # 确保初始化逻辑线程安全
if self._initialized: # 再次检查,防止锁等待期间其他线程已完成初始化
return
logger.info("正在初始化 HeartFC_Controller 单例...")
logger.info("正在初始化 HeartFCController 单例...")
self.gpt = ResponseGenerator()
self.mood_manager = MoodManager.get_instance()
# 注意mood_manager 的 start_mood_update 可能需要在应用主循环启动后调用,
# 或者确保其内部实现是安全的。这里保持原状。
self.mood_manager.start_mood_update()
self.tool_user = ToolUser()
# 注意InterestManager() 可能是另一个单例或需要特定初始化。
# 假设 InterestManager() 返回的是正确配置的实例。
self.interest_manager = InterestManager()
self._interest_monitor_task: Optional[asyncio.Task] = None
self.pf_chatting_instances: Dict[str, PFChatting] = {}
self._pf_chatting_lock = Lock() # 这个可以是 asyncio.Lock用于异步上下文
self.emoji_manager = emoji_manager
self.relationship_manager = relationship_manager
# _pf_chatting_lock 用于保护 pf_chatting_instances 的异步操作
self._pf_chatting_lock = asyncio.Lock() # 这个是 asyncio.Lock用于异步上下文
self.emoji_manager = emoji_manager # 假设是全局或已初始化的实例
self.relationship_manager = relationship_manager # 假设是全局或已初始化的实例
# MessageManager 可能是类本身或单例实例,根据其设计确定
self.MessageManager = MessageManager
self._initialized = True
logger.info("HeartFC_Controller 单例初始化完成。")
logger.info("HeartFCController 单例初始化完成。")
@classmethod
def get_instance(cls):
"""获取 HeartFC_Controller 的单例实例。"""
"""获取 HeartFCController 的单例实例。"""
# 如果实例尚未创建,调用构造函数(这将触发 __new__ 和 __init__
if cls._instance is None:
logger.warning("HeartFC_Controller 实例在首次 get_instance 时创建,可能未在 main 中正确初始化。")
cls() # 调用构造函数创建
# 在首次调用 get_instance 时创建实例。
# __new__ 中的锁会确保线程安全。
cls()
# 添加日志记录,说明实例是在 get_instance 调用时创建的
logger.info("HeartFCController 实例在首次 get_instance 时创建。")
elif not cls._initialized:
# 实例已创建但可能未初始化完成(理论上不太可能发生,除非 __init__ 异常)
logger.warning("HeartFCController 实例存在但尚未完成初始化。")
return cls._instance
# --- 新增:检查 PFChatting 状态的方法 --- #
@@ -83,9 +106,9 @@ class HeartFC_Controller:
async def start(self):
"""启动异步任务,如回复启动器"""
logger.debug("HeartFC_Controller 正在启动异步任务...")
logger.debug("HeartFCController 正在启动异步任务...")
self._initialize_monitor_task()
logger.info("HeartFC_Controller 异步任务启动完成")
logger.info("HeartFCController 异步任务启动完成")
def _initialize_monitor_task(self):
"""启动后台兴趣监控任务,可以检查兴趣是否足以开启心流对话"""
@@ -105,7 +128,7 @@ class HeartFC_Controller:
async with self._pf_chatting_lock:
if stream_id not in self.pf_chatting_instances:
logger.info(f"为流 {stream_id} 创建新的PFChatting实例")
# 传递 self (HeartFC_Controller 实例) 进行依赖注入
# 传递 self (HeartFCController 实例) 进行依赖注入
instance = PFChatting(stream_id, self)
# 执行异步初始化
if not await instance._initialize():

View File

@@ -26,7 +26,7 @@ logger = get_module_logger("heartFC_processor", config=processor_config)
# INTEREST_INCREASE_THRESHOLD = 0.5
class HeartFC_Processor:
class HeartFCProcessor:
def __init__(self):
self.storage = MessageStorage()
self.interest_manager = InterestManager()
@@ -97,21 +97,21 @@ class HeartFC_Processor:
# 处理缓冲器结果 (Bombing logic)
if not buffer_result:
F_type = "seglist"
f_type = "seglist"
if message.message_segment.type != "seglist":
F_type = message.message_segment.type
f_type = message.message_segment.type
else:
if (
isinstance(message.message_segment.data, list)
and all(isinstance(x, Seg) for x in message.message_segment.data)
and len(message.message_segment.data) == 1
):
F_type = message.message_segment.data[0].type
if F_type == "text":
f_type = message.message_segment.data[0].type
if f_type == "text":
logger.debug(f"触发缓冲,消息:{message.processed_plain_text}")
elif F_type == "image":
elif f_type == "image":
logger.debug("触发缓冲,表情包/图片等待中")
elif F_type == "seglist":
elif f_type == "seglist":
logger.debug("触发缓冲,消息列表等待中")
return # 被缓冲器拦截,不生成回复

View File

@@ -28,7 +28,7 @@ logger = get_module_logger("PFCLoop", config=interest_log_config) # Logger Name
# Forward declaration for type hinting
if TYPE_CHECKING:
from .heartFC_controler import HeartFC_Controller
from .heartFC_controler import HeartFCController
PLANNER_TOOL_DEFINITION = [
{
@@ -64,7 +64,7 @@ class PFChatting:
只要计时器>0循环就会继续。
"""
def __init__(self, chat_id: str, heartfc_controller_instance: "HeartFC_Controller"):
def __init__(self, chat_id: str, heartfc_controller_instance: "HeartFCController"):
"""
初始化PFChatting实例。
@@ -377,6 +377,22 @@ class PFChatting:
)
action_taken_this_cycle = False
# --- Print Timer Results --- #
if cycle_timers: # 先检查cycle_timers是否非空
timer_strings = []
for name, elapsed in cycle_timers.items():
# 直接格式化存储在字典中的浮点数 elapsed
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}"
timer_strings.append(f"{name}: {formatted_time}")
if timer_strings: # 如果有有效计时器数据才打印
logger.debug(
f"{log_prefix} test testtesttesttesttesttesttesttesttesttest Cycle Timers: {'; '.join(timer_strings)}"
)
# --- Timer Decrement --- #
cycle_duration = time.monotonic() - loop_cycle_start_time
except Exception as e_cycle:
logger.error(f"{log_prefix} 循环周期执行时发生错误: {e_cycle}")
logger.error(traceback.format_exc())
@@ -390,21 +406,6 @@ class PFChatting:
self._processing_lock.release()
logger.trace(f"{log_prefix} 循环释放了处理锁.")
# --- Print Timer Results --- #
if cycle_timers: # 先检查cycle_timers是否非空
timer_strings = []
for name, elapsed in cycle_timers.items():
# 直接格式化存储在字典中的浮点数 elapsed
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}"
timer_strings.append(f"{name}: {formatted_time}")
if timer_strings: # 如果有有效计时器数据才打印
logger.debug(
f"{log_prefix} test testtesttesttesttesttesttesttesttesttest Cycle Timers: {'; '.join(timer_strings)}"
)
# --- Timer Decrement --- #
cycle_duration = time.monotonic() - loop_cycle_start_time
async with self._timer_lock:
self._loop_timer -= cycle_duration
# Log timer decrement less aggressively
@@ -774,7 +775,7 @@ class PFChatting:
logger.error(traceback.format_exc())
return None
# --- Methods moved from HeartFC_Controller start ---
# --- Methods moved from HeartFCController start ---
async def _create_thinking_message(self, anchor_message: Optional[MessageRecv]) -> Optional[str]:
"""创建思考消息 (尝试锚定到 anchor_message)"""
if not anchor_message or not anchor_message.chat_stream: