讲师中心 微信公众号
AI工具推荐 视频效率加速

Discord.py 交互式按钮实现随机响应与指令重触发教程

云宇同学_9477

云宇同学_9477

发布时间:2025-11-16 11:09:01

|

855人浏览过

|

来源于php中文网

原创

discord.py 交互式按钮实现随机响应与指令重触发教程

本教程详细指导如何在 Discord.py 机器人中创建一个带有随机回复功能的指令,并添加一个交互式按钮。用户点击按钮后,无需重复输入指令即可重新触发随机回复,同时文章还将探讨如何实现特定角色访问限制,并解决常见的交互失败问题,提升用户体验。

引言:提升 Discord 机器人交互性

在 Discord 机器人开发中,为用户提供更丰富的交互体验是提升机器人实用性的关键。传统的指令模式需要用户反复输入文本,而利用 Discord.py 提供的 UI 组件(如按钮),我们可以创建更直观、更便捷的交互方式。本教程将聚焦于如何实现一个带有随机回复的指令,并为其添加一个“重生成”按钮,允许用户无需重新输入指令即可获取新的随机回复,同时还会讲解如何限制特定角色才能使用这些功能。

核心组件:discord.ui.View 与 discord.ui.Button

Discord.py 1.7 版本及以上引入了 discord.ui 模块,它允许开发者创建复杂的交互式组件。其中,View 是一个容器,用于管理多个 Button 或其他组件。Button 则是可点击的交互元素。

使用 discord.ui.View 的类式方法(Class-based View)是管理组件状态和回调的最佳实践,它比使用全局变量更加健壮和易于维护。

构建随机回复指令

首先,我们需要一个能够生成并发送随机 discord.Embed 的基础指令。

import discord
from discord.ext import commands
import random

# 假设 bot 已经初始化
# intents = discord.Intents.default()
# intents.message_content = True # 如果需要读取消息内容,请启用此意图
# bot = commands.Bot(command_prefix='!', intents=intents)

# 随机 Embed 列表
EMBED_ITEMS = [
    discord.Embed(title="这是一个测试", description="第一条随机消息。"),
    discord.Embed(title="这是第二个测试", description="第二条随机消息。"),
    discord.Embed(title="这是第三个测试", description="第三条随机消息。"),
    discord.Embed(title="这是第四个测试", description="第四条随机消息。"),
    discord.Embed(title="这是第五个测试", description="第五条随机消息。"),
    discord.Embed(title="这是第六个测试", description="第六条随机消息。"),
    discord.Embed(title="这是第七个测试", description="第七条随机消息。"),
    discord.Embed(title="这是第八个测试", description="第八条随机消息。")
]

@bot.command(name="random_message")
async def random_message_command(ctx: commands.Context):
    """发送一条随机的嵌入消息。"""
    initial_embed = random.choice(EMBED_ITEMS)
    await ctx.reply(embed=initial_embed)

这段代码定义了一个名为 random_message 的指令,当被调用时,它会从 EMBED_ITEMS 列表中随机选择一个 discord.Embed 并发送回复。

添加交互式重触发按钮

现在,我们将增强上述指令,使其在发送随机 Embed 的同时,附带一个按钮,用户点击该按钮即可重新生成并更新 Embed。我们将使用一个继承自 discord.ui.View 的自定义类来管理按钮及其回调。

AI舌诊面诊问诊医疗系统+诊疗商城系统源码
AI舌诊面诊问诊医疗系统+诊疗商城系统源码

AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。

下载

创建自定义 View 类

这个类将包含我们的按钮逻辑,并且能够存储 EMBED_ITEMS 列表以及对原始消息的引用,以便在按钮点击时进行编辑。

class RandomEmbedView(discord.ui.View):
    def __init__(self, items: list[discord.Embed], original_message: discord.Message, allowed_role_id: int = None):
        super().__init__(timeout=180) # 视图在180秒(3分钟)后失效
        self.items = items
        self.original_message = original_message
        self.allowed_role_id = allowed_role_id
        self.add_item(discord.ui.Button(label="重新生成", style=discord.ButtonStyle.primary, custom_id="reroll_button"))

    async def interaction_check(self, interaction: discord.Interaction) -> bool:
        """
        在处理任何按钮点击之前,检查交互是否被允许。
        这里用于实现角色限制。
        """
        if self.allowed_role_id:
            # 检查用户是否拥有指定角色
            if not any(role.id == self.allowed_role_id for role in interaction.user.roles):
                await interaction.response.send_message("您没有权限使用此按钮。", ephemeral=True)
                return False
        return True

    @discord.ui.button(label="重新生成", style=discord.ButtonStyle.primary, custom_id="reroll_button_callback")
    async def reroll_button_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
        """
        当“重新生成”按钮被点击时执行的回调函数。
        """
        # 立即响应交互,避免“Interaction Failed”错误
        await interaction.response.defer() 

        current_embed = self.original_message.embeds[0] if self.original_message.embeds else None

        next_embed = random.choice(self.items)
        # 循环确保新生成的 Embed 与当前显示的不同,除非列表中只有一个选项
        if current_embed and len(self.items) > 1:
            while next_embed.title == current_embed.title: # 简单地比较标题来判断是否相同
                next_embed = random.choice(self.items)

        # 编辑原始消息,更新 Embed 并保持视图活跃
        await self.original_message.edit(embed=next_embed, view=self)

    async def on_timeout(self):
        """
        当视图超时时执行。
        """
        # 可以选择移除按钮或禁用它们
        for item in self.children:
            item.disabled = True
        await self.original_message.edit(view=self)

更新指令以使用 View

现在,我们将修改 random_message_command 指令,使其能够创建并发送带有这个自定义 View 的消息。

# 假设 bot 已经初始化
# intents = discord.Intents.default()
# intents.message_content = True
# bot = commands.Bot(command_prefix='!', intents=intents)

# ... EMBED_ITEMS 定义 ...
# ... RandomEmbedView 类定义 ...

@bot.command(name="random_message")
async def random_message_command(ctx: commands.Context, role_id: int = None):
    """
    发送一条随机的嵌入消息,并附带一个按钮用于重新生成。
    可选参数 role_id 用于限制按钮的使用权限。
    """
    initial_embed = random.choice(EMBED_ITEMS)

    # 首先发送消息,以便获取消息对象
    msg = await ctx.reply(embed=initial_embed)

    # 创建视图实例,传入 Embed 列表、消息对象和可选的角色ID
    view = RandomEmbedView(EMBED_ITEMS, msg, allowed_role_id=role_id)

    # 编辑原始消息,将视图添加到其中
    await msg.edit(view=view)

处理 Discord 交互响应:避免 "Interaction Failed" 错误

当用户点击按钮时,Discord 会向你的机器人发送一个交互事件。机器人必须在 3 秒内对这个交互做出响应,否则 Discord 客户端会显示“Interaction Failed”错误。

在 reroll_button_callback 方法中,我们通过 await interaction.response.defer() 来解决这个问题。defer() 方法会立即向 Discord 发送一个“思考”状态,表示机器人已收到交互请求并正在处理,从而避免超时。之后,我们可以继续执行耗时操作(如生成新的 Embed),最后通过 self.original_message.edit() 更新消息。

如果不需要显示“思考”状态,也可以直接使用 await interaction.response.edit_message(embed=next_embed, view=self) 来同时响应交互并更新消息,但这要求更新操作本身在 3 秒内完成。对于我们的场景,defer() 后再 edit() 更为灵活。

实现特定角色访问限制

教程中提供了两种实现角色限制的方法:

  1. 针对指令本身的限制(使用装饰器): 如果你希望整个 random_message 指令只能由特定角色执行,可以使用 discord.ext.commands.has_role 装饰器。

    # 替换为你的角色名称或ID
    REQUIRED_ROLE_NAME = "管理员" 
    # 或 REQUIRED_ROLE_ID = 123456789012345678 
    
    @bot.command(name="random_message")
    @commands.has_role(REQUIRED_ROLE_NAME) # 或者 @commands.has_role(REQUIRED_ROLE_ID)
    async def random_message_command(ctx: commands.Context):
        # ... 指令内容 ...
        pass
    
    # 添加一个错误处理,以便在没有权限时给出反馈
    @random_message_command.error
    async def random_message_command_error(ctx, error):
        if isinstance(error, commands.MissingRole):
            await ctx.send(f"抱歉,{ctx.author.mention},您没有 '{REQUIRED_ROLE_NAME}' 角色来执行此指令。", ephemeral=True)
        else:
            raise error
  2. 针对按钮点击的限制(在 View 中实现): 如果你希望指令可以被所有人调用,但只有特定角色才能点击“重新生成”按钮,那么在 RandomEmbedView 的 interaction_check 方法中实现角色检查是最佳选择。我们已经在 RandomEmbedView 类中实现了这一点,通过 allowed_role_id 参数传入允许的角色 ID。当用户点击按钮时,interaction_check 会首先验证用户是否拥有该角色。

    如何获取角色 ID: 在 Discord 客户端中,启用开发者模式(用户设置 -> 高级 -> 开发者模式)。然后右键点击服务器中的角色,选择“复制 ID”。

完整代码示例

import discord
from discord.ext import commands
import random

# 配置你的机器人
# 请替换为你的机器人Token
TOKEN = "YOUR_BOT_TOKEN" 
# 确保你的机器人具有消息内容意图(如果需要)和默认意图
intents = discord.Intents.default()
intents.message_content = True 
intents.members = True # 如果需要检查成员的角色,需要启用此意图

bot = commands.Bot(command_prefix='!', intents=intents)

# 随机 Embed 列表
EMBED_ITEMS = [
    discord.Embed(title="这是一个测试", description="第一条随机消息。", color=discord.Color.blue()),
    discord.Embed(title="这是第二个测试", description="第二条随机消息。", color=discord.Color.green()),
    discord.Embed(title="这是第三个测试", description="第三条随机消息。", color=discord.Color.red()),
    discord.Embed(title="这是第四个测试", description="第四条随机消息。", color=discord.Color.purple()),
    discord.Embed(title="这是第五个测试", description="第五条随机消息。", color=discord.Color.orange()),
    discord.Embed(title="这是第六个测试", description="第六条随机消息。", color=discord.Color.teal()),
    discord.Embed(title="这是第七个测试", description="第七条随机消息。", color=discord.Color.dark_gold()),
    discord.Embed(title="这是第八个测试", description="第八条随机消息。", color=discord.Color.dark_magenta())
]

class RandomEmbedView(discord.ui.View):
    def __init__(self, items: list[discord.Embed], original_message: discord.Message, allowed_role_id: int = None):
        super().__init__(timeout=180) # 视图在180秒(3分钟)后失效
        self.items = items
        self.original_message = original_message
        self.allowed_role_id = allowed_role_id
        # 添加按钮
        self.add_item(discord.ui.Button(label="重新生成", style=discord.ButtonStyle.primary, custom_id="reroll_button_callback"))

    async def interaction_check(self, interaction: discord.Interaction) -> bool:
        """
        在处理任何按钮点击之前,检查交互是否被允许。
        这里用于实现角色限制。
        """
        if self.allowed_role_id:
            # 检查用户是否拥有指定角色
            # interaction.user.roles 是一个列表,包含 discord.Role 对象
            if not any(role.id == self.allowed_role_id for role in interaction.user.roles):
                await interaction.response.send_message("您没有权限使用此按钮。", ephemeral=True)
                return False
        return True

    @discord.ui.button(label="重新生成", style=discord.ButtonStyle.primary, custom_id="reroll_button_callback")
    async def reroll_button_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
        """
        当“重新生成”按钮被点击时执行的回调函数。
        """
        # 立即响应交互,避免“Interaction Failed”错误
        await interaction.response.defer() 

        current_embed = self.original_message.embeds[0] if self.original_message.embeds else None

        next_embed = random.choice(self.items)
        # 循环确保新生成的 Embed 与当前显示的不同,除非列表中只有一个选项
        if current_embed and len(self.items) > 1:
            while next_embed.title == current_embed.title: # 简单地比较标题来判断是否相同
                next_embed = random.choice(self.items)

        # 编辑原始消息,更新 Embed 并保持视图活跃
        await self.original_message.edit(embed=next_embed, view=self)

    async def on_timeout(self):
        """
        当视图超时时执行。
        超时后,按钮将变为禁用状态。
        """
        for item in self.children:
            if isinstance(item, discord.ui.Button):
                item.disabled = True
        await self.original_message.edit(view=self)

@bot.event
async def on_ready():
    print(f'Bot {bot.user} 已上线!')
    print(f'Discord.py 版本: {discord.__version__}')

@bot.command(name="random_message")
async def random_message_command(ctx: commands.Context, allowed_role_id: int = None):
    """
    发送一条随机的嵌入消息,并附带一个按钮用于重新生成。
    用法: !random_message [允许的角色ID]
    例如: !random_message 123456789012345678 (只有ID为123...的角色才能点击按钮)
    """

热门AI工具

更多
墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

相关专题

更多
全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

4405

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

1830

2025.09.18

c++ 全局变量
c++ 全局变量

本专题整合了c++全局变量的使用、定义、作用域等等内容,阅读专题下面的文章了解更多详细内容。

199

2026.03.17

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

3796

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

306

2025.12.06

Revel框架入门与安装配置
Revel框架入门与安装配置

本专题从Revel框架环境搭建讲起,系统介绍命令行工具安装、项目创建、目录结构、配置文件及热代码重载,帮助开发者快速完成首个Go Web应用。

0

2026.10.16

Linux 新手先学哪些命令
Linux 新手先学哪些命令

Linux新手命令专题汇集终端基础、文件目录操作、文本查看、软件安装和权限管理等入门文章,帮助按实际任务练习常用命令并建立命令行操作习惯。

0

2026.10.15

MySQL 忘记密码怎么办
MySQL 忘记密码怎么办

MySQL忘记密码专题汇集不同版本与系统下的root密码重置方法,覆盖MySQL 5.7、8.0、Mac、Linux及本地集成环境,并提示恢复权限与重新登录的检查步骤。

0

2026.10.15

Vue.js 中 ref 和 reactive 的区别
Vue.js 中 ref 和 reactive 的区别

Vue.js中ref和reactive的区别专题汇集两种响应式API的定义、访问方式、对象解构、侦听与性能取舍等文章,帮助结合实际状态类型选择合适写法。

0

2026.10.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn