typing and ruff fix

This commit is contained in:
UnCLAS-Prommer
2025-07-27 12:43:59 +08:00
parent 03098b2c13
commit c4c0983947
2 changed files with 134 additions and 112 deletions

View File

@@ -2,7 +2,7 @@ import asyncio
import time import time
import traceback import traceback
import random import random
from typing import List, Optional, Dict, Any from typing import List, Optional, Dict, Any, Tuple
from rich.traceback import install from rich.traceback import install
from src.config.config import global_config from src.config.config import global_config
@@ -219,7 +219,9 @@ class HeartFChatting:
if global_config.chat.focus_value != 0: if global_config.chat.focus_value != 0:
if len(new_messages_data) > 3 / pow(global_config.chat.focus_value, 0.5): if len(new_messages_data) > 3 / pow(global_config.chat.focus_value, 0.5):
self.loop_mode = ChatMode.FOCUS self.loop_mode = ChatMode.FOCUS
self.energy_value = 10 + (len(new_messages_data) / (3 / pow(global_config.chat.focus_value,0.5))) * 10 self.energy_value = (
10 + (len(new_messages_data) / (3 / pow(global_config.chat.focus_value, 0.5))) * 10
)
return True return True
if self.energy_value >= 30: if self.energy_value >= 30:
@@ -261,9 +263,10 @@ class HeartFChatting:
reply_to_str, reply_to_str,
loop_start_time, loop_start_time,
action_message, action_message,
cycle_timers, cycle_timers: Dict[str, float],
thinking_id, thinking_id,
plan_result): plan_result,
) -> Tuple[Dict[str, Any], str, Dict[str, float]]:
with Timer("回复发送", cycle_timers): with Timer("回复发送", cycle_timers):
reply_text = await self._send_response(response_set, reply_to_str, loop_start_time, action_message) reply_text = await self._send_response(response_set, reply_to_str, loop_start_time, action_message)
@@ -286,9 +289,8 @@ class HeartFChatting:
action_name="reply", action_name="reply",
) )
# 构建循环信息 # 构建循环信息
loop_info = { loop_info: Dict[str, Any] = {
"loop_plan_info": { "loop_plan_info": {
"action_result": plan_result.get("action_result", {}), "action_result": plan_result.get("action_result", {}),
}, },
@@ -337,8 +339,9 @@ class HeartFChatting:
skip_planner = False skip_planner = False
if self.loop_mode == ChatMode.NORMAL: if self.loop_mode == ChatMode.NORMAL:
# 过滤掉reply相关的动作检查是否还有其他动作 # 过滤掉reply相关的动作检查是否还有其他动作
non_reply_actions = {k: v for k, v in available_actions.items() non_reply_actions = {
if k not in ['reply', 'no_reply', 'no_action']} k: v for k, v in available_actions.items() if k not in ["reply", "no_reply", "no_action"]
}
if not non_reply_actions: if not non_reply_actions:
skip_planner = True skip_planner = True
@@ -366,17 +369,20 @@ class HeartFChatting:
# 如果normal模式且不跳过规划器开始一个回复生成进程先准备好回复其实是和planer同时进行的 # 如果normal模式且不跳过规划器开始一个回复生成进程先准备好回复其实是和planer同时进行的
if not skip_planner: if not skip_planner:
reply_to_str = await self.build_reply_to_str(message_data) reply_to_str = await self.build_reply_to_str(message_data)
gen_task = asyncio.create_task(self._generate_response( gen_task = asyncio.create_task(
self._generate_response(
message_data=message_data, message_data=message_data,
available_actions=available_actions, available_actions=available_actions,
reply_to=reply_to_str, reply_to=reply_to_str,
request_type="chat.replyer.normal")) request_type="chat.replyer.normal",
)
)
if not skip_planner: if not skip_planner:
with Timer("规划器", cycle_timers): with Timer("规划器", cycle_timers):
plan_result, target_message = await self.action_planner.plan(mode=self.loop_mode) plan_result, target_message = await self.action_planner.plan(mode=self.loop_mode)
action_result: dict = plan_result.get("action_result", {}) # type: ignore action_result: Dict[str, Any] = plan_result.get("action_result", {}) # type: ignore
action_type, action_data, reasoning, is_parallel = ( action_type, action_data, reasoning, is_parallel = (
action_result.get("action_type", "error"), action_result.get("action_type", "error"),
action_result.get("action_data", {}), action_result.get("action_data", {}),
@@ -386,29 +392,27 @@ class HeartFChatting:
action_data["loop_start_time"] = loop_start_time action_data["loop_start_time"] = loop_start_time
if action_type == "reply": if action_type == "reply":
logger.info(f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复") logger.info(f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复")
elif is_parallel: elif is_parallel:
logger.info( logger.info(f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复, 同时执行{action_type}动作")
f"{self.log_prefix}{global_config.bot.nickname} 决定进行回复, 同时执行{action_type}动作"
)
else: else:
# 只有在gen_task存在时才进行相关操作 # 只有在gen_task存在时才进行相关操作
if gen_task is not None: if gen_task:
if not gen_task.done(): if not gen_task.done():
gen_task.cancel() gen_task.cancel()
logger.debug(f"{self.log_prefix} 已取消预生成的回复任务") logger.debug(f"{self.log_prefix} 已取消预生成的回复任务")
logger.info( logger.info(
f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复,但选择执行{action_type},不发表回复" f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复,但选择执行{action_type},不发表回复"
) )
else: elif generation_result := gen_task.result():
content = " ".join([item[1] for item in gen_task.result() if item[0] == "text"]) content = " ".join([item[1] for item in generation_result if item[0] == "text"])
logger.debug(f"{self.log_prefix} 预生成的回复任务已完成") logger.debug(f"{self.log_prefix} 预生成的回复任务已完成")
logger.info( logger.info(
f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复:{content},但选择执行{action_type},不发表回复" f"{self.log_prefix}{global_config.bot.nickname} 原本想要回复:{content},但选择执行{action_type},不发表回复"
) )
else:
logger.warning(f"{self.log_prefix} 预生成的回复任务未生成有效内容")
action_message: Dict[str, Any] = message_data or target_message # type: ignore action_message: Dict[str, Any] = message_data or target_message # type: ignore
if action_type == "reply": if action_type == "reply":
@@ -417,11 +421,14 @@ class HeartFChatting:
# 只有在gen_task存在时才等待 # 只有在gen_task存在时才等待
if not gen_task: if not gen_task:
reply_to_str = await self.build_reply_to_str(message_data) reply_to_str = await self.build_reply_to_str(message_data)
gen_task = asyncio.create_task(self._generate_response( gen_task = asyncio.create_task(
self._generate_response(
message_data=message_data, message_data=message_data,
available_actions=available_actions, available_actions=available_actions,
reply_to=reply_to_str, reply_to=reply_to_str,
request_type="chat.replyer.normal")) request_type="chat.replyer.normal",
)
)
gather_timeout = global_config.chat.thinking_timeout gather_timeout = global_config.chat.thinking_timeout
try: try:
@@ -446,30 +453,37 @@ class HeartFChatting:
message_data=action_message, message_data=action_message,
available_actions=available_actions, available_actions=available_actions,
reply_to=reply_to_str, reply_to=reply_to_str,
request_type="chat.replyer.focus") request_type="chat.replyer.focus",
)
if not response_set: if not response_set:
logger.warning(f"{self.log_prefix}模型未生成回复内容") logger.warning(f"{self.log_prefix}模型未生成回复内容")
return False return False
loop_info, reply_text,cycle_timers = await self._send_and_store_reply(response_set, reply_to_str, loop_start_time, action_message, cycle_timers, thinking_id, plan_result) loop_info, reply_text, cycle_timers = await self._send_and_store_reply(
response_set, reply_to_str, loop_start_time, action_message, cycle_timers, thinking_id, plan_result
)
return True return True
else: else:
# 并行执行:同时进行回复发送和动作执行 # 并行执行:同时进行回复发送和动作执行
tasks = [] # 先置空防止未定义错误
background_reply_task = None
background_action_task = None
# 如果是并行执行且在normal模式下需要等待预生成的回复任务完成并发送回复 # 如果是并行执行且在normal模式下需要等待预生成的回复任务完成并发送回复
if self.loop_mode == ChatMode.NORMAL and is_parallel and gen_task: if self.loop_mode == ChatMode.NORMAL and is_parallel and gen_task:
async def handle_reply_task():
async def handle_reply_task() -> Tuple[Optional[Dict[str, Any]], str, Dict[str, float]]:
# 等待预生成的回复任务完成 # 等待预生成的回复任务完成
gather_timeout = global_config.chat.thinking_timeout gather_timeout = global_config.chat.thinking_timeout
try: try:
response_set = await asyncio.wait_for(gen_task, timeout=gather_timeout) response_set = await asyncio.wait_for(gen_task, timeout=gather_timeout)
except asyncio.TimeoutError: except asyncio.TimeoutError:
logger.warning(f"{self.log_prefix} 并行执行:回复生成超时>{global_config.chat.thinking_timeout}s已跳过") logger.warning(
f"{self.log_prefix} 并行执行:回复生成超时>{global_config.chat.thinking_timeout}s已跳过"
)
return None, "", {} return None, "", {}
except asyncio.CancelledError: except asyncio.CancelledError:
logger.debug(f"{self.log_prefix} 并行执行:回复生成任务已被取消") logger.debug(f"{self.log_prefix} 并行执行:回复生成任务已被取消")
@@ -480,11 +494,19 @@ class HeartFChatting:
return None, "", {} return None, "", {}
reply_to_str = await self.build_reply_to_str(action_message) reply_to_str = await self.build_reply_to_str(action_message)
loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(response_set, reply_to_str, loop_start_time, action_message, cycle_timers, thinking_id, plan_result) loop_info, reply_text, cycle_timers_reply = await self._send_and_store_reply(
response_set,
reply_to_str,
loop_start_time,
action_message,
cycle_timers,
thinking_id,
plan_result,
)
return loop_info, reply_text, cycle_timers_reply return loop_info, reply_text, cycle_timers_reply
# 添加回复任务到并行任务列表 # 执行回复任务并赋值到变量
tasks.append(asyncio.create_task(handle_reply_task())) background_reply_task = asyncio.create_task(handle_reply_task())
# 动作执行任务 # 动作执行任务
async def handle_action_task(): async def handle_action_task():
@@ -494,51 +516,54 @@ class HeartFChatting:
) )
return success, reply_text, command return success, reply_text, command
# 添加动作执行任务到并行任务列表 # 执行动作任务并赋值到变量
tasks.append(asyncio.create_task(handle_action_task())) background_action_task = asyncio.create_task(handle_action_task())
# 并行执行所有任务
results = await asyncio.gather(*tasks, return_exceptions=True)
# 处理结果
reply_loop_info = None reply_loop_info = None
reply_text_from_reply = "" reply_text_from_reply = ""
action_success = False action_success = False
action_reply_text = "" action_reply_text = ""
action_command = "" action_command = ""
if len(tasks) == 2: # 有回复任务和动作任务 # 并行执行所有任务
if background_reply_task:
results = await asyncio.gather(
background_reply_task, background_action_task, return_exceptions=True
)
# 处理回复任务结果 # 处理回复任务结果
reply_result = results[0] reply_result = results[0]
if isinstance(reply_result, Exception): if isinstance(reply_result, BaseException):
logger.error(f"{self.log_prefix} 回复任务执行异常: {reply_result}") logger.error(f"{self.log_prefix} 回复任务执行异常: {reply_result}")
elif reply_result and reply_result[0] is not None: elif reply_result and reply_result[0] is not None:
reply_loop_info, reply_text_from_reply, _ = reply_result reply_loop_info, reply_text_from_reply, _ = reply_result
# 处理动作任务结果 # 处理动作任务结果
action_result = results[1] action_task_result = results[1]
if isinstance(action_result, Exception): if isinstance(action_task_result, BaseException):
logger.error(f"{self.log_prefix} 动作任务执行异常: {action_result}") logger.error(f"{self.log_prefix} 动作任务执行异常: {action_task_result}")
else: else:
action_success, action_reply_text, action_command = action_result action_success, action_reply_text, action_command = action_task_result
else: # 只有动作任务
action_result = results[0]
if isinstance(action_result, Exception):
logger.error(f"{self.log_prefix} 动作任务执行异常: {action_result}")
else: else:
action_success, action_reply_text, action_command = action_result results = await asyncio.gather(background_action_task, return_exceptions=True)
# 只有动作任务
action_task_result = results[0]
if isinstance(action_task_result, BaseException):
logger.error(f"{self.log_prefix} 动作任务执行异常: {action_task_result}")
else:
action_success, action_reply_text, action_command = action_task_result
# 构建最终的循环信息 # 构建最终的循环信息
if reply_loop_info: if reply_loop_info:
# 如果有回复信息使用回复的loop_info作为基础 # 如果有回复信息使用回复的loop_info作为基础
loop_info = reply_loop_info loop_info = reply_loop_info
# 更新动作执行信息 # 更新动作执行信息
loop_info["loop_action_info"].update({ loop_info["loop_action_info"].update(
{
"action_taken": action_success, "action_taken": action_success,
"command": action_command, "command": action_command,
"taken_time": time.time(), "taken_time": time.time(),
}) }
)
reply_text = reply_text_from_reply reply_text = reply_text_from_reply
else: else:
# 没有回复信息构建纯动作的loop_info # 没有回复信息构建纯动作的loop_info
@@ -555,7 +580,6 @@ class HeartFChatting:
} }
reply_text = action_reply_text reply_text = action_reply_text
if ENABLE_S4U: if 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)
@@ -603,7 +627,7 @@ class HeartFChatting:
action: str, action: str,
reasoning: str, reasoning: str,
action_data: dict, action_data: dict,
cycle_timers: dict, cycle_timers: Dict[str, float],
thinking_id: str, thinking_id: str,
action_message: dict, action_message: dict,
) -> tuple[bool, str, str]: ) -> tuple[bool, str, str]:
@@ -712,7 +736,11 @@ class HeartFChatting:
return False return False
async def _generate_response( async def _generate_response(
self, message_data: dict, available_actions: Optional[Dict[str, ActionInfo]], reply_to: str, request_type: str = "chat.replyer.normal" self,
message_data: dict,
available_actions: Optional[Dict[str, ActionInfo]],
reply_to: str,
request_type: str = "chat.replyer.normal",
) -> Optional[list]: ) -> Optional[list]:
"""生成普通回复""" """生成普通回复"""
try: try:
@@ -734,7 +762,7 @@ class HeartFChatting:
logger.error(f"{self.log_prefix}回复生成出现错误:{str(e)} {traceback.format_exc()}") logger.error(f"{self.log_prefix}回复生成出现错误:{str(e)} {traceback.format_exc()}")
return None return None
async def _send_response(self, reply_set, reply_to, thinking_start_time, message_data): async def _send_response(self, reply_set, reply_to, thinking_start_time, message_data) -> str:
current_time = time.time() current_time = time.time()
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=thinking_start_time, end_time=current_time chat_id=self.chat_stream.stream_id, start_time=thinking_start_time, end_time=current_time
@@ -746,13 +774,9 @@ class HeartFChatting:
need_reply = new_message_count >= random.randint(2, 4) need_reply = new_message_count >= random.randint(2, 4)
if need_reply: if need_reply:
logger.info( logger.info(f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,使用引用回复")
f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,使用引用回复"
)
else: else:
logger.info( logger.info(f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,不使用引用回复")
f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,不使用引用回复"
)
reply_text = "" reply_text = ""
first_replied = False first_replied = False

View File

@@ -211,8 +211,7 @@ class ActionPlanner:
reasoning = f"Planner 内部处理错误: {outer_e}" reasoning = f"Planner 内部处理错误: {outer_e}"
is_parallel = False is_parallel = False
if mode == ChatMode.NORMAL: if mode == ChatMode.NORMAL and action in current_available_actions:
if action in current_available_actions:
is_parallel = current_available_actions[action].parallel_action is_parallel = current_available_actions[action].parallel_action
action_result = { action_result = {
@@ -276,7 +275,6 @@ class ActionPlanner:
if global_config.chat.at_bot_inevitable_reply: if global_config.chat.at_bot_inevitable_reply:
mentioned_bonus = "\n- 有人提到你或者at你" mentioned_bonus = "\n- 有人提到你或者at你"
by_what = "聊天内容" by_what = "聊天内容"
target_prompt = '\n "target_message_id":"触发action的消息id"' target_prompt = '\n "target_message_id":"触发action的消息id"'
no_action_block = f"""重要说明: no_action_block = f"""重要说明: