Files
LangBot/zh/develop/adapter/discord/api_reference.mdx
T
Xiaoyu SuandJunyan Chin 310c566148 refactor: migration to mintlify
* 重构文档结构:移除 docs 目录,调整文件组织结构

* Reorder "插件 SDK API" section in docs.json

* Refactor and clarify various documentation sections

* Refine warnings and info boxes across multiple docs

* Refactor and simplify Japanese documentation content

* Update package.json to include mintlify as a dependency and add pnpm-lock.yaml for dependency management

* Update blog link and add description in docs.json

---------

Co-authored-by: Junyan Chin <[email protected]>
2026-02-21 23:55:53 +08:00

554 lines
13 KiB
Plaintext

---
title: "Discord 适配器 API 参考"
---
## 概述
Discord 适配器提供完整的 Discord 平台集成功能,包括消息处理、图像管理、语音连接等。所有功能基于 discord.py 库的原生 API 实现。
## 核心 API
### DiscordAdapter 类
Discord 平台适配器主类,提供与 Discord 平台交互的完整接口。
#### 消息相关方法
##### `send_message(target_type, target_id, message)`
发送消息到指定频道。
**参数:**
- `target_type` (str): 目标类型,通常为 "channel"
- `target_id` (str): 目标频道 ID
- `message` (MessageChain): 要发送的消息链
**功能:**
- 支持文本消息发送
- 支持图像文件批量发送
- 自动处理消息格式转换
**示例:**
```python
# 发送纯文本消息
await adapter.send_message("channel", "123456789", MessageChain([Plain("Hello!")]))
# 发送带图像的消息
message_chain = MessageChain([
Plain("看看这张图片:"),
Image(path="path/to/image.jpg"),
Image(url="https://example.com/image.png")
])
await adapter.send_message("channel", "123456789", message_chain)
```
---
##### `reply_message(message_source, message, quote_origin=False)`
回复指定消息。
**参数:**
- `message_source` (MessageEvent): 要回复的原始消息事件
- `message` (MessageChain): 回复内容
- `quote_origin` (bool): 是否引用原消息
**示例:**
```python
# 简单回复
await adapter.reply_message(
message_event,
MessageChain([Plain("收到你的消息了!")])
)
# 引用回复
await adapter.reply_message(
message_event,
MessageChain([Plain("这是对你消息的回复")]),
quote_origin=True
)
```
#### 语音相关方法
##### `join_voice_channel(guild_id, channel_id, user_id=None)`
加入指定的语音频道。
**参数:**
- `guild_id` (int): Discord 服务器 ID
- `channel_id` (int): 语音频道 ID
- `user_id` (int, optional): 请求用户 ID,用于权限验证
**返回值:**
- `discord.VoiceClient`: 语音客户端对象
**异常:**
- `VoicePermissionError`: 权限不足
- `VoiceNetworkError`: 网络连接问题
- `VoiceConnectionError`: 其他连接错误
**示例:**
```python
try:
voice_client = await adapter.join_voice_channel(
guild_id=123456789,
channel_id=987654321,
user_id=555666777
)
print(f"成功连接,延迟: {voice_client.latency*1000:.2f}ms")
except VoicePermissionError as e:
print(f"权限错误: {e.missing_permissions}")
```
---
##### `leave_voice_channel(guild_id)`
离开指定服务器的语音频道。
**参数:**
- `guild_id` (int): Discord 服务器 ID
**返回值:**
- `bool`: 成功断开返回 `True`
**示例:**
```python
success = await adapter.leave_voice_channel(guild_id=123456789)
if success:
print("成功离开语音频道")
```
---
##### `get_voice_client(guild_id)`
获取指定服务器的语音客户端对象。
**参数:**
- `guild_id` (int): Discord 服务器 ID
**返回值:**
- `discord.VoiceClient`: 语音客户端对象,如果存在连接
- `None`: 如果没有活跃连接
**示例:**
```python
voice_client = await adapter.get_voice_client(guild_id=123456789)
if voice_client:
# 播放音频
import discord
audio = discord.FFmpegPCMAudio("path/to/audio.mp3")
voice_client.play(audio)
```
---
##### `is_connected_to_voice(guild_id)`
检查是否连接到指定服务器的语音频道。
**参数:**
- `guild_id` (int): Discord 服务器 ID
**返回值:**
- `bool`: 已连接返回 `True`
**示例:**
```python
if await adapter.is_connected_to_voice(guild_id=123456789):
print("已连接到语音频道")
```
---
##### `get_voice_connection_status(guild_id)`
获取语音连接的详细状态信息。
**参数:**
- `guild_id` (int): Discord 服务器 ID
**返回值:**
- `dict`: 连接状态信息字典,如果存在连接
- `None`: 如果没有连接
**状态信息结构:**
```python
{
'guild_id': int,
'channel_id': int,
'channel_name': str,
'connected': bool,
'connection_time': datetime,
'last_activity': datetime,
'status': str, # VoiceConnectionStatus 枚举值
'user_count': int,
'latency': float,
'connection_health': str
}
```
---
##### `list_active_voice_connections()`
获取所有活跃的语音连接列表。
**返回值:**
- `List[dict]`: 活跃连接状态列表
**示例:**
```python
connections = await adapter.list_active_voice_connections()
for conn in connections:
print(f"服务器: {conn['guild_id']}, 频道: {conn['channel_name']}")
```
---
##### `get_voice_channel_info(guild_id, channel_id)`
获取指定语音频道的详细信息。
**参数:**
- `guild_id` (int): 服务器 ID
- `channel_id` (int): 频道 ID
**返回值:**
- `dict`: 频道信息字典
- `None`: 如果频道不存在
**频道信息结构:**
```python
{
'channel_id': int,
'channel_name': str,
'guild_id': int,
'guild_name': str,
'user_limit': int,
'current_users': List[dict],
'user_count': int,
'bitrate': int,
'permissions': dict
}
```
#### 管理方法
##### `is_muted(group_id)`
检查群组是否被静音(Discord 适配器始终返回 False)。
**参数:**
- `group_id` (int): 群组 ID
**返回值:**
- `bool`: 是否静音
---
##### `register_listener(event_type, callback)`
注册事件监听器。
**参数:**
- `event_type` (Type[Event]): 事件类型
- `callback` (Callable): 回调函数
---
##### `unregister_listener(event_type, callback)`
注销事件监听器。
**参数:**
- `event_type` (Type[Event]): 事件类型
- `callback` (Callable): 回调函数
---
##### `run_async()`
启动 Discord 适配器,建立与 Discord 的连接。
**功能:**
- 初始化语音管理器
- 启动连接监控
- 建立 WebSocket 连接
---
##### `kill()`
关闭 Discord 适配器。
**返回值:**
- `bool`: 是否成功关闭
**功能:**
- 断开所有语音连接
- 关闭 Discord 客户端
- 清理资源
## 消息转换器 API
### DiscordMessageConverter 类
负责在 LangBot 和 Discord 消息格式之间进行转换。
#### `yiri2target(message_chain)`
将 LangBot MessageChain 转换为 Discord 格式。
**参数:**
- `message_chain` (MessageChain): LangBot 消息链
**返回值:**
- `Tuple[str, List[discord.File]]`: (文本内容, 文件列表)
**支持的消息元素:**
- `Plain`: 纯文本内容
- `Image`: 图像内容(支持 base64、URL、文件路径)
- `At`: @ 提及(会被移除)
- `Forward`: 转发消息
**图像处理特性:**
- **Base64 图像**: 自动检测格式并解码
- **URL 图像**: 异步下载并转换
- **文件路径**: 读取本地文件
- **格式检测**: 支持 PNG、JPG、GIF、WebP
- **错误处理**: 跳过无效图像
**示例:**
```python
message_chain = MessageChain([
Plain("文本内容"),
Image(base64="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="),
Image(url="https://example.com/image.jpg"),
Image(path="/path/to/local/image.png")
])
text, files = await DiscordMessageConverter.yiri2target(message_chain)
# text: "文本内容"
# files: [discord.File, discord.File, discord.File]
```
---
#### `target2yiri(message)`
将 Discord 消息转换为 LangBot MessageChain。
**参数:**
- `message` (discord.Message): Discord 消息对象
**返回值:**
- `MessageChain`: LangBot 消息链
**转换规则:**
- 文本内容 → `Plain` 元素
- 附件图像 → `Image` 元素
- 嵌入内容 → `Plain` 元素(描述文本)
## 事件转换器 API
### DiscordEventConverter 类
负责将 Discord 事件转换为 LangBot 平台事件。
#### `target2yiri(message)`
将 Discord 消息转换为 LangBot MessageEvent。
**参数:**
- `message` (discord.Message): Discord 消息对象
**返回值:**
- `MessageEvent`: LangBot 消息事件
**事件字段:**
- `message_chain`: 转换后的消息链
- `sender`: 发送者信息
- `query`: 查询上下文信息
## 异常类
### VoiceConnectionError
基础语音连接异常类。
**属性:**
- `error_code` (str): 错误代码
- `guild_id` (int): 相关服务器 ID
- `timestamp` (datetime): 错误发生时间
**常见错误代码:**
- `"GUILD_NOT_FOUND"`: 服务器不存在
- `"CHANNEL_NOT_FOUND"`: 频道不存在
- `"MANAGER_NOT_READY"`: 语音管理器未初始化
- `"OPUS_NOT_LOADED"`: Opus编码器未加载
- `"UNKNOWN_ERROR"`: 未知错误
### VoicePermissionError
语音权限异常,继承自 `VoiceConnectionError`。
**属性:**
- `missing_permissions` (List[str]): 缺失的权限列表
- `user_id` (int): 相关用户 ID
- `channel_id` (int): 相关频道 ID
**常见权限错误:**
- `"user_not_in_channel"`: 用户不在语音频道中
- `"member_not_found"`: 找不到用户
- `"connect"`: Bot缺少连接权限
- `"speak"`: Bot缺少发言权限
### VoiceNetworkError
语音网络异常,继承自 `VoiceConnectionError`。
**属性:**
- `retry_count` (int): 重试次数
- `last_attempt` (datetime): 最后尝试时间
## 使用示例
### 综合消息处理
```python
async def handle_complex_message(adapter, channel_id):
"""处理包含多种元素的复杂消息"""
# 构建包含文本和图像的消息
message_chain = MessageChain([
Plain("这是一个包含多种内容的消息:\\n"),
Plain("1. 文本内容\\n"),
Plain("2. 网络图像\\n"),
Image(url="https://example.com/image1.jpg"),
Plain("3. 本地图像\\n"),
Image(path="/path/to/local/image.png"),
Plain("4. Base64 图像\\n"),
Image(base64="data:image/png;base64,iVBORw0KGgo...")
])
# 发送消息
await adapter.send_message("channel", channel_id, message_chain)
```
### 语音播放控制
```python
async def voice_player_example(adapter, guild_id, channel_id, audio_files):
"""语音播放器示例"""
# 连接到语音频道
try:
voice_client = await adapter.join_voice_channel(guild_id, channel_id)
except VoicePermissionError as e:
print(f"权限不足: {e.missing_permissions}")
return
# 播放音频队列
for audio_file in audio_files:
if voice_client.is_connected():
# 等待当前播放完成
while voice_client.is_playing():
await asyncio.sleep(1)
# 播放下一个音频
audio_source = discord.FFmpegPCMAudio(audio_file)
voice_client.play(audio_source)
print(f"正在播放: {audio_file}")
# 播放完成后离开频道
await adapter.leave_voice_channel(guild_id)
```
### 状态监控
```python
async def monitor_connections(adapter):
"""监控所有语音连接状态"""
connections = await adapter.list_active_voice_connections()
for conn in connections:
print(f"服务器: {conn['guild_id']}")
print(f"频道: {conn['channel_name']}")
print(f"延迟: {conn['latency']:.2f}ms")
print(f"用户数: {conn['user_count']}")
print(f"健康度: {conn['connection_health']}")
print("---")
```
## 最佳实践
### 错误处理
```python
async def safe_discord_operation():
try:
# Discord 操作
pass
except VoicePermissionError as e:
if "user_not_in_channel" in e.missing_permissions:
await send_error("请先加入语音频道")
elif "connect" in e.missing_permissions:
await send_error("机器人没有连接权限")
except discord.HTTPException as e:
if e.status == 403:
await send_error("权限不足")
elif e.status == 404:
await send_error("频道不存在")
except Exception as e:
await send_error(f"未知错误: {e}")
```
### 资源管理
```python
async def with_voice_connection(adapter, guild_id, channel_id, operation):
"""安全的语音连接管理"""
voice_client = None
try:
voice_client = await adapter.join_voice_channel(guild_id, channel_id)
await operation(voice_client)
finally:
if voice_client:
await adapter.leave_voice_channel(guild_id)
```
### 图像处理优化
```python
async def batch_image_processing(image_list):
"""批量图像处理"""
processed_images = []
for image_element in image_list:
try:
if image_element.url:
# 异步下载
async with aiohttp.ClientSession() as session:
async with session.get(image_element.url) as response:
image_data = await response.read()
processed_images.append(process_image_data(image_data))
elif image_element.path:
# 本地文件处理
with open(image_element.path, 'rb') as f:
image_data = f.read()
processed_images.append(process_image_data(image_data))
except Exception as e:
print(f"图像处理失败: {e}")
continue
return processed_images
```
---
> **注意**: 本 API 文档基于实际的 discord.py 实现,涵盖了 Discord 适配器的完整功能集。图像处理功能无需额外依赖,语音功能需要安装可选依赖。