🤖 自动格式化代码 [skip ci]
This commit is contained in:
@@ -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}",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Observation:
|
|||||||
self.observe_type = observe_type
|
self.observe_type = observe_type
|
||||||
self.observe_id = observe_id
|
self.observe_id = observe_id
|
||||||
self.last_observe_time = datetime.now().timestamp() # 初始化为当前时间
|
self.last_observe_time = datetime.now().timestamp() # 初始化为当前时间
|
||||||
|
|
||||||
async def observe(self):
|
async def observe(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class InterestChatting:
|
|||||||
self.max_reply_probability: float = max_probability
|
self.max_reply_probability: float = max_probability
|
||||||
self.current_reply_probability: float = 0.0
|
self.current_reply_probability: float = 0.0
|
||||||
self.is_above_threshold: bool = False
|
self.is_above_threshold: bool = False
|
||||||
|
|
||||||
# 任务相关属性初始化
|
# 任务相关属性初始化
|
||||||
self.update_task: Optional[asyncio.Task] = None
|
self.update_task: Optional[asyncio.Task] = None
|
||||||
self._stop_event = asyncio.Event()
|
self._stop_event = asyncio.Event()
|
||||||
|
|||||||
@@ -271,11 +271,10 @@ class SubHeartflowManager:
|
|||||||
log_prefix = "[兴趣评估]"
|
log_prefix = "[兴趣评估]"
|
||||||
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}个群激情聊天")
|
||||||
|
|
||||||
if focused_limit <= 0:
|
if focused_limit <= 0:
|
||||||
# logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 不允许 FOCUSED 子心流")
|
# logger.debug(f"{log_prefix} 当前状态 ({current_state.value}) 不允许 FOCUSED 子心流")
|
||||||
return
|
return
|
||||||
@@ -288,22 +287,23 @@ 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()):
|
||||||
flow_id = sub_hf.subheartflow_id
|
flow_id = sub_hf.subheartflow_id
|
||||||
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
stream_name = chat_manager.get_stream_name(flow_id) or flow_id
|
||||||
|
|
||||||
# 跳过非CHAT状态或已经是FOCUSED状态的子心流
|
# 跳过非CHAT状态或已经是FOCUSED状态的子心流
|
||||||
if sub_hf.chat_state.chat_status == ChatState.FOCUSED:
|
if sub_hf.chat_state.chat_status == ChatState.FOCUSED:
|
||||||
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
|
||||||
|
|
||||||
# 检查是否满足提升概率
|
# 检查是否满足提升概率
|
||||||
if random.random() >= sub_hf.interest_chatting.start_hfc_probability:
|
if random.random() >= sub_hf.interest_chatting.start_hfc_probability:
|
||||||
continue
|
continue
|
||||||
@@ -324,12 +324,12 @@ 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 \
|
|
||||||
final_subflow.chat_state.chat_status == ChatState.FOCUSED:
|
|
||||||
current_focused_count += 1
|
|
||||||
|
|
||||||
|
# 验证提升结果
|
||||||
|
if (
|
||||||
|
final_subflow := self.subheartflows.get(flow_id)
|
||||||
|
) and final_subflow.chat_state.chat_status == ChatState.FOCUSED:
|
||||||
|
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 状态。"""
|
||||||
|
|||||||
@@ -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:
|
||||||
"""定义一个表情包"""
|
"""定义一个表情包"""
|
||||||
@@ -258,7 +259,7 @@ class EmojiManager:
|
|||||||
if emoji.hash == hash:
|
if emoji.hash == hash:
|
||||||
emoji.usage_count += 1
|
emoji.usage_count += 1
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"记录表情使用失败: {str(e)}")
|
logger.error(f"记录表情使用失败: {str(e)}")
|
||||||
|
|
||||||
@@ -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:
|
||||||
@@ -784,16 +787,15 @@ class EmojiManager:
|
|||||||
logger.error(f"[错误] 注册表情包失败: {str(e)}")
|
logger.error(f"[错误] 注册表情包失败: {str(e)}")
|
||||||
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目录下的所有文件
|
||||||
当目录中文件数超过50时,会全部删除
|
当目录中文件数超过50时,会全部删除
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info("[清理] 开始清理临时表情包...")
|
logger.info("[清理] 开始清理临时表情包...")
|
||||||
|
|
||||||
# 清理emoji目录
|
# 清理emoji目录
|
||||||
emoji_dir = os.path.join(BASE_DIR, "emoji")
|
emoji_dir = os.path.join(BASE_DIR, "emoji")
|
||||||
if os.path.exists(emoji_dir):
|
if os.path.exists(emoji_dir):
|
||||||
@@ -805,7 +807,7 @@ class EmojiManager:
|
|||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
logger.debug(f"[清理] 删除表情包文件: {filename}")
|
logger.debug(f"[清理] 删除表情包文件: {filename}")
|
||||||
|
|
||||||
# 清理image目录
|
# 清理image目录
|
||||||
image_dir = os.path.join(BASE_DIR, "image")
|
image_dir = os.path.join(BASE_DIR, "image")
|
||||||
if os.path.exists(image_dir):
|
if os.path.exists(image_dir):
|
||||||
@@ -817,10 +819,8 @@ class EmojiManager:
|
|||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
logger.debug(f"[清理] 删除图片文件: {filename}")
|
logger.debug(f"[清理] 删除图片文件: {filename}")
|
||||||
|
|
||||||
logger.success("[清理] 临时文件清理完成")
|
logger.success("[清理] 临时文件清理完成")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 创建全局单例
|
# 创建全局单例
|
||||||
|
|||||||
@@ -38,31 +38,28 @@ 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:
|
||||||
"""动作管理器:控制每次决策可以使用的动作"""
|
"""动作管理器:控制每次决策可以使用的动作"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# 初始化为默认动作集
|
# 初始化为默认动作集
|
||||||
self._available_actions: Dict[str, str] = DEFAULT_ACTIONS.copy()
|
self._available_actions: Dict[str, str] = DEFAULT_ACTIONS.copy()
|
||||||
|
|
||||||
def get_available_actions(self) -> Dict[str, str]:
|
def get_available_actions(self) -> Dict[str, str]:
|
||||||
"""获取当前可用的动作集"""
|
"""获取当前可用的动作集"""
|
||||||
return self._available_actions
|
return self._available_actions
|
||||||
|
|
||||||
def add_action(self, action_name: str, description: str) -> bool:
|
def add_action(self, action_name: str, description: str) -> bool:
|
||||||
"""
|
"""
|
||||||
添加新的动作
|
添加新的动作
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
action_name: 动作名称
|
action_name: 动作名称
|
||||||
description: 动作描述
|
description: 动作描述
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否添加成功
|
bool: 是否添加成功
|
||||||
"""
|
"""
|
||||||
@@ -70,14 +67,14 @@ class ActionManager:
|
|||||||
return False
|
return False
|
||||||
self._available_actions[action_name] = description
|
self._available_actions[action_name] = description
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def remove_action(self, action_name: str) -> bool:
|
def remove_action(self, action_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
移除指定动作
|
移除指定动作
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
action_name: 动作名称
|
action_name: 动作名称
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否移除成功
|
bool: 是否移除成功
|
||||||
"""
|
"""
|
||||||
@@ -85,63 +82,73 @@ class ActionManager:
|
|||||||
return False
|
return False
|
||||||
del self._available_actions[action_name]
|
del self._available_actions[action_name]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def clear_actions(self):
|
def clear_actions(self):
|
||||||
"""清空所有动作"""
|
"""清空所有动作"""
|
||||||
self._available_actions.clear()
|
self._available_actions.clear()
|
||||||
|
|
||||||
def reset_to_default(self):
|
def reset_to_default(self):
|
||||||
"""重置为默认动作集"""
|
"""重置为默认动作集"""
|
||||||
self._available_actions = DEFAULT_ACTIONS.copy()
|
self._available_actions = DEFAULT_ACTIONS.copy()
|
||||||
|
|
||||||
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()
|
||||||
@@ -151,16 +158,16 @@ class CycleInfo:
|
|||||||
self.reasoning = ""
|
self.reasoning = ""
|
||||||
self.timers: Dict[str, float] = {}
|
self.timers: Dict[str, float] = {}
|
||||||
self.thinking_id = ""
|
self.thinking_id = ""
|
||||||
|
|
||||||
# 添加响应信息相关字段
|
# 添加响应信息相关字段
|
||||||
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": "", # 子思维思考内容
|
||||||
}
|
}
|
||||||
|
|
||||||
def to_dict(self) -> Dict[str, Any]:
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
"""将循环信息转换为字典格式"""
|
"""将循环信息转换为字典格式"""
|
||||||
return {
|
return {
|
||||||
@@ -172,29 +179,31 @@ 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):
|
||||||
"""完成循环,记录结束时间"""
|
"""完成循环,记录结束时间"""
|
||||||
self.end_time = time.time()
|
self.end_time = time.time()
|
||||||
|
|
||||||
def set_action_info(self, action_type: str, reasoning: str, action_taken: bool):
|
def set_action_info(self, action_type: str, reasoning: str, action_taken: bool):
|
||||||
"""设置动作信息"""
|
"""设置动作信息"""
|
||||||
self.action_type = action_type
|
self.action_type = action_type
|
||||||
self.reasoning = reasoning
|
self.reasoning = reasoning
|
||||||
self.action_taken = action_taken
|
self.action_taken = action_taken
|
||||||
|
|
||||||
def set_thinking_id(self, thinking_id: str):
|
def set_thinking_id(self, thinking_id: str):
|
||||||
"""设置思考消息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
|
||||||
@@ -227,7 +236,7 @@ class HeartFChatting:
|
|||||||
self.chat_stream: Optional[ChatStream] = None # 关联的聊天流
|
self.chat_stream: Optional[ChatStream] = None # 关联的聊天流
|
||||||
self.sub_mind: SubMind = sub_mind # 关联的子思维
|
self.sub_mind: SubMind = sub_mind # 关联的子思维
|
||||||
self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态
|
self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态
|
||||||
|
|
||||||
# 日志前缀
|
# 日志前缀
|
||||||
self.log_prefix: str = f"[{chat_manager.get_stream_name(chat_id) or chat_id}]"
|
self.log_prefix: str = f"[{chat_manager.get_stream_name(chat_id) or chat_id}]"
|
||||||
|
|
||||||
@@ -274,7 +283,7 @@ class HeartFChatting:
|
|||||||
|
|
||||||
# 更新日志前缀(以防流名称发生变化)
|
# 更新日志前缀(以防流名称发生变化)
|
||||||
self.log_prefix = f"[{chat_manager.get_stream_name(self.stream_id) or self.stream_id}]"
|
self.log_prefix = f"[{chat_manager.get_stream_name(self.stream_id) or self.stream_id}]"
|
||||||
|
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
logger.info(f"麦麦感觉到了,可以开始激情水群{self.log_prefix} ")
|
logger.info(f"麦麦感觉到了,可以开始激情水群{self.log_prefix} ")
|
||||||
return True
|
return True
|
||||||
@@ -333,52 +342,50 @@ class HeartFChatting:
|
|||||||
self._processing_lock.release()
|
self._processing_lock.release()
|
||||||
|
|
||||||
async def _hfc_loop(self):
|
async def _hfc_loop(self):
|
||||||
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
||||||
try:
|
try:
|
||||||
while True: # 主循环
|
while True: # 主循环
|
||||||
# 创建新的循环信息
|
# 创建新的循环信息
|
||||||
self._cycle_counter += 1
|
self._cycle_counter += 1
|
||||||
self._current_cycle = CycleInfo(self._cycle_counter)
|
self._current_cycle = CycleInfo(self._cycle_counter)
|
||||||
|
|
||||||
# 初始化周期状态
|
# 初始化周期状态
|
||||||
cycle_timers = {}
|
cycle_timers = {}
|
||||||
loop_cycle_start_time = time.monotonic()
|
loop_cycle_start_time = time.monotonic()
|
||||||
|
|
||||||
# 执行规划和处理阶段
|
# 执行规划和处理阶段
|
||||||
async with self._get_cycle_context() as acquired_lock:
|
async with self._get_cycle_context() as acquired_lock:
|
||||||
if not acquired_lock:
|
if not acquired_lock:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 记录规划开始时间点
|
# 记录规划开始时间点
|
||||||
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)
|
||||||
self._current_cycle.timers = cycle_timers
|
self._current_cycle.timers = cycle_timers
|
||||||
|
|
||||||
# 防止循环过快消耗资源
|
# 防止循环过快消耗资源
|
||||||
await self._handle_cycle_delay(action_taken, loop_cycle_start_time, self.log_prefix)
|
await self._handle_cycle_delay(action_taken, loop_cycle_start_time, self.log_prefix)
|
||||||
|
|
||||||
# 等待直到所有消息都发送完成
|
# 等待直到所有消息都发送完成
|
||||||
with Timer("发送消息", cycle_timers):
|
with Timer("发送消息", cycle_timers):
|
||||||
while await self._should_skip_cycle(thinking_id):
|
while await self._should_skip_cycle(thinking_id):
|
||||||
await asyncio.sleep(0.2)
|
await asyncio.sleep(0.2)
|
||||||
|
|
||||||
# 完成当前循环并保存历史
|
# 完成当前循环并保存历史
|
||||||
self._current_cycle.complete_cycle()
|
self._current_cycle.complete_cycle()
|
||||||
self._cycle_history.append(self._current_cycle)
|
self._cycle_history.append(self._current_cycle)
|
||||||
|
|
||||||
# 记录循环信息和计时器结果
|
# 记录循环信息和计时器结果
|
||||||
timer_strings = []
|
timer_strings = []
|
||||||
for name, elapsed in cycle_timers.items():
|
for name, elapsed in cycle_timers.items():
|
||||||
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒"
|
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒"
|
||||||
timer_strings.append(f"{name}: {formatted_time}")
|
timer_strings.append(f"{name}: {formatted_time}")
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 第 #{self._current_cycle.cycle_id}次思考完成,"
|
f"{self.log_prefix} 第 #{self._current_cycle.cycle_id}次思考完成,"
|
||||||
f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, "
|
f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, "
|
||||||
@@ -396,7 +403,7 @@ class HeartFChatting:
|
|||||||
async def _get_cycle_context(self):
|
async def _get_cycle_context(self):
|
||||||
"""
|
"""
|
||||||
循环周期的上下文管理器
|
循环周期的上下文管理器
|
||||||
|
|
||||||
用于确保资源的正确获取和释放:
|
用于确保资源的正确获取和释放:
|
||||||
1. 获取处理锁
|
1. 获取处理锁
|
||||||
2. 执行操作
|
2. 执行操作
|
||||||
@@ -414,10 +421,10 @@ class HeartFChatting:
|
|||||||
async def _check_new_messages(self, start_time: float) -> bool:
|
async def _check_new_messages(self, start_time: float) -> bool:
|
||||||
"""
|
"""
|
||||||
检查从指定时间点后是否有新消息
|
检查从指定时间点后是否有新消息
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
start_time: 开始检查的时间点
|
start_time: 开始检查的时间点
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否有新消息
|
bool: 是否有新消息
|
||||||
"""
|
"""
|
||||||
@@ -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:
|
||||||
# 获取子思维思考结果
|
# 获取子思维思考结果
|
||||||
@@ -443,34 +448,36 @@ class HeartFChatting:
|
|||||||
# 记录子思维思考内容
|
# 记录子思维思考内容
|
||||||
if self._current_cycle:
|
if self._current_cycle:
|
||||||
self._current_cycle.set_response_info(sub_mind_thinking=current_mind)
|
self._current_cycle.set_response_info(sub_mind_thinking=current_mind)
|
||||||
|
|
||||||
# 执行规划
|
# 执行规划
|
||||||
with Timer("决策", cycle_timers):
|
with Timer("决策", cycle_timers):
|
||||||
planner_result = await self._planner(current_mind, cycle_timers)
|
planner_result = await self._planner(current_mind, cycle_timers)
|
||||||
|
|
||||||
# 在获取规划结果后检查新消息
|
# 在获取规划结果后检查新消息
|
||||||
if await self._check_new_messages(planner_start_db_time):
|
if await self._check_new_messages(planner_start_db_time):
|
||||||
# 更新循环信息
|
# 更新循环信息
|
||||||
logger.info(f"{self.log_prefix} 思考到一半,检测到新消息,重新思考")
|
logger.info(f"{self.log_prefix} 思考到一半,检测到新消息,重新思考")
|
||||||
self._current_cycle.set_action_info("new_messages", "检测到新消息", False)
|
self._current_cycle.set_action_info("new_messages", "检测到新消息", False)
|
||||||
return False, "new_messages"
|
return False, "new_messages"
|
||||||
|
|
||||||
# 解析规划结果
|
# 解析规划结果
|
||||||
action = planner_result.get("action", "error")
|
action = planner_result.get("action", "error")
|
||||||
reasoning = planner_result.get("reasoning", "未提供理由")
|
reasoning = planner_result.get("reasoning", "未提供理由")
|
||||||
|
|
||||||
# 更新循环信息
|
# 更新循环信息
|
||||||
self._current_cycle.set_action_info(action, reasoning, True)
|
self._current_cycle.set_action_info(action, reasoning, True)
|
||||||
|
|
||||||
# 处理LLM错误
|
# 处理LLM错误
|
||||||
if planner_result.get("llm_error"):
|
if planner_result.get("llm_error"):
|
||||||
logger.error(f"{self.log_prefix} LLM失败: {reasoning}")
|
logger.error(f"{self.log_prefix} LLM失败: {reasoning}")
|
||||||
return False, ""
|
return False, ""
|
||||||
|
|
||||||
# 根据动作类型执行对应处理
|
# 根据动作类型执行对应处理
|
||||||
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,37 +485,32 @@ 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]:
|
||||||
"""
|
"""
|
||||||
处理规划动作
|
处理规划动作
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
action: 动作类型
|
action: 动作类型
|
||||||
reasoning: 决策理由
|
reasoning: 决策理由
|
||||||
emoji_query: 表情查询
|
emoji_query: 表情查询
|
||||||
cycle_timers: 计时器字典
|
cycle_timers: 计时器字典
|
||||||
planner_start_db_time: 规划开始时间
|
planner_start_db_time: 规划开始时间
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
tuple[bool, str]: (是否执行了动作, 思考消息ID)
|
tuple[bool, str]: (是否执行了动作, 思考消息ID)
|
||||||
"""
|
"""
|
||||||
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)
|
||||||
if not handler:
|
if not handler:
|
||||||
logger.warning(f"{self.log_prefix} 未知动作: {action}, 原因: {reasoning}")
|
logger.warning(f"{self.log_prefix} 未知动作: {action}, 原因: {reasoning}")
|
||||||
return False, ""
|
return False, ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if action == "text_reply":
|
if action == "text_reply":
|
||||||
return await handler(reasoning, emoji_query, cycle_timers)
|
return await handler(reasoning, emoji_query, cycle_timers)
|
||||||
@@ -520,37 +522,35 @@ 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]:
|
|
||||||
"""
|
"""
|
||||||
处理文本回复
|
处理文本回复
|
||||||
|
|
||||||
工作流程:
|
工作流程:
|
||||||
1. 获取锚点消息
|
1. 获取锚点消息
|
||||||
2. 创建思考消息
|
2. 创建思考消息
|
||||||
3. 生成回复
|
3. 生成回复
|
||||||
4. 发送消息
|
4. 发送消息
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
reasoning: 回复原因
|
reasoning: 回复原因
|
||||||
emoji_query: 表情查询
|
emoji_query: 表情查询
|
||||||
cycle_timers: 计时器字典
|
cycle_timers: 计时器字典
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
tuple[bool, str]: (是否回复成功, 思考消息ID)
|
tuple[bool, str]: (是否回复成功, 思考消息ID)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 获取锚点消息
|
# 获取锚点消息
|
||||||
anchor_message = await self._get_anchor_message()
|
anchor_message = await self._get_anchor_message()
|
||||||
if not anchor_message:
|
if not anchor_message:
|
||||||
raise PlannerError("无法获取锚点消息")
|
raise PlannerError("无法获取锚点消息")
|
||||||
|
|
||||||
# 创建思考消息
|
# 创建思考消息
|
||||||
thinking_id = await self._create_thinking_message(anchor_message)
|
thinking_id = await self._create_thinking_message(anchor_message)
|
||||||
if not thinking_id:
|
if not thinking_id:
|
||||||
raise PlannerError("无法创建思考消息")
|
raise PlannerError("无法创建思考消息")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 生成回复
|
# 生成回复
|
||||||
with Timer("Replier", cycle_timers):
|
with Timer("Replier", cycle_timers):
|
||||||
@@ -559,10 +559,10 @@ class HeartFChatting:
|
|||||||
thinking_id=thinking_id,
|
thinking_id=thinking_id,
|
||||||
reason=reasoning,
|
reason=reasoning,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not reply:
|
if not reply:
|
||||||
raise ReplierError("回复生成失败")
|
raise ReplierError("回复生成失败")
|
||||||
|
|
||||||
# 发送消息
|
# 发送消息
|
||||||
with Timer("Sender", cycle_timers):
|
with Timer("Sender", cycle_timers):
|
||||||
await self._sender(
|
await self._sender(
|
||||||
@@ -571,9 +571,9 @@ class HeartFChatting:
|
|||||||
response_set=reply,
|
response_set=reply,
|
||||||
send_emoji=emoji_query,
|
send_emoji=emoji_query,
|
||||||
)
|
)
|
||||||
|
|
||||||
return True, thinking_id
|
return True, thinking_id
|
||||||
|
|
||||||
except (ReplierError, SenderError) as e:
|
except (ReplierError, SenderError) as e:
|
||||||
logger.error(f"{self.log_prefix} 回复失败: {e}")
|
logger.error(f"{self.log_prefix} 回复失败: {e}")
|
||||||
return True, thinking_id # 仍然返回thinking_id以便跟踪
|
return True, thinking_id # 仍然返回thinking_id以便跟踪
|
||||||
@@ -581,72 +581,68 @@ class HeartFChatting:
|
|||||||
async def _handle_emoji_reply(self, reasoning: str, emoji_query: str) -> bool:
|
async def _handle_emoji_reply(self, reasoning: str, emoji_query: str) -> bool:
|
||||||
"""
|
"""
|
||||||
处理表情回复
|
处理表情回复
|
||||||
|
|
||||||
工作流程:
|
工作流程:
|
||||||
1. 获取锚点消息
|
1. 获取锚点消息
|
||||||
2. 发送表情
|
2. 发送表情
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
reasoning: 回复原因
|
reasoning: 回复原因
|
||||||
emoji_query: 表情查询
|
emoji_query: 表情查询
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否发送成功
|
bool: 是否发送成功
|
||||||
"""
|
"""
|
||||||
logger.info(f"{self.log_prefix} 决定回复表情({emoji_query}): {reasoning}")
|
logger.info(f"{self.log_prefix} 决定回复表情({emoji_query}): {reasoning}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
anchor = await self._get_anchor_message()
|
anchor = await self._get_anchor_message()
|
||||||
if not anchor:
|
if not anchor:
|
||||||
raise PlannerError("无法获取锚点消息")
|
raise PlannerError("无法获取锚点消息")
|
||||||
|
|
||||||
await self._handle_emoji(anchor, [], emoji_query)
|
await self._handle_emoji(anchor, [], emoji_query)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
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:
|
|
||||||
"""
|
"""
|
||||||
处理不回复的情况
|
处理不回复的情况
|
||||||
|
|
||||||
工作流程:
|
工作流程:
|
||||||
1. 等待新消息
|
1. 等待新消息
|
||||||
2. 超时或收到新消息时返回
|
2. 超时或收到新消息时返回
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
reasoning: 不回复的原因
|
reasoning: 不回复的原因
|
||||||
planner_start_db_time: 规划开始时间
|
planner_start_db_time: 规划开始时间
|
||||||
cycle_timers: 计时器字典
|
cycle_timers: 计时器字典
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否成功处理
|
bool: 是否成功处理
|
||||||
"""
|
"""
|
||||||
logger.info(f"{self.log_prefix} 决定不回复: {reasoning}")
|
logger.info(f"{self.log_prefix} 决定不回复: {reasoning}")
|
||||||
|
|
||||||
observation = self.observations[0] if self.observations else None
|
observation = self.observations[0] if self.observations else None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with Timer("Wait New Msg", cycle_timers):
|
with Timer("Wait New Msg", cycle_timers):
|
||||||
return await self._wait_for_new_message(observation, planner_start_db_time, self.log_prefix)
|
return await self._wait_for_new_message(observation, planner_start_db_time, self.log_prefix)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
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:
|
|
||||||
"""
|
"""
|
||||||
等待新消息
|
等待新消息
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
observation: 观察实例
|
observation: 观察实例
|
||||||
planner_start_db_time: 开始等待的时间
|
planner_start_db_time: 开始等待的时间
|
||||||
log_prefix: 日志前缀
|
log_prefix: 日志前缀
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
bool: 是否检测到新消息
|
bool: 是否检测到新消息
|
||||||
"""
|
"""
|
||||||
@@ -655,11 +651,11 @@ class HeartFChatting:
|
|||||||
if await observation.has_new_messages_since(planner_start_db_time):
|
if await observation.has_new_messages_since(planner_start_db_time):
|
||||||
logger.info(f"{log_prefix} 检测到新消息")
|
logger.info(f"{log_prefix} 检测到新消息")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if time.monotonic() - wait_start_time > 60:
|
if time.monotonic() - wait_start_time > 60:
|
||||||
logger.warning(f"{log_prefix} 等待超时(60秒)")
|
logger.warning(f"{log_prefix} 等待超时(60秒)")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await asyncio.sleep(1.5)
|
await asyncio.sleep(1.5)
|
||||||
|
|
||||||
async def _should_skip_cycle(self, thinking_id: str) -> bool:
|
async def _should_skip_cycle(self, thinking_id: 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
|
||||||
@@ -702,7 +696,7 @@ class HeartFChatting:
|
|||||||
async def _get_submind_thinking(self) -> str:
|
async def _get_submind_thinking(self) -> str:
|
||||||
"""
|
"""
|
||||||
获取子思维的思考结果
|
获取子思维的思考结果
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
str: 思考结果,如果思考失败则返回错误信息
|
str: 思考结果,如果思考失败则返回错误信息
|
||||||
"""
|
"""
|
||||||
@@ -719,7 +713,7 @@ class HeartFChatting:
|
|||||||
async def _planner(self, current_mind: str, cycle_timers: dict) -> Dict[str, Any]:
|
async def _planner(self, current_mind: str, cycle_timers: dict) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
规划器 (Planner): 使用LLM根据上下文决定是否和如何回复。
|
规划器 (Planner): 使用LLM根据上下文决定是否和如何回复。
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
current_mind: 子思维的当前思考结果
|
current_mind: 子思维的当前思考结果
|
||||||
"""
|
"""
|
||||||
@@ -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}")
|
||||||
@@ -960,9 +958,6 @@ class HeartFChatting:
|
|||||||
message=anchor_message, # Pass anchor_message positionally (matches 'message' parameter)
|
message=anchor_message, # Pass anchor_message positionally (matches 'message' parameter)
|
||||||
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生成了一个空回复集。")
|
||||||
@@ -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)
|
||||||
@@ -1117,10 +1109,10 @@ class HeartFChatting:
|
|||||||
|
|
||||||
def get_cycle_history(self, last_n: Optional[int] = None) -> List[Dict[str, Any]]:
|
def get_cycle_history(self, last_n: Optional[int] = None) -> List[Dict[str, Any]]:
|
||||||
"""获取循环历史记录
|
"""获取循环历史记录
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
last_n: 获取最近n个循环的信息,如果为None则获取所有历史记录
|
last_n: 获取最近n个循环的信息,如果为None则获取所有历史记录
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
List[Dict[str, Any]]: 循环历史记录列表
|
List[Dict[str, Any]]: 循环历史记录列表
|
||||||
"""
|
"""
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ logger = get_module_logger("heartflow_processor", config=processor_config)
|
|||||||
|
|
||||||
class HeartFCProcessor:
|
class HeartFCProcessor:
|
||||||
"""心流处理器,负责处理接收到的消息并计算兴趣度"""
|
"""心流处理器,负责处理接收到的消息并计算兴趣度"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""初始化心流处理器,创建消息存储实例"""
|
"""初始化心流处理器,创建消息存储实例"""
|
||||||
self.storage = MessageStorage()
|
self.storage = MessageStorage()
|
||||||
|
|
||||||
async def _handle_error(self, error: Exception, context: str, message: Optional[MessageRecv] = None) -> None:
|
async def _handle_error(self, error: Exception, context: str, message: Optional[MessageRecv] = None) -> None:
|
||||||
"""统一的错误处理函数
|
"""统一的错误处理函数
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
error: 捕获到的异常
|
error: 捕获到的异常
|
||||||
context: 错误发生的上下文描述
|
context: 错误发生的上下文描述
|
||||||
@@ -39,12 +39,12 @@ 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:
|
||||||
"""处理用户关系逻辑
|
"""处理用户关系逻辑
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message: 消息对象,包含用户信息
|
message: 消息对象,包含用户信息
|
||||||
"""
|
"""
|
||||||
@@ -54,24 +54,20 @@ class HeartFCProcessor:
|
|||||||
cardname = message.message_info.user_info.user_cardname or nickname
|
cardname = message.message_info.user_info.user_cardname or nickname
|
||||||
|
|
||||||
is_known = await relationship_manager.is_known_some_one(platform, user_id)
|
is_known = await relationship_manager.is_known_some_one(platform, user_id)
|
||||||
|
|
||||||
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]:
|
||||||
"""计算消息的兴趣度
|
"""计算消息的兴趣度
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message: 待处理的消息对象
|
message: 待处理的消息对象
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[float, bool]: (兴趣度, 是否被提及)
|
Tuple[float, bool]: (兴趣度, 是否被提及)
|
||||||
"""
|
"""
|
||||||
@@ -93,33 +89,35 @@ class HeartFCProcessor:
|
|||||||
|
|
||||||
def _get_message_type(self, message: MessageRecv) -> str:
|
def _get_message_type(self, message: MessageRecv) -> str:
|
||||||
"""获取消息类型
|
"""获取消息类型
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message: 消息对象
|
message: 消息对象
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 消息类型
|
str: 消息类型
|
||||||
"""
|
"""
|
||||||
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"
|
||||||
|
|
||||||
async def process_message(self, message_data: str) -> None:
|
async def process_message(self, message_data: str) -> None:
|
||||||
"""处理接收到的原始消息数据
|
"""处理接收到的原始消息数据
|
||||||
|
|
||||||
主要流程:
|
主要流程:
|
||||||
1. 消息解析与初始化
|
1. 消息解析与初始化
|
||||||
2. 消息缓冲处理
|
2. 消息缓冲处理
|
||||||
3. 过滤检查
|
3. 过滤检查
|
||||||
4. 兴趣度计算
|
4. 兴趣度计算
|
||||||
5. 关系处理
|
5. 关系处理
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message_data: 原始消息字符串
|
message_data: 原始消息字符串
|
||||||
"""
|
"""
|
||||||
@@ -133,20 +131,21 @@ class HeartFCProcessor:
|
|||||||
|
|
||||||
# 2. 消息缓冲与流程序化
|
# 2. 消息缓冲与流程序化
|
||||||
await message_buffer.start_caching_messages(message)
|
await message_buffer.start_caching_messages(message)
|
||||||
|
|
||||||
chat = await chat_manager.get_or_create_stream(
|
chat = await chat_manager.get_or_create_stream(
|
||||||
platform=messageinfo.platform,
|
platform=messageinfo.platform,
|
||||||
user_info=userinfo,
|
user_info=userinfo,
|
||||||
group_info=groupinfo,
|
group_info=groupinfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
subheartflow = await heartflow.create_subheartflow(chat.stream_id)
|
subheartflow = await heartflow.create_subheartflow(chat.stream_id)
|
||||||
message.update_chat_stream(chat)
|
message.update_chat_stream(chat)
|
||||||
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
|
||||||
@@ -189,12 +188,12 @@ class HeartFCProcessor:
|
|||||||
|
|
||||||
def _check_ban_words(self, text: str, chat, userinfo) -> bool:
|
def _check_ban_words(self, text: str, chat, userinfo) -> bool:
|
||||||
"""检查消息是否包含过滤词
|
"""检查消息是否包含过滤词
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: 待检查的文本
|
text: 待检查的文本
|
||||||
chat: 聊天对象
|
chat: 聊天对象
|
||||||
userinfo: 用户信息
|
userinfo: 用户信息
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否包含过滤词
|
bool: 是否包含过滤词
|
||||||
"""
|
"""
|
||||||
@@ -208,12 +207,12 @@ class HeartFCProcessor:
|
|||||||
|
|
||||||
def _check_ban_regex(self, text: str, chat, userinfo) -> bool:
|
def _check_ban_regex(self, text: str, chat, userinfo) -> bool:
|
||||||
"""检查消息是否匹配过滤正则表达式
|
"""检查消息是否匹配过滤正则表达式
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: 待检查的文本
|
text: 待检查的文本
|
||||||
chat: 聊天对象
|
chat: 聊天对象
|
||||||
userinfo: 用户信息
|
userinfo: 用户信息
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否匹配过滤正则
|
bool: 是否匹配过滤正则
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -37,12 +37,15 @@ def init_prompt():
|
|||||||
{moderation_prompt}。注意:回复不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。""",
|
{moderation_prompt}。注意:回复不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。""",
|
||||||
"heart_flow_prompt",
|
"heart_flow_prompt",
|
||||||
)
|
)
|
||||||
|
|
||||||
Prompt("""
|
Prompt(
|
||||||
|
"""
|
||||||
你有以下信息可供参考:
|
你有以下信息可供参考:
|
||||||
{structured_info}
|
{structured_info}
|
||||||
以上的消息是你获取到的消息,或许可以帮助你更好地回复。
|
以上的消息是你获取到的消息,或许可以帮助你更好地回复。
|
||||||
""", "info_from_tools")
|
""",
|
||||||
|
"info_from_tools",
|
||||||
|
)
|
||||||
|
|
||||||
# Planner提示词
|
# Planner提示词
|
||||||
Prompt(
|
Prompt(
|
||||||
@@ -163,11 +166,11 @@ class PromptBuilder:
|
|||||||
prompt_ger += "你喜欢用倒装句"
|
prompt_ger += "你喜欢用倒装句"
|
||||||
if random.random() < 0.02:
|
if random.random() < 0.02:
|
||||||
prompt_ger += "你喜欢用反问句"
|
prompt_ger += "你喜欢用反问句"
|
||||||
|
|
||||||
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 = ""
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user