You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用discord.py让机器人对自身投票消息添加反应并实现超时逻辑?

Discord机器人投票反应与动态超时实现方案

核心实现步骤

  • 添加投票反应:发送投票消息后,立即为消息添加指定反应(如✅)
  • 动态超时逻辑:设置初始超时,定时检查反应数量,按照规则调整剩余超时时长
  • 反应监听与统计:监听反应添加事件,排除机器人自身反应,统计有效票数
  • 执行超时操作:投票结束后根据最终票数判断是否执行超时

修改后的完整代码

import asyncio
import discord
from discord import app_commands

@bot.tree.command(name='timeout_vote', description='发起超时投票')
@app_commands.checks.has_any_role('verified')
@app_commands.describe(timeout='要投票超时的成员', reason='超时理由(可选)')
async def timeout_vote(interaction: discord.Interaction, timeout: discord.Member, reason: str = '未提供理由'):
    # 构建投票嵌入消息
    embed = discord.Embed(title='⏱️ 超时投票', description=f'投票目标:{timeout.mention}\n发起者:{interaction.user.mention}\n理由:{reason}')
    embed.set_author(name=timeout.name, icon_url=timeout.display_avatar.url)
    embed.set_image(url=timeout.display_avatar.url)
    
    # 发送消息并获取消息对象(必须存下来才能后续操作)
    vote_msg = await interaction.response.send_message(embed=embed)
    # 添加投票反应
    await vote_msg.add_reaction('✅')
    
    # 定义反应数对应超时的规则
    vote_timeout_map = {
        5: 60,    # 5票 → 60秒超时
        10: 120   # 10票 → 120秒超时
    }
    current_timeout = 300  # 初始超时(5分钟,可自定义)
    check_interval = 10    # 每10秒检查一次反应数
    
    try:
        while current_timeout > 0:
            # 等待反应或检查间隔到期
            done, pending = await asyncio.wait(
                [bot.wait_for('reaction_add', timeout=check_interval)],
                return_when=asyncio.FIRST_COMPLETED
            )
            
            # 统计有效票数(减去机器人自己的反应)
            valid_votes = sum(r.count for r in vote_msg.reactions if r.emoji == '✅') - 1
            
            # 根据当前票数调整超时时间
            for vote_count, target_timeout in sorted(vote_timeout_map.items(), reverse=True):
                if valid_votes >= vote_count:
                    current_timeout = target_timeout
                    break
            
            # 减少剩余超时时间
            current_timeout -= check_interval
            
            # 达到最高票数阈值直接结束等待
            if valid_votes >= max(vote_timeout_map.keys()):
                current_timeout = 0
                break
            
            # 取消未完成的监听任务
            for task in pending:
                task.cancel()
        
        # 投票结束,更新消息并执行后续操作
        final_votes = sum(r.count for r in vote_msg.reactions if r.emoji == '✅') - 1
        await vote_msg.edit(content=f'投票结束!有效票数:{final_votes}', embed=embed)
        
        # 判断是否执行超时
        if final_votes >= 5:
            # 匹配对应超时时长
            duration = vote_timeout_map.get(next(k for k in sorted(vote_timeout_map.keys()) if final_votes >= k), 60)
            await timeout.timeout_for(seconds=duration, reason=reason)
            await interaction.followup.send(f'{timeout.mention} 因「{reason}」被超时{duration//60}分钟!')
        else:
            await interaction.followup.send('投票未达到阈值,超时操作取消。')
    
    except asyncio.TimeoutError:
        # 无反应触发导致超时结束
        final_votes = sum(r.count for r in vote_msg.reactions if r.emoji == '✅') - 1
        await vote_msg.edit(content=f'投票超时结束!有效票数:{final_votes}', embed=embed)
        await interaction.followup.send('投票超时,未达到执行条件。')

@timeout_vote.error
async def timeout_vote_error(interaction: discord.Interaction, error):
    if isinstance(error, app_commands.MissingAnyRole):
        await bot.get_channel(1106325554942197992).send('你需要拥有「verified」角色才能使用该命令!')

关键细节说明

  • 消息对象获取:必须保存interaction.response.send_message返回的消息对象,才能对消息添加反应和后续编辑
  • 有效票数统计:减去机器人自身的反应,避免把机器人的投票算入有效票数
  • 动态超时调整:通过循环定时检查反应数,实时更新剩余超时,确保达到指定票数时自动缩短等待时间
  • 错误处理修正:原错误函数参数错误,app_commands的错误处理第一个参数应为interaction而非ctx

内容的提问来源于stack exchange,提问作者kinsv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:53:13