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

This commit is contained in:
github-actions[bot]
2025-06-19 12:22:36 +00:00
parent 0467f97e7c
commit 7ed3ecb561
26 changed files with 450 additions and 450 deletions

View File

@@ -1183,4 +1183,3 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -370,7 +370,6 @@ class VirtualLogDisplay:
self.text_widget.tag_add(tag_name, f"{start_pos}+{tag_info[1]}c", f"{start_pos}+{tag_info[2]}c") self.text_widget.tag_add(tag_name, f"{start_pos}+{tag_info[1]}c", f"{start_pos}+{tag_info[2]}c")
class AsyncLogLoader: class AsyncLogLoader:
"""异步日志加载器""" """异步日志加载器"""

View File

@@ -99,7 +99,6 @@ class HeartFCSender:
message.build_reply() message.build_reply()
logger.debug(f"[{chat_id}] 选择回复引用消息: {message.processed_plain_text[:20]}...") logger.debug(f"[{chat_id}] 选择回复引用消息: {message.processed_plain_text[:20]}...")
await message.process() await message.process()
if typing: if typing:
@@ -110,7 +109,6 @@ class HeartFCSender:
) )
await asyncio.sleep(typing_time) await asyncio.sleep(typing_time)
sent_msg = await send_message(message) sent_msg = await send_message(message)
if not sent_msg: if not sent_msg:
return False return False

View File

@@ -14,7 +14,7 @@ ActionInfo = Dict[str, Any]
class ActionManager: class ActionManager:
""" """
动作管理器,用于管理各种类型的动作 动作管理器,用于管理各种类型的动作
现在统一使用新插件系统,简化了原有的新旧兼容逻辑。 现在统一使用新插件系统,简化了原有的新旧兼容逻辑。
""" """

View File

@@ -12,7 +12,9 @@ class BasePlanner(ABC):
self.action_manager = action_manager self.action_manager = action_manager
@abstractmethod @abstractmethod
async def plan(self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float) -> Dict[str, Any]: async def plan(
self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float
) -> Dict[str, Any]:
""" """
规划下一步行动 规划下一步行动

View File

@@ -242,7 +242,7 @@ class ActionModifier:
for action_name, action_info in actions_with_info.items(): for action_name, action_info in actions_with_info.items():
activation_type = action_info.get("focus_activation_type", "always") activation_type = action_info.get("focus_activation_type", "always")
print(f"action_name: {action_name}, activation_type: {activation_type}") print(f"action_name: {action_name}, activation_type: {activation_type}")
# 现在统一是字符串格式的激活类型值 # 现在统一是字符串格式的激活类型值

View File

@@ -82,7 +82,9 @@ class ActionPlanner(BasePlanner):
request_type="focus.planner", # 用于动作规划 request_type="focus.planner", # 用于动作规划
) )
async def plan(self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float) -> Dict[str, Any]: async def plan(
self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]], loop_start_time: float
) -> Dict[str, Any]:
""" """
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。 规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
@@ -243,7 +245,7 @@ class ActionPlanner(BasePlanner):
if selected_expressions: if selected_expressions:
action_data["selected_expressions"] = selected_expressions action_data["selected_expressions"] = selected_expressions
logger.debug(f"{self.log_prefix} 传递{len(selected_expressions)}个选中的表达方式到action_data") logger.debug(f"{self.log_prefix} 传递{len(selected_expressions)}个选中的表达方式到action_data")
action_data["loop_start_time"] = loop_start_time action_data["loop_start_time"] = loop_start_time
# 对于reply动作不需要额外处理因为相关字段已经在上面的循环中添加到action_data # 对于reply动作不需要额外处理因为相关字段已经在上面的循环中添加到action_data

View File

@@ -71,7 +71,7 @@ def init_prompt():
""", """,
"default_generator_private_prompt", "default_generator_private_prompt",
) )
Prompt( Prompt(
""" """
你可以参考你的以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中: 你可以参考你的以下的语言习惯,如果情景合适就使用,不要盲目使用,不要生硬使用,而是结合到表达中:
@@ -156,7 +156,7 @@ class DefaultReplyer:
await self.heart_fc_sender.register_thinking(thinking_message) await self.heart_fc_sender.register_thinking(thinking_message)
return None return None
async def generate_reply_with_context( async def generate_reply_with_context(
self, self,
reply_data: Dict[str, Any], reply_data: Dict[str, Any],
@@ -166,8 +166,6 @@ class DefaultReplyer:
(已整合原 HeartFCGenerator 的功能) (已整合原 HeartFCGenerator 的功能)
""" """
try: try:
# 3. 构建 Prompt # 3. 构建 Prompt
with Timer("构建Prompt", {}): # 内部计时器,可选保留 with Timer("构建Prompt", {}): # 内部计时器,可选保留
prompt = await self.build_prompt_reply_context( prompt = await self.build_prompt_reply_context(
@@ -206,13 +204,13 @@ class DefaultReplyer:
reply_seg = ("text", str) reply_seg = ("text", str)
reply_set.append(reply_seg) reply_set.append(reply_seg)
return True , reply_set return True, reply_set
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix}回复生成意外失败: {e}") logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
traceback.print_exc() traceback.print_exc()
return False, None return False, None
async def rewrite_reply_with_context( async def rewrite_reply_with_context(
self, self,
reply_data: Dict[str, Any], reply_data: Dict[str, Any],
@@ -221,8 +219,6 @@ class DefaultReplyer:
表达器 (Expressor): 核心逻辑,负责生成回复文本。 表达器 (Expressor): 核心逻辑,负责生成回复文本。
""" """
try: try:
reply_to = reply_data.get("reply_to", "") reply_to = reply_data.get("reply_to", "")
raw_reply = reply_data.get("raw_reply", "") raw_reply = reply_data.get("raw_reply", "")
reason = reply_data.get("reason", "") reason = reply_data.get("reason", "")
@@ -275,24 +271,20 @@ class DefaultReplyer:
logger.error(f"{self.log_prefix}回复生成意外失败: {e}") logger.error(f"{self.log_prefix}回复生成意外失败: {e}")
traceback.print_exc() traceback.print_exc()
return False, None return False, None
async def build_prompt_reply_context( async def build_prompt_reply_context(
self, self,
reply_data=None, reply_data=None,
) -> str: ) -> str:
chat_stream = self.chat_stream chat_stream = self.chat_stream
is_group_chat = bool(chat_stream.group_info) is_group_chat = bool(chat_stream.group_info)
identity = reply_data.get("identity", "") identity = reply_data.get("identity", "")
extra_info_block = reply_data.get("extra_info_block", "") extra_info_block = reply_data.get("extra_info_block", "")
relation_info_block = reply_data.get("relation_info_block", "") relation_info_block = reply_data.get("relation_info_block", "")
reply_to = reply_data.get("reply_to", "none") reply_to = reply_data.get("reply_to", "none")
sender = "" sender = ""
target = "" target = ""
if ":" in reply_to or "" in reply_to: if ":" in reply_to or "" in reply_to:
@@ -301,7 +293,6 @@ class DefaultReplyer:
if len(parts) == 2: if len(parts) == 2:
sender = parts[0].strip() sender = parts[0].strip()
target = parts[1].strip() target = parts[1].strip()
message_list_before_now = get_raw_msg_before_timestamp_with_chat( message_list_before_now = get_raw_msg_before_timestamp_with_chat(
chat_id=chat_stream.stream_id, chat_id=chat_stream.stream_id,
@@ -379,9 +370,7 @@ class DefaultReplyer:
# logger.debug("开始构建 focus prompt") # logger.debug("开始构建 focus prompt")
if sender: if sender:
reply_target_block = ( reply_target_block = f"现在{sender}说的:{target}。引起了你的注意,你想要在群里发言或者回复这条消息。"
f"现在{sender}说的:{target}。引起了你的注意,你想要在群里发言或者回复这条消息。"
)
elif target: elif target:
reply_target_block = f"现在{target}引起了你的注意,你想要在群里发言或者回复这条消息。" reply_target_block = f"现在{target}引起了你的注意,你想要在群里发言或者回复这条消息。"
else: else:
@@ -436,9 +425,6 @@ class DefaultReplyer:
raw_reply, raw_reply,
reply_to, reply_to,
) -> str: ) -> str:
sender = "" sender = ""
target = "" target = ""
if ":" in reply_to or "" in reply_to: if ":" in reply_to or "" in reply_to:
@@ -447,9 +433,9 @@ class DefaultReplyer:
if len(parts) == 2: if len(parts) == 2:
sender = parts[0].strip() sender = parts[0].strip()
target = parts[1].strip() target = parts[1].strip()
chat_stream = self.chat_stream chat_stream = self.chat_stream
is_group_chat = bool(chat_stream.group_info) is_group_chat = bool(chat_stream.group_info)
message_list_before_now = get_raw_msg_before_timestamp_with_chat( message_list_before_now = get_raw_msg_before_timestamp_with_chat(
@@ -608,23 +594,22 @@ class DefaultReplyer:
) )
try: try:
if (bot_message.is_private_message() or if (
bot_message.reply.processed_plain_text != "[System Trigger Context]" or bot_message.is_private_message()
mark_head): or bot_message.reply.processed_plain_text != "[System Trigger Context]"
or mark_head
):
set_reply = False set_reply = False
else: else:
set_reply = True set_reply = True
if not mark_head: if not mark_head:
mark_head = True mark_head = True
typing = False typing = False
else: else:
typing = True typing = True
sent_msg = await self.heart_fc_sender.send_message(bot_message, typing=typing, set_reply=set_reply)
sent_msg = await self.heart_fc_sender.send_message(
bot_message, typing=typing, set_reply=set_reply
)
reply_message_ids.append(part_message_id) # 记录我们生成的ID reply_message_ids.append(part_message_id) # 记录我们生成的ID
@@ -652,7 +637,7 @@ class DefaultReplyer:
is_emoji: bool, is_emoji: bool,
thinking_start_time: float, thinking_start_time: float,
display_message: str, display_message: str,
anchor_message: MessageRecv = None anchor_message: MessageRecv = None,
) -> MessageSending: ) -> MessageSending:
"""构建单个发送消息""" """构建单个发送消息"""

View File

@@ -16,6 +16,7 @@ from src.common.logger import get_logger
from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
from src.chat.message_receive.chat_stream import get_chat_manager from src.chat.message_receive.chat_stream import get_chat_manager
from src.person_info.person_info import get_person_info_manager from src.person_info.person_info import get_person_info_manager
logger = get_logger("observation") logger = get_logger("observation")
# 定义提示模板 # 定义提示模板
@@ -71,7 +72,7 @@ class ChattingObservation(Observation):
self.oldest_messages = [] self.oldest_messages = []
self.oldest_messages_str = "" self.oldest_messages_str = ""
self.last_observe_time = datetime.now().timestamp() -1 self.last_observe_time = datetime.now().timestamp() - 1
print(f"last_observe_time: {self.last_observe_time}") print(f"last_observe_time: {self.last_observe_time}")
initial_messages = get_raw_msg_before_timestamp_with_chat(self.chat_id, self.last_observe_time, 10) initial_messages = get_raw_msg_before_timestamp_with_chat(self.chat_id, self.last_observe_time, 10)
self.last_observe_time = initial_messages[-1]["time"] if initial_messages else self.last_observe_time self.last_observe_time = initial_messages[-1]["time"] if initial_messages else self.last_observe_time
@@ -159,10 +160,9 @@ class ChattingObservation(Observation):
"processed_plain_text": find_msg.get("processed_plain_text"), "processed_plain_text": find_msg.get("processed_plain_text"),
} }
find_rec_msg = MessageRecv(message_dict) find_rec_msg = MessageRecv(message_dict)
find_rec_msg.update_chat_stream(get_chat_manager().get_or_create_stream(self.chat_id)) find_rec_msg.update_chat_stream(get_chat_manager().get_or_create_stream(self.chat_id))
return find_rec_msg return find_rec_msg
async def observe(self): async def observe(self):

View File

@@ -171,7 +171,7 @@ class ChatManager:
# 使用MD5生成唯一ID # 使用MD5生成唯一ID
key = "_".join(components) key = "_".join(components)
return hashlib.md5(key.encode()).hexdigest() return hashlib.md5(key.encode()).hexdigest()
def get_stream_id(self, platform: str, chat_id: str, is_group: bool = True) -> str: def get_stream_id(self, platform: str, chat_id: str, is_group: bool = True) -> str:
"""获取聊天流ID""" """获取聊天流ID"""
if is_group: if is_group:

View File

@@ -15,7 +15,7 @@ from src.plugin_system.apis import (
message_api, message_api,
person_api, person_api,
send_api, send_api,
utils_api utils_api,
) )
# 导出所有API模块使它们可以通过 apis.xxx 方式访问 # 导出所有API模块使它们可以通过 apis.xxx 方式访问
@@ -29,5 +29,5 @@ __all__ = [
"message_api", "message_api",
"person_api", "person_api",
"send_api", "send_api",
"utils_api" "utils_api",
] ]

View File

@@ -6,7 +6,7 @@
from src.plugin_system.apis import chat_api from src.plugin_system.apis import chat_api
streams = chat_api.get_all_group_streams() streams = chat_api.get_all_group_streams()
chat_type = chat_api.get_stream_type(stream) chat_type = chat_api.get_stream_type(stream)
或者: 或者:
from src.plugin_system.apis.chat_api import ChatManager as chat from src.plugin_system.apis.chat_api import ChatManager as chat
streams = chat.get_all_group_streams() streams = chat.get_all_group_streams()
@@ -24,14 +24,14 @@ logger = get_logger("chat_api")
class ChatManager: class ChatManager:
"""聊天管理器 - 专门负责聊天信息的查询和管理""" """聊天管理器 - 专门负责聊天信息的查询和管理"""
@staticmethod @staticmethod
def get_all_streams(platform: str = "qq") -> List[ChatStream]: def get_all_streams(platform: str = "qq") -> List[ChatStream]:
"""获取所有聊天流 """获取所有聊天流
Args: Args:
platform: 平台筛选,默认为"qq" platform: 平台筛选,默认为"qq"
Returns: Returns:
List[ChatStream]: 聊天流列表 List[ChatStream]: 聊天流列表
""" """
@@ -44,14 +44,14 @@ class ChatManager:
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 获取聊天流失败: {e}") logger.error(f"[ChatAPI] 获取聊天流失败: {e}")
return streams return streams
@staticmethod @staticmethod
def get_group_streams(platform: str = "qq") -> List[ChatStream]: def get_group_streams(platform: str = "qq") -> List[ChatStream]:
"""获取所有群聊聊天流 """获取所有群聊聊天流
Args: Args:
platform: 平台筛选,默认为"qq" platform: 平台筛选,默认为"qq"
Returns: Returns:
List[ChatStream]: 群聊聊天流列表 List[ChatStream]: 群聊聊天流列表
""" """
@@ -64,14 +64,14 @@ class ChatManager:
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 获取群聊流失败: {e}") logger.error(f"[ChatAPI] 获取群聊流失败: {e}")
return streams return streams
@staticmethod @staticmethod
def get_private_streams(platform: str = "qq") -> List[ChatStream]: def get_private_streams(platform: str = "qq") -> List[ChatStream]:
"""获取所有私聊聊天流 """获取所有私聊聊天流
Args: Args:
platform: 平台筛选,默认为"qq" platform: 平台筛选,默认为"qq"
Returns: Returns:
List[ChatStream]: 私聊聊天流列表 List[ChatStream]: 私聊聊天流列表
""" """
@@ -84,15 +84,15 @@ class ChatManager:
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 获取私聊流失败: {e}") logger.error(f"[ChatAPI] 获取私聊流失败: {e}")
return streams return streams
@staticmethod @staticmethod
def get_stream_by_group_id(group_id: str, platform: str = "qq") -> Optional[ChatStream]: def get_stream_by_group_id(group_id: str, platform: str = "qq") -> Optional[ChatStream]:
"""根据群ID获取聊天流 """根据群ID获取聊天流
Args: Args:
group_id: 群聊ID group_id: 群聊ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
Optional[ChatStream]: 聊天流对象如果未找到返回None Optional[ChatStream]: 聊天流对象如果未找到返回None
""" """
@@ -109,15 +109,15 @@ class ChatManager:
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 查找群聊流失败: {e}") logger.error(f"[ChatAPI] 查找群聊流失败: {e}")
return None return None
@staticmethod @staticmethod
def get_stream_by_user_id(user_id: str, platform: str = "qq") -> Optional[ChatStream]: def get_stream_by_user_id(user_id: str, platform: str = "qq") -> Optional[ChatStream]:
"""根据用户ID获取私聊流 """根据用户ID获取私聊流
Args: Args:
user_id: 用户ID user_id: 用户ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
Optional[ChatStream]: 聊天流对象如果未找到返回None Optional[ChatStream]: 聊天流对象如果未找到返回None
""" """
@@ -134,74 +134,78 @@ class ChatManager:
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 查找私聊流失败: {e}") logger.error(f"[ChatAPI] 查找私聊流失败: {e}")
return None return None
@staticmethod @staticmethod
def get_stream_type(chat_stream: ChatStream) -> str: def get_stream_type(chat_stream: ChatStream) -> str:
"""获取聊天流类型 """获取聊天流类型
Args: Args:
chat_stream: 聊天流对象 chat_stream: 聊天流对象
Returns: Returns:
str: 聊天类型 ("group", "private", "unknown") str: 聊天类型 ("group", "private", "unknown")
""" """
if not chat_stream: if not chat_stream:
return "unknown" return "unknown"
if hasattr(chat_stream, "group_info"): if hasattr(chat_stream, "group_info"):
return "group" if chat_stream.group_info else "private" return "group" if chat_stream.group_info else "private"
return "unknown" return "unknown"
@staticmethod @staticmethod
def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]: def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
"""获取聊天流详细信息 """获取聊天流详细信息
Args: Args:
chat_stream: 聊天流对象 chat_stream: 聊天流对象
Returns: Returns:
Dict[str, Any]: 聊天流信息字典 Dict[str, Any]: 聊天流信息字典
""" """
if not chat_stream: if not chat_stream:
return {} return {}
try: try:
info = { info = {
"stream_id": chat_stream.stream_id, "stream_id": chat_stream.stream_id,
"platform": chat_stream.platform, "platform": chat_stream.platform,
"type": ChatManager.get_stream_type(chat_stream), "type": ChatManager.get_stream_type(chat_stream),
} }
if chat_stream.group_info: if chat_stream.group_info:
info.update({ info.update(
"group_id": chat_stream.group_info.group_id, {
"group_name": getattr(chat_stream.group_info, "group_name", "未知群聊"), "group_id": chat_stream.group_info.group_id,
}) "group_name": getattr(chat_stream.group_info, "group_name", "未知群聊"),
}
)
if chat_stream.user_info: if chat_stream.user_info:
info.update({ info.update(
"user_id": chat_stream.user_info.user_id, {
"user_name": chat_stream.user_info.user_nickname, "user_id": chat_stream.user_info.user_id,
}) "user_name": chat_stream.user_info.user_nickname,
}
)
return info return info
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 获取聊天流信息失败: {e}") logger.error(f"[ChatAPI] 获取聊天流信息失败: {e}")
return {} return {}
@staticmethod @staticmethod
def get_recent_messages_from_obs(observations: List[Any], count: int = 5) -> List[Dict[str, Any]]: def get_recent_messages_from_obs(observations: List[Any], count: int = 5) -> List[Dict[str, Any]]:
"""从观察对象获取最近的消息 """从观察对象获取最近的消息
Args: Args:
observations: 观察对象列表 observations: 观察对象列表
count: 要获取的消息数量 count: 要获取的消息数量
Returns: Returns:
List[Dict]: 消息列表,每个消息包含发送者、内容等信息 List[Dict]: 消息列表,每个消息包含发送者、内容等信息
""" """
messages = [] messages = []
try: try:
if observations and len(observations) > 0: if observations and len(observations) > 0:
obs = observations[0] obs = observations[0]
@@ -219,13 +223,13 @@ class ChatManager:
logger.debug(f"[ChatAPI] 获取到 {len(messages)} 条最近消息") logger.debug(f"[ChatAPI] 获取到 {len(messages)} 条最近消息")
except Exception as e: except Exception as e:
logger.error(f"[ChatAPI] 获取最近消息失败: {e}") logger.error(f"[ChatAPI] 获取最近消息失败: {e}")
return messages return messages
@staticmethod @staticmethod
def get_streams_summary() -> Dict[str, int]: def get_streams_summary() -> Dict[str, int]:
"""获取聊天流统计摘要 """获取聊天流统计摘要
Returns: Returns:
Dict[str, int]: 包含各种统计信息的字典 Dict[str, int]: 包含各种统计信息的字典
""" """
@@ -233,14 +237,14 @@ class ChatManager:
all_streams = ChatManager.get_all_streams() all_streams = ChatManager.get_all_streams()
group_streams = ChatManager.get_group_streams() group_streams = ChatManager.get_group_streams()
private_streams = ChatManager.get_private_streams() private_streams = ChatManager.get_private_streams()
summary = { summary = {
"total_streams": len(all_streams), "total_streams": len(all_streams),
"group_streams": len(group_streams), "group_streams": len(group_streams),
"private_streams": len(private_streams), "private_streams": len(private_streams),
"qq_streams": len([s for s in all_streams if s.platform == "qq"]), "qq_streams": len([s for s in all_streams if s.platform == "qq"]),
} }
logger.debug(f"[ChatAPI] 聊天流统计: {summary}") logger.debug(f"[ChatAPI] 聊天流统计: {summary}")
return summary return summary
except Exception as e: except Exception as e:
@@ -252,6 +256,7 @@ class ChatManager:
# 模块级别的便捷函数 - 类似 requests.get(), requests.post() 的设计 # 模块级别的便捷函数 - 类似 requests.get(), requests.post() 的设计
# ============================================================================= # =============================================================================
def get_all_streams(platform: str = "qq") -> List[ChatStream]: def get_all_streams(platform: str = "qq") -> List[ChatStream]:
"""获取所有聊天流的便捷函数""" """获取所有聊天流的便捷函数"""
return ChatManager.get_all_streams(platform) return ChatManager.get_all_streams(platform)
@@ -289,4 +294,4 @@ def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
def get_streams_summary() -> Dict[str, int]: def get_streams_summary() -> Dict[str, int]:
"""获取聊天流统计摘要的便捷函数""" """获取聊天流统计摘要的便捷函数"""
return ChatManager.get_streams_summary() return ChatManager.get_streams_summary()

View File

@@ -19,6 +19,7 @@ logger = get_logger("config_api")
# 配置访问API函数 # 配置访问API函数
# ============================================================================= # =============================================================================
def get_global_config(key: str, default: Any = None) -> Any: def get_global_config(key: str, default: Any = None) -> Any:
""" """
安全地从全局配置中获取一个值。 安全地从全局配置中获取一个值。
@@ -34,7 +35,7 @@ def get_global_config(key: str, default: Any = None) -> Any:
# 支持嵌套键访问 # 支持嵌套键访问
keys = key.split(".") keys = key.split(".")
current = global_config current = global_config
try: try:
for k in keys: for k in keys:
if hasattr(current, k): if hasattr(current, k):
@@ -79,6 +80,7 @@ def get_plugin_config(plugin_config: dict, key: str, default: Any = None) -> Any
# 用户信息API函数 # 用户信息API函数
# ============================================================================= # =============================================================================
async def get_user_id_by_person_name(person_name: str) -> tuple[str, str]: async def get_user_id_by_person_name(person_name: str) -> tuple[str, str]:
"""根据用户名获取用户ID """根据用户名获取用户ID

View File

@@ -18,6 +18,7 @@ logger = get_logger("database_api")
# 通用数据库查询API函数 # 通用数据库查询API函数
# ============================================================================= # =============================================================================
async def db_query( async def db_query(
model_class: Type[Model], model_class: Type[Model],
query_type: str = "get", query_type: str = "get",
@@ -202,9 +203,7 @@ async def db_save(
# 如果提供了key_field和key_value尝试更新现有记录 # 如果提供了key_field和key_value尝试更新现有记录
if key_field and key_value is not None: if key_field and key_value is not None:
# 查找现有记录 # 查找现有记录
existing_records = list( existing_records = list(model_class.select().where(getattr(model_class, key_field) == key_value).limit(1))
model_class.select().where(getattr(model_class, key_field) == key_value).limit(1)
)
if existing_records: if existing_records:
# 更新现有记录 # 更新现有记录
@@ -307,9 +306,9 @@ async def store_action_info(
action_name: str = "", action_name: str = "",
) -> Union[Dict[str, Any], None]: ) -> Union[Dict[str, Any], None]:
"""存储动作信息到数据库 """存储动作信息到数据库
将Action执行的相关信息保存到ActionRecords表中用于后续的记忆和上下文构建。 将Action执行的相关信息保存到ActionRecords表中用于后续的记忆和上下文构建。
Args: Args:
chat_stream: 聊天流对象,包含聊天相关信息 chat_stream: 聊天流对象,包含聊天相关信息
action_build_into_prompt: 是否将此动作构建到提示中 action_build_into_prompt: 是否将此动作构建到提示中
@@ -318,11 +317,11 @@ async def store_action_info(
thinking_id: 关联的思考ID thinking_id: 关联的思考ID
action_data: 动作数据字典 action_data: 动作数据字典
action_name: 动作名称 action_name: 动作名称
Returns: Returns:
Dict[str, Any]: 保存的记录数据 Dict[str, Any]: 保存的记录数据
None: 如果保存失败 None: 如果保存失败
示例: 示例:
record = await database_api.store_action_info( record = await database_api.store_action_info(
chat_stream=chat_stream, chat_stream=chat_stream,
@@ -338,7 +337,7 @@ async def store_action_info(
import time import time
import json import json
from src.common.database.database_model import ActionRecords from src.common.database.database_model import ActionRecords
# 构建动作记录数据 # 构建动作记录数据
record_data = { record_data = {
"action_id": thinking_id or str(int(time.time() * 1000000)), # 使用thinking_id或生成唯一ID "action_id": thinking_id or str(int(time.time() * 1000000)), # 使用thinking_id或生成唯一ID
@@ -349,38 +348,39 @@ async def store_action_info(
"action_build_into_prompt": action_build_into_prompt, "action_build_into_prompt": action_build_into_prompt,
"action_prompt_display": action_prompt_display, "action_prompt_display": action_prompt_display,
} }
# 从chat_stream获取聊天信息 # 从chat_stream获取聊天信息
if chat_stream: if chat_stream:
record_data.update({ record_data.update(
"chat_id": getattr(chat_stream, 'stream_id', ''), {
"chat_info_stream_id": getattr(chat_stream, 'stream_id', ''), "chat_id": getattr(chat_stream, "stream_id", ""),
"chat_info_platform": getattr(chat_stream, 'platform', ''), "chat_info_stream_id": getattr(chat_stream, "stream_id", ""),
}) "chat_info_platform": getattr(chat_stream, "platform", ""),
}
)
else: else:
# 如果没有chat_stream设置默认值 # 如果没有chat_stream设置默认值
record_data.update({ record_data.update(
"chat_id": "", {
"chat_info_stream_id": "", "chat_id": "",
"chat_info_platform": "", "chat_info_stream_id": "",
}) "chat_info_platform": "",
}
)
# 使用已有的db_save函数保存记录 # 使用已有的db_save函数保存记录
saved_record = await db_save( saved_record = await db_save(
ActionRecords, ActionRecords, data=record_data, key_field="action_id", key_value=record_data["action_id"]
data=record_data,
key_field="action_id",
key_value=record_data["action_id"]
) )
if saved_record: if saved_record:
logger.info(f"[DatabaseAPI] 成功存储动作信息: {action_name} (ID: {record_data['action_id']})") logger.info(f"[DatabaseAPI] 成功存储动作信息: {action_name} (ID: {record_data['action_id']})")
else: else:
logger.error(f"[DatabaseAPI] 存储动作信息失败: {action_name}") logger.error(f"[DatabaseAPI] 存储动作信息失败: {action_name}")
return saved_record return saved_record
except Exception as e: except Exception as e:
logger.error(f"[DatabaseAPI] 存储动作信息时发生错误: {e}") logger.error(f"[DatabaseAPI] 存储动作信息时发生错误: {e}")
traceback.print_exc() traceback.print_exc()
return None return None

View File

@@ -20,35 +20,36 @@ logger = get_logger("emoji_api")
# 表情包获取API函数 # 表情包获取API函数
# ============================================================================= # =============================================================================
async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]: async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]:
"""根据描述选择表情包 """根据描述选择表情包
Args: Args:
description: 表情包的描述文本,例如"开心""难过""愤怒" description: 表情包的描述文本,例如"开心""难过""愤怒"
Returns: Returns:
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
""" """
try: try:
logger.info(f"[EmojiAPI] 根据描述获取表情包: {description}") logger.info(f"[EmojiAPI] 根据描述获取表情包: {description}")
emoji_manager = get_emoji_manager() emoji_manager = get_emoji_manager()
emoji_result = await emoji_manager.get_emoji_for_text(description) emoji_result = await emoji_manager.get_emoji_for_text(description)
if not emoji_result: if not emoji_result:
logger.warning(f"[EmojiAPI] 未找到匹配描述 '{description}' 的表情包") logger.warning(f"[EmojiAPI] 未找到匹配描述 '{description}' 的表情包")
return None return None
emoji_path, emoji_description, matched_emotion = emoji_result emoji_path, emoji_description, matched_emotion = emoji_result
emoji_base64 = image_path_to_base64(emoji_path) emoji_base64 = image_path_to_base64(emoji_path)
if not emoji_base64: if not emoji_base64:
logger.error(f"[EmojiAPI] 无法将表情包文件转换为base64: {emoji_path}") logger.error(f"[EmojiAPI] 无法将表情包文件转换为base64: {emoji_path}")
return None return None
logger.info(f"[EmojiAPI] 成功获取表情包: {emoji_description}, 匹配情感: {matched_emotion}") logger.info(f"[EmojiAPI] 成功获取表情包: {emoji_description}, 匹配情感: {matched_emotion}")
return emoji_base64, emoji_description, matched_emotion return emoji_base64, emoji_description, matched_emotion
except Exception as e: except Exception as e:
logger.error(f"[EmojiAPI] 获取表情包失败: {e}") logger.error(f"[EmojiAPI] 获取表情包失败: {e}")
return None return None
@@ -56,43 +57,44 @@ async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]
async def get_random() -> Optional[Tuple[str, str, str]]: async def get_random() -> Optional[Tuple[str, str, str]]:
"""随机获取表情包 """随机获取表情包
Returns: Returns:
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 随机情感标签) 或 None Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 随机情感标签) 或 None
""" """
try: try:
logger.info("[EmojiAPI] 随机获取表情包") logger.info("[EmojiAPI] 随机获取表情包")
emoji_manager = get_emoji_manager() emoji_manager = get_emoji_manager()
all_emojis = emoji_manager.emoji_objects all_emojis = emoji_manager.emoji_objects
if not all_emojis: if not all_emojis:
logger.warning("[EmojiAPI] 没有可用的表情包") logger.warning("[EmojiAPI] 没有可用的表情包")
return None return None
# 过滤有效表情包 # 过滤有效表情包
valid_emojis = [emoji for emoji in all_emojis if not emoji.is_deleted] valid_emojis = [emoji for emoji in all_emojis if not emoji.is_deleted]
if not valid_emojis: if not valid_emojis:
logger.warning("[EmojiAPI] 没有有效的表情包") logger.warning("[EmojiAPI] 没有有效的表情包")
return None return None
# 随机选择 # 随机选择
import random import random
selected_emoji = random.choice(valid_emojis) selected_emoji = random.choice(valid_emojis)
emoji_base64 = image_path_to_base64(selected_emoji.full_path) emoji_base64 = image_path_to_base64(selected_emoji.full_path)
if not emoji_base64: if not emoji_base64:
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}") logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
return None return None
matched_emotion = random.choice(selected_emoji.emotion) if selected_emoji.emotion else "随机表情" matched_emotion = random.choice(selected_emoji.emotion) if selected_emoji.emotion else "随机表情"
# 记录使用次数 # 记录使用次数
emoji_manager.record_usage(selected_emoji.hash) emoji_manager.record_usage(selected_emoji.hash)
logger.info(f"[EmojiAPI] 成功获取随机表情包: {selected_emoji.description}") logger.info(f"[EmojiAPI] 成功获取随机表情包: {selected_emoji.description}")
return emoji_base64, selected_emoji.description, matched_emotion return emoji_base64, selected_emoji.description, matched_emotion
except Exception as e: except Exception as e:
logger.error(f"[EmojiAPI] 获取随机表情包失败: {e}") logger.error(f"[EmojiAPI] 获取随机表情包失败: {e}")
return None return None
@@ -100,44 +102,45 @@ async def get_random() -> Optional[Tuple[str, str, str]]:
async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]: async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
"""根据情感标签获取表情包 """根据情感标签获取表情包
Args: Args:
emotion: 情感标签,如"happy""sad""angry" emotion: 情感标签,如"happy""sad""angry"
Returns: Returns:
Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None Optional[Tuple[str, str, str]]: (base64编码, 表情包描述, 匹配的情感标签) 或 None
""" """
try: try:
logger.info(f"[EmojiAPI] 根据情感获取表情包: {emotion}") logger.info(f"[EmojiAPI] 根据情感获取表情包: {emotion}")
emoji_manager = get_emoji_manager() emoji_manager = get_emoji_manager()
all_emojis = emoji_manager.emoji_objects all_emojis = emoji_manager.emoji_objects
# 筛选匹配情感的表情包 # 筛选匹配情感的表情包
matching_emojis = [] matching_emojis = []
for emoji_obj in all_emojis: for emoji_obj in all_emojis:
if not emoji_obj.is_deleted and emotion.lower() in [e.lower() for e in emoji_obj.emotion]: if not emoji_obj.is_deleted and emotion.lower() in [e.lower() for e in emoji_obj.emotion]:
matching_emojis.append(emoji_obj) matching_emojis.append(emoji_obj)
if not matching_emojis: if not matching_emojis:
logger.warning(f"[EmojiAPI] 未找到匹配情感 '{emotion}' 的表情包") logger.warning(f"[EmojiAPI] 未找到匹配情感 '{emotion}' 的表情包")
return None return None
# 随机选择匹配的表情包 # 随机选择匹配的表情包
import random import random
selected_emoji = random.choice(matching_emojis) selected_emoji = random.choice(matching_emojis)
emoji_base64 = image_path_to_base64(selected_emoji.full_path) emoji_base64 = image_path_to_base64(selected_emoji.full_path)
if not emoji_base64: if not emoji_base64:
logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}") logger.error(f"[EmojiAPI] 无法转换表情包为base64: {selected_emoji.full_path}")
return None return None
# 记录使用次数 # 记录使用次数
emoji_manager.record_usage(selected_emoji.hash) emoji_manager.record_usage(selected_emoji.hash)
logger.info(f"[EmojiAPI] 成功获取情感表情包: {selected_emoji.description}") logger.info(f"[EmojiAPI] 成功获取情感表情包: {selected_emoji.description}")
return emoji_base64, selected_emoji.description, emotion return emoji_base64, selected_emoji.description, emotion
except Exception as e: except Exception as e:
logger.error(f"[EmojiAPI] 根据情感获取表情包失败: {e}") logger.error(f"[EmojiAPI] 根据情感获取表情包失败: {e}")
return None return None
@@ -147,9 +150,10 @@ async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
# 表情包信息查询API函数 # 表情包信息查询API函数
# ============================================================================= # =============================================================================
def get_count() -> int: def get_count() -> int:
"""获取表情包数量 """获取表情包数量
Returns: Returns:
int: 当前可用的表情包数量 int: 当前可用的表情包数量
""" """
@@ -163,7 +167,7 @@ def get_count() -> int:
def get_info() -> dict: def get_info() -> dict:
"""获取表情包系统信息 """获取表情包系统信息
Returns: Returns:
dict: 包含表情包数量、最大数量等信息 dict: 包含表情包数量、最大数量等信息
""" """
@@ -181,18 +185,18 @@ def get_info() -> dict:
def get_emotions() -> list: def get_emotions() -> list:
"""获取所有可用的情感标签 """获取所有可用的情感标签
Returns: Returns:
list: 所有表情包的情感标签列表(去重) list: 所有表情包的情感标签列表(去重)
""" """
try: try:
emoji_manager = get_emoji_manager() emoji_manager = get_emoji_manager()
emotions = set() emotions = set()
for emoji_obj in emoji_manager.emoji_objects: for emoji_obj in emoji_manager.emoji_objects:
if not emoji_obj.is_deleted and emoji_obj.emotion: if not emoji_obj.is_deleted and emoji_obj.emotion:
emotions.update(emoji_obj.emotion) emotions.update(emoji_obj.emotion)
return sorted(list(emotions)) return sorted(list(emotions))
except Exception as e: except Exception as e:
logger.error(f"[EmojiAPI] 获取情感标签失败: {e}") logger.error(f"[EmojiAPI] 获取情感标签失败: {e}")
@@ -201,18 +205,18 @@ def get_emotions() -> list:
def get_descriptions() -> list: def get_descriptions() -> list:
"""获取所有表情包描述 """获取所有表情包描述
Returns: Returns:
list: 所有可用表情包的描述列表 list: 所有可用表情包的描述列表
""" """
try: try:
emoji_manager = get_emoji_manager() emoji_manager = get_emoji_manager()
descriptions = [] descriptions = []
for emoji_obj in emoji_manager.emoji_objects: for emoji_obj in emoji_manager.emoji_objects:
if not emoji_obj.is_deleted and emoji_obj.description: if not emoji_obj.is_deleted and emoji_obj.description:
descriptions.append(emoji_obj.description) descriptions.append(emoji_obj.description)
return descriptions return descriptions
except Exception as e: except Exception as e:
logger.error(f"[EmojiAPI] 获取表情包描述失败: {e}") logger.error(f"[EmojiAPI] 获取表情包描述失败: {e}")

View File

@@ -16,22 +16,22 @@ from src.chat.message_receive.chat_stream import get_chat_manager
logger = get_logger("generator_api") logger = get_logger("generator_api")
# ============================================================================= # =============================================================================
# 回复器获取API函数 # 回复器获取API函数
# ============================================================================= # =============================================================================
def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_group: bool = True) -> DefaultReplyer: def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_group: bool = True) -> DefaultReplyer:
"""获取回复器对象 """获取回复器对象
优先使用chat_stream如果没有则使用platform和chat_id组合 优先使用chat_stream如果没有则使用platform和chat_id组合
Args: Args:
chat_stream: 聊天流对象(优先) chat_stream: 聊天流对象(优先)
platform: 平台名称,如"qq" platform: 平台名称,如"qq"
chat_id: 聊天ID群ID或用户ID chat_id: 聊天ID群ID或用户ID
is_group: 是否为群聊 is_group: 是否为群聊
Returns: Returns:
Optional[Any]: 回复器对象如果获取失败则返回None Optional[Any]: 回复器对象如果获取失败则返回None
""" """
@@ -40,7 +40,7 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
if chat_stream: if chat_stream:
logger.debug("[GeneratorAPI] 使用聊天流获取回复器") logger.debug("[GeneratorAPI] 使用聊天流获取回复器")
return DefaultReplyer(chat_stream=chat_stream) return DefaultReplyer(chat_stream=chat_stream)
# 使用平台和ID组合 # 使用平台和ID组合
if platform and chat_id: if platform and chat_id:
logger.debug("[GeneratorAPI] 使用平台和ID获取回复器") logger.debug("[GeneratorAPI] 使用平台和ID获取回复器")
@@ -48,7 +48,7 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
if not chat_manager: if not chat_manager:
logger.warning("[GeneratorAPI] 无法获取聊天管理器") logger.warning("[GeneratorAPI] 无法获取聊天管理器")
return None return None
# 查找对应的聊天流 # 查找对应的聊天流
target_stream = None target_stream = None
for _stream_id, stream in chat_manager.streams.items(): for _stream_id, stream in chat_manager.streams.items():
@@ -61,29 +61,31 @@ def get_replyer(chat_stream=None, platform: str = None, chat_id: str = None, is_
if str(stream.user_info.user_id) == str(chat_id): if str(stream.user_info.user_id) == str(chat_id):
target_stream = stream target_stream = stream
break break
return DefaultReplyer(chat_stream=target_stream) return DefaultReplyer(chat_stream=target_stream)
logger.warning("[GeneratorAPI] 缺少必要参数,无法获取回复器") logger.warning("[GeneratorAPI] 缺少必要参数,无法获取回复器")
return None return None
except Exception as e: except Exception as e:
logger.error(f"[GeneratorAPI] 获取回复器失败: {e}") logger.error(f"[GeneratorAPI] 获取回复器失败: {e}")
return None return None
# ============================================================================= # =============================================================================
# 回复生成API函数 # 回复生成API函数
# ============================================================================= # =============================================================================
async def generate_reply( async def generate_reply(
chat_stream=None, chat_stream=None,
action_data: Dict[str, Any] = None, action_data: Dict[str, Any] = None,
platform: str = None, platform: str = None,
chat_id: str = None, chat_id: str = None,
is_group: bool = True is_group: bool = True,
) -> Tuple[bool, List[Tuple[str, Any]]]: ) -> Tuple[bool, List[Tuple[str, Any]]]:
"""生成回复 """生成回复
Args: Args:
chat_stream: 聊天流对象(优先) chat_stream: 聊天流对象(优先)
action_data: 动作数据 action_data: 动作数据
@@ -94,7 +96,7 @@ async def generate_reply(
platform: 平台名称(备用) platform: 平台名称(备用)
chat_id: 聊天ID备用 chat_id: 聊天ID备用
is_group: 是否为群聊(备用) is_group: 是否为群聊(备用)
Returns: Returns:
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合) Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
""" """
@@ -104,41 +106,42 @@ async def generate_reply(
if not replyer: if not replyer:
logger.error("[GeneratorAPI] 无法获取回复器") logger.error("[GeneratorAPI] 无法获取回复器")
return False, [] return False, []
logger.info("[GeneratorAPI] 开始生成回复") logger.info("[GeneratorAPI] 开始生成回复")
# 调用回复器生成回复 # 调用回复器生成回复
success, reply_set = await replyer.generate_reply_with_context( success, reply_set = await replyer.generate_reply_with_context(
reply_data=action_data or {}, reply_data=action_data or {},
) )
if success: if success:
logger.info(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项") logger.info(f"[GeneratorAPI] 回复生成成功,生成了 {len(reply_set)} 个回复项")
else: else:
logger.warning("[GeneratorAPI] 回复生成失败") logger.warning("[GeneratorAPI] 回复生成失败")
return success, reply_set or [] return success, reply_set or []
except Exception as e: except Exception as e:
logger.error(f"[GeneratorAPI] 生成回复时出错: {e}") logger.error(f"[GeneratorAPI] 生成回复时出错: {e}")
return False, [] return False, []
async def rewrite_reply( async def rewrite_reply(
chat_stream=None, chat_stream=None,
reply_data: Dict[str, Any] = None, reply_data: Dict[str, Any] = None,
platform: str = None, platform: str = None,
chat_id: str = None, chat_id: str = None,
is_group: bool = True is_group: bool = True,
) -> Tuple[bool, List[Tuple[str, Any]]]: ) -> Tuple[bool, List[Tuple[str, Any]]]:
"""重写回复 """重写回复
Args: Args:
chat_stream: 聊天流对象(优先) chat_stream: 聊天流对象(优先)
action_data: 动作数据 action_data: 动作数据
platform: 平台名称(备用) platform: 平台名称(备用)
chat_id: 聊天ID备用 chat_id: 聊天ID备用
is_group: 是否为群聊(备用) is_group: 是否为群聊(备用)
Returns: Returns:
Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合) Tuple[bool, List[Tuple[str, Any]]]: (是否成功, 回复集合)
""" """
@@ -148,23 +151,21 @@ async def rewrite_reply(
if not replyer: if not replyer:
logger.error("[GeneratorAPI] 无法获取回复器") logger.error("[GeneratorAPI] 无法获取回复器")
return False, [] return False, []
logger.info("[GeneratorAPI] 开始重写回复") logger.info("[GeneratorAPI] 开始重写回复")
# 调用回复器重写回复 # 调用回复器重写回复
success, reply_set = await replyer.rewrite_reply_with_context( success, reply_set = await replyer.rewrite_reply_with_context(
reply_data=reply_data or {}, reply_data=reply_data or {},
) )
if success: if success:
logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项") logger.info(f"[GeneratorAPI] 重写回复成功,生成了 {len(reply_set)} 个回复项")
else: else:
logger.warning("[GeneratorAPI] 重写回复失败") logger.warning("[GeneratorAPI] 重写回复失败")
return success, reply_set or [] return success, reply_set or []
except Exception as e: except Exception as e:
logger.error(f"[GeneratorAPI] 重写回复时出错: {e}") logger.error(f"[GeneratorAPI] 重写回复时出错: {e}")
return False, [] return False, []

View File

@@ -19,6 +19,7 @@ logger = get_logger("llm_api")
# LLM模型API函数 # LLM模型API函数
# ============================================================================= # =============================================================================
def get_available_models() -> Dict[str, Any]: def get_available_models() -> Dict[str, Any]:
"""获取所有可用的模型配置 """获取所有可用的模型配置

View File

@@ -32,18 +32,19 @@ from src.chat.utils.chat_message_builder import (
# 消息查询API函数 # 消息查询API函数
# ============================================================================= # =============================================================================
def get_messages_by_time( def get_messages_by_time(
start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest" start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest"
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定时间范围内的消息 获取指定时间范围内的消息
Args: Args:
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳 end_time: 结束时间戳
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -55,14 +56,14 @@ def get_messages_by_time_in_chat(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定聊天中指定时间范围内的消息 获取指定聊天中指定时间范围内的消息
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳 end_time: 结束时间戳
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -74,14 +75,14 @@ def get_messages_by_time_in_chat_inclusive(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定聊天中指定时间范围内的消息(包含边界) 获取指定聊天中指定时间范围内的消息(包含边界)
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
start_time: 开始时间戳(包含) start_time: 开始时间戳(包含)
end_time: 结束时间戳(包含) end_time: 结束时间戳(包含)
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -98,7 +99,7 @@ def get_messages_by_time_in_chat_for_users(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定聊天中指定用户在指定时间范围内的消息 获取指定聊天中指定用户在指定时间范围内的消息
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
start_time: 开始时间戳 start_time: 开始时间戳
@@ -106,7 +107,7 @@ def get_messages_by_time_in_chat_for_users(
person_ids: 用户ID列表 person_ids: 用户ID列表
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -118,13 +119,13 @@ def get_random_chat_messages(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
随机选择一个聊天,返回该聊天在指定时间范围内的消息 随机选择一个聊天,返回该聊天在指定时间范围内的消息
Args: Args:
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳 end_time: 结束时间戳
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -136,14 +137,14 @@ def get_messages_by_time_for_users(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定用户在所有聊天中指定时间范围内的消息 获取指定用户在所有聊天中指定时间范围内的消息
Args: Args:
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳 end_time: 结束时间戳
person_ids: 用户ID列表 person_ids: 用户ID列表
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -153,11 +154,11 @@ def get_messages_by_time_for_users(
def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str, Any]]: def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
""" """
获取指定时间戳之前的消息 获取指定时间戳之前的消息
Args: Args:
timestamp: 时间戳 timestamp: 时间戳
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
Returns: Returns:
消息列表 消息列表
""" """
@@ -167,29 +168,27 @@ def get_messages_before_time(timestamp: float, limit: int = 0) -> List[Dict[str,
def get_messages_before_time_in_chat(chat_id: str, timestamp: float, limit: int = 0) -> List[Dict[str, Any]]: def get_messages_before_time_in_chat(chat_id: str, timestamp: float, limit: int = 0) -> List[Dict[str, Any]]:
""" """
获取指定聊天中指定时间戳之前的消息 获取指定聊天中指定时间戳之前的消息
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
timestamp: 时间戳 timestamp: 时间戳
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
Returns: Returns:
消息列表 消息列表
""" """
return get_raw_msg_before_timestamp_with_chat(chat_id, timestamp, limit) return get_raw_msg_before_timestamp_with_chat(chat_id, timestamp, limit)
def get_messages_before_time_for_users( def get_messages_before_time_for_users(timestamp: float, person_ids: list, limit: int = 0) -> List[Dict[str, Any]]:
timestamp: float, person_ids: list, limit: int = 0
) -> List[Dict[str, Any]]:
""" """
获取指定用户在指定时间戳之前的消息 获取指定用户在指定时间戳之前的消息
Args: Args:
timestamp: 时间戳 timestamp: 时间戳
person_ids: 用户ID列表 person_ids: 用户ID列表
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
Returns: Returns:
消息列表 消息列表
""" """
@@ -197,20 +196,17 @@ def get_messages_before_time_for_users(
def get_recent_messages( def get_recent_messages(
chat_id: str, chat_id: str, hours: float = 24.0, limit: int = 100, limit_mode: str = "latest"
hours: float = 24.0,
limit: int = 100,
limit_mode: str = "latest"
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取指定聊天中最近一段时间的消息 获取指定聊天中最近一段时间的消息
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
hours: 最近多少小时默认24小时 hours: 最近多少小时默认24小时
limit: 限制返回的消息数量默认100条 limit: 限制返回的消息数量默认100条
limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录 limit_mode: 当limit>0时生效'earliest'表示获取最早的记录,'latest'表示获取最新的记录
Returns: Returns:
消息列表 消息列表
""" """
@@ -223,35 +219,32 @@ def get_recent_messages(
# 消息计数API函数 # 消息计数API函数
# ============================================================================= # =============================================================================
def count_new_messages(
chat_id: str, start_time: float = 0.0, end_time: Optional[float] = None def count_new_messages(chat_id: str, start_time: float = 0.0, end_time: Optional[float] = None) -> int:
) -> int:
""" """
计算指定聊天中从开始时间到结束时间的新消息数量 计算指定聊天中从开始时间到结束时间的新消息数量
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳如果为None则使用当前时间 end_time: 结束时间戳如果为None则使用当前时间
Returns: Returns:
新消息数量 新消息数量
""" """
return num_new_messages_since(chat_id, start_time, end_time) return num_new_messages_since(chat_id, start_time, end_time)
def count_new_messages_for_users( def count_new_messages_for_users(chat_id: str, start_time: float, end_time: float, person_ids: list) -> int:
chat_id: str, start_time: float, end_time: float, person_ids: list
) -> int:
""" """
计算指定聊天中指定用户从开始时间到结束时间的新消息数量 计算指定聊天中指定用户从开始时间到结束时间的新消息数量
Args: Args:
chat_id: 聊天ID chat_id: 聊天ID
start_time: 开始时间戳 start_time: 开始时间戳
end_time: 结束时间戳 end_time: 结束时间戳
person_ids: 用户ID列表 person_ids: 用户ID列表
Returns: Returns:
新消息数量 新消息数量
""" """
@@ -262,6 +255,7 @@ def count_new_messages_for_users(
# 消息格式化API函数 # 消息格式化API函数
# ============================================================================= # =============================================================================
def build_readable_messages_to_str( def build_readable_messages_to_str(
messages: List[Dict[str, Any]], messages: List[Dict[str, Any]],
replace_bot_name: bool = True, replace_bot_name: bool = True,
@@ -273,7 +267,7 @@ def build_readable_messages_to_str(
) -> str: ) -> str:
""" """
将消息列表构建成可读的字符串 将消息列表构建成可读的字符串
Args: Args:
messages: 消息列表 messages: 消息列表
replace_bot_name: 是否将机器人的名称替换为"" replace_bot_name: 是否将机器人的名称替换为""
@@ -282,7 +276,7 @@ def build_readable_messages_to_str(
read_mark: 已读标记时间戳,用于分割已读和未读消息 read_mark: 已读标记时间戳,用于分割已读和未读消息
truncate: 是否截断长消息 truncate: 是否截断长消息
show_actions: 是否显示动作记录 show_actions: 是否显示动作记录
Returns: Returns:
格式化后的可读字符串 格式化后的可读字符串
""" """
@@ -300,29 +294,27 @@ async def build_readable_messages_with_details(
) -> Tuple[str, List[Tuple[float, str, str]]]: ) -> Tuple[str, List[Tuple[float, str, str]]]:
""" """
将消息列表构建成可读的字符串,并返回详细信息 将消息列表构建成可读的字符串,并返回详细信息
Args: Args:
messages: 消息列表 messages: 消息列表
replace_bot_name: 是否将机器人的名称替换为"" replace_bot_name: 是否将机器人的名称替换为""
merge_messages: 是否合并连续消息 merge_messages: 是否合并连续消息
timestamp_mode: 时间戳显示模式,'relative''absolute' timestamp_mode: 时间戳显示模式,'relative''absolute'
truncate: 是否截断长消息 truncate: 是否截断长消息
Returns: Returns:
格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容) 格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容)
""" """
return await build_readable_messages_with_list( return await build_readable_messages_with_list(messages, replace_bot_name, merge_messages, timestamp_mode, truncate)
messages, replace_bot_name, merge_messages, timestamp_mode, truncate
)
async def get_person_ids_from_messages(messages: List[Dict[str, Any]]) -> List[str]: async def get_person_ids_from_messages(messages: List[Dict[str, Any]]) -> List[str]:
""" """
从消息列表中提取不重复的用户ID列表 从消息列表中提取不重复的用户ID列表
Args: Args:
messages: 消息列表 messages: 消息列表
Returns: Returns:
用户ID列表 用户ID列表
""" """

View File

@@ -18,16 +18,17 @@ logger = get_logger("person_api")
# 个人信息API函数 # 个人信息API函数
# ============================================================================= # =============================================================================
def get_person_id(platform: str, user_id: int) -> str: def get_person_id(platform: str, user_id: int) -> str:
"""根据平台和用户ID获取person_id """根据平台和用户ID获取person_id
Args: Args:
platform: 平台名称,如 "qq", "telegram" platform: 平台名称,如 "qq", "telegram"
user_id: 用户ID user_id: 用户ID
Returns: Returns:
str: 唯一的person_idMD5哈希值 str: 唯一的person_idMD5哈希值
示例: 示例:
person_id = person_api.get_person_id("qq", 123456) person_id = person_api.get_person_id("qq", 123456)
""" """
@@ -40,15 +41,15 @@ def get_person_id(platform: str, user_id: int) -> str:
async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any: async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any:
"""根据person_id和字段名获取某个值 """根据person_id和字段名获取某个值
Args: Args:
person_id: 用户的唯一标识ID person_id: 用户的唯一标识ID
field_name: 要获取的字段名,如 "nickname", "impression" field_name: 要获取的字段名,如 "nickname", "impression"
default: 当字段不存在或获取失败时返回的默认值 default: 当字段不存在或获取失败时返回的默认值
Returns: Returns:
Any: 字段值或默认值 Any: 字段值或默认值
示例: 示例:
nickname = await person_api.get_person_value(person_id, "nickname", "未知用户") nickname = await person_api.get_person_value(person_id, "nickname", "未知用户")
impression = await person_api.get_person_value(person_id, "impression") impression = await person_api.get_person_value(person_id, "impression")
@@ -64,18 +65,18 @@ async def get_person_value(person_id: str, field_name: str, default: Any = None)
async def get_person_values(person_id: str, field_names: list, default_dict: dict = None) -> dict: async def get_person_values(person_id: str, field_names: list, default_dict: dict = None) -> dict:
"""批量获取用户信息字段值 """批量获取用户信息字段值
Args: Args:
person_id: 用户的唯一标识ID person_id: 用户的唯一标识ID
field_names: 要获取的字段名列表 field_names: 要获取的字段名列表
default_dict: 默认值字典,键为字段名,值为默认值 default_dict: 默认值字典,键为字段名,值为默认值
Returns: Returns:
dict: 字段名到值的映射字典 dict: 字段名到值的映射字典
示例: 示例:
values = await person_api.get_person_values( values = await person_api.get_person_values(
person_id, person_id,
["nickname", "impression", "know_times"], ["nickname", "impression", "know_times"],
{"nickname": "未知用户", "know_times": 0} {"nickname": "未知用户", "know_times": 0}
) )
@@ -83,11 +84,11 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
try: try:
person_info_manager = get_person_info_manager() person_info_manager = get_person_info_manager()
values = await person_info_manager.get_values(person_id, field_names) values = await person_info_manager.get_values(person_id, field_names)
# 如果获取成功,返回结果 # 如果获取成功,返回结果
if values: if values:
return values return values
# 如果获取失败,构建默认值字典 # 如果获取失败,构建默认值字典
result = {} result = {}
if default_dict: if default_dict:
@@ -96,9 +97,9 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
else: else:
for field in field_names: for field in field_names:
result[field] = None result[field] = None
return result return result
except Exception as e: except Exception as e:
logger.error(f"[PersonAPI] 批量获取用户信息失败: person_id={person_id}, fields={field_names}, error={e}") logger.error(f"[PersonAPI] 批量获取用户信息失败: person_id={person_id}, fields={field_names}, error={e}")
# 返回默认值字典 # 返回默认值字典
@@ -114,14 +115,14 @@ async def get_person_values(person_id: str, field_names: list, default_dict: dic
async def is_person_known(platform: str, user_id: int) -> bool: async def is_person_known(platform: str, user_id: int) -> bool:
"""判断是否认识某个用户 """判断是否认识某个用户
Args: Args:
platform: 平台名称 platform: 平台名称
user_id: 用户ID user_id: 用户ID
Returns: Returns:
bool: 是否认识该用户 bool: 是否认识该用户
示例: 示例:
known = await person_api.is_person_known("qq", 123456) known = await person_api.is_person_known("qq", 123456)
""" """
@@ -135,13 +136,13 @@ async def is_person_known(platform: str, user_id: int) -> bool:
def get_person_id_by_name(person_name: str) -> str: def get_person_id_by_name(person_name: str) -> str:
"""根据用户名获取person_id """根据用户名获取person_id
Args: Args:
person_name: 用户名 person_name: 用户名
Returns: Returns:
str: person_id如果未找到返回空字符串 str: person_id如果未找到返回空字符串
示例: 示例:
person_id = person_api.get_person_id_by_name("张三") person_id = person_api.get_person_id_by_name("张三")
""" """

View File

@@ -31,6 +31,7 @@ logger = get_logger("send_api")
# 内部实现函数(不暴露给外部) # 内部实现函数(不暴露给外部)
# ============================================================================= # =============================================================================
async def _send_to_target( async def _send_to_target(
message_type: str, message_type: str,
content: str, content: str,
@@ -41,7 +42,7 @@ async def _send_to_target(
storage_message: bool = True, storage_message: bool = True,
) -> bool: ) -> bool:
"""向指定目标发送消息的内部实现 """向指定目标发送消息的内部实现
Args: Args:
message_type: 消息类型,如"text""image""emoji" message_type: 消息类型,如"text""image""emoji"
content: 消息内容 content: 消息内容
@@ -49,41 +50,41 @@ async def _send_to_target(
display_message: 显示消息 display_message: 显示消息
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息的格式,如"发送者:消息内容" reply_to: 回复消息的格式,如"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
try: try:
logger.info(f"[SendAPI] 发送{message_type}消息到 {stream_id}") logger.info(f"[SendAPI] 发送{message_type}消息到 {stream_id}")
# 查找目标聊天流 # 查找目标聊天流
target_stream = get_chat_manager().get_stream(stream_id) target_stream = get_chat_manager().get_stream(stream_id)
if not target_stream: if not target_stream:
logger.error(f"[SendAPI] 未找到聊天流: {stream_id}") logger.error(f"[SendAPI] 未找到聊天流: {stream_id}")
return False return False
# 创建发送器 # 创建发送器
heart_fc_sender = HeartFCSender() heart_fc_sender = HeartFCSender()
# 生成消息ID # 生成消息ID
current_time = time.time() current_time = time.time()
message_id = f"send_api_{int(current_time * 1000)}" message_id = f"send_api_{int(current_time * 1000)}"
# 构建机器人用户信息 # 构建机器人用户信息
bot_user_info = UserInfo( bot_user_info = UserInfo(
user_id=global_config.bot.qq_account, user_id=global_config.bot.qq_account,
user_nickname=global_config.bot.nickname, user_nickname=global_config.bot.nickname,
platform=target_stream.platform, platform=target_stream.platform,
) )
# 创建消息段 # 创建消息段
message_segment = Seg(type=message_type, data=content) message_segment = Seg(type=message_type, data=content)
# 处理回复消息 # 处理回复消息
anchor_message = None anchor_message = None
if reply_to: if reply_to:
anchor_message = await _find_reply_message(target_stream, reply_to) anchor_message = await _find_reply_message(target_stream, reply_to)
# 构建发送消息对象 # 构建发送消息对象
bot_message = MessageSending( bot_message = MessageSending(
message_id=message_id, message_id=message_id,
@@ -97,19 +98,19 @@ async def _send_to_target(
is_emoji=(message_type == "emoji"), is_emoji=(message_type == "emoji"),
thinking_start_time=current_time, thinking_start_time=current_time,
) )
# 发送消息 # 发送消息
sent_msg = await heart_fc_sender.send_message( sent_msg = await heart_fc_sender.send_message(
bot_message, typing=typing, set_reply=(anchor_message is not None), storage_message=storage_message bot_message, typing=typing, set_reply=(anchor_message is not None), storage_message=storage_message
) )
if sent_msg: if sent_msg:
logger.info(f"[SendAPI] 成功发送消息到 {stream_id}") logger.info(f"[SendAPI] 成功发送消息到 {stream_id}")
return True return True
else: else:
logger.error("[SendAPI] 发送消息失败") logger.error("[SendAPI] 发送消息失败")
return False return False
except Exception as e: except Exception as e:
logger.error(f"[SendAPI] 发送消息时出错: {e}") logger.error(f"[SendAPI] 发送消息时出错: {e}")
traceback.print_exc() traceback.print_exc()
@@ -118,11 +119,11 @@ async def _send_to_target(
async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageRecv]: async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageRecv]:
"""查找要回复的消息 """查找要回复的消息
Args: Args:
target_stream: 目标聊天流 target_stream: 目标聊天流
reply_to: 回复格式,如"发送者:消息内容""发送者:消息内容" reply_to: 回复格式,如"发送者:消息内容""发送者:消息内容"
Returns: Returns:
Optional[MessageRecv]: 找到的消息如果没找到则返回None Optional[MessageRecv]: 找到的消息如果没找到则返回None
""" """
@@ -139,20 +140,20 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
if len(parts) != 2: if len(parts) != 2:
logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}") logger.warning(f"[SendAPI] reply_to格式不正确: {reply_to}")
return None return None
sender = parts[0].strip() sender = parts[0].strip()
text = parts[1].strip() text = parts[1].strip()
# 获取聊天流的最新20条消息 # 获取聊天流的最新20条消息
reverse_talking_message = get_raw_msg_before_timestamp_with_chat( reverse_talking_message = get_raw_msg_before_timestamp_with_chat(
target_stream.stream_id, target_stream.stream_id,
time.time(), # 当前时间之前的消息 time.time(), # 当前时间之前的消息
20 # 最新的20条消息 20, # 最新的20条消息
) )
# 反转列表,使最新的消息在前面 # 反转列表,使最新的消息在前面
reverse_talking_message = list(reversed(reverse_talking_message)) reverse_talking_message = list(reversed(reverse_talking_message))
find_msg = None find_msg = None
for message in reverse_talking_message: for message in reverse_talking_message:
user_id = message["user_id"] user_id = message["user_id"]
@@ -198,20 +199,20 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
"format_info": format_info, "format_info": format_info,
"template_info": template_info, "template_info": template_info,
} }
message_dict = { message_dict = {
"message_info": message_info, "message_info": message_info,
"raw_message": find_msg.get("processed_plain_text"), "raw_message": find_msg.get("processed_plain_text"),
"detailed_plain_text": find_msg.get("processed_plain_text"), "detailed_plain_text": find_msg.get("processed_plain_text"),
"processed_plain_text": find_msg.get("processed_plain_text"), "processed_plain_text": find_msg.get("processed_plain_text"),
} }
find_rec_msg = MessageRecv(message_dict) find_rec_msg = MessageRecv(message_dict)
find_rec_msg.update_chat_stream(target_stream) find_rec_msg.update_chat_stream(target_stream)
logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {sender}") logger.info(f"[SendAPI] 找到匹配的回复消息,发送者: {sender}")
return find_rec_msg return find_rec_msg
except Exception as e: except Exception as e:
logger.error(f"[SendAPI] 查找回复消息时出错: {e}") logger.error(f"[SendAPI] 查找回复消息时出错: {e}")
traceback.print_exc() traceback.print_exc()
@@ -222,34 +223,49 @@ async def _find_reply_message(target_stream, reply_to: str) -> Optional[MessageR
# 公共API函数 - 预定义类型的发送函数 # 公共API函数 - 预定义类型的发送函数
# ============================================================================= # =============================================================================
async def text_to_group(text: str, group_id: str, platform: str = "qq", typing: bool = False, reply_to: str = "", storage_message: bool = True) -> bool:
async def text_to_group(
text: str,
group_id: str,
platform: str = "qq",
typing: bool = False,
reply_to: str = "",
storage_message: bool = True,
) -> bool:
"""向群聊发送文本消息 """向群聊发送文本消息
Args: Args:
text: 要发送的文本内容 text: 要发送的文本内容
group_id: 群聊ID group_id: 群聊ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息,格式为"发送者:消息内容" reply_to: 回复消息,格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
stream_id = get_chat_manager().get_stream_id(platform, group_id, True) stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
return await _send_to_target("text", text, stream_id, "", typing, reply_to, storage_message) return await _send_to_target("text", text, stream_id, "", typing, reply_to, storage_message)
async def text_to_user(text: str, user_id: str, platform: str = "qq", typing: bool = False, reply_to: str = "", storage_message: bool = True) -> bool: async def text_to_user(
text: str,
user_id: str,
platform: str = "qq",
typing: bool = False,
reply_to: str = "",
storage_message: bool = True,
) -> bool:
"""向用户发送私聊文本消息 """向用户发送私聊文本消息
Args: Args:
text: 要发送的文本内容 text: 要发送的文本内容
user_id: 用户ID user_id: 用户ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息,格式为"发送者:消息内容" reply_to: 回复消息,格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -259,12 +275,12 @@ async def text_to_user(text: str, user_id: str, platform: str = "qq", typing: bo
async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向群聊发送表情包 """向群聊发送表情包
Args: Args:
emoji_base64: 表情包的base64编码 emoji_base64: 表情包的base64编码
group_id: 群聊ID group_id: 群聊ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -274,12 +290,12 @@ async def emoji_to_group(emoji_base64: str, group_id: str, platform: str = "qq",
async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向用户发送表情包 """向用户发送表情包
Args: Args:
emoji_base64: 表情包的base64编码 emoji_base64: 表情包的base64编码
user_id: 用户ID user_id: 用户ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -289,12 +305,12 @@ async def emoji_to_user(emoji_base64: str, user_id: str, platform: str = "qq", s
async def image_to_group(image_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def image_to_group(image_base64: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向群聊发送图片 """向群聊发送图片
Args: Args:
image_base64: 图片的base64编码 image_base64: 图片的base64编码
group_id: 群聊ID group_id: 群聊ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -304,40 +320,42 @@ async def image_to_group(image_base64: str, group_id: str, platform: str = "qq",
async def image_to_user(image_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def image_to_user(image_base64: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向用户发送图片 """向用户发送图片
Args: Args:
image_base64: 图片的base64编码 image_base64: 图片的base64编码
user_id: 用户ID user_id: 用户ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
stream_id = get_chat_manager().get_stream_id(platform, user_id, False) stream_id = get_chat_manager().get_stream_id(platform, user_id, False)
return await _send_to_target("image", image_base64, stream_id, "", typing=False) return await _send_to_target("image", image_base64, stream_id, "", typing=False)
async def command_to_group(command: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def command_to_group(command: str, group_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向群聊发送命令 """向群聊发送命令
Args: Args:
command: 命令 command: 命令
group_id: 群聊ID group_id: 群聊ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
stream_id = get_chat_manager().get_stream_id(platform, group_id, True) stream_id = get_chat_manager().get_stream_id(platform, group_id, True)
return await _send_to_target("command", command, stream_id, "", typing=False, storage_message=storage_message) return await _send_to_target("command", command, stream_id, "", typing=False, storage_message=storage_message)
async def command_to_user(command: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool: async def command_to_user(command: str, user_id: str, platform: str = "qq", storage_message: bool = True) -> bool:
"""向用户发送命令 """向用户发送命令
Args: Args:
command: 命令 command: 命令
user_id: 用户ID user_id: 用户ID
platform: 平台,默认为"qq" platform: 平台,默认为"qq"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -349,18 +367,19 @@ async def command_to_user(command: str, user_id: str, platform: str = "qq", stor
# 通用发送函数 - 支持任意消息类型 # 通用发送函数 - 支持任意消息类型
# ============================================================================= # =============================================================================
async def custom_to_group( async def custom_to_group(
message_type: str, message_type: str,
content: str, content: str,
group_id: str, group_id: str,
platform: str = "qq", platform: str = "qq",
display_message: str = "", display_message: str = "",
typing: bool = False, typing: bool = False,
reply_to: str = "", reply_to: str = "",
storage_message: bool = True storage_message: bool = True,
) -> bool: ) -> bool:
"""向群聊发送自定义类型消息 """向群聊发送自定义类型消息
Args: Args:
message_type: 消息类型,如"text""image""emoji""video""file" message_type: 消息类型,如"text""image""emoji""video""file"
content: 消息内容通常是base64编码或文本 content: 消息内容通常是base64编码或文本
@@ -369,7 +388,7 @@ async def custom_to_group(
display_message: 显示消息 display_message: 显示消息
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息,格式为"发送者:消息内容" reply_to: 回复消息,格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -378,17 +397,17 @@ async def custom_to_group(
async def custom_to_user( async def custom_to_user(
message_type: str, message_type: str,
content: str, content: str,
user_id: str, user_id: str,
platform: str = "qq", platform: str = "qq",
display_message: str = "", display_message: str = "",
typing: bool = False, typing: bool = False,
reply_to: str = "", reply_to: str = "",
storage_message: bool = True storage_message: bool = True,
) -> bool: ) -> bool:
"""向用户发送自定义类型消息 """向用户发送自定义类型消息
Args: Args:
message_type: 消息类型,如"text""image""emoji""video""file" message_type: 消息类型,如"text""image""emoji""video""file"
content: 消息内容通常是base64编码或文本 content: 消息内容通常是base64编码或文本
@@ -397,7 +416,7 @@ async def custom_to_user(
display_message: 显示消息 display_message: 显示消息
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息,格式为"发送者:消息内容" reply_to: 回复消息,格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
""" """
@@ -414,10 +433,10 @@ async def custom_message(
display_message: str = "", display_message: str = "",
typing: bool = False, typing: bool = False,
reply_to: str = "", reply_to: str = "",
storage_message: bool = True storage_message: bool = True,
) -> bool: ) -> bool:
"""发送自定义消息的通用接口 """发送自定义消息的通用接口
Args: Args:
message_type: 消息类型,如"text""image""emoji""video""file""audio" message_type: 消息类型,如"text""image""emoji""video""file""audio"
content: 消息内容 content: 消息内容
@@ -427,19 +446,19 @@ async def custom_message(
display_message: 显示消息 display_message: 显示消息
typing: 是否显示正在输入 typing: 是否显示正在输入
reply_to: 回复消息,格式为"发送者:消息内容" reply_to: 回复消息,格式为"发送者:消息内容"
Returns: Returns:
bool: 是否发送成功 bool: 是否发送成功
示例: 示例:
# 发送视频到群聊 # 发送视频到群聊
await send_api.custom_message("video", video_base64, "123456", True) await send_api.custom_message("video", video_base64, "123456", True)
# 发送文件到用户 # 发送文件到用户
await send_api.custom_message("file", file_base64, "987654", False) await send_api.custom_message("file", file_base64, "987654", False)
# 发送音频到群聊并回复特定消息 # 发送音频到群聊并回复特定消息
await send_api.custom_message("audio", audio_base64, "123456", True, reply_to="张三:你好") await send_api.custom_message("audio", audio_base64, "123456", True, reply_to="张三:你好")
""" """
stream_id = get_chat_manager().get_stream_id(platform, target_id, is_group) stream_id = get_chat_manager().get_stream_id(platform, target_id, is_group)
return await _send_to_target(message_type, content, stream_id, display_message, typing, reply_to, storage_message) return await _send_to_target(message_type, content, stream_id, display_message, typing, reply_to, storage_message)

View File

@@ -24,6 +24,7 @@ logger = get_logger("utils_api")
# 文件操作API函数 # 文件操作API函数
# ============================================================================= # =============================================================================
def get_plugin_path(caller_frame=None) -> str: def get_plugin_path(caller_frame=None) -> str:
"""获取调用者插件的路径 """获取调用者插件的路径
@@ -106,6 +107,7 @@ def write_json_file(file_path: str, data: Any, indent: int = 2) -> bool:
# 时间相关API函数 # 时间相关API函数
# ============================================================================= # =============================================================================
def get_timestamp() -> int: def get_timestamp() -> int:
"""获取当前时间戳 """获取当前时间戳
@@ -156,6 +158,7 @@ def parse_time(time_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> int:
# 其他工具函数 # 其他工具函数
# ============================================================================= # =============================================================================
def generate_unique_id() -> str: def generate_unique_id() -> str:
"""生成唯一ID """生成唯一ID

View File

@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
from typing import Tuple, Optional from typing import Tuple, Optional
from src.common.logger import get_logger from src.common.logger import get_logger
from src.plugin_system.base.component_types import ActionActivationType, ChatMode, ActionInfo, ComponentType from src.plugin_system.base.component_types import ActionActivationType, ChatMode, ActionInfo, ComponentType
from src.plugin_system.apis import send_api, database_api,message_api from src.plugin_system.apis import send_api, database_api, message_api
import time import time
import asyncio import asyncio
@@ -59,7 +59,7 @@ class BaseAction(ABC):
self.thinking_id = thinking_id self.thinking_id = thinking_id
self.log_prefix = log_prefix self.log_prefix = log_prefix
self.shutting_down = shutting_down self.shutting_down = shutting_down
# 保存插件配置 # 保存插件配置
self.plugin_config = plugin_config or {} self.plugin_config = plugin_config or {}
@@ -83,11 +83,10 @@ class BaseAction(ABC):
# ============================================================================= # =============================================================================
# 便捷属性 - 直接在初始化时获取常用聊天信息(带类型注解) # 便捷属性 - 直接在初始化时获取常用聊天信息(带类型注解)
# ============================================================================= # =============================================================================
# 获取聊天流对象 # 获取聊天流对象
self.chat_stream = chat_stream or kwargs.get("chat_stream") self.chat_stream = chat_stream or kwargs.get("chat_stream")
self.chat_id = self.chat_stream.stream_id self.chat_id = self.chat_stream.stream_id
# 初始化基础信息(带类型注解) # 初始化基础信息(带类型注解)
self.is_group: bool = False self.is_group: bool = False
@@ -97,28 +96,30 @@ class BaseAction(ABC):
self.target_id: Optional[str] = None self.target_id: Optional[str] = None
self.group_name: Optional[str] = None self.group_name: Optional[str] = None
self.user_nickname: Optional[str] = None self.user_nickname: Optional[str] = None
# 如果有聊天流,提取所有信息 # 如果有聊天流,提取所有信息
if self.chat_stream: if self.chat_stream:
self.platform = getattr(self.chat_stream, 'platform', None) self.platform = getattr(self.chat_stream, "platform", None)
# 获取群聊信息 # 获取群聊信息
# print(self.chat_stream) # print(self.chat_stream)
# print(self.chat_stream.group_info) # print(self.chat_stream.group_info)
if self.chat_stream.group_info: if self.chat_stream.group_info:
self.is_group = True self.is_group = True
self.group_id = str(self.chat_stream.group_info.group_id) self.group_id = str(self.chat_stream.group_info.group_id)
self.group_name = getattr(self.chat_stream.group_info, 'group_name', None) self.group_name = getattr(self.chat_stream.group_info, "group_name", None)
else: else:
self.is_group = False self.is_group = False
self.user_id = str(self.chat_stream.user_info.user_id) self.user_id = str(self.chat_stream.user_info.user_id)
self.user_nickname = getattr(self.chat_stream.user_info, 'user_nickname', None) self.user_nickname = getattr(self.chat_stream.user_info, "user_nickname", None)
# 设置目标ID群聊用群ID私聊用户ID # 设置目标ID群聊用群ID私聊用户ID
self.target_id = self.group_id if self.is_group else self.user_id self.target_id = self.group_id if self.is_group else self.user_id
logger.debug(f"{self.log_prefix} Action组件初始化完成") logger.debug(f"{self.log_prefix} Action组件初始化完成")
logger.debug(f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}") logger.debug(
f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}"
)
def _get_activation_type_value(self, attr_name: str, default: str) -> str: def _get_activation_type_value(self, attr_name: str, default: str) -> str:
"""获取激活类型的字符串值""" """获取激活类型的字符串值"""
@@ -138,10 +139,9 @@ class BaseAction(ABC):
return attr.value return attr.value
return str(attr) return str(attr)
async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]: async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]:
"""等待新消息或超时 """等待新消息或超时
在loop_start_time之后等待新消息如果没有新消息且没有超时就一直等待。 在loop_start_time之后等待新消息如果没有新消息且没有超时就一直等待。
使用message_api检查self.chat_id对应的聊天中是否有新消息。 使用message_api检查self.chat_id对应的聊天中是否有新消息。
@@ -155,7 +155,7 @@ class BaseAction(ABC):
# 获取循环开始时间,如果没有则使用当前时间 # 获取循环开始时间,如果没有则使用当前时间
loop_start_time = self.action_data.get("loop_start_time", time.time()) loop_start_time = self.action_data.get("loop_start_time", time.time())
logger.info(f"{self.log_prefix} 开始等待新消息... (最长等待: {timeout}秒, 从时间点: {loop_start_time})") logger.info(f"{self.log_prefix} 开始等待新消息... (最长等待: {timeout}秒, 从时间点: {loop_start_time})")
# 确保有有效的chat_id # 确保有有效的chat_id
if not self.chat_id: if not self.chat_id:
logger.error(f"{self.log_prefix} 等待新消息失败: 没有有效的chat_id") logger.error(f"{self.log_prefix} 等待新消息失败: 没有有效的chat_id")
@@ -166,17 +166,15 @@ class BaseAction(ABC):
# 检查关闭标志 # 检查关闭标志
# shutting_down = self.get_action_context("shutting_down", False) # shutting_down = self.get_action_context("shutting_down", False)
# if shutting_down: # if shutting_down:
# logger.info(f"{self.log_prefix} 等待新消息时检测到关闭信号,中断等待") # logger.info(f"{self.log_prefix} 等待新消息时检测到关闭信号,中断等待")
# return False, "" # return False, ""
# 检查新消息 # 检查新消息
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_id, chat_id=self.chat_id, start_time=loop_start_time, end_time=current_time
start_time=loop_start_time,
end_time=current_time
) )
if new_message_count > 0: if new_message_count > 0:
logger.info(f"{self.log_prefix} 检测到{new_message_count}条新消息聊天ID: {self.chat_id}") logger.info(f"{self.log_prefix} 检测到{new_message_count}条新消息聊天ID: {self.chat_id}")
return True, "" return True, ""
@@ -186,7 +184,7 @@ class BaseAction(ABC):
if elapsed_time > timeout: if elapsed_time > timeout:
logger.warning(f"{self.log_prefix} 等待新消息超时({timeout}秒)聊天ID: {self.chat_id}") logger.warning(f"{self.log_prefix} 等待新消息超时({timeout}秒)聊天ID: {self.chat_id}")
return False, "" return False, ""
# 每30秒记录一次等待状态 # 每30秒记录一次等待状态
if int(elapsed_time) % 15 == 0 and int(elapsed_time) > 0: if int(elapsed_time) % 15 == 0 and int(elapsed_time) > 0:
logger.debug(f"{self.log_prefix} 已等待{int(elapsed_time)}秒,继续等待新消息...") logger.debug(f"{self.log_prefix} 已等待{int(elapsed_time)}秒,继续等待新消息...")
@@ -234,7 +232,7 @@ class BaseAction(ABC):
""" """
# 导入send_api # 导入send_api
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
if not self.target_id or not self.platform: if not self.target_id or not self.platform:
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息") logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
return False return False
@@ -255,7 +253,7 @@ class BaseAction(ABC):
""" """
# 导入send_api # 导入send_api
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
if not self.target_id or not self.platform: if not self.target_id or not self.platform:
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息") logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
return False return False
@@ -278,7 +276,7 @@ class BaseAction(ABC):
""" """
# 导入send_api # 导入send_api
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
if not self.target_id or not self.platform: if not self.target_id or not self.platform:
logger.error(f"{self.log_prefix} 缺少发送消息所需的信息") logger.error(f"{self.log_prefix} 缺少发送消息所需的信息")
return False return False
@@ -289,7 +287,7 @@ class BaseAction(ABC):
target_id=self.target_id, target_id=self.target_id,
is_group=self.is_group, is_group=self.is_group,
platform=self.platform, platform=self.platform,
typing=typing typing=typing,
) )
async def store_action_info( async def store_action_info(
@@ -299,7 +297,7 @@ class BaseAction(ABC):
action_done: bool = True, action_done: bool = True,
) -> None: ) -> None:
"""存储动作信息到数据库 """存储动作信息到数据库
Args: Args:
action_build_into_prompt: 是否构建到提示中 action_build_into_prompt: 是否构建到提示中
action_prompt_display: 显示的action提示信息 action_prompt_display: 显示的action提示信息
@@ -315,7 +313,9 @@ class BaseAction(ABC):
action_name=self.action_name, action_name=self.action_name,
) )
async def send_command(self, command_name: str, args: dict = None, display_message: str = None, storage_message: bool = True) -> bool: async def send_command(
self, command_name: str, args: dict = None, display_message: str = None, storage_message: bool = True
) -> bool:
"""发送命令消息 """发送命令消息
使用和send_text相同的方式通过MessageAPI发送命令 使用和send_text相同的方式通过MessageAPI发送命令
@@ -338,7 +338,7 @@ class BaseAction(ABC):
command=command_data, command=command_data,
group_id=str(self.group_id), group_id=str(self.group_id),
platform=self.platform, platform=self.platform,
storage_message=storage_message storage_message=storage_message,
) )
else: else:
# 私聊 # 私聊
@@ -346,7 +346,7 @@ class BaseAction(ABC):
command=command_data, command=command_data,
user_id=str(self.user_id), user_id=str(self.user_id),
platform=self.platform, platform=self.platform,
storage_message=storage_message storage_message=storage_message,
) )
if success: if success:
@@ -433,11 +433,11 @@ class BaseAction(ABC):
def get_action_context(self, key: str, default=None): def get_action_context(self, key: str, default=None):
"""获取action上下文信息 """获取action上下文信息
Args: Args:
key: 上下文键名 key: 上下文键名
default: 默认值 default: 默认值
Returns: Returns:
Any: 上下文值或默认值 Any: 上下文值或默认值
""" """
@@ -445,17 +445,17 @@ class BaseAction(ABC):
def get_config(self, key: str, default=None): def get_config(self, key: str, default=None):
"""获取插件配置值,支持嵌套键访问 """获取插件配置值,支持嵌套键访问
Args: Args:
key: 配置键名,支持嵌套访问如 "section.subsection.key" key: 配置键名,支持嵌套访问如 "section.subsection.key"
default: 默认值 default: 默认值
Returns: Returns:
Any: 配置值或默认值 Any: 配置值或默认值
""" """
if not self.plugin_config: if not self.plugin_config:
return default return default
# 支持嵌套键访问 # 支持嵌套键访问
keys = key.split(".") keys = key.split(".")
current = self.plugin_config current = self.plugin_config

View File

@@ -22,7 +22,7 @@ class BaseCommand(ABC):
command_name: str = "" command_name: str = ""
command_description: str = "" command_description: str = ""
# 默认命令设置(子类可以覆盖) # 默认命令设置(子类可以覆盖)
command_pattern: str = "" command_pattern: str = ""
command_help: str = "" command_help: str = ""
@@ -63,17 +63,17 @@ class BaseCommand(ABC):
def get_config(self, key: str, default=None): def get_config(self, key: str, default=None):
"""获取插件配置值,支持嵌套键访问 """获取插件配置值,支持嵌套键访问
Args: Args:
key: 配置键名,支持嵌套访问如 "section.subsection.key" key: 配置键名,支持嵌套访问如 "section.subsection.key"
default: 默认值 default: 默认值
Returns: Returns:
Any: 配置值或默认值 Any: 配置值或默认值
""" """
if not self.plugin_config: if not self.plugin_config:
return default return default
# 支持嵌套键访问 # 支持嵌套键访问
keys = key.split(".") keys = key.split(".")
current = self.plugin_config current = self.plugin_config
@@ -97,19 +97,15 @@ class BaseCommand(ABC):
if chat_stream.group_info: if chat_stream.group_info:
# 群聊 # 群聊
await send_api.text_to_group( await send_api.text_to_group(
text=content, text=content, group_id=str(chat_stream.group_info.group_id), platform=chat_stream.platform
group_id=str(chat_stream.group_info.group_id),
platform=chat_stream.platform
) )
else: else:
# 私聊 # 私聊
await send_api.text_to_user( await send_api.text_to_user(
text=content, text=content, user_id=str(chat_stream.user_info.user_id), platform=chat_stream.platform
user_id=str(chat_stream.user_info.user_id),
platform=chat_stream.platform
) )
async def send_type( async def send_type(
@@ -131,6 +127,7 @@ class BaseCommand(ABC):
if chat_stream.group_info: if chat_stream.group_info:
# 群聊 # 群聊
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
return await send_api.custom_message( return await send_api.custom_message(
message_type=message_type, message_type=message_type,
content=content, content=content,
@@ -142,6 +139,7 @@ class BaseCommand(ABC):
else: else:
# 私聊 # 私聊
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
return await send_api.custom_message( return await send_api.custom_message(
message_type=message_type, message_type=message_type,
content=content, content=content,
@@ -172,6 +170,7 @@ class BaseCommand(ABC):
if chat_stream.group_info: if chat_stream.group_info:
# 群聊 # 群聊
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
success = await send_api.custom_message( success = await send_api.custom_message(
message_type="command", message_type="command",
content=command_data, content=command_data,
@@ -182,6 +181,7 @@ class BaseCommand(ABC):
else: else:
# 私聊 # 私聊
from src.plugin_system.apis import send_api from src.plugin_system.apis import send_api
success = await send_api.custom_message( success = await send_api.custom_message(
message_type="command", message_type="command",
content=command_data, content=command_data,

View File

@@ -54,7 +54,7 @@ class ComponentRegistry:
""" """
component_name = component_info.name component_name = component_info.name
component_type = component_info.component_type component_type = component_info.component_type
plugin_name = getattr(component_info, 'plugin_name', 'unknown') plugin_name = getattr(component_info, "plugin_name", "unknown")
# 🔥 系统级别自动区分:为不同类型的组件添加命名空间前缀 # 🔥 系统级别自动区分:为不同类型的组件添加命名空间前缀
if component_type == ComponentType.ACTION: if component_type == ComponentType.ACTION:
@@ -68,8 +68,8 @@ class ComponentRegistry:
# 检查命名空间化的名称是否冲突 # 检查命名空间化的名称是否冲突
if namespaced_name in self._components: if namespaced_name in self._components:
existing_info = self._components[namespaced_name] existing_info = self._components[namespaced_name]
existing_plugin = getattr(existing_info, 'plugin_name', 'unknown') existing_plugin = getattr(existing_info, "plugin_name", "unknown")
logger.warning( logger.warning(
f"组件冲突: {component_type.value}组件 '{component_name}' " f"组件冲突: {component_type.value}组件 '{component_name}' "
f"已被插件 '{existing_plugin}' 注册,跳过插件 '{plugin_name}' 的注册" f"已被插件 '{existing_plugin}' 注册,跳过插件 '{plugin_name}' 的注册"
@@ -116,18 +116,18 @@ class ComponentRegistry:
def get_component_info(self, component_name: str, component_type: ComponentType = None) -> Optional[ComponentInfo]: def get_component_info(self, component_name: str, component_type: ComponentType = None) -> Optional[ComponentInfo]:
"""获取组件信息,支持自动命名空间解析 """获取组件信息,支持自动命名空间解析
Args: Args:
component_name: 组件名称,可以是原始名称或命名空间化的名称 component_name: 组件名称,可以是原始名称或命名空间化的名称
component_type: 组件类型,如果提供则优先在该类型中查找 component_type: 组件类型,如果提供则优先在该类型中查找
Returns: Returns:
Optional[ComponentInfo]: 组件信息或None Optional[ComponentInfo]: 组件信息或None
""" """
# 1. 如果已经是命名空间化的名称,直接查找 # 1. 如果已经是命名空间化的名称,直接查找
if '.' in component_name: if "." in component_name:
return self._components.get(component_name) return self._components.get(component_name)
# 2. 如果指定了组件类型,构造命名空间化的名称查找 # 2. 如果指定了组件类型,构造命名空间化的名称查找
if component_type: if component_type:
if component_type == ComponentType.ACTION: if component_type == ComponentType.ACTION:
@@ -136,9 +136,9 @@ class ComponentRegistry:
namespaced_name = f"command.{component_name}" namespaced_name = f"command.{component_name}"
else: else:
namespaced_name = f"{component_type.value}.{component_name}" namespaced_name = f"{component_type.value}.{component_name}"
return self._components.get(namespaced_name) return self._components.get(namespaced_name)
# 3. 如果没有指定类型,尝试在所有命名空间中查找 # 3. 如果没有指定类型,尝试在所有命名空间中查找
candidates = [] candidates = []
for namespace_prefix in ["action", "command"]: for namespace_prefix in ["action", "command"]:
@@ -146,7 +146,7 @@ class ComponentRegistry:
component_info = self._components.get(namespaced_name) component_info = self._components.get(namespaced_name)
if component_info: if component_info:
candidates.append((namespace_prefix, namespaced_name, component_info)) candidates.append((namespace_prefix, namespaced_name, component_info))
if len(candidates) == 1: if len(candidates) == 1:
# 只有一个匹配,直接返回 # 只有一个匹配,直接返回
return candidates[0][2] return candidates[0][2]
@@ -154,28 +154,27 @@ class ComponentRegistry:
# 多个匹配,记录警告并返回第一个 # 多个匹配,记录警告并返回第一个
namespaces = [ns for ns, _, _ in candidates] namespaces = [ns for ns, _, _ in candidates]
logger.warning( logger.warning(
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces}" f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces}使用第一个匹配项: {candidates[0][1]}"
f"使用第一个匹配项: {candidates[0][1]}"
) )
return candidates[0][2] return candidates[0][2]
# 4. 都没找到 # 4. 都没找到
return None return None
def get_component_class(self, component_name: str, component_type: ComponentType = None) -> Optional[Type]: def get_component_class(self, component_name: str, component_type: ComponentType = None) -> Optional[Type]:
"""获取组件类,支持自动命名空间解析 """获取组件类,支持自动命名空间解析
Args: Args:
component_name: 组件名称,可以是原始名称或命名空间化的名称 component_name: 组件名称,可以是原始名称或命名空间化的名称
component_type: 组件类型,如果提供则优先在该类型中查找 component_type: 组件类型,如果提供则优先在该类型中查找
Returns: Returns:
Optional[Type]: 组件类或None Optional[Type]: 组件类或None
""" """
# 1. 如果已经是命名空间化的名称,直接查找 # 1. 如果已经是命名空间化的名称,直接查找
if '.' in component_name: if "." in component_name:
return self._component_classes.get(component_name) return self._component_classes.get(component_name)
# 2. 如果指定了组件类型,构造命名空间化的名称查找 # 2. 如果指定了组件类型,构造命名空间化的名称查找
if component_type: if component_type:
if component_type == ComponentType.ACTION: if component_type == ComponentType.ACTION:
@@ -184,9 +183,9 @@ class ComponentRegistry:
namespaced_name = f"command.{component_name}" namespaced_name = f"command.{component_name}"
else: else:
namespaced_name = f"{component_type.value}.{component_name}" namespaced_name = f"{component_type.value}.{component_name}"
return self._component_classes.get(namespaced_name) return self._component_classes.get(namespaced_name)
# 3. 如果没有指定类型,尝试在所有命名空间中查找 # 3. 如果没有指定类型,尝试在所有命名空间中查找
candidates = [] candidates = []
for namespace_prefix in ["action", "command"]: for namespace_prefix in ["action", "command"]:
@@ -194,7 +193,7 @@ class ComponentRegistry:
component_class = self._component_classes.get(namespaced_name) component_class = self._component_classes.get(namespaced_name)
if component_class: if component_class:
candidates.append((namespace_prefix, namespaced_name, component_class)) candidates.append((namespace_prefix, namespaced_name, component_class))
if len(candidates) == 1: if len(candidates) == 1:
# 只有一个匹配,直接返回 # 只有一个匹配,直接返回
namespace, full_name, cls = candidates[0] namespace, full_name, cls = candidates[0]
@@ -204,11 +203,10 @@ class ComponentRegistry:
# 多个匹配,记录警告并返回第一个 # 多个匹配,记录警告并返回第一个
namespaces = [ns for ns, _, _ in candidates] namespaces = [ns for ns, _, _ in candidates]
logger.warning( logger.warning(
f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces}" f"组件名称 '{component_name}' 在多个命名空间中存在: {namespaces}使用第一个匹配项: {candidates[0][1]}"
f"使用第一个匹配项: {candidates[0][1]}"
) )
return candidates[0][2] return candidates[0][2]
# 4. 都没找到 # 4. 都没找到
return None return None
@@ -262,7 +260,6 @@ class ComponentRegistry:
""" """
for pattern, command_class in self._command_patterns.items(): for pattern, command_class in self._command_patterns.items():
match = pattern.match(text) match = pattern.match(text)
if match: if match:
command_name = None command_name = None
@@ -271,7 +268,7 @@ class ComponentRegistry:
if cls == command_class: if cls == command_class:
command_name = name command_name = name
break break
# 检查命令是否启用 # 检查命令是否启用
if command_name: if command_name:
command_info = self.get_command_info(command_name) command_info = self.get_command_info(command_name)
@@ -346,15 +343,19 @@ class ComponentRegistry:
component_info = self.get_component_info(component_name, component_type) component_info = self.get_component_info(component_name, component_type)
if not component_info: if not component_info:
return False return False
# 根据组件类型构造正确的命名空间化名称 # 根据组件类型构造正确的命名空间化名称
if component_info.component_type == ComponentType.ACTION: if component_info.component_type == ComponentType.ACTION:
namespaced_name = f"action.{component_name}" if '.' not in component_name else component_name namespaced_name = f"action.{component_name}" if "." not in component_name else component_name
elif component_info.component_type == ComponentType.COMMAND: elif component_info.component_type == ComponentType.COMMAND:
namespaced_name = f"command.{component_name}" if '.' not in component_name else component_name namespaced_name = f"command.{component_name}" if "." not in component_name else component_name
else: else:
namespaced_name = f"{component_info.component_type.value}.{component_name}" if '.' not in component_name else component_name namespaced_name = (
f"{component_info.component_type.value}.{component_name}"
if "." not in component_name
else component_name
)
if namespaced_name in self._components: if namespaced_name in self._components:
self._components[namespaced_name].enabled = True self._components[namespaced_name].enabled = True
# 如果是Action更新默认动作集 # 如果是Action更新默认动作集
@@ -370,15 +371,19 @@ class ComponentRegistry:
component_info = self.get_component_info(component_name, component_type) component_info = self.get_component_info(component_name, component_type)
if not component_info: if not component_info:
return False return False
# 根据组件类型构造正确的命名空间化名称 # 根据组件类型构造正确的命名空间化名称
if component_info.component_type == ComponentType.ACTION: if component_info.component_type == ComponentType.ACTION:
namespaced_name = f"action.{component_name}" if '.' not in component_name else component_name namespaced_name = f"action.{component_name}" if "." not in component_name else component_name
elif component_info.component_type == ComponentType.COMMAND: elif component_info.component_type == ComponentType.COMMAND:
namespaced_name = f"command.{component_name}" if '.' not in component_name else component_name namespaced_name = f"command.{component_name}" if "." not in component_name else component_name
else: else:
namespaced_name = f"{component_info.component_type.value}.{component_name}" if '.' not in component_name else component_name namespaced_name = (
f"{component_info.component_type.value}.{component_name}"
if "." not in component_name
else component_name
)
if namespaced_name in self._components: if namespaced_name in self._components:
self._components[namespaced_name].enabled = False self._components[namespaced_name].enabled = False
# 如果是Action从默认动作集中移除 # 如果是Action从默认动作集中移除

View File

@@ -38,9 +38,7 @@ class ReplyAction(BaseAction):
action_description = "参与聊天回复,发送文本进行表达" action_description = "参与聊天回复,发送文本进行表达"
# 动作参数定义 # 动作参数定义
action_parameters = { action_parameters = {"reply_to": "你要回复的对方的发言内容,格式:(用户名:发言内容可以为none"}
"reply_to": "你要回复的对方的发言内容,格式:(用户名:发言内容可以为none"
}
# 动作使用场景 # 动作使用场景
action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"] action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"]
@@ -53,45 +51,40 @@ class ReplyAction(BaseAction):
logger.info(f"{self.log_prefix} 决定回复: {self.reasoning}") logger.info(f"{self.log_prefix} 决定回复: {self.reasoning}")
start_time = self.action_data.get("loop_start_time", time.time()) start_time = self.action_data.get("loop_start_time", time.time())
try: try:
success, reply_set = await generator_api.generate_reply( success, reply_set = await generator_api.generate_reply(
chat_stream=self.chat_stream, chat_stream=self.chat_stream,
action_data=self.action_data, action_data=self.action_data,
platform=self.platform, platform=self.platform,
chat_id=self.chat_id, chat_id=self.chat_id,
is_group=self.is_group is_group=self.is_group,
) )
# 检查从start_time以来的新消息数量 # 检查从start_time以来的新消息数量
# 获取动作触发时间或使用默认值 # 获取动作触发时间或使用默认值
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_id, chat_id=self.chat_id, start_time=start_time, end_time=current_time
start_time=start_time,
end_time=current_time
) )
# 根据新消息数量决定是否使用reply_to # 根据新消息数量决定是否使用reply_to
need_reply = new_message_count >= 4 need_reply = new_message_count >= 4
logger.info(f"{self.log_prefix}{start_time}{current_time}共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}reply_to") logger.info(
f"{self.log_prefix}{start_time}{current_time}共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}reply_to"
)
# 构建回复文本 # 构建回复文本
reply_text = "" reply_text = ""
first_reply = False first_reply = False
for reply_seg in reply_set: for reply_seg in reply_set:
data = reply_seg[1] data = reply_seg[1]
if not first_reply and need_reply: if not first_reply and need_reply:
await self.send_text( await self.send_text(content=data, reply_to=self.action_data.get("reply_to", ""))
content=data,
reply_to=self.action_data.get("reply_to", "")
)
else: else:
await self.send_text(content=data) await self.send_text(content=data)
first_reply = True first_reply = True
reply_text += data reply_text += data
# 存储动作记录 # 存储动作记录
await self.store_action_info( await self.store_action_info(
@@ -110,7 +103,6 @@ class ReplyAction(BaseAction):
return False, f"回复失败: {str(e)}" return False, f"回复失败: {str(e)}"
class NoReplyAction(BaseAction): class NoReplyAction(BaseAction):
"""不回复动作,继承时会等待新消息或超时""" """不回复动作,继承时会等待新消息或超时"""
@@ -168,7 +160,7 @@ class NoReplyAction(BaseAction):
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} 不回复动作执行失败: {e}") logger.error(f"{self.log_prefix} 不回复动作执行失败: {e}")
return False, f"不回复动作执行失败: {e}" return False, f"不回复动作执行失败: {e}"
@classmethod @classmethod
def reset_consecutive_count(cls): def reset_consecutive_count(cls):
@@ -218,17 +210,17 @@ class EmojiAction(BaseAction):
# 1. 根据描述选择表情包 # 1. 根据描述选择表情包
description = self.action_data.get("description", "") description = self.action_data.get("description", "")
emoji_result = await emoji_api.get_by_description(description) emoji_result = await emoji_api.get_by_description(description)
if not emoji_result: if not emoji_result:
logger.warning(f"{self.log_prefix} 未找到匹配描述 '{description}' 的表情包") logger.warning(f"{self.log_prefix} 未找到匹配描述 '{description}' 的表情包")
return False, f"未找到匹配 '{description}' 的表情包" return False, f"未找到匹配 '{description}' 的表情包"
emoji_base64, emoji_description, matched_emotion = emoji_result emoji_base64, emoji_description, matched_emotion = emoji_result
logger.info(f"{self.log_prefix} 找到表情包: {emoji_description}, 匹配情感: {matched_emotion}") logger.info(f"{self.log_prefix} 找到表情包: {emoji_description}, 匹配情感: {matched_emotion}")
# 使用BaseAction的便捷方法发送表情包 # 使用BaseAction的便捷方法发送表情包
success = await self.send_emoji(emoji_base64) success = await self.send_emoji(emoji_base64)
if not success: if not success:
logger.error(f"{self.log_prefix} 表情包发送失败") logger.error(f"{self.log_prefix} 表情包发送失败")
return False, "表情包发送失败" return False, "表情包发送失败"
@@ -430,10 +422,6 @@ class CoreActionsPlugin(BasePlugin):
return components return components
# class DeepReplyAction(BaseAction): # class DeepReplyAction(BaseAction):
# """回复动作 - 参与聊天回复""" # """回复动作 - 参与聊天回复"""
@@ -467,42 +455,39 @@ class CoreActionsPlugin(BasePlugin):
# chatting_observation = self._get_chatting_observation() # chatting_observation = self._get_chatting_observation()
# if not chatting_observation: # if not chatting_observation:
# return False, "未找到聊天观察" # return False, "未找到聊天观察"
# talking_message_str = chatting_observation.talking_message_str # talking_message_str = chatting_observation.talking_message_str
# # 处理回复目标 # # 处理回复目标
# chat_stream = self.api.get_service("chat_stream") # chat_stream = self.api.get_service("chat_stream")
# anchor_message = await create_empty_anchor_message(chat_stream.platform, chat_stream.group_info, chat_stream) # anchor_message = await create_empty_anchor_message(chat_stream.platform, chat_stream.group_info, chat_stream)
# llm_model = self.api.get_available_models().replyer_1 # llm_model = self.api.get_available_models().replyer_1
# prompt = f""" # prompt = f"""
# {talking_message_str} # {talking_message_str}
# 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,形成深刻观点,请你思考,总结成一份学术论文,APA标准格式 # 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,形成深刻观点,请你思考,总结成一份学术论文,APA标准格式
# """ # """
# success, response, reasoning, model_name = await self.api.generate_with_model(prompt, llm_model) # success, response, reasoning, model_name = await self.api.generate_with_model(prompt, llm_model)
# print(prompt) # print(prompt)
# print(f"DeepReplyAction: {response}") # print(f"DeepReplyAction: {response}")
# # prompt = f""" # # prompt = f"""
# # {talking_message_str} # # {talking_message_str}
# # 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,请你思考 # # 在上面的聊天中,你对{self.action_data.get("topic", "")}感兴趣,请你思考
# # """ # # """
# extra_info_block = self.action_data.get("extra_info_block", "") # extra_info_block = self.action_data.get("extra_info_block", "")
# extra_info_block += response # extra_info_block += response
# # extra_info_block += f"\n--------------------------------\n注意这是最重要的内容你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n\n--------------------------------\n注意你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n" # # extra_info_block += f"\n--------------------------------\n注意这是最重要的内容你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n\n--------------------------------\n注意你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n"
# # extra_info_block += f"\n--------------------------------\n注意优先关注这句你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n\n--------------------------------\n注意你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以其他的回复要求不再适用请你自由的表达不论字数长短限制\n" # # extra_info_block += f"\n--------------------------------\n注意优先关注这句你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以下方聊天记录的回复要求不再适用请你自由的表达不论字数长短限制\n\n--------------------------------\n注意你现在可以用比较长的篇幅来表达你的观点不要只回复一个字或者几个字\n由于你进入了深度思考模式所以其他的回复要求不再适用请你自由的表达不论字数长短限制\n"
# self.action_data["extra_info_block"] = extra_info_block # self.action_data["extra_info_block"] = extra_info_block
# # 获取回复器服务 # # 获取回复器服务
# # replyer = self.api.get_service("replyer") # # replyer = self.api.get_service("replyer")
@@ -558,4 +543,4 @@ class CoreActionsPlugin(BasePlugin):
# for reply in reply_set: # for reply in reply_set:
# data = reply[1] # data = reply[1]
# reply_text += data # reply_text += data
# return reply_text # return reply_text

View File

@@ -26,6 +26,7 @@ from src.plugin_system.base.base_command import BaseCommand
from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode
from src.plugin_system.base.config_types import ConfigField from src.plugin_system.base.config_types import ConfigField
from src.common.logger import get_logger from src.common.logger import get_logger
# 导入配置API可选的简便方法 # 导入配置API可选的简便方法
from src.plugin_system.apis import person_api, generator_api from src.plugin_system.apis import person_api, generator_api
@@ -140,28 +141,28 @@ class MuteAction(BaseAction):
# 获取用户ID # 获取用户ID
person_id = person_api.get_person_id_by_name(target) person_id = person_api.get_person_id_by_name(target)
user_id = await person_api.get_person_value(person_id,"user_id") user_id = await person_api.get_person_value(person_id, "user_id")
if not user_id: if not user_id:
error_msg = f"未找到用户 {target} 的ID" error_msg = f"未找到用户 {target} 的ID"
await self.send_text(f"找不到 {target} 这个人呢~") await self.send_text(f"找不到 {target} 这个人呢~")
logger.error(f"{self.log_prefix} {error_msg}") logger.error(f"{self.log_prefix} {error_msg}")
return False, error_msg return False, error_msg
# 格式化时长显示 # 格式化时长显示
enable_formatting = self.get_config("mute.enable_duration_formatting", True) enable_formatting = self.get_config("mute.enable_duration_formatting", True)
time_str = self._format_duration(duration_int) if enable_formatting else f"{duration_int}" time_str = self._format_duration(duration_int) if enable_formatting else f"{duration_int}"
# 获取模板化消息 # 获取模板化消息
message = self._get_template_message(target, time_str, reason) message = self._get_template_message(target, time_str, reason)
result_status,result_message = await generator_api.rewrite_reply( result_status, result_message = await generator_api.rewrite_reply(
chat_stream=self.chat_stream, chat_stream=self.chat_stream,
reply_data={ reply_data={
"raw_reply": message, "raw_reply": message,
"reason": reason, "reason": reason,
} },
) )
if result_status: if result_status:
for reply_seg in result_message: for reply_seg in result_message:
data = reply_seg[1] data = reply_seg[1]
@@ -169,9 +170,7 @@ class MuteAction(BaseAction):
# 发送群聊禁言命令 # 发送群聊禁言命令
success = await self.send_command( success = await self.send_command(
command_name="GROUP_BAN", command_name="GROUP_BAN", args={"qq_id": str(user_id), "duration": str(duration_int)}, storage_message=False
args={"qq_id": str(user_id), "duration": str(duration_int)},
storage_message=False
) )
if success: if success:
@@ -186,15 +185,13 @@ class MuteAction(BaseAction):
else: else:
error_msg = "发送禁言命令失败" error_msg = "发送禁言命令失败"
logger.error(f"{self.log_prefix} {error_msg}") logger.error(f"{self.log_prefix} {error_msg}")
await self.send_text("执行禁言动作失败") await self.send_text("执行禁言动作失败")
return False, error_msg return False, error_msg
def _get_template_message(self, target: str, duration_str: str, reason: str) -> str: def _get_template_message(self, target: str, duration_str: str, reason: str) -> str:
"""获取模板化的禁言消息""" """获取模板化的禁言消息"""
templates = self.get_config( templates = self.get_config("mute.templates")
"mute.templates"
)
template = random.choice(templates) template = random.choice(templates)
return template.format(target=target, duration=duration_str, reason=reason) return template.format(target=target, duration=duration_str, reason=reason)