I built a Discord bot to teach me Portuguese
Anneta Wamono
Posted on December 26, 2022
I've been trying to learn Portuguese on my own for three years. I dream of becoming fluent and impressing my partner's family with wit and charm. Unfortunately, it takes a lot of effort to learn a language. Something that helps with picking up a language is expanding your vocabulary. I have a Google Sheet of about 700 words and phrases that I've been learning, but there are better ways to learn than looking at a spreadsheet. I was inspired by this article to build a bot with some personality to teach me Portuguese. This article will briefly discuss the technology I learned to make my bot and some challenges I ran into.
Table of contents
- Goals for the project
- Having fun
- Learning the Discord API
- Learning Google Sheets API
- Creating a command to fetch vocab words
- Setting up a cron job
- Deploy to Heroku
Goals for the project
My primary goal was to build a bot that would send me some vocab words every day, and my secondary goal was to make it fun to interact with. My first decision was to use Discord because it's an app I use every day and have open on all my devices, and it has a Javascript API for building bots. My second decision was to keep my vocabulary list in Google Sheets and use the Google Sheets API to connect to my data. I wanted as little friction as possible to get my bot up and running.
Having fun
The best way to trick me into doing something is to have fun while doing it. I wanted to build a bot that would inspire me to engage with Brazillian culture, so I chose a beloved folklore character to teach me Portuguese - Cuca 🐊.
Cuca is best known as a crocodile from the children's show Sítio do Picapau Amarelo. If you've ever watched Cidade Invisível on Netflix, you may know her as the lady who can enter people's dreams. However, I prefer her crocodile form 😂.
Every vocab list Cuca sends me comes with a fun gif. And there are a lot of fun gifs to choose from.
Learning the Discord API for NodeJs
Setting up the Discord bot was very simple. There's a helpful guide that takes you through the basics of installing discord.js
through npm and creating a new bot on the developer's portal. The most important thing to note is your bot's security token. You can invite your bot to your server by generating an invite link. The invite link is a URL with your bot's client_id and some permissions and scopes appended to it. Scopes and permissions allow your bot certain functions, so be sure to choose what you need. For my bot, I wanted to create slash commands, so I selected the bot
, guild
and applications.commands
scope and Embed Links
and Mention Everyone
permissions.
This is an example of my generated link:
https://discord.com/api/oauth2/authorize?client_id=XXXXXXXXX&permissions=147456&scope=applications.commands%20bot%20guilds
Learning Google Sheets API
My most significant pain point in the project was understanding how to authenticate for the Google Sheets API. Typically for other APIs I've used, I would be given an API key to send along with my request. Google Cloud gives you two authentication options: OAuth 2.0 Client IDs and Service Accounts. There were more tutorials explaining Service Accounts, so I went down that route. When you create a service account, you're prompted to download a JSON file that holds your account details and private key. That file is what you use to authenticate your API requests. Your service account also acts like a google account, one that you can share your google sheet documents with (like any other google account).
Creating a slash command to retrieve vocab words
I created a slash command that connects to my Google API service and returns a randomized list of vocab words and their translations. This /vocab
command connects to my Google API service code and passes my spreadsheet id and the range of values I want to return. My vocab list is two columns: one column for the Portuguese words and the next for the translation, so I select the range of values and randomly select 20 values.
async function getWordsTranslationsMeanings() {
try {
const auth = await getAuthToken();
const response = await getRangeSpreadSheetValues({
spreadsheetId,
sheetName,
auth,
range
})
const translationsArray = response.data.values;
const translationsArrayLength = translationsArray.length;
// Selecting random number of words
const randomWords = []
for (let index = 0; index < numOfWords; index++) { // numOfWords = 20
const randomWordIndex = Math.floor(Math.random() * translationsArrayLength);
randomWords[index] = translationsArray[randomWordIndex]
}
return randomWords;
} catch (error) {
console.log(error.message, error.stack);
}
}
To send my vocab words to Discord, I used embed
messages. These are nifty blocks of messages that can hold different media like images and gifs.
Here's a snippet of the embed code:
const embed = new MessageEmbed();
await getWordsTranslationsMeanings().then( words => {
let fields = words.map(word => { return { name: word[0], value: word[1] } })
embed.setColor('#2A8947')
.setTitle('Palavras de vocabulario')
.setDescription('Agora vai!')
.addField('\u200B', '\u200B')
.addFields(fields)
.setImage(getGucaGif())
.setTimestamp()
.setFooter({ text: 'Feito por Anneta Wamono');
if (interaction) {
interaction.channel.send({ embeds: [embed] });
}
},
err => {
console.log(err);
}
);
And the SlashCommandBuilder
code:
const { SlashCommandBuilder } = require('@discordjs/builders');
const { createEmbedWith20Words } = require('../actions/send20Words.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('vocab')
.setDescription('Replies with a list of vocabulary words!'),
async execute(interaction) {
await createEmbedWith20Words({ interaction });
await interaction.reply('Aqui estão suas palavras!');
},
};
Setting up the cron job
The ideal situation would be for Cuca bot to send me my vocab list daily at a convenient time to practise. The best solution was cron. The cron syntax is quite straightforward once you understand it.
For my purposes, I wanted to send a message every day at 8am.
The asterisks indicate that your job will run for every value in that range.
Deployment
I used Heroku to deploy my bot, even though I've struggled with it before. That's because I've never known what a procfile was and how to use it. Procfiles are used to configure the dyno your code will run on. In my case, setting the dyno as a worker was important. By default, dynos are configured for web processes to receive HTTP traffic. Worker dynos are for background jobs, queueing systems, and timed jobs, and you won't receive a timeout error when running your bot.
Project takeaways
This was a really fun project to do. I got the opportunity to learn more about new APIs and gained more confidence when deploying my projects. Am I fluent in Portuguese now? Nope, but every day I get a little bit better. I want to add more features to Cuca bot, like a command that issues a test and keeps track of my score.
Resources
Thank you for reading my article. If there is anything you would like more details on, leave a comment below. I'd like to continue improving the quality of my articles, so any feedback is appreciated.
See you at the next one!
Posted on December 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.