One place for hosting & domains

      How To Build a Telegram Quotes Generator Bot With Node.js, Telegraf, Jimp, and Pexels


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      In this tutorial, you will use Node.js, telegraf, jimp, and the Pexels API to build a Telegram chatbot that will send you a randomly selected image with a fact overlayed. A Telegram bot is a bot you can interact with using custom slash commands through your preferred Telegram client. You will create the bot through Telegram, and define its logic to select a random animal image and a fact on the animal using JavaScript.

      At the end of this tutorial you will have a Telegram chatbot that looks like the following:

      Imgur

      Once you’ve completed your bot, you will receive a fact about an animal whenever you send a custom Telegram slash command.

      Prerequisites

      In order to follow this tutorial the reader will need the following tools:

      This tutorial was verified with Node v12.18.2 and npm v6.14.8.

      Step 1 — Creating the Project Root Directory

      In this section, you will create the directory where you will build the chatbot, create a Node project, and install the required dependencies.

      Open a terminal window and create a new directory called facts-bot:

      Navigate into the directory:

      Create a directory named temp:

      With the command above, you created a directory named temp. In this directory, you will temporarily store the images that your bot will send to the user.

      Now, you’ll create a new Node.js project. Running npm’s init command will create a package.json file, which will manage your dependencies and metadata.

      Run the initialization command:

      To accept the default values, press ENTER to all prompts. Alternately, you can personalize your responses. To do this, review npm’s initialization settings in Step 1 of the tutorial How To Use Node.js Modules with npm and package.json.

      Open the package.json file and edit it:

      Now, you’ll update the properties in your package.json file. Replace the contents inside the file with the highlighted code:

      package.json

      {
        "name": "facts-bot",
        "version": "1.0.0",
        "description": "",
        "main": "main.js",
        "scripts": {
          "start": "nodemon main.js"
        },
        "author": "",
        "license": "ISC"
      }
      

      Here you changed the main and scripts properties. By changing the main property, you have set the application main file to main.js. This will inform Node the main.js file is the primary entry point to your program. In the scripts property you have have added a script named start, which allows you to set the command that is supposed to run when you start the application. Once you call the script the command nodemon will run the main.js file you will create in the next step.

      With your settings now defined in your package.json file, you will now create a file that will store your environment variables. In your terminal, create a file named .env:

      touch .env
      

      In your .env file, you will store your Telegram bot token and Pexels API key. A Telegram Bot token allows you to interact with your Telegram bot. The Pexels API key allows you to interact with the Pexels API. You will store your environment variables in a later step.

      This time, you’ll use npm to install the dependencies telegraf, dotenv, pexels, jimp, and uuid. You’ll also use the --save flag to save the dependencies. In your terminal, run the following command:

      • npm install telegraf dotenv pexels jimp uuid --save

      In this command, you have installed:

      • telegraf: a library that helps you develop your own Telegram bots using JavaScript or TypeScript. You are going to use it to build your bot.
      • dotenv: a zero-dependency module that loads environment variables from a .env file into process.env. You are going to use this module to retrieve the bot token and Pexels API key from the .env file you created.
      • pexels: a convenient wrapper around the Pexels API that can be used both on the server in Node.js and the browser. You are going to use this module to retrieve animal images from Pexels.
      • jimp: an image processing library written entirely in JavaScript for Node, with zero external or native dependencies. You are going to use this library to edit images retrieved from Pexels and insert a fact about an animal in them.
      • uuid: a module that allows you to generate RFC-compliant UUIDs in JavaScript. You are going to use this module to create a unique name for the image retrieved from Pexels.

      Now, install nodemon as a dev dependency:

      • npm install nodemon --save-dev

      nodemon is a tool that develops Node.js based applications by automatically restarting the Node application when it detects file changes in the directory. You will use this module to start and keep your app running as you test your bot.

      Note: At the time of writing these are the versions of the modules that are being used:telegraf : 4.3.0 ; dotenv : 8.2.0; pexels : 1.2.1 ;jimp : 0.16.1 ; uuid : 8.3.2; nodemon : 2.0.12.

      In this step, you created a project directory and initialized a Node.js project for your bot. You also installed the modules needed to build the bot. In the next step, you will register a bot in Telegram and retrieve an API key for the Pexels API.

      Step 2 — Registering Your Bot and Retrieving an API Key From the Pexels API

      In this section, you will first register a bot with BotFather, then retrieve an API key for the Pexels API. BotFather is a chatbot managed by Telegram that allows users to create and manage chatbots.

      Open your preferred Telegram client, search for @BotFather, and start the chat. Send the /newbot slash command and follow the instructions sent by the BotFather:

      Imgur

      After choosing your bot name and username you will receive a message containing your bot access token:

      Imgur

      Copy the bot token, and open your .env file:

      Save the Bot token in a variable named BOT_TOKEN:

      .env

      BOT_TOKEN = "Your bot token"
      

      Now that you have saved your bot token in the .env file, it’s time to retrieve the Pexels API key.

      Navigate to Pexels, and log in to your Pexels account. Click on the Image & Video API tab and create a new API key:

      Imgur

      Copy the API key, and open your .env file:

      Save the API key in a variable named PEXELS_API_KEY. Your .env should look like the following:

      .env

      BOT_TOKEN = "Your_bot_token"
      PEXELS_API_KEY = "Your_Pexels_API_key"
      

      In this section, You have registered your bot, retrieved your Pexels API key, and saved your bot token and Pexels API key in your .env file. In the next section, you are going to create the file responsible for running the bot.

      Step 3 — Creating the main.js File

      In this section, you will create and build out your bot. You will create a file with the label main.js, and this will contain your bot’s logic.

      In the root directory of your project, create and open the main.js file using your preferred text editor:

      Within the main.js file, add the following code to import the libraries you’ll use:

      main.js

      const { Telegraf } = require('telegraf')
      const { v4: uuidV4 } = require('uuid')
      require('dotenv').config()
      let factGenerator = require('./factGenerator')
      

      In this code block, you have required in the telegraf, the uuid, the dotenv module, and a file named factGenerator.js. You are going to use the telegraf module to start and manage the bot, the uuidmodule to generate a unique file name for the image, and the dotenv module to get your Telegram bot token and Pexels API key stored in the .env file. The factGenerator.js file will be used to retrieve a random animal image from Pexels, insert a fact about the animal, and delete the image after it’s sent to the user. You will create this file in the next section.

      Below the require statements, add the following code to create an instance of the bot:

      main.js

      . . .
      
      const bot = new Telegraf(process.env.BOT_TOKEN)
      
      bot.start((ctx) => {
          let message = ` Please use the /fact command to receive a new fact`
          ctx.reply(message)
      })
      

      Here, you retrieved and used the BOT_TOKEN that BotFather sent, created a new bot instance, and assigned it to a variable called bot. After creating a new bot instance, you added a command listener for the /start command. This command is responsible for initiating a conversation between a user and the bot. Once a user sends a message containing /start the bot replies with a message asking the user to use the /fact command to receive a new fact.

      You have now created the command handler responsible for starting the interaction with your chatbot. Now, let’s create the command handler for generating a fact. Below the .start() command, add the following code:

      main.js

      . . .
      
      bot.command('fact', async (ctx) => {
          try {
              ctx.reply('Generating image, Please wait !!!')
              let imagePath = `./temp/${uuidV4()}.jpg`
              await factGenerator.generateImage(imagePath)
              await ctx.replyWithPhoto({ source: imagePath })
              factGenerator.deleteImage(imagePath)
          } catch (error) {
              console.log('error', error)
              ctx.reply('error sending image')
          }
      })
      
      bot.launch()
      

      In this code block, you created a command listener for the custom /fact slash command. Once this command is triggered from the Telegram user interface, the bot sends a message to the user. The uuid module is used to generate the image name and path. The image will be stored in the /temp directory that you created in Step 1. Afterwards, the image path is passed to a method named generateImage() you’ll define in the factGenerator.js file to generate an image containing a fact about an animal. Once the image is generated, the image is sent to the user. Then, the image path is passed to a method named deleteFile in the factGenerator.js file to delete the image. Lastly, you launched your bot by calling the bot.launch() method.

      The main.js file will look like the following:

      main.js

      const { Telegraf } = require('telegraf')
      const { v4: uuidV4 } = require('uuid')
      require('dotenv').config()
      let factGenerator = require('./factGenerator')
      
      
      const bot = new Telegraf(process.env.BOT_TOKEN)
      
      bot.start((ctx) => {
          let message = ` Please use the /fact command to receive a new fact`
          ctx.reply(message)
      })
      
      
      bot.command('fact', async (ctx) => {
          try {
              ctx.reply('Generating image, Please wait !!!')
              let imagePath = `./temp/${uuidV4()}.jpg`
              await factGenerator.generateImage(imagePath)
              await ctx.replyWithPhoto({ source: imagePath })
              factGenerator.deleteImage(imagePath)
          } catch (error) {
              console.log('error', error)
              ctx.reply('error sending image')
          }
      });
      
      
      bot.launch()
      

      You have created the file responsible for running and managing your bot. You will now set facts for the animal and build out the bot’s logic in the factGenerator.js file.

      Step 4 — Creating the Fact Generator File and Building the Bot Logic

      In this section, you will create files named fact.js and factGenerator.js. fact.js will store facts about animals in one data source. The factGenerator.js file will contain the code needed to retrieve a random fact about an animal from a file, retrieve an image from Pexels, use jimp to write the fact in the retrieved image, and delete the image.

      In the root directory of your project, create and open the facts.js file using your preferred text editor:

      Within the facts.js file add the following code to create your data source:

      facts.js

      const facts = [
          {
              fact: "Mother pandas keep contact with their cub nearly 100% of the time during their first month - with the cub resting on her front and remaining covered by her paw, arm or head.",
              animal: "Panda"
          },
          {
              fact: "The elephant's temporal lobe (the area of the brain associated with memory) is larger and denser than that of people - hence the saying 'elephants never forget'.",
              animal: "Elephant"
          },
          {
              fact: "On average, males weigh 190kg and females weigh 126kg . They need this weight and power behind them to hunt large prey and defend their pride.  ",
              animal: "Lion"
          },
          {
              fact: "The Amazon river is home to four species of river dolphin that are found nowhere else on Earth. ",
              animal: "Dolphin"
          },
      ]
      
      module.exports = { facts }
      

      In this code block, you defined an object with an array containing facts about animals and stored in a variable named facts. Each object has the following properties: fact and animal. In the property named fact, its value is a fact about an animal, while the property animal stores the name of the animal. Lastly, you are exporting the facts array.

      Now, create a file named factGenerator.js:

      Inside the factGenerator.js file, add the following code to require in the dependencies you’ll use to build out the logic to make your animal image:

      factGenerator.js

      let { createClient } = require('pexels')
      let Jimp = require('jimp')
      const fs = require('fs')
      let { facts } = require('./facts')
      

      Here, you required in the pexels, the jimp, the fs module, and your facts.js file. You will use the pexels module to retrieve animal images from Pexels, the jimp module to edit the image retrieved from Pexels, and the fs module to delete the image from your file directory after it’s sent to the user.

      Below the require statements, add the following code to generate an image:

      factGenerator.js

      . . .
      
      async function generateImage(imagePath) {
        let fact = randomFact()
        let photo = await getRandomImage(fact.animal)
        await editImage(photo, imagePath, fact.fact)
      }
      

      In this code block, you created a function named generateImage(). This function takes as an argument the path of the Pexel image in your file directory. Once this function is called a function named randomFact() is called and the value returned is stored in a variable named fact. The randomFact() function randomly selects an object in the facts.js file. After receiving the object, its property animal is passed to a function named getRandomImage(). The getRandomImage() function will use the pexels module to search for images containing the name of the animal passed, and selects a random image. The value returned is stored in a variable named photo. Finally, the photo, imagePath, and the fact property from the facts.js file are passed to a function named editImage(). The editImage() function uses the jimp module to insert the random fact in the random image and then save the edited image in the imagePath.

      Here, you have created the function that is called when you send the /fact slash command to the bot. Now you’ll create the functions getRandomImage() and editImage() and construct the logic behind selecting and editing a random image.

      Below the generateImage() function, add the following code to set the randomization logic:

      factGenerator.js

      . . .
      
      function randomFact() {
        let fact = facts[randomInteger(0, (facts.length - 1))]
        return fact
      }
      
      
      function randomInteger(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      

      You have now created the functions randomFact() and randomInteger(). The randomFact() function selects a random fact in the facts.js file by calling the randomInteger() function, and returns this object. The randomInteger() function returns a random integer in the interval of 0 and the number of facts in the facts.js file.

      Now that you’ve defined functions to return a random fact and random integer, you’ll need to create a function to get a random image from Pexels. Below the randomInteger() function, add the following code to get a random image:

      factGenerator.js

      . . .
      
      async function getRandomImage(animal) {
        try {
          const client = createClient(process.env.PEXELS_API_KEY)
          const query = animal
          let image
      
          await client.photos.search({ query, per_page: 10 }).then(res => {
            let images = res.photos
            image = images[randomInteger(0, (images.length - 1))]
      
          })
      
          return image
      
        } catch (error) {
          console.log('error downloading image', error)
          getRandomImage(animal)
        }
      }
      

      In this code block, you have created a function named getRandomImage(). This function takes as an argument an animal name. When this function is called a client object is created by using createClient() method object from the pexels module and the Pexels API key stored in the .env file. The animal name is stored in a variable called query, then the client object is used to search for images containing the value in the query. Once the images are found, a random image is selected with the help of the randomInteger() function. Finally, the random image is returned to the generateImage() method in your main.js file.

      With your getRandomImage() function in place, the image selected needs to have a text overlay before it’s sent to your Telegram bot. Below the getRandomImage() function, add the following code to set the overlay:

      factGenerator.js

      . . .
      
      async function editImage(image, imagePath, fact) {
        try {
          let imgURL = image.src.medium
          let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
          let animalImageWidth = animalImage.bitmap.width
          let animalImageHeight = animalImage.bitmap.height
          let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
          imgDarkener = await imgDarkener.opacity(0.5)
          animalImage = await animalImage.composite(imgDarkener, 0, 0);
      
      
        } catch (error) {
          console.log("error editing image", error)
        } 
      
      }
      
      

      Here, you created a function named editImage(). This function takes as arguments a random animal labeled image, the imagePath, and a fact about this random animal. In the variable imgURL, the URL for the medium size of the image is retrieved from the Pexels API. Afterwards the read() method of jimp is used to load the image. Once the image is loaded and stored in a variable named animalImage, the image width and height are retrieved and stored in the variables animalImageWidth and animalImageHeight respectively. The variable imgDarkener stores new instance of Jimp() and darkens the image. The opacity() method of jimp is used to set imgDarkener’s opacity to 50%. Finally, the composite() method of jimp is used to put the contents in imgDarkener over the image in animalImage. This in return makes the image in animalImage darker before adding the text stored in the fact variable, and make the text visible over the image.

      Note: Jimp by default provides a method named color() that allows you to adjust an image’s tonal levels. For the purpose of this tutorial, you’ll write a custom tonal adjuster as the color() method does not offer the precision necessary here.

      At the bottom of the try block inside the editImage() function, add the following code:

      factGenerator.js

      . . .
      
      async function editImage(image, imagePath,fact) {
        try {
          . . .
      
          let posX = animalImageWidth / 15
          let posY = animalImageHeight / 15
          let maxWidth = animalImageWidth - (posX * 2)
          let maxHeight = animalImageHeight - posY
      
          let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
          await animalImage.print(font, posX, posY, {
            text: fact,
            alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
            alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
          }, maxWidth, maxHeight)
      
          await animalImage.writeAsync(imagePath)
          console.log("Image generated successfully")
      
      
        } catch (error) {
          . . .
        }
      }
      
      

      In this code block, you used the animalImageWidth, and animalImageHeight to get the values that will be used to center the text in the animalImage. After, you used the loadFont() method of jimp to load the font, and store the font in a variable named font. The font color is white, the type is sans-serif (SANS), and the size is 16. Finally, you used the print() method of jimp to insert the fact in the animalImage, and the write() method to save the animalImage in the imagePath.

      Now that you’ve created the function responsible for editing the image, you’ll need a function to delete the image from your file structure after it is sent to the user. Below your editImage() function, add the following code:

      factGenerator.js

      . . .
      
      const deleteImage = (imagePath) => {
          fs.unlink(imagePath, (err) => {
              if (err) {
                  return
              }
              console.log('file deleted')
          })
      }
      
      
      module.exports = { generateImage, deleteImage }
      

      Here, you have created a function named deleteImage(). This function takes as an argument the variable imagePath. Once this function is called, the fs module is used to delete the image stored in the variable imagePath. Lastly, you exported the generateImage() function and the deleteImage() function.

      With your functions in place, the factGenerator.js file will look like the following:

      factGenerator.js

      let { createClient } = require('pexels')
      let Jimp = require('jimp')
      const fs = require('fs')
      let { facts } = require('./facts')
      
      async function generateImage(imagePath) {
        let fact = randomFact()
        let photo = await getRandomImage(fact.animal)
        await editImage(photo, imagePath, fact.fact)
      }
      
      
      function randomFact() {
        let fact = facts[randomInteger(0, (facts.length - 1))]
        return fact
      }
      
      
      function randomInteger(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      
      
      async function getRandomImage(animal) {
        try {
          const client = createClient(process.env.PEXELS_API_KEY)
          const query = animal
          let image
      
          await client.photos.search({ query, per_page: 10 }).then(res => {
            let images = res.photos
            image = images[randomInteger(0, (images.length - 1))]
      
          })
      
          return image
      
        } catch (error) {
          console.log('error downloading image', error)
          getRandomImage(animal)
        }
      }
      
      
      async function editImage(image, imagePath, fact) {
        try {
          let imgURL = image.src.medium
          let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
          let animalImageWidth = animalImage.bitmap.width
          let animalImageHeight = animalImage.bitmap.height
          let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
          imgDarkener = await imgDarkener.opacity(0.5)
          animalImage = await animalImage.composite(imgDarkener, 0, 0);
      
          let posX = animalImageWidth / 15
          let posY = animalImageHeight / 15
          let maxWidth = animalImageWidth - (posX * 2)
          let maxHeight = animalImageHeight - posY
      
          let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
          await animalImage.print(font, posX, posY, {
            text: fact,
            alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
            alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
          }, maxWidth, maxHeight)
      
          await animalImage.writeAsync(imagePath)
          console.log("Image generated successfully")
      
        } catch (error) {
          console.log("error editing image", error)
        }
      
      }
      
      
      const deleteImage = (imagePath) => {
        fs.unlink(imagePath, (err) => {
          if (err) {
            return
          }
          console.log('file deleted')
        })
      }
      
      
      module.exports = { generateImage, deleteImage }
      
      

      Save your factGenerator.js file. Return to your terminal, and run the following command to start your bot:

      Open your preferred Telegram client, and search for your bot. Send a message with the /start command to initiate the conversation, or click the Start button. Then, send a message with the /fact command to receive your image.

      You will receive an image similar to the following:

      Imgur

      You now see the image in your preferred Telegram client with a fact imposed over the image. You’ve created the file and functions responsible for retrieving a random fact from the facts.js file, retrieving an animal image from Pexels, and inserting a fact onto the image.

      Conclusion

      In this tutorial, you built a Telegram chatbot that sends an image of an animal with a fact overlayed through a custom slash command. You created the command handlers for the bot through the telegraf module. You also created functions responsible for retrieving a random fact, random images from Pexels using the pexels module, and inserting a fact over the random image using the jimp module. For more information about the Pexels API, telegraf and jimp modules please refer to documentation on the Pexels API, telegraf, jimp.



      Source link

      Building a Discord Bot in Python


      How to Join

      This Tech Talk is free and open to everyone. Register below to get a link to join the live stream or receive the video recording after it airs.

      DateTimeRSVP
      September 8, 202111 a.m.–12 p.m. ET / 3–4 p.m. GMT

      About the Talk

      Discord is becoming an ever more popular tool for open source communities to connect. Discord isn’t just a great chat and voice app, it also has a rich ecosystem for extending and building bots. Get an overview of the Discord Python library, how Discord handles events, and build your first Discord bot!

      What You’ll Learn

      How to build and deploy your very own Discord bot

      This Talk Is Designed For

      Developers who want to build discord bots

      Resources

      Discord Developer Documentation
      Discord API Documentation
      DigitalOcean Droplets + Docs
      DigitalOcean App Platform + Docs

      To join the live Tech Talk, register here.



      Source link

      How To Build a Discord Bot in Python on Ubuntu 20.04


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Discord is a popular voice and text messaging platform used by gamers, open-source communities, conference organizers, and more. It has gained popularity due to features like superb voice chat, various text channels, and extensibility using automated assistants or “bots.”

      In this guide, you will build a Discord bot using the Python programming language and deploy it to an Ubuntu 20.04 server. You’ll be using the Discord Python library, discord.py, to program your bot.

      Note: Discord has two different names for their chat/voice rooms. They refer to these as both Servers and Guilds, depending on where you are in the documentation. For this tutorial, we will use the term Guild. Just know that these terms can be used interchangeably and often are in the official Discord documentation.

      Prerequisites

      To complete this tutorial, you’ll need:

      Step 1 — Creating a Bot User For Your Discord Guild

      Before you start coding, you need to create and register your bot in the Discord developer portal.

      Sign in to the developer portal and click on the New Application button to start the process. A Discord application allows you to interact with the Discord API. Bots are bound to applications; that is how they function.

      Click the New Application Button

      Next, add a name for the application in the modal and press the Create button. For this tutorial, we’ll name ours SammySharkBot.

      Name Your Application

      Discord will create your application. Next, you’ll note a page with information regarding your bot. You can choose to add a picture to serve as an icon for your bot. Click on the Choose a Neat Icon button in the App Icon section of the page. This is not required.

      Add an optional icon for your bot

      If you did upload an icon, you’d note a dialog box prompting you to save your changes. Press Save Changes to save your icon.

      Save your changes

      Now that you’ve set up your application, it’s time to create a bot that is associated with the application. Navigate to the Bot link in the Settings navigation pane on the left-hand side of the screen.

      Add a bot to your application

      Now click the Add Bot button to add the bot to your application.

      Confirm the creation of the bot

      Once you’ve done that, a Bot will appear with the optional icon you set up earlier. Remember this page; you’ll need to come back to it later to retrieve the API Token.

      Bot confirmation page

      You’ll be prompted with a modal that states Adding a bot user gives your app visible life in Discord. However, this action is irrevocable! Choose wisely. Go ahead and press Yes, do it! to create the bot user.

      Next, navigate to the OAuth2 link in the Settings navigation pane on the left-hand side of the screen. You need to add the appropriate permissions so your bot can function properly.

      Navigate to OAuth2 menu

      You’ll need to add the scopes in which your bot can function. Only check the bot option because that’s all you want this bot to do. For more information about the other scopes, visit the Discord OAuth2 Documentation.

      Add bot designation

      Now scroll down and give your bot the following permissions: View Channels, Send Messages, Read Message History. This will give your bot a limited set of actions that it can perform. If you want to create a bot with no restrictions, you can select the Administrator option; this is not recommended.

      Once you have done this, a Discord URL followed by a Copy button will appear. Click that button to copy the link and open it in a new window in your browser.

      Add bot permissions and copy the link

      A prompt will appear for your bot to connect your Guild. You may have permission to install bots in multiple Guilds, so you may note more than one here. Select the Guild you wish to install your bot into and click Authorize.

      Add bot to your Guild

      Before a bot is added to your Guild, Discord shows you all the permissions the bot will have. This ensures that you are aware of what you are installing. If you don’t want the bot to have a specific permission, you can uncheck it. However, don’t do that for this bot because the bot won’t work otherwise. Click Authorize to accept and add the bot to your Guild.

      Authorize bot permissions

      Go back to your Guild and check the channel where posts about new members appear. You will note that your bot joined your Guild. Your bot will also appear in the member list on the right-hand side, although the bot will appear offline; this will change after you start the bot code.

      Check if your bot joined your guild

      Now that your bot is added to your Guild, you are ready to bring it to life with some Python code.

      Step 2 — Creating a Python Virtual Environment for Your Project

      Before you get started coding, you need to set up your Python developer environment. In this step, you will install and activate your Python requirements within a virtual environment for easier management.

      First, create a directory in your home directory that you can use to store all of your virtual environments:

      Now create your virtual environment using Python:

      • python3 -m venv ~/.venvs/discord

      This will create a directory called discord within your .venvs directory. Inside, it will install a local version of Python and a local version of pip. You can use this to install and configure an isolated Python environment for your project.

      Before you install your project’s Python requirements, activate the virtual environment:

      • source ~/.venvs/discord/bin/activate

      Your prompt should change to indicate that you are now operating within a Python virtual environment. It will look something like this: (discord)user@host:~$.

      With your virtual environment active, install discord.py with the local instance of pip:

      Note: Once you have activate your virtual environment (when your prompt has (discord) preceding it), use pip instead of pip3, even if you are using Python 3. The virtual environment’s copy of the tool is always named pip, regardless of the Python version.

      Now that you have the Discord package installed, you will need to save this requirement and its dependencies. This is good practice so you can recreate your developer environment as needed.

      Use pip to save your environment’s information to a requirements.txt file:

      • pip freeze > requirements.txt

      You now have the libraries necessary to build a discord bot.

      Step 3 — Building a Minimal Discord Bot

      You will now begin coding your Discord bot. Once completed, your bot will listen for certain phrases shared in a text chat, and then it will respond to them accordingly. Specifically, your bot will flip a coin on behalf of the users.

      In this step, you will build a minimal version of your bot. You will then add more functionality in Step 4 and Step 5.

      To begin, open a file named bot.py in your preferred text editor:

      Now add the following imports to the file: os, random, and discord. The os library will allow you to read valuable information, such as API Tokens and Guild Name from your environment variables. The random library will allow you to generate the output for your random events. And the discord library will provide you with the methods, objects, and decorators required to interact with the discord API. The code is as follows:

      bot.py

      import os
      import random
      import discord
      

      Next, you will need to retrieve the Discord API token and your bot’s guild from environment variables. You’ll use the method getenv from the os library in the Python standard library. Append the following code to bot.py:

      bot.py

      ...
      
      token = os.getenv("DISCORD_TOKEN")
      my_guild = os.getenv("DISCORD_GUILD")
      

      In version 1.5 of discord.py, Intents were introduced. This was a breaking change from prior versions of Discord libraries that allowed bots to subscribe to certain events that happen within the Guild. For this tutorial, you’ll set the client’s available intents to default, but you may need to revisit if you plan on interacting with the GUILD_PRESENCES or GUILD_MEMBERS intents. These are Privileged Gateway Intents.

      Append the following code to bot.py to properly set up the intents:

      bot.py

      ...
      
      intents = discord.Intents.default()
      client = discord.Client(intents=intents)
      

      Now, let’s write some code that responds to an event in Discord. Events are actions that happen on the Discord Guild, such as sending a message or joining a channel. For a full list of supported events, check the Discord Event Reference API.

      The first segment of code will activate on the on_ready event. This event triggers when your bot loads into a Guild. Note that the Discord API does not guarantee that this event only happens once. If you are planning on putting code here that should only run once, do some checks to ensure that it indeed only executes once.

      You’ll write a print statement that prints when your bot has successfully connected to your Guild. Discord bots require the use of async methods so that the bot sits in a ready state and waits for calls.

      Append the following code to the end of bot.py:

      bot.py

      ...
      
      @client.event
      async def on_ready():
          for guild in client.guilds:
              if guild.name == my_guild:
                  break
      
          print(
              f"{client.user} is connected to the following guild:n"
              f"{guild.name}(id: {guild.id})"
          )
      

      You use a for loop to find your Guild among all available Guilds, and then you print information about the Guild and your connection to it.

      Finally, you need to tell the client to run when the script is executed using your API token. Append the following line to bot.py to run your bot:

      bot.py

      ...
      
      client.run(token)
      

      At this point, your code should look like this:

      bot.py

      import os
      import random
      import discord
      
      token = os.getenv("DISCORD_TOKEN")
      my_guild = os.getenv("DISCORD_GUILD")
      
      intents = discord.Intents.default()
      client = discord.Client(intents=intents)
      
      @client.event
      async def on_ready():
          for guild in client.guilds:
              if guild.name == my_guild:
                  break
      
          print(
              f"{client.user} is connected to the following guild:n"
              f"{guild.name}(id: {guild.id})"
          )
      
      client.run(token)
      

      You have just written the skeleton code that will allow your bot to connect to a Guild. Now you will test your bot’s basic functionality.

      Step 4 — Testing Your Bot Locally

      Before you code any more, check that your bot can connect to Discord. Navigate back to the discord developer panel and click on the Bot link in the navigation bar on the left. From here, locate the Token underneath the bot username and click the Copy button to copy the token to your clipboard.

      Get Bot Token

      Once you have copied the token, return to the terminal with your activated virtual environment. Export the Discord token so it is available in the environment variables for your bot to read on startup:

      • export DISCORD_TOKEN=YOUR_DISCORD_TOKEN

      Now you need to get the Guild name that your bot will join. Navigate to your Discord Guild. The Guild name should be in the top left-hand corner of your Guild page. This was the name you chose when you created a Guild in the prerequisites section.

      Get Guild Name

      Now, export the Discord Guild so it is available in the environment variables for your bot to read on startup:

      • export DISCORD_GUILD=YOUR_DISCORD_GUILD

      Now that you have exported the necessary environment variables, you are ready to test your bot:

      Run the application:

      It might take a few seconds, but you will receive an output like this. Note that your bot number and id will differ:

      Output

      SammySharkBot#8143 is connected to the following Guild: SammyShark(id: 801529616116350998)

      Navigate back to your Discord Guild and you will note that your bot now has a green circle near its name. This indicates that the bot is online.

      Verify your bot is online

      You may notice in your terminal that your code does not terminate. This is because the bot is a constantly running process. To stop your bot at any time, press the CTRL + C key combo.

      Step 5 — Extending the Discord Bot to Perform Random Tasks

      Now that your bot is working, it’s time to extend its functionality. For your bot to respond to messages sent in the text chat, you’ll need to listen to the on_message event. This function takes in one argument, message, which contains the message object, including various attributes and methods for responding to messages.

      One thing that you’ll need to ensure is that your bot doesn’t answer itself. If the bot were to interpret its own message as a trigger, then it would create an infinite loop. To avoid this, check that the user sending the message isn’t the bot.

      Append the following code to bot.py to declare the on_message function and to check who sent the message:

      bot.py

      ...
      @client.event
      async def on_message(message):
          if message.author == client.user:
              return
      

      Lastly, add the code to flip the coin. You will also perform a string manipulation on the message content to lower case (or upper, if you prefer) so you don’t have to worry about matching exact case in strings. Use the randint() function in the Python random library to simulate flipping a coin. Finally, once you have crafted a message, you will send it to the channel using the method for sending a message. Remember, this is asynchronous programming, so you’ll have to use the await keyword when sending the message.

      Append the following code to bot.py within the on_message function; this will add the coin-flipping functionality:

      bot.py

          message_content = message.content.lower()
          if "flip a coin" in message_content:
              rand_int = random.randint(0, 1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
              await message.channel.send(results)
      

      What follows is the finished code for the bot. Ensure that your code looks like this, or copy and paste this code:

      bot.py

      import os
      import random
      import discord
      
      token = os.getenv("DISCORD_TOKEN")
      my_guild = os.getenv("DISCORD_GUILD")
      
      intents = discord.Intents.default()
      client = discord.Client(intents=intents)
      
      
      @client.event
      async def on_ready():
          for guild in client.guilds:
              if guild.name == my_guild:
                  break
      
          print(
              f"{client.user} is connected to the following guild:n"
              f"{guild.name}(id: {guild.id})"
          )
      
      
      @client.event
      async def on_message(message):
          if message.author == client.user:
              return
      
          message_content = message.content.lower()
          if "flip a coin" in message_content:
              rand_int = random.randint(0, 1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
              await message.channel.send(results)
      
      client.run(token)
      

      Now that the bot is finished, it’s time to test it. Save and close the file.

      Rerun the app:

      After the app connects to your Guild, navigate to the #general channel in your Discord Guild. Type flip a coin in the text chat, and the bot will respond with either Heads or Tails.

      Your bot should respond with Heads or Tails

      Now that you have confirmed that your bot is functional, you are ready to deploy it to production on an Ubuntu 20.04 server.

      Step 6 — Deploying to Ubuntu 20.04

      You can leave your bot running from your local machine, but having to leave a terminal active or worry about power outages can be annoying. For convenience, you can deploy it to a server.

      It is best practice to run your bot as a non-root user. This tutorial uses the username sammy.

      First, copy your code and Python library requirements to the server using the scp command. Send everything to your user’s root directory:

      • scp bot.py requirements.txt sammy@your_server_ip:~

      Next, ssh into your server:

      You will now enter commands into the server’s terminal.

      You need to install the proper Python system packages to run your bot on your server.

      Install python3, python3-venv, and screen:

      • sudo apt update && sudo apt install python3 python3-venv screen

      Now, you’re going to use a tool called screen to create a virtual terminal. Without this tool, if you were to exit your terminal while the bot was running, the process would terminate, and your bot would go offline. With this tool, you can connect and disconnect to sessions so your code remains running. To learn more about screen, check out our tutorial on installing and using screen.

      To start a screen session, use the following command:

      screen will prompt you with a license agreement. Press Return to continue.

      Now that you have a virtual session set up, you need to create a Python virtual environment to run your code.

      First, like before, create a directory to store your virtual environments:

      Then create a new virtual environment:

      • python3 -m venv ~/.venvs/discord

      Activate the virtual environment:

      • source ~/.venvs/discord/bin/activate

      Next, install the necessary libraries using pip:

      • pip install -r requirements.txt

      Before you can run your bot, you’ll need to export the DISCORD_TOKEN and DISCORD_GUILD so your bot can access the API Key and Guild information:

      • export DISCORD_TOKEN=YOUR_DISCORD_TOKEN
      • export DISCORD_GUILD=YOUR_DISCORD_GUILD

      Finally, run your bot:

      Your bot will start up and start accepting messages. You can disconnect from the screen session using the key combination CTRL + A + D. When you are ready to reconnect to the session, you can use this screen command:

      You have successfully built a Discord bot using Python. The application runs on a server and responds to certain phrases shared in a Guild.

      Conclusion

      In this tutorial, you set up a Discord Guild, built a Discord bot, installed the bot in your Guild, and deployed the bot to an Ubuntu 20.04 server. You’ve only begun to explore the Discord API. Bots are powerful and extendable. To explore other capabilities, check out the discord.py API docs.

      Alternately, if you wish learn more about Python programming, visit our tutorial series, How To Code in Python 3.



      Source link