---
sidebar_position: 4
description: 辅助模型
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# 辅助功能

`uniseg` 模块同时提供了多种方法以通用消息操作。

:::note

这些方法中与 `event`, `bot` 相关的参数都会尝试从上下文中获取对象。

:::

## 消息事件 ID

消息事件 ID 是用来标识当前消息事件的唯一 ID，通常用于回复/撤回/编辑/表态当前消息。

<Tabs groupId="get_msgid">
<TabItem value="depend" label="使用依赖注入">

通过提供的 `MessageId` 或 `MsgId` 依赖注入器来获取消息事件 id。

```python
from nonebot_plugin_alconna.uniseg import MsgId


matcher = on_xxx(...)

@matcher.handle()
asycn def _(msg_id: MsgId):
    ...
```

</TabItem>
<TabItem value="method" label="使用获取函数">

```python
from nonebot import Event, Bot
from nonebot_plugin_alconna.uniseg import get_message_id


matcher = on_xxx(...)

@matcher.handle()
asycn def _(bot: Bot, event: Event):
    msg_id: str = get_message_id(event, bot)

```

</TabItem>
</Tabs>

:::caution

该方法获取的消息事件 ID 不推荐直接用于各适配器的 API 调用中，可能会操作失败。

:::

## 发送对象

消息发送对象是用来描述当前消息事件的可发送对象或者主动发送消息时的目标对象，它包含了以下属性：

```python
class Target:
    id: str
    """目标id；若为群聊则为 group_id 或者 channel_id，若为私聊则为 user_id"""
    parent_id: str
    """父级id；若为频道则为 guild_id，其他情况下可能为空字符串（例如 Feishu 下可作为部门 id）"""
    channel: bool
    """是否为频道，仅当目标平台符合频道概念时"""
    private: bool
    """是否为私聊"""
    source: str
    """可能的事件id"""
    self_id: str | None
    """机器人id，若为 None 则 Bot 对象会随机选择"""
    selector: Callable[[Bot], Awaitable[bool]] | None
    """选择器，用于在多个 Bot 对象中选择特定 Bot"""
    extra: dict[str, Any]
    """额外信息，用于适配器扩展"""
```

<Tabs groupId="get_target">
<TabItem value="depend" label="使用依赖注入">

通过提供的 `MessageTarget` 或 `MsgTarget` 依赖注入器来获取消息发送对象。

```python
from nonebot_plugin_alconna.uniseg import MsgTarget


matcher = on_xxx(...)

@matcher.handle()
asycn def _(target: MsgTarget):
    ...
```

</TabItem>
<TabItem value="method" label="使用获取函数">

```python
from nonebot import Event, Bot
from nonebot_plugin_alconna.uniseg import Target, get_target


matcher = on_xxx(...)

@matcher.handle()
asycn def _(bot: Bot, event: Event):
    target: Target = get_target(event, bot)

```

</TabItem>
</Tabs>

主动构造一个发送对象时，则需要如下参数：

- `id`: 目标ID；若为群聊则为 `group_id` 或者 `channel_id`，若为私聊则为 `user_id`
- `parent_id`: 父级ID；若为频道则为 `guild_id`，其他情况下可能为空字符串（例如 Feishu 下可作为部门 id）
- `channel`: 是否为频道，仅当目标平台符合频道概念时
- `private`: 是否为私聊
- `source`: 可能的事件ID
- `self_id`: 机器人id，若为 None 则 Bot 对象会随机选择
- `selector`: 选择器，用于在多个 Bot 对象中选择特定 Bot
- `scope`: 平台范围，表示当前发送对象的平台类别
- `adapter`: 适配器名称，若为 None 则需要明确指定 Bot 对象
- `platform`: 平台名称，仅当目标适配器存在多个平台时使用
- `extra`: 额外信息，用于适配器扩展

通过 `Target` 对象，我们可以在 `UniMessage.send` 中指定发送对象：

```python
from nonebot_plugin_alconna.uniseg import UniMessage, MsgTarget, Target, SupportScope


matcher = on_xxx(...)

@matcher.handle()
async def _(target: MsgTarget):
    # 将消息发送给当前事件的发送者
    await UniMessage("Hello!").send(target=target)
    # 主动发送消息给群号为 12345 的 QQ 群聊
    target1 = Target("12345", scope=SupportScope.qq_client)
    await UniMessage("Hello!").send(target=target1)
```

### 选择器

一般来说，主动发送消息时，`UniMessage.send` 或 `Target.self_id` 应指定一个 `Bot` 对象。但是这样会加重开发者的负担。

因此，我们提供了选择器来帮助开发者选择一个 `Bot` 对象。当然，这并非说明一定需要传入 `selector` 参数。

事实上，构造 `Target` 对象时，`self_id`, `scope`, `adapter` 和 `platform` 都会参与到 `selector` 的构造中。

::tip

你其实可以使用 `Target` 来帮你筛选 `Bot` 对象：

```python
async def _():
    target = Target("12345", scope=SupportScope.qq_client)
    bot = await target.select()
```

:::

若配置了 [`alconna_apply_fetch_targets`](../config.md#alconna_apply_fetch_targets) 选项，则在启动时会主动拉取一次发送对象列表。即对于
某一主动构造的 `Target` 对象，插件将其与拉取下来的众多发送对象进行匹配，并选择第一个符合条件的发送对象，以选择对应的 Bot 对象。

## 撤回消息

通过 `message_recall` 方法来撤回消息事件。

```python
from nonebot_plugin_alconna.uniseg import message_recall

matcher = on_xxx(...)

@matcher.handle()
async def _(msg_id: MsgId):
    await message_recall(msg_id)
```

`message_recall` 方法的参数如下：

```python
async def message_recall(
    message_id: str | None = None,
    event: Event | None = None,
    bot: Bot | None = None,
    adapter: str | None = None
): ...
```

当 `message_id` 为 `None` 时，插件会尝试从 `event` 中获取消息事件 ID。

## 编辑消息

通过 `message_edit` 方法来编辑消息事件。

```python
from nonebot_plugin_alconna.uniseg import UniMessage, message_edit

matcher = on_xxx(...)

@matcher.handle()
async def _():
    await message_edit(UniMessage.text("1234"))
```

`message_edit` 方法的参数如下：

```python
async def message_edit(
    msg: UniMessage,
    message_id: str | None = None,
    event: Event | None = None,
    bot: Bot | None = None,
    adapter: str | None = None,
): ...
```

当 `message_id` 为 `None` 时，插件会尝试从 `event` 中获取消息事件 ID。

## 表态消息

:::caution

该方法属于实验性功能。其接口可能会在未来的版本中发生变化。

:::

通过 `message_reaction` 方法来表态消息事件。

```python
from nonebot_plugin_alconna.uniseg import message_reaction

matcher = on_xxx(...)

@matcher.handle()
async def _():
    await message_reaction("👍")
```

`message_reaction` 方法的参数如下：

```python
async def message_reaction(
    reaction: str | Emoji,
    message_id: str | None = None,
    event: Event | None = None,
    bot: Bot | None = None,
    adapter: str | None = None,
    delete: bool = False,
): ...
```

当 `message_id` 为 `None` 时，插件会尝试从 `event` 中获取消息事件 ID。

`delete` 参数表示是否删除**自己的**表态消息，默认为 `False`。

## 响应规则

`uniseg` 模块提供了两个响应规则：

- `at_in`: 是否在消息中 @ 了指定的用户
- `at_me`: 是否在消息中 @ 了机器人

相较于 NoneBot 内置的 `to_me` 规则，`at_me` 规则只会在消息中 @ 机器人时触发。

```python
from nonebot_plugin_alconna.uniseg import at_me

matcher = on_xxx(..., rule=at_me())
```
