feat: 增加根据qq号/群号主动发送消息的封装, 增加事件构造 (#2629)
* feat: 增加根据qq号/群号主动发送消息的封装, 增加事件构造 * fix: 增加不支持平台提示, 修正文档字符串 * chore: lint --------- Co-authored-by: Soulter <905617992@qq.com>
This commit is contained in:
+116
-21
@@ -1,15 +1,37 @@
|
||||
"""
|
||||
插件开发工具集
|
||||
封装了许多常用的操作,方便插件开发者使用
|
||||
|
||||
说明:
|
||||
|
||||
主动发送消息: send_message(session, message_chain)
|
||||
根据 session (unified_msg_origin) 主动发送消息, 前提是需要提前获得或构造 session
|
||||
|
||||
根据id直接主动发送消息: send_message_by_id(type, id, message_chain, platform="aiocqhttp")
|
||||
根据 id (例如 qq 号, 群号等) 直接, 主动地发送消息
|
||||
|
||||
以上两种方式需要构造消息链, 也就是消息组件的列表
|
||||
|
||||
构造事件:
|
||||
|
||||
首先需要构造一个 AstrBotMessage 对象, 使用 create_message 方法
|
||||
然后使用 create_event 方法提交事件到指定平台
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Union, Awaitable, List, Optional, ClassVar
|
||||
from astrbot.core.message.components import BaseMessageComponent
|
||||
from astrbot.core.message.message_event_result import MessageChain
|
||||
from astrbot.api.platform import MessageMember, AstrBotMessage
|
||||
from astrbot.api.platform import MessageMember, AstrBotMessage, MessageType
|
||||
from astrbot.core.platform.astr_message_event import MessageSesion
|
||||
from astrbot.core.star.context import Context
|
||||
from astrbot.core.star.star import star_map
|
||||
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
||||
|
||||
from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_message_event import AiocqhttpMessageEvent
|
||||
from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_platform_adapter import AiocqhttpAdapter
|
||||
|
||||
class StarTools:
|
||||
"""
|
||||
@@ -49,42 +71,76 @@ class StarTools:
|
||||
Note:
|
||||
qq_official(QQ官方API平台)不支持此方法
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
return await cls._context.send_message(session, message_chain)
|
||||
|
||||
@classmethod
|
||||
async def send_message_by_id(
|
||||
cls, type: str, id: str, message_chain: MessageChain, platform: str = "aiocqhttp"
|
||||
):
|
||||
"""
|
||||
根据 id(例如qq号, 群号等) 直接, 主动地发送消息
|
||||
|
||||
Args:
|
||||
type (str): 消息类型, 可选: PrivateMessage, GroupMessage
|
||||
id (str): 目标ID, 例如QQ号, 群号等
|
||||
message_chain (MessageChain): 消息链
|
||||
platform (str): 可选的平台名称,默认平台(aiocqhttp), 目前只支持 aiocqhttp
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
platforms = cls._context.platform_manager.get_insts()
|
||||
if platform == "aiocqhttp":
|
||||
adapter = next((p for p in platforms if isinstance(p, AiocqhttpAdapter)), None)
|
||||
if adapter is None:
|
||||
raise ValueError("未找到适配器: AiocqhttpAdapter")
|
||||
await AiocqhttpMessageEvent.send_message(
|
||||
bot=adapter.bot,
|
||||
message_chain=message_chain,
|
||||
is_group=(type == "GroupMessage"),
|
||||
session_id=id,
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"不支持的平台: {platform}")
|
||||
|
||||
@classmethod
|
||||
async def create_message(
|
||||
cls,
|
||||
type: str,
|
||||
self_id: str,
|
||||
session_id: str,
|
||||
message_id: str,
|
||||
sender: MessageMember,
|
||||
message: List[BaseMessageComponent],
|
||||
message_str: str,
|
||||
raw_message: object,
|
||||
group_id: str = "",
|
||||
):
|
||||
message_id: str = "",
|
||||
raw_message: object = None,
|
||||
group_id: str = ""
|
||||
) -> AstrBotMessage:
|
||||
"""
|
||||
创建一个AstrBot消息对象
|
||||
|
||||
Args:
|
||||
type (str): 消息类型
|
||||
type (str): 消息类型, 例如 "GroupMessage" "FriendMessage" "OtherMessage"
|
||||
self_id (str): 机器人自身ID
|
||||
session_id (str): 会话ID(通常为用户ID)(QQ号, 群号等)
|
||||
message_id (str): 消息ID
|
||||
sender (MessageMember): 发送者信息
|
||||
message (List[BaseMessageComponent]): 消息组件列表
|
||||
message_str (str): 消息字符串
|
||||
raw_message (object): 原始消息对象
|
||||
sender (MessageMember): 发送者信息, 例如 MessageMember(user_id="123456", nickname="昵称")
|
||||
message (List[BaseMessageComponent]): 消息组件列表, 也就是消息链, 这个不会发给 llm, 但是会经过其他处理
|
||||
message_str (str): 消息字符串, 也就是纯文本消息, 也就是发送给 llm 的消息, 与消息链一致
|
||||
|
||||
message_id (str): 消息ID, 构造消息时可以随意填写也可不填
|
||||
raw_message (object): 原始消息对象, 可以随意填写也可不填
|
||||
group_id (str, optional): 群组ID, 如果为私聊则为空. Defaults to "".
|
||||
|
||||
Returns:
|
||||
AstrBotMessage: 创建的消息对象
|
||||
"""
|
||||
abm = AstrBotMessage()
|
||||
abm.type = type
|
||||
abm.type = MessageType(type)
|
||||
abm.self_id = self_id
|
||||
abm.session_id = session_id
|
||||
if message_id == "":
|
||||
message_id = uuid.uuid4().hex
|
||||
abm.message_id = message_id
|
||||
abm.sender = sender
|
||||
abm.message = message
|
||||
@@ -93,13 +149,38 @@ class StarTools:
|
||||
abm.group_id = group_id
|
||||
return abm
|
||||
|
||||
# todo: 添加构造事件的方法
|
||||
# async def create_event(
|
||||
# self, platform: str, umo: str, sender_id: str, session_id: str
|
||||
# ):
|
||||
# platform = self._context.get_platform(platform)
|
||||
@classmethod
|
||||
async def create_event(
|
||||
cls, abm: AstrBotMessage, platform: str = "aiocqhttp", is_wake: bool = True
|
||||
|
||||
# todo: 添加找到对应平台并提交对应事件的方法
|
||||
) -> None:
|
||||
"""
|
||||
创建并提交事件到指定平台
|
||||
当有需要创建一个事件, 触发某些处理流程时, 使用该方法
|
||||
|
||||
Args:
|
||||
abm (AstrBotMessage): 要提交的消息对象, 请先使用 create_message 创建
|
||||
platform (str): 可选的平台名称,默认平台(aiocqhttp), 目前只支持 aiocqhttp
|
||||
is_wake (bool): 是否标记为唤醒事件, 默认为 True, 只有唤醒事件才会被 llm 响应
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
platforms = cls._context.platform_manager.get_insts()
|
||||
if platform == "aiocqhttp":
|
||||
adapter = next((p for p in platforms if isinstance(p, AiocqhttpAdapter)), None)
|
||||
if adapter is None:
|
||||
raise ValueError("未找到适配器: AiocqhttpAdapter")
|
||||
event = AiocqhttpMessageEvent(
|
||||
message_str=abm.message_str,
|
||||
message_obj=abm,
|
||||
platform_meta=adapter.metadata,
|
||||
session_id=abm.session_id,
|
||||
bot=adapter.bot,
|
||||
)
|
||||
event.is_wake = is_wake
|
||||
adapter.commit_event(event)
|
||||
else:
|
||||
raise ValueError(f"不支持的平台: {platform}")
|
||||
|
||||
@classmethod
|
||||
def activate_llm_tool(cls, name: str) -> bool:
|
||||
@@ -110,6 +191,8 @@ class StarTools:
|
||||
Args:
|
||||
name (str): 工具名称
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
return cls._context.activate_llm_tool(name)
|
||||
|
||||
@classmethod
|
||||
@@ -120,6 +203,8 @@ class StarTools:
|
||||
Args:
|
||||
name (str): 工具名称
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
return cls._context.deactivate_llm_tool(name)
|
||||
|
||||
@classmethod
|
||||
@@ -135,6 +220,8 @@ class StarTools:
|
||||
desc (str): 工具描述
|
||||
func_obj (Awaitable): 函数对象,必须是异步函数
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
cls._context.register_llm_tool(name, func_args, desc, func_obj)
|
||||
|
||||
@classmethod
|
||||
@@ -146,6 +233,8 @@ class StarTools:
|
||||
Args:
|
||||
name (str): 工具名称
|
||||
"""
|
||||
if cls._context is None:
|
||||
raise ValueError("StarTools not initialized")
|
||||
cls._context.unregister_llm_tool(name)
|
||||
|
||||
@classmethod
|
||||
@@ -169,8 +258,11 @@ class StarTools:
|
||||
- 创建目录失败(权限不足或其他IO错误)
|
||||
"""
|
||||
if not plugin_name:
|
||||
frame = inspect.currentframe().f_back
|
||||
module = inspect.getmodule(frame)
|
||||
frame = inspect.currentframe()
|
||||
module = None
|
||||
if frame:
|
||||
frame = frame.f_back
|
||||
module = inspect.getmodule(frame)
|
||||
|
||||
if not module:
|
||||
raise RuntimeError("无法获取调用者模块信息")
|
||||
@@ -182,6 +274,9 @@ class StarTools:
|
||||
|
||||
plugin_name = metadata.name
|
||||
|
||||
if not plugin_name:
|
||||
raise ValueError("无法获取插件名称")
|
||||
|
||||
data_dir = Path(os.path.join(get_astrbot_data_path(), "plugin_data", plugin_name))
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user