Code Repo. Recording (note: after 1 hour stuff it’s just random student questions but not related to the workshop itself)

We all started using online chatting applications more than ever before to communicate with our families, friends, and even classes and work with the pandemic. What if we could make cool bots for these chats? Facebook bots for stores, Discord bots for your friends, or Slack bots for your clubs and jobs. The possibilities are endless.

If you’ve never done python before, here’s a start. Coming from Java or C++, this might seem almost underwhelming, but python allows you to do so many of the same things with a lot less work. This brevity does have disadvantages, but this trait of python makes it an excellent language for trying new ideas and adding to them quickly.

print("Hello Chatbots")

Hosted by: Harsh Deep

Motivation

Learn Python the Hard Way - This is advice I honestly feel everyone new to CS should read and follow.

Keeping that in mind, for this website:

How to Learn Programming the Proper Way

  • Every single piece of code that I show, you will type by hand. No copy-pasting, no “I can see what it does, it’s obvious,” no “I already know this, let me move on.” I want you to do this to make sure that you process what we’re learning together. You can only copy-paste if I tell you that you can. Trust me. It may feel like a slight difference, but not following along like this will reduce your learning tenfold.
  • Attention to detail: this comes from the last point, but when you type everything out yourself and look at it closely, you’re forced to concentrate on what you’re doing. For example, consider the difference between 5 and "5". Programming is exact, and errors like these can create bugs that can be very difficult to track down if you’re not prepared for them, especially in languages like python, every tiny detail matters.

Tools

Set this up before we start.

  • VSCode - Here’s our written guide, but the internet also has a lot of information on it if you need it.

  • git - install it locally and enter $ git --version into the terminal/command line to make sure that it’s installed.

  • Github - create an account if you don’t have one already.

Getting Ready

You should finish this part before the workshop, but don’t worry if you’re not done since we’re recording everything. All the material is available as text on the website as well.

  1. Submit the initial form, which gives us an idea of who all are here. All the forms we’re taking (initial form, final form, project forms) will be for internally tracking how we can improve our content and giving you personalized responses. We might even make some fun visualizations in the end.

  2. If you’re on Windows, I highly recommend getting WSL2 (WSL1 is also acceptable, just slower). For historical reasons, the command line in Windows isn’t as good as that of Mac or Linux. Eventually, they just said, “Hey what if we had full Linux on Windows?” Thus, WSL. We will use the command line a fair amount here, so it’s an excellent idea to set it up.

  3. Install a recent version of python (3.7+) on your computer and make sure to enable pip as well.
    • Windows Guide (select installer and make sure to add to PATH). This guide is pretty useful too.
    • MacOS Guide or try homebrew with brew install python
    • Linux Gudide or try your distro package installer
    • Do python –version to check which you got. If it says 2.x, then you will have to use python3 scriptname.py and pip3; otherwise, you’ll end up using older versions of stuff.
  4. Set up VSCode or a different code editor of your choice. See the page we wrote for VSCode for help.

  5. Install discord.py.

     $ pip install discord.py
     [install output]
    
  6. Create an account on Discord if you don’t have one already. The principles of making chatbots are the same regardless of platform, but Discord has one of the best support.

  7. Create a test server on Discord (sometimes called a guild) that you will add your bot to. You can add the bot to a real server once it’s working well, but this is good for debugging. Here’s a guide.

Workshop

First, we’ll create a new folder for the project by typing this into your command line. In general, if there is a $ before a code line, it means that you should run it on your command line. This $ is a convention not just for this site but for programming tutorials in general.

$ mkdir first_discord_bot
$ cd first_discord_bot

mkdir stands for make directory (another word for folder). This command is how we create a folder in our current directory.

cd stands for change directory. Here, we’ve already created a folder, and now we’re just entering it. The command-line prompt can only point to one folder at a time, so this is how we change where it’s pointing.

We set up git in the folder to transform our project into a git repository.

$ git init

You’ve probably seen git before. It adds time travel powers to your work. git lets you put your code on sites like Gitlab, Github and sr.ht.

Now let’s get started with the coding. Let’s open VSCode:

$ code .

Note: Don’t worry too much about the command line or git just yet. More on that next week :)

Getting the Bot Token

Note: This tutorial also has a good section on getting the Discord bot token.

  1. Go to the Discord applications page on your web browser.

  2. Click on “New Application” and give it a nice name that you can recognize. Feel free to provide an icon, too, if you want.

  3. Go to the Bot page on the side tab and click ‘Add Bot’. This page is for the bot that we’ll be coding that the users will see. Feel free to change its username, but the default one should be fine.

  4. Scroll down to ‘TOKEN’ and click the ‘Copy’ button. This token is like your bot’s password, and it’s required for your bot to log in. Tokens are a typical pattern when dealing with APIs and external services (like Discord here). If your token is leaked, make sure to reset it.

  5. The important thing is that you should never, ever share this token. One classic mistake people make is accidentally adding it on their online Git repository or storing somewhere that someone can inspect the browser state for it. This paper explains how hundreds of thousands of codebases have made this mistake. We’ll put the token in a separate file and read it from there to deal with this.

  6. Now, we’ll make the file for the token. In VSCode, create a file called BOT_TOKEN.txt and paste the token into it. Make sure the file only has one line for the token.

  7. Create a file called .gitignore. In the first line, add BOT_TOKEN.txt. This file tells git to avoid this file and make sure that your token doesn’t end up on the public internet. Once your repo is online, make sure to doublecheck yourself that your token isn’t there just in case.

Adding the Bot to the Test Server

First, we need to generate an invite link to add our bot user to our server. To handle this, we’ll use OAuth2, a typical web standard for managing authentication and identity on the internet.

  1. Go back to the Discord developers page. Go to the ‘OAuth2’ tab.

  2. Under ‘OAuth2 URL Generator’, go to ‘Scopes’ and select the ‘bot’ checkbox.

  3. Now, we have to figure out the list of permissions for our bot. For your actual bot, I highly suggest taking the time to understand this so you can give it the permissions you need, but for the workshop, check off “View Channels” under “General Permissions” and ‘Send Messages’ under ‘Text Permissions’.

  4. Based on what you checked off, the invite URL should have updated. Hit ‘Copy’ and paste it in a new tab on your browser.

  5. The page will ask you which server to add the bot, and you should pick your test server that we created earlier.

That’s all the setup done. Now let’s get to coding!

Idea bot

The whole point of this eight-week program is to learn how to make projects from start to finish. However, ideas are hard, so for now, how about we make a Discord bot that can give us ideas? We could just type !idea, and the bot will appear and give us an excellent starting point to get moving. Let’s get started with bot.py as shown below.

from discord.ext import commands

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

with open("BOT_TOKEN.txt", "r") as token_file:
    TOKEN = token_file.read()
    print("Token file read")
    bot.run(TOKEN)

discord.py is the library that handles many network heavy lifting, allowing us to focus on the bot logic itself. We’re using the commands module, making it easy to create command bots (bots that respond to commands).

The command_prefix option lets us pick how the bot’s commands will be called. So if our prefix is $ and our command is version, then we’d type $version into the chatbox to call the bot.

Now let’s try running it:

$ python bot.py

(Some systems might need python3 instead of based on your installation)

If this runs with the only output as Token file read, then the login worked. If you got an error like discord.errors.LoginFailure, there was something wrong with the token you set up, and I suggest going over the above steps again. When you’re done running it, you can hit ctrl+c to exit.

Now let’s start working on our command.

from discord.ext import commands

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

@bot.command(name="idea")
async def idea(ctx):
    await ctx.send("Ideas are hard")

with open("BOT_TOKEN.txt", "r") as token_file:
    TOKEN = token_file.read()
    print("Token file read")
    bot.run(TOKEN)

Don’t worry if you don’t fully understand the syntax just yet. This new function combines quite a bit of python syntax that you might have seen here or there. Still, if you try reading it, you can figure out what this code does. Let’s go over it together.

The first concept is decorators. Decorators modify the behavior of a function without changing anything from the inside. Here, the decorator says that this function called idea is a particular function that should be called when the discord bot sees !idea in the chat. Check out DataCamp - Decorators in Python to learn more.

async is a keyword that indicates that this function can run asynchronously. await tells the program that it can do other things in the meantime while waiting on this command, which is helpful if the given code might take a while or if the program will need to wait for the command to execute. The rule of thumb is that if you want to call an async function, then you should await before calling it. If your function uses await in the body, you add async to the function signature.

Async+Await combo means we can run this command and then suspend it to do other things and come back. This type of programming is a key concept in computer science called concurrency, and it’s a pretty complicated idea. Here are some links so that you can learn more about it: Python docs - asyncio and Real Python - Async IO.

ctx is a variable that stands for context, and this abbreviation is a standard convention for context in programming. Using ctx.send() can send messages into the chat, but you can do lots of things with the context variable to interact with the chatroom.

Anyways, let’s run the program and leave it running. When you’re done, you can hit ctrl+c to exit.

$ python bot.py

Now, if you go to your test server, the server should show your bot as online. If you type in !idea, you will get back Ideas are hard. If this works, that means our basic Discord bot is working so far. Now let’s flesh out the function a little.

from discord.ext import commands
import random

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

@bot.command(name="idea")
async def idea(ctx):
    await ctx.send("Ideas are hard")
    await ctx.send("Worry not, I think you should...")

    topics = ['chat bot', 'cli', 'game', 'web bot', 'browser extention', 'api', 'web interface']
    areas = ['note taking', 'social life', 'physical fitness', 'mental health', 'pet care']

    idea = f'Create a new {random.choice(topics)} that helps with {random.choice(areas)}! :slight_smile:'
    await ctx.send(idea)

# make sure to create a token file (in real life use env variables)
with open("BOT_TOKEN.txt", "r") as token_file:
    TOKEN = token_file.read()
    print("Token file read")
    bot.run(TOKEN)

So now we’re sending a couple of messages and using random.choice() to pick elements from a list.

Now restart the bot (unfortunately, it doesn’t automatically update). Exit with ctrl+c, and then you can start it up again and leave it running.

$ python bot.py

Now, if we post !idea on the server, we should get a response:

Ideas are hard
Worry not, I think you should...
Create a new browser extension that helps with social life! :slight_smile:

Yours might not look the same since this is randomized. If you want to learn more about random in python, check out Real Python - Generating Random Data in Python (Guide).

Exercise

  • Have the idea bot randomly pick a programming language as well. Don’t worry if the combo makes sense. This is to flesh out the program some more.

Calculator Bot

Let’s add another command, calc, that can do the standard four-function calculator stuff. This new command will help us learn how to collect chatbot inputs and how to have branching accordingly.

@bot.command(name="calc")
async def calc(ctx, x, fn, y):
    x = float(x)
    y = float(y)
    if fn == '+':
        await ctx.send(x + y)
    elif fn == '-':
        await ctx.send(x - y)
    elif fn == '*':
        await ctx.send(x * y)
    elif fn == '/':
        await ctx.send(x / y)
    else:
        await ctx.send("We only support 4 function operations")

We have to add more parameters after ctx, which will become the program’s inputs. So if I restart my bot:

$ python bot.py

And I ask it !calc 1 - 3, it responds with -2.0.

We can shorten this code a bit. Right now, every input comes in like a python string (str), and then we convert the numbers into floats for computation. However, python has optional type annotations (most don’t know this), which we can use to our advantage. So if we change our function heading to

async def calc(ctx, x: float, fn: str, y: float):

Then discord.py will make sure all the conversions are done automatically. To learn more about Python type annotations, check out Using Python’s Type Annotations and mypy.

Exercise

Add ** (to the power of) as an operator onto the calc command as well. This option will probably involve adding another level of branching. Example: !calc 5**3 should give us 125.0.

Help Information

Using the decorators can also provide helpful information for users trying to figure out how a bot works.

@bot.command(name="idea", help="Get a side project idea")
@bot.command(name="calc", help="Perform a calculation where fn is either +,-,*, or /")

And (after restart), if we type !help, we get:

No Category:
  calc Perform a calculation where fn is either +,-,*, or /
  help Shows this message
  idea Get a side project idea

Type !help command for more info on a command.
You can also type !help category for more info on a category.

And if we check for a given command, for example, !help calc:

!calc <x> <fn> <y>

Perform a calculation where fn is either +,-,*, or /

Now make sure to update everything with git

$ git add bot.py .gitignore
$ git commit -m "Create basic chatbot"

You can follow instructions on Github on how to add a remote and then using git push to upload it here.

Final Code

Everything put together, our final code is:

from discord.ext import commands
import random

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

@bot.command(name="idea", help="Get a side project idea")
async def idea(ctx):
    await ctx.send("Ideas are hard")
    await ctx.send("Worry not, I think you should...")

    topics = ['chat bot', 'cli', 'game', 'web bot', 'browser extention', 'api', 'web interface']
    areas = ['note taking', 'social life', 'physical fitness', 'mental health', 'pet care']

    idea = f'Create a new {random.choice(topics)} that helps with {random.choice(areas)}! :slight_smile:'
    await ctx.send(idea)

@bot.command(name="calc", help="Perform a calculation where fn is either +,-,*, or /")
async def calc(ctx, x: float, fn: str, y: float):
    if fn == '+':
        await ctx.send(x + y)
    elif fn == '-':
        await ctx.send(x - y)
    elif fn == '*':
        await ctx.send(x * y)
    elif fn == '/':
        await ctx.send(x / y)
    else:
        await ctx.send("We only support 4 function operations")

# make sure to create a token file (in real life use env variables)
with open("BOT_TOKEN.txt", "r") as token_file:
    TOKEN = token_file.read()
    print("Token file read")
    bot.run(TOKEN)

Go Forth and Make Something

Every week, we’re going to make one project themed on what we just did. This project workflow will have two stages.

  • Idea - come up with an idea and a set of features (MVP + sprinkles) due every Wednesday. There will be a form linked at the bottom of each article so that you can submit these.

  • Project - submit a form and create a public forum post with your project every Monday. The form for this will also be linked at the bottom of each article.

Open Source License

Many people incorrectly assume that just publicly posting a project on Github makes a project open source. However, you have to add a License to your project explicitly. For all the projects you make, a license is mandatory. Here is a guide to the more popular open-source licenses today. Adding one shouldn’t take more than a few minutes.

If you’re unsure/lazy, you can go for either MIT, ApacheV2, or GPL.

Having a proper open source license on your project makes your project an open-source project! Congrats, and welcome to creating code for all of society.

Learn More About Chatbots

Learn More About Python Concepts

Ethics

Ideas

Feel free to come up with anything you want as long as it’s chatbot-related. Here are some ideas to help you get started, but feel free to come up with more. Don’t worry if it’s already been done or if someone else is doing it. The point is to learn and have fun. :)

  • Think of a bot you’ve seen in real life. Could you recreate a simple subset of its features?

  • Maybe a bot that could provide the user information, like recipes or sports teams?

  • Or a bot that can have a basic conversation with you. Could it help you break down tasks or provide you with a gratitude journal?

  • Maybe a bot that can automate something you find annoying? So you can use it to fire off commands to do some tasks.

  • The bot doesn’t have to be a Discord bot. You can make it on Slack, Facebook, IRC, or any chat service out there.

Requirements

These aren’t strict requirements, but you should try your best to hit all of them.

  • The chatbot connects to a real chat service, including but not limited to: Discord, Slack, Telegram, IRC, Facebook.

  • It has different responses based on various inputs.

  • Try to get your pylint score as good as possible. If you haven’t used it before, check our guide at /pylint.

  • This has to be available on a site like Github (feel free to use alternatives like GitLab if you prefer).

  • Show your bot’s images/animations/videos in action in a README.md file in your repository.

  • Has to use an Open Source license via a LICENSE file

Contributors: Harsh, Maaheen