Related
Hello guys i'm coding a Discord bot in Python and i wanted to code a roll dice command. And i think im doing something wrong. Here is the code:
#client.command()
async def rolldice(ctx):
dice4 = ["1","2","3","4"]
dice6 = ["1","2","3","4","5","6"]
dice8 = ["1","2","3","4","5","6","7","8"]
dice10 = ["1","2","3","4","5","6","7","8","9","10"]
dice12 = ["1","2","3","4","5","6","7","8","9","10","11","12"]
dice20 = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"]
message = await ctx.send("Choose a number:\n**4**, **6**, **8**, **10**, **12**, **20** ")
def check4(m):
return m.author == ctx.author and m.content == "4"
try:
await client.wait_for('message', check=check4, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice4)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
def check6(m):
return m.author == ctx.author and m.content == "6"
try:
await client.wait_for('message', check=check6, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice6)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
def check8(m):
return m.author == ctx.author and m.content == "8"
try:
await client.wait_for('message', check=check8, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice8)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
def check10(m):
return m.author == ctx.author and m.content == "10"
try:
await client.wait_for('message', check=check10, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice10)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
def check12(m):
return m.author == ctx.author and m.content == "12"
try:
await client.wait_for('message', check=check12, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice12)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
def check20(m):
return m.author == ctx.author and m.content == "20"
try:
await client.wait_for('message', check=check20, timeout=30.0)
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.choice(dice20)}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't answer in **30** second!")
When i type the command and select number 4 my command does works but when i try another number, for an example 6, it doesn't work. What am i doing wrong? Please help.
That's because it checks for 4 first, then 6, and so on... Even after you send 4, it'll check for 6, 8 and so on.. And when you send 6, it'll check for 4 first, then 6 and so on.. Why don't you try something like this instead:
#client.command()
async def rolldice(ctx):
message = await ctx.send("Choose a number:\n**4**, **6**, **8**, **10**, **12**, **20** ")
def check(m):
return m.author == ctx.author
try:
message = await client.wait_for("message", check = check, timeout = 30.0)
m = message.content
if m != "4" and m != "6" and m != "8" and m != "10" and m != "12" and m != "20":
await ctx.send("Sorry, invalid choice.")
return
coming = await ctx.send("Here it comes...")
time.sleep(1)
await coming.delete()
await ctx.send(f"**{random.randint(1, int(m))}**")
except asyncio.TimeoutError:
await message.delete()
await ctx.send("Procces has been canceled because you didn't respond in **30** seconds.")
Note: I recommend using await asyncio.sleep(1) instead of time.sleep(1). That way other commands will still be functional. Remember to import asyncio in this case.
so i was making a discord bot and made a modmail system and got this error. can someone plz help and tell me where i am going wrong i searched many similar errors but didnt find the answer.
bot:
import random
import os
import sys
import asyncio
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
client = commands.Bot(command_prefix='-', intents=intents)
client.remove_command("help")
#client.event
async def on_ready():
await client.change_presence(status=discord.Status.idle, activity=discord.Game('Do -help'))
print('functioning...')
#client.event
async def on_member_join(member):
print(f'{member} has joined the server.')
await member.create_dm()
await member.dm_channel.send(f'Hi {member.mention}, welcome to my Discord server!')
#client.event
async def on_member_remove(member):
print(f'{member} has left the server.')
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
client.load_extension(f'cogs.{filename[:-3]}')
#client.command(brief="Load", help="Loading cogs")
async def load(ctx, extension):
client.load_extension(f'cogs.{extension}')
#client.command(brief="Unload", help="Unloading cogs")
async def unload(ctx, extension):
client.unload_extension(f'cogs.{extension}')
#client.command(brief="Ping", help="The time it takes for a small data set to be transmitted from your device to a server on the Internet and back to your device again.")
async def ping(ctx):
await ctx.send(f'Pong! {round(client.latency*1000)}ms')
#client.command(aliases=['test','8ball', 'future'], brief="8ball", help="A little fun game.")
async def _8ball(ctx, *,question):
responses=[ "It is certain.",
"It is decidedly so.",
"Without a doubt.",
"Yes definitely.",
"You may rely on it.",
"As I see it, yes.",
"Most likely.",
"Outlook good.",
"Yes.",
"Signs point to yes.",
"Reply hazy, try again.",
"Ask again later.",
"Better not tell you now.",
"Cannot predict now.",
"Concentrate and ask again.",
"Don't count on it.",
"My reply is no.",
"My sources say no.",
"Outlook not so good.",
"Very doubtful."]
await ctx.send(f'Question: {question}\nAnswer: {random.choice(responses)}')
#client.command(aliases=['purge','clean'], brief="Purge", help="Clears a fixed number of messahes.")
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount=5):
await ctx.channel.purge(limit=amount)
#client.command(brief="Kick", help="Kicks a person out of the guild.")
#commands.has_permissions(manage_messages=True)
async def kick(ctx, member:discord.Member, *, reason=None):
message = f"You have been kicked from {ctx.guild.name}, reason: {reason}"
await member.send(message)
await member.kick(reason=reason)
await ctx.send(f'Kicked {member.mention}')
#client.command(brief="Ban", help="Bans a person in the guild.")
#commands.has_permissions(manage_messages=True)
async def ban(ctx, member:discord.Member, *, reason=None):
message = f"You have been banned from {ctx.guild.name}, reason: {reason}"
await member.send(message)
await member.ban(reason=reason)
await ctx.send(f'Banned {member.mention}')
#client.command(brief="Unban", help="Unbans a banned person in the guild.")
#commands.has_permissions(manage_messages=True)
async def unban(ctx, *, user=None):
try:
user = await commands.converter.UserConverter().convert(ctx, user)
except:
await ctx.send("Error: user could not be found!")
return
try:
bans = tuple(ban_entry.user for ban_entry in await ctx.guild.bans())
if user in bans:
await ctx.guild.unban(user, reason="Responsible moderator: "+ str(ctx.author))
else:
await ctx.send("User not banned!")
return
except discord.Forbidden:
await ctx.send("I do not have permission to unban!")
return
except:
await ctx.send("Unbanning failed!")
return
await ctx.send(f"Successfully unbanned {user.mention}!")
class DurationConverter(commands.Converter):
async def convert(self, ctx, argument):
amount=argument[:-1]
unit=argument[-1]
if amount.isdigit() and unit in ['s','m','h','d']:
return(int(amount),unit)
raise commands.BadArgument(message="Not a valid duration")
#client.command(brief="Tempban", help="Temporarily bans a person in the guild.")
#commands.has_permissions(manage_messages=True)
async def tempban(ctx, member: commands.MemberConverter, duration: DurationConverter):
multiplier={'s':1, 'm':60, 'h':3600, 'd':86400}
amount, unit= duration
message = f"You have been banned from {ctx.guild.name}, for {amount}{unit}"
await member.send(message)
await ctx.guild.ban(member)
await ctx.send(f'{member.mention} has been banned for {amount}{unit}')
await asyncio.sleep(amount*multiplier[unit])
await ctx.guild.unban(member)
#client.command(brief="Tempmute", help="Temporarily mutes a person in the guild.")
#commands.has_permissions(manage_messages=True)
async def tempmute(ctx, member: discord.Member, duration: DurationConverter, reason=None):
multiplier = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
amount, unit = duration
guild = ctx.guild
muteRole = discord.utils.get(guild.roles, name="Muted")
await member.add_roles(muteRole, reason=reason)
await ctx.send(f"{member.mention} has been muted in {ctx.guild} for {amount}{unit}")
await member.send(f"You have been muted in {ctx.guild} for {amount}{unit}")
await asyncio.sleep(amount*multiplier[unit])
await member.remove_roles(muteRole, reason=reason)
await ctx.send(f"{member.mention} has been unmuted in {ctx.guild} ")
await member.send(f"You have been unmuted in {ctx.guild} ")
def restart_bot():
os.execv(sys.executable, ['python'] + sys.argv)
#client.command(name= 'restart', brief="Restart", help="Restarts the bot.")
async def restart(ctx):
await ctx.send("Restarting bot...")
restart_bot()
#client.command( brief="Connects", help="Connects the bot.")
async def connect(self):
print(" bot connected")
#client.command(brief="Disconnects", help="Disconnects the bot.")
async def disconnect(self):
print("bot disconnected")
#client.command(brief="Mute", help="Mutes a person in the guild.")
#commands.has_permissions(manage_messages=True)
async def mute(ctx, member: discord.Member, *, reason=None):
guild = ctx.guild
muteRole = discord.utils.get(guild.roles, name="Muted")
if not muteRole:
await ctx.send("No Mute Role found! Creating one now...")
muteRole = await guild.create_role(name="Muted")
for channel in guild.channels:
await channel.set_permissions(muteRole, speak=False, send_messages=False, read_messages=True,
read_message_history=True)
await member.add_roles(muteRole, reason=reason)
await ctx.send(f"{member.mention} has been muted in {ctx.guild} | Reason: {reason}")
await member.send(f"You have been muted in {ctx.guild} | Reason: {reason}")
#client.command(brief="Unmute", help="Unmutes a muted person in the guild.")
#commands.has_permissions(manage_messages=True)
async def unmute(ctx, member: discord.Member, *, reason=None):
guild = ctx.guild
muteRole = discord.utils.get(guild.roles, name="Muted")
await member.remove_roles(muteRole, reason=reason)
await ctx.send(f"{member.mention} has been unmuted in {ctx.guild}")
await member.send(f"You have been unmuted in {ctx.guild}")
#client.command(brief="Slowmode", help="Enables a rate limit per message.")
#commands.has_permissions(manage_messages=True)
async def slowmode(ctx, time:int):
if (not ctx.author.guild_permissions.manage_messages):
await ctx.send('Cannot run command! Requires: ``Manage Messages``')
return
if time == 0:
await ctx.send('Slowmode is currently set to `0`')
await ctx.channel.edit(slowmode_delay = 0)
elif time > 21600:
await ctx.send('You cannot keep the slowmode higher than 6 hours!')
return
else:
await ctx.channel.edit(slowmode_delay = time)
await ctx.send(f"Slowmode has been set to `{time}` seconds!")
#client.command(brief="Prefix", help="Changes the prefix.")
async def setprefix(ctx, prefix):
client.command_prefix = prefix
await ctx.send(f"Prefix changed to ``{prefix}``")
#client.command(brief="Avatar", help="Displays a guild members pfp.")
async def avatar(ctx, member: discord.Member = None):
if member == None:
member = ctx.author
icon_url = member.avatar_url
avatarEmbed = discord.Embed(title=f"{member.name}\'s Avatar", color=0x802BAE)
avatarEmbed.set_image(url=f"{icon_url}")
avatarEmbed.timestamp = ctx.message.created_at
await ctx.send(embed=avatarEmbed)
client.run(token)
modmail:
import discord
import asyncio
from discord.ext.commands import Cog
client = discord.Client()
sent_users = []
class modmail(Cog):
def __init__(self, bot):
self.bot = bot
#Cog.listener()
async def on_message(self,message):
if message.guild: # ensure the channel is a DM
return
if message.author.bot:
return
if message.author == client.user:
return
if message.author.id in sent_users: # Ensure the intial message hasn't been sent before
return
modmail_channel = discord.utils.get(client.get_all_channels(), name="modmail")
embed = discord.Embed(color=0x00FFFF)
embed.set_author(name=f"Modmail System",
icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
embed.add_field(name='Report a member:', value=f"React with 1️⃣ if you want to report a member.")
embed.add_field(name='Report a Staff Member:', value=f"React with 2️⃣ if you want to report a Staff Member.")
embed.add_field(name='Warn Appeal:', value=f"React with 3️⃣ if you would like to appeal a warning.")
embed.add_field(name='Question:',
value=f"React with 4️⃣ if you have a question about our moderation system or the server rules.")
embed.set_footer(text="Modmail")
msg = await message.channel.send(embed=embed)
await msg.add_reaction("1️⃣")
await msg.add_reaction("2️⃣")
await msg.add_reaction("3️⃣")
await msg.add_reaction("4️⃣")
sent_users.append(message.author.id) # add this user to the list of sent users
try:
def check(reaction, user):
return user == message.author and str(reaction.emoji) in ["1️⃣", "2️⃣", "3️⃣", "4️⃣"]
reaction, user = await client.wait_for("reaction_add", timeout=60, check=check)
if str(reaction.emoji) == "1️⃣":
embed = discord.Embed(color=0x00FFFF)
embed.set_author(name=f"Modmail System",
icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
embed.add_field(name='How to Report:',
value="Send the ID of the person you are reporting and attach add a screen shot of them breaking a rule (can be ToS or a server rule).")
embed.set_footer(text="Report a member ")
await message.author.send(embed=embed)
message = await client.wait_for("message", timeout=60, check=lambda
m: m.channel == message.channel and m.author == message.author)
embed = discord.Embed(title=f"{message.content}", color=0x00FFFF)
await modmail_channel.send(embed=embed)
except asyncio.TimeoutError:
await message.channel.send("Reaction timeout!!!")
#Cog.listener()
async def on_ready(self):
print("modmail ready")
def setup(bot):
bot.add_cog(modmail(bot))
logcog:
import discord
import datetime
from datetime import datetime
from discord.ext.commands import Cog
class Example(Cog):
def __init__(self, client):
self.client = client
#Cog.listener()
async def on_ready(self):
print("log ready")
#Cog.listener()
async def on_message(self, message):
if not message.guild:
pass
else:
if not message.content and message.channel:
pass
else:
channel = discord.utils.get(message.guild.channels, name='log')
embed = discord.Embed(title="Message sent", description=message.author, color=message.author.color,
timestamp=datetime.utcnow())
embed.add_field(name="Message Sent", value=message.content, inline=True)
embed.add_field(name="Channel Sent", value=message.channel, inline=True)
await channel.send(embed=embed)
#Cog.listener()
async def on_message_edit(self, before, after):
if len(before.content)==0 and len(after.content)==0 and len(before.channel)==0:
pass
elif not before.guild:
pass
else:
channel = discord.utils.get(before.guild.channels, name='log')
embed = discord.Embed(title="Message edited", description=before.author, color=before.author.color,
timestamp=datetime.utcnow())
embed.add_field(name="Before edit", value=before.content, inline=True)
embed.add_field(name="After edit", value=after.content, inline=True)
embed.add_field(name="Channel Sent", value=before.channel, inline=True)
await channel.send(embed=embed)
#Cog.listener()
async def on_message_delete(self, message):
if not message.content and message.channel:
pass
elif not message.guild:
pass
else:
channel = discord.utils.get(message.guild.channels, name='log')
embed = discord.Embed(title="Message deleted", description=message.author, color=message.author.color,
timestamp=datetime.utcnow())
embed.add_field(name="Deleted Message", value=message.content, inline=True)
embed.add_field(name="The channel is", value=message.channel, inline=True)
await channel.send(embed=embed)
def setup(client):
client.add_cog(Example(client))
so when i run this code i get the reaction message and embed in the dm but when i click on the reaction i get no further out put and after 60s a message comes reaction timeout. I dont get any error message either.
So I finally solved the problem, which stemmed from the intents setup. In my main file I used this code:
intents = discord.Intents.default()
intents.members = True
bot = commands.Bot(command_prefix='!', intents=intents)
bot.load_extension("cogs.maincog")
bot.run(token)
You may want to do this slightly differently (like by using client), but the important part is the intents. This is apparently because the privileged intent "members" is required when testing for reactions is direct messages. I replaced the client with the Bot class, so the testing function became:
reaction, user = await self.bot.wait_for("reaction_add", timeout=60, check=check)
As far as I have tested, this should work perfectly well but let me know if you have any problems or want me to link the full code.
Edit: Look at how to enable privileged intents here.
I am currently working on a kick command that does a double check with the user before carrying out action for my discord bot, and came up with this:
#bot.command()
#commands.has_permissions(manage_guild=True)
async def kick(ctx,
member: discord.Member = None,
*,
reason="No reason provided"):
server_name = ctx.guild.name
user = member
if member == None:
await ctx.send(
f'{x_mark} **{ctx.message.author.name},** please mention somebody to kick.')
return
if member == ctx.message.author:
await ctx.send(
f'{x_mark} **{ctx.message.author.name},** you can\'t kick yourself, silly.')
return
embedcheck = discord.Embed(
title="Kick",
colour=0xFFD166,
description=f'Are you sure you want to kick **{user}?**')
embeddone = discord.Embed(
title="Kicked",
colour=0x06D6A0,
description=f'**{user}** has been kicked from the server.')
embedfail = discord.Embed(
title="Not Kicked",
colour=0xEF476F,
description=f'The kick did not carry out.')
msg = await ctx.send(embed=embedcheck)
await msg.add_reaction(check_mark)
await msg.add_reaction(x_mark)
def check(rctn, user):
return user.id == ctx.author.id and str(rctn) in [check_mark, x_mark]
while True:
try:
reaction, user = await bot.wait_for(
'reaction_add', timeout=60.0, check=check)
if str(reaction.emoji) == check_mark:
await msg.edit(embed=embeddone)
await user.kick(reason=reason)
if reason == None:
await user.send(
f'**{user.name}**, you were kicked from {server_name}. No reason was provided.'
)
else:
await user.send(
f'**{user.name}**, you were kicked from {server_name} for {reason}.'
)
return
elif str(reaction.emoji) == x_mark:
await msg.edit(embed=embedfail)
return
except asyncio.TimeoutError:
await msg.edit(embed=embedfail)
return
However when I do this, I get the error:
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: Forbidden: 403 Forbidden (error code: 50013): Missing Permissions
I have no clue why this is happening, as the bot has every permission checked, as do I, and I am the server owner. Any help would be appriciated, thank you.
Update: I found the error, when running the command it would try to kick the user of the command instead of the specified member. Here is my updated code:
#commands.command()
#commands.has_permissions(kick_members = True)
#commands.bot_has_permissions(kick_members = True)
async def kick(self, ctx, member: discord.Member, *, reason="No reason provided"):
server_name = ctx.guild.name
if member == ctx.message.author:
await ctx.send(
f'{x_mark} **{ctx.message.author.name},** you can\'t kick yourself, silly.')
return
embedcheck = discord.Embed(
title="Kick",
colour=0xFFD166,
description=f'Are you sure you want to kick **{member}?**')
embeddone = discord.Embed(
title="Kicked",
colour=0x06D6A0,
description=f'**{member}** has been kicked from the server.')
embedfail = discord.Embed(
title="Not Kicked",
colour=0xEF476F,
description=f'The kick did not carry out.')
msg = await ctx.send(embed=embedcheck)
await msg.add_reaction(check_mark)
await msg.add_reaction(x_mark)
def check(rctn, user):
return user.id == ctx.author.id and str(rctn) in [check_mark, x_mark]
while True:
try:
reaction, user = await self.bot.wait_for(
'reaction_add', timeout=60.0, check=check)
if str(reaction.emoji) == check_mark:
await msg.edit(embed=embeddone)
await member.kick(reason=reason)
await member.send(f'**{member.name}**, you were kicked from {server_name} for {reason}.')
return
elif str(reaction.emoji) == x_mark:
await msg.edit(embed=embedfail)
return
except asyncio.TimeoutError:
await msg.edit(embed=embedfail)
return
#kick.error
async def kick_error(self, ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send(f'{x_mark} **{ctx.message.author.name}**, you need to mention someone to kick.')
elif isinstance(error, commands.BadArgument):
await ctx.send(f'{x_mark} **{ctx.message.author.name}**, I could not find a user with that name.')
else:
raise error
This issue is that you are checking for manage_guild which is not the correct permission. Also keep in mind you are mixing up bot and commands
#bot.command()
#bot.has_permissions(kick_user = True) # to check the user itself
#bot.bot_has_permissions(kick_user = True) # to check the bot
async def kick(ctx):
Remember to allow all intents like this
intents = discord.Intents().all()
bot = commands.Bot(command_prefix="$", intents=intents)
How can I make the bot choose a right random answer (as a reaction)
And if the user gets it right send a winner message
if its wrong send a loser message.
redcrew = '<:redcrewmates:776867415514153031>'
bluecrew = '<:bluecrewmates:776867439085617153>'
limecrew = '<:limecrewmates:776867489866711041>'
whitecrew = '<:whitecrewmates:776867529900425217>'
await msg1.add_reaction(redcrew)
await msg1.add_reaction(bluecrew)
await msg1.add_reaction(limecrew)
await msg1.add_reaction(whitecrew)
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) ==
try:
reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send('Sorry, you took too long to vote!')
else:
await ctx.send('hello')
def setup(bot):
bot.add_cog(games(bot))```
**DONT WORRY ABOUT THE INDENTS**
import random
#bot.command()
async def reaction_game(ctx):
reactions = [
'<:redcrewmates:776867415514153031>',
'<:bluecrewmates:776867439085617153>',
'<:limecrewmates:776867489866711041>',
'<:whitecrewmates:776867529900425217>'
]
winning_reaction = random.choice(reactions)
message = await ctx.send('some message')
for reaction in reactions:
await ctx.add_reaction(reaction)
def check(reaction, user):
return user == ctx.author and str(reaction) == winning_reaction
try:
reaction, user = await bot.wait_for('reaction_add', check=check, timeout=60.0)
await ctx.send('You reacted with the winning emoji')
except asyncio.TimeoutError:
await ctx.send('You took too long to react')
else:
await ctx.send('hello')
Assuming a command similar to this:
#bot.command()
async def test(ctx):
def check(r, u):
return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'
await ctx.send("React to this with ✅")
try:
reaction, user = await bot.wait_for('reaction_add', timeout=300.0, check=check)
except asyncio.TimeoutError:
await ctx.send('Timeout')
else:
await ctx.send('Cool, thanks!')
Is there any way to cancel that wait_for if the user sends the same command multiple times before actually reacting to the message? So the bot stop waiting for reactions on previously sent messages and only waits for the last one.
Would something like this work for you?
pending_tasks = dict()
async def test(ctx):
def check(r, u):
return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'
await ctx.send("React to this with ✅")
try:
if ctx.message.author in pending_tasks:
pending_tasks[ctx.message.author].close()
pending_tasks[ctx.message.author] = bot.wait_for('reaction_add', timeout=300.0, check=check)
reaction, user = await pending_tasks[ctx.message.author]
except asyncio.TimeoutError:
await ctx.send('Timeout')
else:
await ctx.send('Cool, thanks!')
You store all of the pending requests in a dict, and before creating another request you check if you are already have an existing task for this user, if you do you cancel it and create a new one