Building a Discord Chatbot with Python (5) - Adding a 'Fortune Telling' Feature

In this article, we’ll expand our chatbot by enabling it to respond to user messages.
We’ll also introduce a fun ‘Fortune Telling’ feature to our chatbot.

As of our previous session, our chatbot can now receive user messages in a chat.
Here’s what our chatbot.py script currently looks like:

import discord


class MyClient(discord.Client):
    async def on_ready(self):
        """Triggered when connecting to Discord."""
        print(f'Connected as {self.user}.')

    async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        print(f'Received a message from {message.author}: {message.content}')


with open('.discord_token') as f:
    token = f.read().strip()

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)

Let’s now enable our chatbot to reply to user messages within the on_message method.
But there’s something we should be wary of:

Think about this:

Question
What would happen if we replaced the print function within on_message with a function that sends a message?




















The answer is, “an infinite message loop would occur.”

Since the on_message function also gets triggered by messages the bot sends, it could endlessly respond to its own messages.

To prevent this infinite loop, we’ll insert a condition at the start of on_message to check if the message sender is the bot.

async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return
    ...

To allow our bot to reply, we’ll use the message.channel.send method.

Let’s modify the on_message function:

async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return

        print(f'Received a message from {message.author}: {message.content}')
        await message.channel.send(f'Hello, {message.author}!')

Since the message.channel.send method is a coroutine function, you should prefix it with await when calling it.
(We’ll delve deeper into the coroutine concept in upcoming sessions.)

Execute the script with:

python chatbot.py

Upon sending a message, you should see the bot replying, as shown below:

With the ability to respond to messages, we can now integrate various functionalities into the on_message function.
Let’s start by introducing a ‘Fortune Telling’ feature.

Here are the specifications for this feature:

  • It gets triggered with the !omikuji message.
    (“Omikuji” is a traditional Japanese fortune-telling method where individuals draw random fortunes written on paper strips.These fortunes range from “Great Blessing” to “Great Misfortune” and provide insights or guidance for the person’s future.)
  • It randomly selects and returns one result from the following options: “Great Blessing”, “Blessing”, “Small Blessing”, “Misfortune”, or “Great Misfortune”.

Let’s proceed with the implementation. Add import random at the beginning of chatbot.py and modify on_message as follows:

async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return

        print(f'Received message from {message.author}: {message.content}')

        if message.content == '!omikuji':
            choice = random.choice(["Great Blessing", "Blessing", "Small Blessing", "Misfortune", "Great Misfortune"])
            await message.channel.send(f"Your fortune for today is: **{choice}**!")

Run the code again, and type !omikuji. The bot should respond with your fortune for the day, as seen below:

Today, we’ve enhanced our chatbot to respond to messages and added a ‘Fortune Telling’ feature.

While this session was centered around a single interaction between the user and the chatbot,
in our next segment, we’ll delve into creating multi-turn interactions.
This will pave the way for adding a ‘Quiz’ feature to our chatbot.

import discord
import random


class MyClient(discord.Client):
    async def on_ready(self):
        """Triggered when connecting to Discord."""
        print(f'Connected as {self.user}.')

    async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return

        print(f'Received a message from {message.author}: {message.content}')

        if message.content == '!omikuji':
            choice = random.choice([
                "Great Blessing", "Blessing", "Small Blessing",
                "Misfortune", "Great Misfortune"
            ])
            await message.channel.send(
                f"Your fortune for today is: **{choice}**!"
            )


with open('.discord_token') as f:
    token = f.read().strip()

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)

Related Content