🤖 自动格式化代码 [skip ci]

This commit is contained in:
github-actions[bot]
2025-04-25 14:59:23 +00:00
parent be1ba83319
commit 8bfff8efe2
9 changed files with 203 additions and 214 deletions

View File

@@ -321,9 +321,7 @@ CHAT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
}, },
"simple": { "simple": {
"console_format": ( "console_format": ("<level>{time:MM-DD HH:mm}</level> | <green>见闻</green> | <green>{message}</green>"), # noqa: E501
"<level>{time:MM-DD HH:mm}</level> | <green>见闻</green> | <green>{message}</green>"
), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
}, },
} }

View File

@@ -272,7 +272,6 @@ class SubHeartflowManager:
current_state = current_mai_state.get_current_state() current_state = current_mai_state.get_current_state()
focused_limit = current_state.get_focused_chat_max_num() focused_limit = current_state.get_focused_chat_max_num()
if int(time.time()) % 20 == 0: # 每20秒输出一次 if int(time.time()) % 20 == 0: # 每20秒输出一次
logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 可以在{focused_limit}个群激情聊天") logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 可以在{focused_limit}个群激情聊天")
@@ -288,7 +287,7 @@ class SubHeartflowManager:
states_num = ( states_num = (
self.count_subflows_by_state(ChatState.ABSENT), self.count_subflows_by_state(ChatState.ABSENT),
self.count_subflows_by_state(ChatState.CHAT), self.count_subflows_by_state(ChatState.CHAT),
current_focused_count current_focused_count,
) )
for sub_hf in list(self.subheartflows.values()): for sub_hf in list(self.subheartflows.values()):
@@ -300,6 +299,7 @@ class SubHeartflowManager:
continue continue
from .mai_state_manager import enable_unlimited_hfc_chat from .mai_state_manager import enable_unlimited_hfc_chat
if not enable_unlimited_hfc_chat: if not enable_unlimited_hfc_chat:
if sub_hf.chat_state.chat_status != ChatState.CHAT: if sub_hf.chat_state.chat_status != ChatState.CHAT:
continue continue
@@ -326,11 +326,11 @@ class SubHeartflowManager:
await current_subflow.set_chat_state(ChatState.FOCUSED, states_num) await current_subflow.set_chat_state(ChatState.FOCUSED, states_num)
# 验证提升结果 # 验证提升结果
if (final_subflow := self.subheartflows.get(flow_id)) and \ if (
final_subflow.chat_state.chat_status == ChatState.FOCUSED: final_subflow := self.subheartflows.get(flow_id)
) and final_subflow.chat_state.chat_status == ChatState.FOCUSED:
current_focused_count += 1 current_focused_count += 1
async def randomly_deactivate_subflows(self, deactivation_probability: float = 0.1): async def randomly_deactivate_subflows(self, deactivation_probability: float = 0.1):
"""以一定概率将 FOCUSED 或 CHAT 状态的子心流回退到 ABSENT 状态。""" """以一定概率将 FOCUSED 或 CHAT 状态的子心流回退到 ABSENT 状态。"""
log_prefix_manager = "[子心流管理器-随机停用]" log_prefix_manager = "[子心流管理器-随机停用]"

View File

@@ -29,10 +29,11 @@ EMOJI_DIR = os.path.join(BASE_DIR, "emoji") # 表情包存储目录
EMOJI_REGISTED_DIR = os.path.join(BASE_DIR, "emoji_registed") # 已注册的表情包注册目录 EMOJI_REGISTED_DIR = os.path.join(BASE_DIR, "emoji_registed") # 已注册的表情包注册目录
''' """
还没经过测试,有些地方数据库和内存数据同步可能不完全 还没经过测试,有些地方数据库和内存数据同步可能不完全
''' """
class MaiEmoji: class MaiEmoji:
"""定义一个表情包""" """定义一个表情包"""
@@ -316,7 +317,9 @@ class EmojiManager:
time_end = time.time() time_end = time.time()
logger.info(f"找到[{text_emotion}]表情包,用时:{time_end - time_start:.2f}秒: {selected_emoji.description} (相似度: {similarity:.4f})") logger.info(
f"找到[{text_emotion}]表情包,用时:{time_end - time_start:.2f}秒: {selected_emoji.description} (相似度: {similarity:.4f})"
)
return selected_emoji.path, f"[ {selected_emoji.description} ]" return selected_emoji.path, f"[ {selected_emoji.description} ]"
except Exception as e: except Exception as e:
@@ -785,7 +788,6 @@ class EmojiManager:
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return False return False
async def clear_temp_emoji(self): async def clear_temp_emoji(self):
"""每天清理临时表情包 """每天清理临时表情包
清理/data/emoji和/data/image目录下的所有文件 清理/data/emoji和/data/image目录下的所有文件
@@ -821,7 +823,5 @@ class EmojiManager:
logger.success("[清理] 临时文件清理完成") logger.success("[清理] 临时文件清理完成")
# 创建全局单例 # 创建全局单例
emoji_manager = EmojiManager() emoji_manager = EmojiManager()

View File

@@ -38,11 +38,8 @@ logger = get_module_logger("HeartFCLoop", config=interest_log_config) # Logger
# 默认动作定义 # 默认动作定义
DEFAULT_ACTIONS = { DEFAULT_ACTIONS = {"no_reply": "不回复", "text_reply": "文本回复, 可选附带表情", "emoji_reply": "仅表情回复"}
"no_reply": "不回复",
"text_reply": "文本回复, 可选附带表情",
"emoji_reply": "仅表情回复"
}
class ActionManager: class ActionManager:
"""动作管理器:控制每次决策可以使用的动作""" """动作管理器:控制每次决策可以使用的动作"""
@@ -96,52 +93,62 @@ class ActionManager:
def get_planner_tool_definition(self) -> List[Dict[str, Any]]: def get_planner_tool_definition(self) -> List[Dict[str, Any]]:
"""获取当前动作集对应的规划器工具定义""" """获取当前动作集对应的规划器工具定义"""
return [{ return [
"type": "function", {
"function": { "type": "function",
"name": "decide_reply_action", "function": {
"description": "根据当前聊天内容和上下文,决定机器人是否应该回复以及如何回复。", "name": "decide_reply_action",
"parameters": { "description": "根据当前聊天内容和上下文,决定机器人是否应该回复以及如何回复。",
"type": "object", "parameters": {
"properties": { "type": "object",
"action": { "properties": {
"type": "string", "action": {
"enum": list(self._available_actions.keys()), "type": "string",
"description": "决定采取的行动:" + "enum": list(self._available_actions.keys()),
", ".join([f"'{k}'({v})" for k, v in self._available_actions.items()]), "description": "决定采取的行动:"
}, + ", ".join([f"'{k}'({v})" for k, v in self._available_actions.items()]),
"reasoning": {"type": "string", "description": "做出此决定的简要理由。"}, },
"emoji_query": { "reasoning": {"type": "string", "description": "做出此决定的简要理由。"},
"type": "string", "emoji_query": {
"description": "如果行动是'emoji_reply',指定表情的主题或概念。如果行动是'text_reply'且希望在文本后追加表情,也在此指定表情主题。", "type": "string",
"description": "如果行动是'emoji_reply',指定表情的主题或概念。如果行动是'text_reply'且希望在文本后追加表情,也在此指定表情主题。",
},
}, },
"required": ["action", "reasoning"],
}, },
"required": ["action", "reasoning"],
}, },
}, }
}] ]
# 在文件开头添加自定义异常类 # 在文件开头添加自定义异常类
class HeartFCError(Exception): class HeartFCError(Exception):
"""麦麦聊天系统基础异常类""" """麦麦聊天系统基础异常类"""
pass pass
class PlannerError(HeartFCError): class PlannerError(HeartFCError):
"""规划器异常""" """规划器异常"""
pass pass
class ReplierError(HeartFCError): class ReplierError(HeartFCError):
"""回复器异常""" """回复器异常"""
pass pass
class SenderError(HeartFCError): class SenderError(HeartFCError):
"""发送器异常""" """发送器异常"""
pass pass
class CycleInfo: class CycleInfo:
"""循环信息记录类""" """循环信息记录类"""
def __init__(self, cycle_id: int): def __init__(self, cycle_id: int):
self.cycle_id = cycle_id self.cycle_id = cycle_id
self.start_time = time.time() self.start_time = time.time()
@@ -155,7 +162,7 @@ class CycleInfo:
# 添加响应信息相关字段 # 添加响应信息相关字段
self.response_info: Dict[str, Any] = { self.response_info: Dict[str, Any] = {
"response_text": [], # 回复的文本列表 "response_text": [], # 回复的文本列表
"emoji_info": "", # 表情信息 "emoji_info": "", # 表情信息
"anchor_message_id": "", # 锚点消息ID "anchor_message_id": "", # 锚点消息ID
"reply_message_ids": [], # 回复消息ID列表 "reply_message_ids": [], # 回复消息ID列表
"sub_mind_thinking": "", # 子思维思考内容 "sub_mind_thinking": "", # 子思维思考内容
@@ -172,7 +179,7 @@ class CycleInfo:
"reasoning": self.reasoning, "reasoning": self.reasoning,
"timers": self.timers, "timers": self.timers,
"thinking_id": self.thinking_id, "thinking_id": self.thinking_id,
"response_info": self.response_info "response_info": self.response_info,
} }
def complete_cycle(self): def complete_cycle(self):
@@ -189,12 +196,14 @@ class CycleInfo:
"""设置思考消息ID""" """设置思考消息ID"""
self.thinking_id = thinking_id self.thinking_id = thinking_id
def set_response_info(self, def set_response_info(
response_text: Optional[List[str]] = None, self,
emoji_info: Optional[str] = None, response_text: Optional[List[str]] = None,
anchor_message_id: Optional[str] = None, emoji_info: Optional[str] = None,
reply_message_ids: Optional[List[str]] = None, anchor_message_id: Optional[str] = None,
sub_mind_thinking: Optional[str] = None): reply_message_ids: Optional[List[str]] = None,
sub_mind_thinking: Optional[str] = None,
):
"""设置响应信息""" """设置响应信息"""
if response_text is not None: if response_text is not None:
self.response_info["response_text"] = response_text self.response_info["response_text"] = response_text
@@ -353,9 +362,7 @@ class HeartFChatting:
planner_start_db_time = time.time() planner_start_db_time = time.time()
# 执行规划阶段 # 执行规划阶段
action_taken, thinking_id = await self._think_plan_execute_loop( action_taken, thinking_id = await self._think_plan_execute_loop(cycle_timers, planner_start_db_time)
cycle_timers, planner_start_db_time
)
# 更新循环信息 # 更新循环信息
self._current_cycle.set_thinking_id(thinking_id) self._current_cycle.set_thinking_id(thinking_id)
@@ -431,9 +438,7 @@ class HeartFChatting:
logger.error(f"{self.log_prefix} 检查新消息时出错: {e}") logger.error(f"{self.log_prefix} 检查新消息时出错: {e}")
return False return False
async def _think_plan_execute_loop( async def _think_plan_execute_loop(self, cycle_timers: dict, planner_start_db_time: float) -> tuple[bool, str]:
self, cycle_timers: dict, planner_start_db_time: float
) -> tuple[bool, str]:
"""执行规划阶段""" """执行规划阶段"""
try: try:
# 获取子思维思考结果 # 获取子思维思考结果
@@ -469,7 +474,9 @@ class HeartFChatting:
# 根据动作类型执行对应处理 # 根据动作类型执行对应处理
with Timer("执行", cycle_timers): with Timer("执行", cycle_timers):
return await self._handle_action(action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time) return await self._handle_action(
action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time
)
except PlannerError as e: except PlannerError as e:
logger.error(f"{self.log_prefix} 规划错误: {e}") logger.error(f"{self.log_prefix} 规划错误: {e}")
@@ -478,12 +485,7 @@ class HeartFChatting:
return False, "" return False, ""
async def _handle_action( async def _handle_action(
self, self, action: str, reasoning: str, emoji_query: str, cycle_timers: dict, planner_start_db_time: float
action: str,
reasoning: str,
emoji_query: str,
cycle_timers: dict,
planner_start_db_time: float
) -> tuple[bool, str]: ) -> tuple[bool, str]:
""" """
处理规划动作 处理规划动作
@@ -501,7 +503,7 @@ class HeartFChatting:
action_handlers = { action_handlers = {
"text_reply": self._handle_text_reply, "text_reply": self._handle_text_reply,
"emoji_reply": self._handle_emoji_reply, "emoji_reply": self._handle_emoji_reply,
"no_reply": self._handle_no_reply "no_reply": self._handle_no_reply,
} }
handler = action_handlers.get(action) handler = action_handlers.get(action)
@@ -520,9 +522,7 @@ class HeartFChatting:
logger.error(f"{self.log_prefix} 处理{action}时出错: {e}") logger.error(f"{self.log_prefix} 处理{action}时出错: {e}")
return False, "" return False, ""
async def _handle_text_reply( async def _handle_text_reply(self, reasoning: str, emoji_query: str, cycle_timers: dict) -> tuple[bool, str]:
self, reasoning: str, emoji_query: str, cycle_timers: dict
) -> tuple[bool, str]:
""" """
处理文本回复 处理文本回复
@@ -607,9 +607,7 @@ class HeartFChatting:
logger.error(f"{self.log_prefix} 表情发送失败: {e}") logger.error(f"{self.log_prefix} 表情发送失败: {e}")
return False return False
async def _handle_no_reply( async def _handle_no_reply(self, reasoning: str, planner_start_db_time: float, cycle_timers: dict) -> bool:
self, reasoning: str, planner_start_db_time: float, cycle_timers: dict
) -> bool:
""" """
处理不回复的情况 处理不回复的情况
@@ -636,9 +634,7 @@ class HeartFChatting:
logger.info(f"{self.log_prefix} 等待被中断") logger.info(f"{self.log_prefix} 等待被中断")
raise raise
async def _wait_for_new_message( async def _wait_for_new_message(self, observation, planner_start_db_time: float, log_prefix: str) -> bool:
self, observation, planner_start_db_time: float, log_prefix: str
) -> bool:
""" """
等待新消息 等待新消息
@@ -677,13 +673,11 @@ class HeartFChatting:
if timer_strings: if timer_strings:
logger.debug(f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}") logger.debug(f"{log_prefix} 该次决策耗时: {'; '.join(timer_strings)}")
async def _handle_cycle_delay( async def _handle_cycle_delay(self, action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str):
self, action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str
):
"""处理循环延迟""" """处理循环延迟"""
cycle_duration = time.monotonic() - cycle_start_time cycle_duration = time.monotonic() - cycle_start_time
# if cycle_duration > 0.1: # if cycle_duration > 0.1:
# logger.debug(f"{log_prefix} HeartFChatting: 周期耗时 {cycle_duration:.2f}s.") # logger.debug(f"{log_prefix} HeartFChatting: 周期耗时 {cycle_duration:.2f}s.")
try: try:
sleep_duration = 0.0 sleep_duration = 0.0
@@ -779,7 +773,9 @@ class HeartFChatting:
action = arguments.get("action", "no_reply") action = arguments.get("action", "no_reply")
# 验证动作是否在可用动作集中 # 验证动作是否在可用动作集中
if action not in self.action_manager.get_available_actions(): if action not in self.action_manager.get_available_actions():
logger.warning(f"{self.log_prefix}[Planner] LLM返回了未授权的动作: {action}使用默认动作no_reply") logger.warning(
f"{self.log_prefix}[Planner] LLM返回了未授权的动作: {action}使用默认动作no_reply"
)
action = "no_reply" action = "no_reply"
reasoning = f"LLM返回了未授权的动作: {action}" reasoning = f"LLM返回了未授权的动作: {action}"
else: else:
@@ -787,7 +783,9 @@ class HeartFChatting:
emoji_query = arguments.get("emoji_query", "") emoji_query = arguments.get("emoji_query", "")
# 记录决策结果 # 记录决策结果
logger.debug(f"{self.log_prefix}[要做什么]\nPrompt:\n{prompt}\n\n决策结果: {action}, 理由: {reasoning}, 表情查询: '{emoji_query}'") logger.debug(
f"{self.log_prefix}[要做什么]\nPrompt:\n{prompt}\n\n决策结果: {action}, 理由: {reasoning}, 表情查询: '{emoji_query}'"
)
else: else:
# 处理工具调用失败 # 处理工具调用失败
logger.warning(f"{self.log_prefix}[Planner] {error_msg}") logger.warning(f"{self.log_prefix}[Planner] {error_msg}")
@@ -961,9 +959,6 @@ class HeartFChatting:
thinking_id=thinking_id, # Pass thinking_id positionally thinking_id=thinking_id, # Pass thinking_id positionally
) )
if not response_set: if not response_set:
logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] LLM生成了一个空回复集。") logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] LLM生成了一个空回复集。")
return None return None
@@ -1014,8 +1009,7 @@ class HeartFChatting:
# 记录锚点消息ID # 记录锚点消息ID
if self._current_cycle and anchor_message: if self._current_cycle and anchor_message:
self._current_cycle.set_response_info( self._current_cycle.set_response_info(
response_text=response_set, response_text=response_set, anchor_message_id=anchor_message.message_info.message_id
anchor_message_id=anchor_message.message_info.message_id
) )
chat = anchor_message.chat_stream chat = anchor_message.chat_stream
@@ -1090,9 +1084,7 @@ class HeartFChatting:
emoji_path, description = emoji_raw emoji_path, description = emoji_raw
# 记录表情信息 # 记录表情信息
if self._current_cycle: if self._current_cycle:
self._current_cycle.set_response_info( self._current_cycle.set_response_info(emoji_info=f"表情: {description}, 路径: {emoji_path}")
emoji_info=f"表情: {description}, 路径: {emoji_path}"
)
emoji_cq = image_path_to_base64(emoji_path) emoji_cq = image_path_to_base64(emoji_path)
thinking_time_point = round(time.time(), 2) thinking_time_point = round(time.time(), 2)
@@ -1134,4 +1126,3 @@ class HeartFChatting:
if self._cycle_history: if self._cycle_history:
return self._cycle_history[-1].to_dict() return self._cycle_history[-1].to_dict()
return None return None

View File

@@ -39,7 +39,7 @@ class HeartFCProcessor:
""" """
logger.error(f"{context}: {error}") logger.error(f"{context}: {error}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
if message and hasattr(message, 'raw_message'): if message and hasattr(message, "raw_message"):
logger.error(f"相关消息原始内容: {message.raw_message}") logger.error(f"相关消息原始内容: {message.raw_message}")
async def _process_relationship(self, message: MessageRecv) -> None: async def _process_relationship(self, message: MessageRecv) -> None:
@@ -57,14 +57,10 @@ class HeartFCProcessor:
if not is_known: if not is_known:
logger.info(f"首次认识用户: {nickname}") logger.info(f"首次认识用户: {nickname}")
await relationship_manager.first_knowing_some_one( await relationship_manager.first_knowing_some_one(platform, user_id, nickname, cardname, "")
platform, user_id, nickname, cardname, ""
)
elif not await relationship_manager.is_qved_name(platform, user_id): elif not await relationship_manager.is_qved_name(platform, user_id):
logger.info(f"给用户({nickname},{cardname})取名: {nickname}") logger.info(f"给用户({nickname},{cardname})取名: {nickname}")
await relationship_manager.first_knowing_some_one( await relationship_manager.first_knowing_some_one(platform, user_id, nickname, cardname, "")
platform, user_id, nickname, cardname, ""
)
async def _calculate_interest(self, message: MessageRecv) -> Tuple[float, bool]: async def _calculate_interest(self, message: MessageRecv) -> Tuple[float, bool]:
"""计算消息的兴趣度 """计算消息的兴趣度
@@ -103,9 +99,11 @@ class HeartFCProcessor:
if message.message_segment.type != "seglist": if message.message_segment.type != "seglist":
return message.message_segment.type return message.message_segment.type
if (isinstance(message.message_segment.data, list) if (
isinstance(message.message_segment.data, list)
and all(isinstance(x, Seg) for x in message.message_segment.data) and all(isinstance(x, Seg) for x in message.message_segment.data)
and len(message.message_segment.data) == 1): and len(message.message_segment.data) == 1
):
return message.message_segment.data[0].type return message.message_segment.data[0].type
return "seglist" return "seglist"
@@ -145,8 +143,9 @@ class HeartFCProcessor:
await message.process() await message.process()
# 3. 过滤检查 # 3. 过滤检查
if self._check_ban_words(message.processed_plain_text, chat, userinfo) or \ if self._check_ban_words(message.processed_plain_text, chat, userinfo) or self._check_ban_regex(
self._check_ban_regex(message.raw_message, chat, userinfo): message.raw_message, chat, userinfo
):
return return
# 4. 缓冲检查 # 4. 缓冲检查
@@ -156,7 +155,7 @@ class HeartFCProcessor:
type_messages = { type_messages = {
"text": f"触发缓冲,消息:{message.processed_plain_text}", "text": f"触发缓冲,消息:{message.processed_plain_text}",
"image": "触发缓冲,表情包/图片等待中", "image": "触发缓冲,表情包/图片等待中",
"seglist": "触发缓冲,消息列表等待中" "seglist": "触发缓冲,消息列表等待中",
} }
logger.debug(type_messages.get(msg_type, "触发未知类型缓冲")) logger.debug(type_messages.get(msg_type, "触发未知类型缓冲"))
return return

View File

@@ -38,11 +38,14 @@ def init_prompt():
"heart_flow_prompt", "heart_flow_prompt",
) )
Prompt(""" Prompt(
"""
你有以下信息可供参考: 你有以下信息可供参考:
{structured_info} {structured_info}
以上的消息是你获取到的消息,或许可以帮助你更好地回复。 以上的消息是你获取到的消息,或许可以帮助你更好地回复。
""", "info_from_tools") """,
"info_from_tools",
)
# Planner提示词 # Planner提示词
Prompt( Prompt(
@@ -166,8 +169,8 @@ class PromptBuilder:
if structured_info: if structured_info:
structured_info_prompt = await global_prompt_manager.format_prompt( structured_info_prompt = await global_prompt_manager.format_prompt(
"info_from_tools", "info_from_tools", structured_info=structured_info
structured_info = structured_info) )
else: else:
structured_info_prompt = "" structured_info_prompt = ""

View File

@@ -303,9 +303,7 @@ async def build_readable_messages(
) )
readable_read_mark = translate_timestamp_to_human_readable(read_mark, mode=timestamp_mode) readable_read_mark = translate_timestamp_to_human_readable(read_mark, mode=timestamp_mode)
read_mark_line = ( read_mark_line = f"\n\n--- 以上消息已读 (标记时间: {readable_read_mark}) ---\n--- 以下新消息未读---\n"
f"\n\n--- 以上消息已读 (标记时间: {readable_read_mark}) ---\n--- 以下新消息未读---\n"
)
# 组合结果,确保空部分不引入多余的标记或换行 # 组合结果,确保空部分不引入多余的标记或换行
if formatted_before and formatted_after: if formatted_before and formatted_after: