为拆分heartFC_chat后的几个文件 添加亿点注释
This commit is contained in:
committed by
Windpicker-owo
parent
86830d49a9
commit
1238ee3089
@@ -21,6 +21,14 @@ logger = get_logger("hfc.processor")
|
||||
|
||||
class CycleProcessor:
|
||||
def __init__(self, context: HfcContext, response_handler: ResponseHandler, cycle_tracker: CycleTracker):
|
||||
"""
|
||||
初始化循环处理器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象,包含聊天流、能量值等信息
|
||||
response_handler: 响应处理器,负责生成和发送回复
|
||||
cycle_tracker: 循环跟踪器,负责记录和管理每次思考循环的信息
|
||||
"""
|
||||
self.context = context
|
||||
self.response_handler = response_handler
|
||||
self.cycle_tracker = cycle_tracker
|
||||
@@ -28,6 +36,22 @@ class CycleProcessor:
|
||||
self.action_modifier = ActionModifier(action_manager=self.context.action_manager, chat_id=self.context.stream_id)
|
||||
|
||||
async def observe(self, message_data: Optional[Dict[str, Any]] = None) -> bool:
|
||||
"""
|
||||
观察和处理单次思考循环的核心方法
|
||||
|
||||
Args:
|
||||
message_data: 可选的消息数据字典,包含用户消息、平台信息等
|
||||
|
||||
Returns:
|
||||
bool: 处理是否成功
|
||||
|
||||
功能说明:
|
||||
- 开始新的思考循环并记录计时
|
||||
- 修改可用动作并获取动作列表
|
||||
- 根据聊天模式和提及情况决定是否跳过规划器
|
||||
- 执行动作规划或直接回复
|
||||
- 根据动作类型分发到相应的处理方法
|
||||
"""
|
||||
if not message_data:
|
||||
message_data = {}
|
||||
|
||||
@@ -105,6 +129,24 @@ class CycleProcessor:
|
||||
return True
|
||||
|
||||
async def _handle_reply_action(self, message_data, available_actions, gen_task, loop_start_time, cycle_timers, thinking_id, plan_result):
|
||||
"""
|
||||
处理回复类型的动作
|
||||
|
||||
Args:
|
||||
message_data: 消息数据
|
||||
available_actions: 可用动作列表
|
||||
gen_task: 预先创建的生成任务(可能为None)
|
||||
loop_start_time: 循环开始时间
|
||||
cycle_timers: 循环计时器
|
||||
thinking_id: 思考ID
|
||||
plan_result: 规划结果
|
||||
|
||||
功能说明:
|
||||
- 根据聊天模式决定是否使用预生成的回复或实时生成
|
||||
- 在NORMAL模式下使用异步生成提高效率
|
||||
- 在FOCUS模式下同步生成确保及时响应
|
||||
- 发送生成的回复并结束循环
|
||||
"""
|
||||
if self.context.loop_mode == ChatMode.NORMAL:
|
||||
if not gen_task:
|
||||
reply_to_str = await self._build_reply_to_str(message_data)
|
||||
@@ -136,6 +178,27 @@ class CycleProcessor:
|
||||
self.cycle_tracker.end_cycle(loop_info, cycle_timers)
|
||||
|
||||
async def _handle_other_actions(self, action_type, reasoning, action_data, is_parallel, gen_task, action_message, cycle_timers, thinking_id, plan_result, loop_start_time):
|
||||
"""
|
||||
处理非回复类型的动作(如no_reply、自定义动作等)
|
||||
|
||||
Args:
|
||||
action_type: 动作类型
|
||||
reasoning: 动作理由
|
||||
action_data: 动作数据
|
||||
is_parallel: 是否并行执行
|
||||
gen_task: 生成任务
|
||||
action_message: 动作消息
|
||||
cycle_timers: 循环计时器
|
||||
thinking_id: 思考ID
|
||||
plan_result: 规划结果
|
||||
loop_start_time: 循环开始时间
|
||||
|
||||
功能说明:
|
||||
- 在NORMAL模式下可能并行执行回复生成和动作处理
|
||||
- 等待所有异步任务完成
|
||||
- 整合回复和动作的执行结果
|
||||
- 构建最终循环信息并结束循环
|
||||
"""
|
||||
background_reply_task = None
|
||||
if self.context.loop_mode == ChatMode.NORMAL and is_parallel and gen_task:
|
||||
background_reply_task = asyncio.create_task(self._handle_parallel_reply(gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result))
|
||||
@@ -172,6 +235,26 @@ class CycleProcessor:
|
||||
self.cycle_tracker.end_cycle(loop_info, cycle_timers)
|
||||
|
||||
async def _handle_parallel_reply(self, gen_task, loop_start_time, action_message, cycle_timers, thinking_id, plan_result):
|
||||
"""
|
||||
处理并行回复生成
|
||||
|
||||
Args:
|
||||
gen_task: 回复生成任务
|
||||
loop_start_time: 循环开始时间
|
||||
action_message: 动作消息
|
||||
cycle_timers: 循环计时器
|
||||
thinking_id: 思考ID
|
||||
plan_result: 规划结果
|
||||
|
||||
Returns:
|
||||
tuple: (循环信息, 回复文本, 计时器信息) 或 None
|
||||
|
||||
功能说明:
|
||||
- 等待并行回复生成任务完成(带超时)
|
||||
- 构建回复目标字符串
|
||||
- 发送生成的回复
|
||||
- 返回循环信息供上级方法使用
|
||||
"""
|
||||
try:
|
||||
response_set = await asyncio.wait_for(gen_task, timeout=global_config.chat.thinking_timeout)
|
||||
except asyncio.TimeoutError:
|
||||
@@ -186,6 +269,25 @@ class CycleProcessor:
|
||||
)
|
||||
|
||||
async def _handle_action(self, action, reasoning, action_data, cycle_timers, thinking_id, action_message) -> tuple[bool, str, str]:
|
||||
"""
|
||||
处理具体的动作执行
|
||||
|
||||
Args:
|
||||
action: 动作名称
|
||||
reasoning: 执行理由
|
||||
action_data: 动作数据
|
||||
cycle_timers: 循环计时器
|
||||
thinking_id: 思考ID
|
||||
action_message: 动作消息
|
||||
|
||||
Returns:
|
||||
tuple: (执行是否成功, 回复文本, 命令文本)
|
||||
|
||||
功能说明:
|
||||
- 创建对应的动作处理器
|
||||
- 执行动作并捕获异常
|
||||
- 返回执行结果供上级方法整合
|
||||
"""
|
||||
if not self.context.chat_stream:
|
||||
return False, "", ""
|
||||
try:
|
||||
@@ -210,6 +312,19 @@ class CycleProcessor:
|
||||
return False, "", ""
|
||||
|
||||
def _get_direct_reply_plan(self, loop_start_time):
|
||||
"""
|
||||
获取直接回复的规划结果
|
||||
|
||||
Args:
|
||||
loop_start_time: 循环开始时间
|
||||
|
||||
Returns:
|
||||
dict: 包含直接回复动作的规划结果
|
||||
|
||||
功能说明:
|
||||
- 在某些情况下跳过复杂规划,直接返回回复动作
|
||||
- 主要用于NORMAL模式下没有其他可用动作时的简化处理
|
||||
"""
|
||||
return {
|
||||
"action_result": {
|
||||
"action_type": "reply",
|
||||
@@ -222,6 +337,20 @@ class CycleProcessor:
|
||||
}
|
||||
|
||||
async def _build_reply_to_str(self, message_data: dict):
|
||||
"""
|
||||
构建回复目标字符串
|
||||
|
||||
Args:
|
||||
message_data: 消息数据字典
|
||||
|
||||
Returns:
|
||||
str: 格式化的回复目标字符串,格式为"用户名:消息内容"
|
||||
|
||||
功能说明:
|
||||
- 从消息数据中提取平台和用户ID信息
|
||||
- 通过人员信息管理器获取用户昵称
|
||||
- 构建用于回复显示的格式化字符串
|
||||
"""
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
person_info_manager = get_person_info_manager()
|
||||
platform = message_data.get("chat_info_platform") or message_data.get("user_platform") or (self.context.chat_stream.platform if self.context.chat_stream else "default")
|
||||
@@ -231,6 +360,24 @@ class CycleProcessor:
|
||||
return f"{person_name}:{message_data.get('processed_plain_text')}"
|
||||
|
||||
def _build_final_loop_info(self, reply_loop_info, action_success, action_reply_text, action_command, plan_result):
|
||||
"""
|
||||
构建最终的循环信息
|
||||
|
||||
Args:
|
||||
reply_loop_info: 回复循环信息(可能为None)
|
||||
action_success: 动作执行是否成功
|
||||
action_reply_text: 动作回复文本
|
||||
action_command: 动作命令
|
||||
plan_result: 规划结果
|
||||
|
||||
Returns:
|
||||
dict: 完整的循环信息,包含规划信息和动作信息
|
||||
|
||||
功能说明:
|
||||
- 如果有回复循环信息,则在其基础上添加动作信息
|
||||
- 如果没有回复信息,则创建新的循环信息结构
|
||||
- 整合所有执行结果供循环跟踪器记录
|
||||
"""
|
||||
if reply_loop_info:
|
||||
loop_info = reply_loop_info
|
||||
loop_info["loop_action_info"].update({
|
||||
|
||||
@@ -9,9 +9,31 @@ logger = get_logger("hfc.cycle")
|
||||
|
||||
class CycleTracker:
|
||||
def __init__(self, context: HfcContext):
|
||||
"""
|
||||
初始化循环跟踪器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象
|
||||
|
||||
功能说明:
|
||||
- 负责跟踪和记录每次思考循环的详细信息
|
||||
- 管理循环的开始、结束和信息存储
|
||||
"""
|
||||
self.context = context
|
||||
|
||||
def start_cycle(self) -> Tuple[Dict[str, float], str]:
|
||||
"""
|
||||
开始新的思考循环
|
||||
|
||||
Returns:
|
||||
tuple: (循环计时器字典, 思考ID字符串)
|
||||
|
||||
功能说明:
|
||||
- 增加循环计数器
|
||||
- 创建新的循环详情对象
|
||||
- 生成唯一的思考ID
|
||||
- 初始化循环计时器
|
||||
"""
|
||||
self.context.cycle_counter += 1
|
||||
self.context.current_cycle_detail = CycleDetail(self.context.cycle_counter)
|
||||
self.context.current_cycle_detail.thinking_id = f"tid{str(round(time.time(), 2))}"
|
||||
@@ -19,6 +41,19 @@ class CycleTracker:
|
||||
return cycle_timers, self.context.current_cycle_detail.thinking_id
|
||||
|
||||
def end_cycle(self, loop_info: Dict[str, Any], cycle_timers: Dict[str, float]):
|
||||
"""
|
||||
结束当前思考循环
|
||||
|
||||
Args:
|
||||
loop_info: 循环信息,包含规划和动作信息
|
||||
cycle_timers: 循环计时器,记录各阶段耗时
|
||||
|
||||
功能说明:
|
||||
- 设置循环详情的完整信息
|
||||
- 将当前循环加入历史记录
|
||||
- 记录计时器和结束时间
|
||||
- 打印循环统计信息
|
||||
"""
|
||||
if self.context.current_cycle_detail:
|
||||
self.context.current_cycle_detail.set_loop_info(loop_info)
|
||||
self.context.history_loop.append(self.context.current_cycle_detail)
|
||||
@@ -27,6 +62,18 @@ class CycleTracker:
|
||||
self.print_cycle_info(cycle_timers)
|
||||
|
||||
def print_cycle_info(self, cycle_timers: Dict[str, float]):
|
||||
"""
|
||||
打印循环统计信息
|
||||
|
||||
Args:
|
||||
cycle_timers: 循环计时器字典
|
||||
|
||||
功能说明:
|
||||
- 格式化各阶段的耗时信息
|
||||
- 计算总体循环持续时间
|
||||
- 输出详细的性能统计日志
|
||||
- 显示选择的动作类型
|
||||
"""
|
||||
if not self.context.current_cycle_detail:
|
||||
return
|
||||
|
||||
|
||||
@@ -10,24 +10,63 @@ logger = get_logger("hfc.energy")
|
||||
|
||||
class EnergyManager:
|
||||
def __init__(self, context: HfcContext):
|
||||
"""
|
||||
初始化能量管理器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象
|
||||
|
||||
功能说明:
|
||||
- 管理聊天机器人的能量值系统
|
||||
- 根据聊天模式自动调整能量消耗
|
||||
- 控制能量值的衰减和记录
|
||||
"""
|
||||
self.context = context
|
||||
self._energy_task: Optional[asyncio.Task] = None
|
||||
self.last_energy_log_time = 0
|
||||
self.energy_log_interval = 90
|
||||
|
||||
async def start(self):
|
||||
"""
|
||||
启动能量管理器
|
||||
|
||||
功能说明:
|
||||
- 检查运行状态,避免重复启动
|
||||
- 创建能量循环异步任务
|
||||
- 设置任务完成回调
|
||||
- 记录启动日志
|
||||
"""
|
||||
if self.context.running and not self._energy_task:
|
||||
self._energy_task = asyncio.create_task(self._energy_loop())
|
||||
self._energy_task.add_done_callback(self._handle_energy_completion)
|
||||
logger.info(f"{self.context.log_prefix} 能量管理器已启动")
|
||||
|
||||
async def stop(self):
|
||||
"""
|
||||
停止能量管理器
|
||||
|
||||
功能说明:
|
||||
- 取消正在运行的能量循环任务
|
||||
- 等待任务完全停止
|
||||
- 记录停止日志
|
||||
"""
|
||||
if self._energy_task and not self._energy_task.done():
|
||||
self._energy_task.cancel()
|
||||
await asyncio.sleep(0)
|
||||
logger.info(f"{self.context.log_prefix} 能量管理器已停止")
|
||||
|
||||
def _handle_energy_completion(self, task: asyncio.Task):
|
||||
"""
|
||||
处理能量循环任务完成
|
||||
|
||||
Args:
|
||||
task: 完成的异步任务对象
|
||||
|
||||
功能说明:
|
||||
- 处理任务正常完成或异常情况
|
||||
- 记录相应的日志信息
|
||||
- 区分取消和异常终止的情况
|
||||
"""
|
||||
try:
|
||||
if exception := task.exception():
|
||||
logger.error(f"{self.context.log_prefix} 能量循环异常: {exception}")
|
||||
@@ -37,6 +76,16 @@ class EnergyManager:
|
||||
logger.info(f"{self.context.log_prefix} 能量循环被取消")
|
||||
|
||||
async def _energy_loop(self):
|
||||
"""
|
||||
能量管理的主循环
|
||||
|
||||
功能说明:
|
||||
- 每10秒执行一次能量更新
|
||||
- 根据群聊配置设置固定的聊天模式和能量值
|
||||
- 在自动模式下根据聊天模式进行能量衰减
|
||||
- NORMAL模式每次衰减0.3,FOCUS模式每次衰减0.6
|
||||
- 确保能量值不低于0.3的最小值
|
||||
"""
|
||||
while self.context.running:
|
||||
await asyncio.sleep(10)
|
||||
|
||||
@@ -63,6 +112,17 @@ class EnergyManager:
|
||||
self._log_energy_change("能量值衰减")
|
||||
|
||||
def _should_log_energy(self) -> bool:
|
||||
"""
|
||||
判断是否应该记录能量变化日志
|
||||
|
||||
Returns:
|
||||
bool: 如果距离上次记录超过间隔时间则返回True
|
||||
|
||||
功能说明:
|
||||
- 控制能量日志的记录频率,避免日志过于频繁
|
||||
- 默认间隔90秒记录一次详细日志
|
||||
- 其他时间使用调试级别日志
|
||||
"""
|
||||
current_time = time.time()
|
||||
if current_time - self.last_energy_log_time >= self.energy_log_interval:
|
||||
self.last_energy_log_time = current_time
|
||||
@@ -70,6 +130,18 @@ class EnergyManager:
|
||||
return False
|
||||
|
||||
def _log_energy_change(self, action: str, reason: str = ""):
|
||||
"""
|
||||
记录能量变化日志
|
||||
|
||||
Args:
|
||||
action: 能量变化的动作描述
|
||||
reason: 可选的变化原因
|
||||
|
||||
功能说明:
|
||||
- 根据时间间隔决定使用info还是debug级别的日志
|
||||
- 格式化能量值显示(保留一位小数)
|
||||
- 可选择性地包含变化原因
|
||||
"""
|
||||
if self._should_log_energy():
|
||||
log_message = f"{self.context.log_prefix} {action},当前能量值:{self.context.energy_value:.1f}"
|
||||
if reason:
|
||||
|
||||
@@ -24,6 +24,18 @@ logger = get_logger("hfc")
|
||||
|
||||
class HeartFChatting:
|
||||
def __init__(self, chat_id: str):
|
||||
"""
|
||||
初始化心跳聊天管理器
|
||||
|
||||
Args:
|
||||
chat_id: 聊天ID标识符
|
||||
|
||||
功能说明:
|
||||
- 创建聊天上下文和所有子管理器
|
||||
- 初始化循环跟踪器、响应处理器、循环处理器等核心组件
|
||||
- 设置能量管理器、主动思考器和普通模式处理器
|
||||
- 初始化聊天模式并记录初始化完成日志
|
||||
"""
|
||||
self.context = HfcContext(chat_id)
|
||||
|
||||
self.cycle_tracker = CycleTracker(self.context)
|
||||
@@ -39,6 +51,16 @@ class HeartFChatting:
|
||||
logger.info(f"{self.context.log_prefix} HeartFChatting 初始化完成")
|
||||
|
||||
def _initialize_chat_mode(self):
|
||||
"""
|
||||
初始化聊天模式
|
||||
|
||||
功能说明:
|
||||
- 检测是否为群聊环境
|
||||
- 根据全局配置设置强制聊天模式
|
||||
- 在focus模式下设置能量值为35
|
||||
- 在normal模式下设置能量值为15
|
||||
- 如果是auto模式则保持默认设置
|
||||
"""
|
||||
is_group_chat = self.context.chat_stream.group_info is not None if self.context.chat_stream else False
|
||||
if is_group_chat and global_config.chat.group_chat_mode != "auto":
|
||||
if global_config.chat.group_chat_mode == "focus":
|
||||
@@ -49,6 +71,16 @@ class HeartFChatting:
|
||||
self.context.energy_value = 15
|
||||
|
||||
async def start(self):
|
||||
"""
|
||||
启动心跳聊天系统
|
||||
|
||||
功能说明:
|
||||
- 检查是否已经在运行,避免重复启动
|
||||
- 初始化关系构建器和表达学习器
|
||||
- 启动能量管理器和主动思考器
|
||||
- 创建主聊天循环任务并设置完成回调
|
||||
- 记录启动完成日志
|
||||
"""
|
||||
if self.context.running:
|
||||
return
|
||||
self.context.running = True
|
||||
@@ -64,6 +96,16 @@ class HeartFChatting:
|
||||
logger.info(f"{self.context.log_prefix} HeartFChatting 启动完成")
|
||||
|
||||
async def stop(self):
|
||||
"""
|
||||
停止心跳聊天系统
|
||||
|
||||
功能说明:
|
||||
- 检查是否正在运行,避免重复停止
|
||||
- 设置运行状态为False
|
||||
- 停止能量管理器和主动思考器
|
||||
- 取消主聊天循环任务
|
||||
- 记录停止完成日志
|
||||
"""
|
||||
if not self.context.running:
|
||||
return
|
||||
self.context.running = False
|
||||
@@ -77,6 +119,18 @@ class HeartFChatting:
|
||||
logger.info(f"{self.context.log_prefix} HeartFChatting 已停止")
|
||||
|
||||
def _handle_loop_completion(self, task: asyncio.Task):
|
||||
"""
|
||||
处理主循环任务完成
|
||||
|
||||
Args:
|
||||
task: 完成的异步任务对象
|
||||
|
||||
功能说明:
|
||||
- 处理任务异常完成的情况
|
||||
- 区分正常停止和异常终止
|
||||
- 记录相应的日志信息
|
||||
- 处理取消任务的情况
|
||||
"""
|
||||
try:
|
||||
if exception := task.exception():
|
||||
logger.error(f"{self.context.log_prefix} HeartFChatting: 脱离了聊天(异常): {exception}")
|
||||
@@ -87,6 +141,16 @@ class HeartFChatting:
|
||||
logger.info(f"{self.context.log_prefix} HeartFChatting: 结束了聊天")
|
||||
|
||||
async def _main_chat_loop(self):
|
||||
"""
|
||||
主聊天循环
|
||||
|
||||
功能说明:
|
||||
- 持续运行聊天处理循环
|
||||
- 每次循环调用_loop_body处理消息
|
||||
- 处理取消和异常情况
|
||||
- 在异常时尝试重新启动循环
|
||||
- 记录循环结束日志
|
||||
"""
|
||||
try:
|
||||
while self.context.running:
|
||||
await self._loop_body()
|
||||
@@ -101,6 +165,17 @@ class HeartFChatting:
|
||||
logger.error(f"{self.context.log_prefix} 结束了当前聊天循环")
|
||||
|
||||
async def _loop_body(self):
|
||||
"""
|
||||
单次循环体处理
|
||||
|
||||
功能说明:
|
||||
- 检查是否处于睡眠模式,如果是则跳过处理
|
||||
- 获取最近的新消息(过滤机器人自己的消息和命令)
|
||||
- 更新最后消息时间和读取时间
|
||||
- 根据当前聊天模式执行不同的处理逻辑
|
||||
- FOCUS模式:直接处理所有消息并检查退出条件
|
||||
- NORMAL模式:检查进入FOCUS模式的条件,并通过normal_mode_handler处理消息
|
||||
"""
|
||||
if schedule_manager.is_sleeping():
|
||||
return
|
||||
|
||||
@@ -129,6 +204,15 @@ class HeartFChatting:
|
||||
await self.normal_mode_handler.handle_message(message)
|
||||
|
||||
def _check_focus_exit(self):
|
||||
"""
|
||||
检查是否应该退出FOCUS模式
|
||||
|
||||
功能说明:
|
||||
- 区分私聊和群聊环境
|
||||
- 在强制私聊focus模式下,能量值低于1时重置为5但不退出
|
||||
- 在群聊focus模式下,如果配置为focus则不退出
|
||||
- 其他情况下,能量值低于1时退出到NORMAL模式
|
||||
"""
|
||||
is_private_chat = self.context.chat_stream.group_info is None if self.context.chat_stream else False
|
||||
is_group_chat = not is_private_chat
|
||||
|
||||
@@ -145,6 +229,19 @@ class HeartFChatting:
|
||||
self.context.loop_mode = ChatMode.NORMAL
|
||||
|
||||
def _check_focus_entry(self, new_message_count: int):
|
||||
"""
|
||||
检查是否应该进入FOCUS模式
|
||||
|
||||
Args:
|
||||
new_message_count: 新消息数量
|
||||
|
||||
功能说明:
|
||||
- 区分私聊和群聊环境
|
||||
- 强制私聊focus模式:直接进入FOCUS模式并设置能量值为10
|
||||
- 群聊normal模式:不进入FOCUS模式
|
||||
- 根据focus_value配置和消息数量决定是否进入FOCUS模式
|
||||
- 当消息数量超过阈值或能量值达到30时进入FOCUS模式
|
||||
"""
|
||||
is_private_chat = self.context.chat_stream.group_info is None if self.context.chat_stream else False
|
||||
is_group_chat = not is_private_chat
|
||||
|
||||
|
||||
@@ -9,6 +9,21 @@ from src.chat.chat_loop.hfc_utils import CycleDetail
|
||||
|
||||
class HfcContext:
|
||||
def __init__(self, chat_id: str):
|
||||
"""
|
||||
初始化HFC聊天上下文
|
||||
|
||||
Args:
|
||||
chat_id: 聊天ID标识符
|
||||
|
||||
功能说明:
|
||||
- 存储和管理单个聊天会话的所有状态信息
|
||||
- 包含聊天流、关系构建器、表达学习器等核心组件
|
||||
- 管理聊天模式、能量值、时间戳等关键状态
|
||||
- 提供循环历史记录和当前循环详情的存储
|
||||
|
||||
Raises:
|
||||
ValueError: 如果找不到对应的聊天流
|
||||
"""
|
||||
self.stream_id: str = chat_id
|
||||
self.chat_stream: Optional[ChatStream] = get_chat_manager().get_stream(self.stream_id)
|
||||
if not self.chat_stream:
|
||||
|
||||
@@ -13,9 +13,28 @@ logger = get_logger(__name__)
|
||||
|
||||
|
||||
class CycleDetail:
|
||||
"""循环信息记录类"""
|
||||
"""
|
||||
循环信息记录类
|
||||
|
||||
功能说明:
|
||||
- 记录单次思考循环的详细信息
|
||||
- 包含循环ID、思考ID、时间戳等基本信息
|
||||
- 存储循环的规划信息和动作信息
|
||||
- 提供序列化和转换功能
|
||||
"""
|
||||
|
||||
def __init__(self, cycle_id: int):
|
||||
"""
|
||||
初始化循环详情记录
|
||||
|
||||
Args:
|
||||
cycle_id: 循环ID,用于标识循环的顺序
|
||||
|
||||
功能说明:
|
||||
- 设置循环基本标识信息
|
||||
- 初始化时间戳和计时器
|
||||
- 准备循环信息存储容器
|
||||
"""
|
||||
self.cycle_id = cycle_id
|
||||
self.thinking_id = ""
|
||||
self.start_time = time.time()
|
||||
@@ -26,7 +45,18 @@ class CycleDetail:
|
||||
self.loop_action_info: Dict[str, Any] = {}
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""将循环信息转换为字典格式"""
|
||||
"""
|
||||
将循环信息转换为字典格式
|
||||
|
||||
Returns:
|
||||
dict: 包含所有循环信息的字典,已处理循环引用和序列化问题
|
||||
|
||||
功能说明:
|
||||
- 递归转换复杂对象为可序列化格式
|
||||
- 防止循环引用导致的无限递归
|
||||
- 限制递归深度避免栈溢出
|
||||
- 只保留基本数据类型和可序列化的值
|
||||
"""
|
||||
|
||||
def convert_to_serializable(obj, depth=0, seen=None):
|
||||
if seen is None:
|
||||
@@ -79,18 +109,36 @@ class CycleDetail:
|
||||
}
|
||||
|
||||
def set_loop_info(self, loop_info: Dict[str, Any]):
|
||||
"""设置循环信息"""
|
||||
"""
|
||||
设置循环信息
|
||||
|
||||
Args:
|
||||
loop_info: 包含循环规划和动作信息的字典
|
||||
|
||||
功能说明:
|
||||
- 从传入的循环信息中提取规划和动作信息
|
||||
- 更新当前循环详情的相关字段
|
||||
"""
|
||||
self.loop_plan_info = loop_info["loop_plan_info"]
|
||||
self.loop_action_info = loop_info["loop_action_info"]
|
||||
|
||||
|
||||
def get_recent_message_stats(minutes: float = 30, chat_id: Optional[str] = None) -> dict:
|
||||
"""
|
||||
获取最近消息统计信息
|
||||
|
||||
Args:
|
||||
minutes (float): 检索的分钟数,默认30分钟
|
||||
chat_id (str, optional): 指定的chat_id,仅统计该chat下的消息。为None时统计全部。
|
||||
minutes: 检索的分钟数,默认30分钟
|
||||
chat_id: 指定的chat_id,仅统计该chat下的消息。为None时统计全部
|
||||
|
||||
Returns:
|
||||
dict: {"bot_reply_count": int, "total_message_count": int}
|
||||
|
||||
功能说明:
|
||||
- 统计指定时间范围内的消息数量
|
||||
- 区分机器人回复和总消息数
|
||||
- 可以针对特定聊天或全局统计
|
||||
- 用于分析聊天活跃度和机器人参与度
|
||||
"""
|
||||
|
||||
now = time.time()
|
||||
@@ -112,6 +160,15 @@ def get_recent_message_stats(minutes: float = 30, chat_id: Optional[str] = None)
|
||||
|
||||
|
||||
async def send_typing():
|
||||
"""
|
||||
发送打字状态指示
|
||||
|
||||
功能说明:
|
||||
- 创建内心聊天流(用于状态显示)
|
||||
- 发送typing状态消息
|
||||
- 不存储到消息记录中
|
||||
- 用于S4U功能的视觉反馈
|
||||
"""
|
||||
group_info = GroupInfo(platform="amaidesu_default", group_id="114514", group_name="内心")
|
||||
|
||||
chat = await get_chat_manager().get_or_create_stream(
|
||||
@@ -125,6 +182,15 @@ async def send_typing():
|
||||
)
|
||||
|
||||
async def stop_typing():
|
||||
"""
|
||||
停止打字状态指示
|
||||
|
||||
功能说明:
|
||||
- 创建内心聊天流(用于状态显示)
|
||||
- 发送stop_typing状态消息
|
||||
- 不存储到消息记录中
|
||||
- 结束S4U功能的视觉反馈
|
||||
"""
|
||||
group_info = GroupInfo(platform="amaidesu_default", group_id="114514", group_name="内心")
|
||||
|
||||
chat = await get_chat_manager().get_or_create_stream(
|
||||
|
||||
@@ -13,11 +13,40 @@ logger = get_logger("hfc.normal_mode")
|
||||
|
||||
class NormalModeHandler:
|
||||
def __init__(self, context: HfcContext, cycle_processor: "CycleProcessor"):
|
||||
"""
|
||||
初始化普通模式处理器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象
|
||||
cycle_processor: 循环处理器,用于处理决定回复的消息
|
||||
|
||||
功能说明:
|
||||
- 处理NORMAL模式下的消息
|
||||
- 根据兴趣度和回复概率决定是否回复
|
||||
- 管理意愿系统和回复概率计算
|
||||
"""
|
||||
self.context = context
|
||||
self.cycle_processor = cycle_processor
|
||||
self.willing_manager = get_willing_manager()
|
||||
|
||||
async def handle_message(self, message_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理NORMAL模式下的单条消息
|
||||
|
||||
Args:
|
||||
message_data: 消息数据字典,包含用户信息、消息内容、兴趣值等
|
||||
|
||||
Returns:
|
||||
bool: 是否进行了回复处理
|
||||
|
||||
功能说明:
|
||||
- 计算消息的兴趣度和基础回复概率
|
||||
- 应用谈话频率调整回复概率
|
||||
- 过滤表情和图片消息(设置回复概率为0)
|
||||
- 根据概率随机决定是否回复
|
||||
- 如果决定回复则调用循环处理器进行处理
|
||||
- 记录详细的决策日志
|
||||
"""
|
||||
if not self.context.chat_stream:
|
||||
return False
|
||||
|
||||
|
||||
@@ -15,6 +15,19 @@ logger = get_logger("hfc.proactive")
|
||||
|
||||
class ProactiveThinker:
|
||||
def __init__(self, context: HfcContext, cycle_processor: "CycleProcessor"):
|
||||
"""
|
||||
初始化主动思考器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象
|
||||
cycle_processor: 循环处理器,用于执行主动思考的结果
|
||||
|
||||
功能说明:
|
||||
- 管理机器人的主动发言功能
|
||||
- 根据沉默时间和配置触发主动思考
|
||||
- 提供私聊和群聊不同的思考提示模板
|
||||
- 使用3-sigma规则计算动态思考间隔
|
||||
"""
|
||||
self.context = context
|
||||
self.cycle_processor = cycle_processor
|
||||
self._proactive_thinking_task: Optional[asyncio.Task] = None
|
||||
@@ -35,18 +48,47 @@ class ProactiveThinker:
|
||||
}
|
||||
|
||||
async def start(self):
|
||||
"""
|
||||
启动主动思考器
|
||||
|
||||
功能说明:
|
||||
- 检查运行状态和配置,避免重复启动
|
||||
- 只有在启用主动思考功能时才启动
|
||||
- 创建主动思考循环异步任务
|
||||
- 设置任务完成回调处理
|
||||
- 记录启动日志
|
||||
"""
|
||||
if self.context.running and not self._proactive_thinking_task and global_config.chat.enable_proactive_thinking:
|
||||
self._proactive_thinking_task = asyncio.create_task(self._proactive_thinking_loop())
|
||||
self._proactive_thinking_task.add_done_callback(self._handle_proactive_thinking_completion)
|
||||
logger.info(f"{self.context.log_prefix} 主动思考器已启动")
|
||||
|
||||
async def stop(self):
|
||||
"""
|
||||
停止主动思考器
|
||||
|
||||
功能说明:
|
||||
- 取消正在运行的主动思考任务
|
||||
- 等待任务完全停止
|
||||
- 记录停止日志
|
||||
"""
|
||||
if self._proactive_thinking_task and not self._proactive_thinking_task.done():
|
||||
self._proactive_thinking_task.cancel()
|
||||
await asyncio.sleep(0)
|
||||
logger.info(f"{self.context.log_prefix} 主动思考器已停止")
|
||||
|
||||
def _handle_proactive_thinking_completion(self, task: asyncio.Task):
|
||||
"""
|
||||
处理主动思考任务完成
|
||||
|
||||
Args:
|
||||
task: 完成的异步任务对象
|
||||
|
||||
功能说明:
|
||||
- 处理任务正常完成或异常情况
|
||||
- 记录相应的日志信息
|
||||
- 区分取消和异常终止的情况
|
||||
"""
|
||||
try:
|
||||
if exception := task.exception():
|
||||
logger.error(f"{self.context.log_prefix} 主动思考循环异常: {exception}")
|
||||
@@ -56,6 +98,17 @@ class ProactiveThinker:
|
||||
logger.info(f"{self.context.log_prefix} 主动思考循环被取消")
|
||||
|
||||
async def _proactive_thinking_loop(self):
|
||||
"""
|
||||
主动思考的主循环
|
||||
|
||||
功能说明:
|
||||
- 每15秒检查一次是否需要主动思考
|
||||
- 只在FOCUS模式下进行主动思考
|
||||
- 检查是否启用主动思考功能
|
||||
- 计算沉默时间并与动态间隔比较
|
||||
- 达到条件时执行主动思考并更新最后消息时间
|
||||
- 处理执行过程中的异常
|
||||
"""
|
||||
while self.context.running:
|
||||
await asyncio.sleep(15)
|
||||
|
||||
@@ -79,6 +132,19 @@ class ProactiveThinker:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
def _should_enable_proactive_thinking(self) -> bool:
|
||||
"""
|
||||
检查是否应该启用主动思考
|
||||
|
||||
Returns:
|
||||
bool: 如果应该启用主动思考则返回True
|
||||
|
||||
功能说明:
|
||||
- 检查聊天流是否存在
|
||||
- 检查当前聊天是否在启用列表中(如果配置了列表)
|
||||
- 根据聊天类型(群聊/私聊)和配置决定是否启用
|
||||
- 群聊需要proactive_thinking_in_group为True
|
||||
- 私聊需要proactive_thinking_in_private为True
|
||||
"""
|
||||
if not self.context.chat_stream:
|
||||
return False
|
||||
|
||||
@@ -101,6 +167,19 @@ class ProactiveThinker:
|
||||
return True
|
||||
|
||||
def _get_dynamic_thinking_interval(self) -> float:
|
||||
"""
|
||||
获取动态思考间隔
|
||||
|
||||
Returns:
|
||||
float: 计算得出的思考间隔时间(秒)
|
||||
|
||||
功能说明:
|
||||
- 使用3-sigma规则计算正态分布的思考间隔
|
||||
- 基于base_interval和delta_sigma配置计算
|
||||
- 处理特殊情况(为0或负数的配置)
|
||||
- 如果timing_utils不可用则使用固定间隔
|
||||
- 间隔范围被限制在1秒到86400秒(1天)之间
|
||||
"""
|
||||
try:
|
||||
from src.utils.timing_utils import get_normal_distributed_interval
|
||||
|
||||
@@ -131,6 +210,21 @@ class ProactiveThinker:
|
||||
return max(300, abs(global_config.chat.proactive_thinking_interval))
|
||||
|
||||
def _format_duration(self, seconds: float) -> str:
|
||||
"""
|
||||
格式化持续时间为中文描述
|
||||
|
||||
Args:
|
||||
seconds: 持续时间(秒)
|
||||
|
||||
Returns:
|
||||
str: 格式化后的时间字符串,如"1小时30分45秒"
|
||||
|
||||
功能说明:
|
||||
- 将秒数转换为小时、分钟、秒的组合
|
||||
- 只显示非零的时间单位
|
||||
- 如果所有单位都为0则显示"0秒"
|
||||
- 用于主动思考日志的时间显示
|
||||
"""
|
||||
hours = int(seconds // 3600)
|
||||
minutes = int((seconds % 3600) // 60)
|
||||
secs = int(seconds % 60)
|
||||
@@ -146,6 +240,19 @@ class ProactiveThinker:
|
||||
return "".join(parts)
|
||||
|
||||
async def _execute_proactive_thinking(self, silence_duration: float):
|
||||
"""
|
||||
执行主动思考
|
||||
|
||||
Args:
|
||||
silence_duration: 沉默持续时间(秒)
|
||||
|
||||
功能说明:
|
||||
- 格式化沉默时间并记录触发日志
|
||||
- 获取适当的思考提示模板
|
||||
- 创建主动思考类型的消息数据
|
||||
- 调用循环处理器执行思考和可能的回复
|
||||
- 处理执行过程中的异常
|
||||
"""
|
||||
formatted_time = self._format_duration(silence_duration)
|
||||
logger.info(f"{self.context.log_prefix} 触发主动思考,已沉默{formatted_time}")
|
||||
|
||||
@@ -172,6 +279,21 @@ class ProactiveThinker:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
def _get_proactive_prompt(self, formatted_time: str) -> str:
|
||||
"""
|
||||
获取主动思考的提示模板
|
||||
|
||||
Args:
|
||||
formatted_time: 格式化后的沉默时间字符串
|
||||
|
||||
Returns:
|
||||
str: 填充了时间信息的提示模板
|
||||
|
||||
功能说明:
|
||||
- 优先使用自定义的提示模板(如果配置了)
|
||||
- 根据聊天类型(群聊/私聊)选择默认模板
|
||||
- 将格式化的时间信息填入模板
|
||||
- 返回完整的主动思考提示文本
|
||||
"""
|
||||
if hasattr(global_config.chat, 'proactive_thinking_prompt_template') and global_config.chat.proactive_thinking_prompt_template.strip():
|
||||
return global_config.chat.proactive_thinking_prompt_template.format(time=formatted_time)
|
||||
|
||||
|
||||
@@ -13,6 +13,17 @@ logger = get_logger("hfc.response")
|
||||
|
||||
class ResponseHandler:
|
||||
def __init__(self, context: HfcContext):
|
||||
"""
|
||||
初始化响应处理器
|
||||
|
||||
Args:
|
||||
context: HFC聊天上下文对象
|
||||
|
||||
功能说明:
|
||||
- 负责生成和发送机器人的回复
|
||||
- 处理回复的格式化和发送逻辑
|
||||
- 管理回复状态和日志记录
|
||||
"""
|
||||
self.context = context
|
||||
|
||||
async def generate_and_send_reply(
|
||||
@@ -25,6 +36,27 @@ class ResponseHandler:
|
||||
thinking_id,
|
||||
plan_result,
|
||||
) -> Tuple[Dict[str, Any], str, Dict[str, float]]:
|
||||
"""
|
||||
生成并发送回复的主方法
|
||||
|
||||
Args:
|
||||
response_set: 生成的回复内容集合
|
||||
reply_to_str: 回复目标字符串
|
||||
loop_start_time: 循环开始时间
|
||||
action_message: 动作消息数据
|
||||
cycle_timers: 循环计时器
|
||||
thinking_id: 思考ID
|
||||
plan_result: 规划结果
|
||||
|
||||
Returns:
|
||||
tuple: (循环信息, 回复文本, 计时器信息)
|
||||
|
||||
功能说明:
|
||||
- 发送生成的回复内容
|
||||
- 存储动作信息到数据库
|
||||
- 构建并返回完整的循环信息
|
||||
- 用于上级方法的状态跟踪
|
||||
"""
|
||||
reply_text = await self._send_response(response_set, reply_to_str, loop_start_time, action_message)
|
||||
|
||||
person_info_manager = get_person_info_manager()
|
||||
@@ -65,6 +97,25 @@ class ResponseHandler:
|
||||
return loop_info, reply_text, cycle_timers
|
||||
|
||||
async def _send_response(self, reply_set, reply_to, thinking_start_time, message_data) -> str:
|
||||
"""
|
||||
发送回复内容的具体实现
|
||||
|
||||
Args:
|
||||
reply_set: 回复内容集合,包含多个回复段
|
||||
reply_to: 回复目标
|
||||
thinking_start_time: 思考开始时间
|
||||
message_data: 消息数据
|
||||
|
||||
Returns:
|
||||
str: 完整的回复文本
|
||||
|
||||
功能说明:
|
||||
- 检查是否有新消息需要回复
|
||||
- 处理主动思考的"沉默"决定
|
||||
- 根据消息数量决定是否添加回复引用
|
||||
- 逐段发送回复内容,支持打字效果
|
||||
- 正确处理元组格式的回复段
|
||||
"""
|
||||
current_time = time.time()
|
||||
new_message_count = message_api.count_new_messages(
|
||||
chat_id=self.context.stream_id, start_time=thinking_start_time, end_time=current_time
|
||||
@@ -131,6 +182,24 @@ class ResponseHandler:
|
||||
reply_to: str,
|
||||
request_type: str = "chat.replyer.normal",
|
||||
) -> Optional[list]:
|
||||
"""
|
||||
生成回复内容
|
||||
|
||||
Args:
|
||||
message_data: 消息数据
|
||||
available_actions: 可用动作列表
|
||||
reply_to: 回复目标
|
||||
request_type: 请求类型,默认为普通回复
|
||||
|
||||
Returns:
|
||||
list: 生成的回复内容列表,失败时返回None
|
||||
|
||||
功能说明:
|
||||
- 调用生成器API生成回复
|
||||
- 根据配置启用或禁用工具功能
|
||||
- 处理生成失败的情况
|
||||
- 记录生成过程中的错误和异常
|
||||
"""
|
||||
try:
|
||||
success, reply_set, _ = await generator_api.generate_reply(
|
||||
chat_stream=self.context.chat_stream,
|
||||
|
||||
Reference in New Issue
Block a user