Guide
07 November 2024
Building an Advanced AI-Powered Trivia Bot for Discord: A Step-by-Step Guide
Are you interested in creating an AI-driven bot for your Discord community that can generate trivia questions based on a knowledge base? This tutorial will walk you through the steps to set up a trivia bot using Google’s Gemini API and Google AI Studio. Though not production-ready, this code provides a straightforward implementation to get started with AI-based content generation.
Note: This example bot serves as a basic guide and is not optimized for production use. Some parts of the code are quick implementations to demonstrate the setup and functionality. A full production-ready bot requires further error handling, authentication layers, and more robust data processing methods.
1. Setting Up Your Discord Bot Application
Step 1.1: Create a New Discord Bot Application
Go to the Discord Developer Portal and create a new application for your bot. Give it a name and navigate to the “Bot” section to create your bot.
Step 1.2: Enable Required Privileges
Under “Privileged Gateway Intents,” enable the following for advanced functionality:
- Presence Intent
- Server Members Intent
- Message Content Intent
Step 1.3: Select Bot Scopes and Permissions
In the OAuth2 tab, select the following scopes to ensure the bot has the required permissions:
- Scopes:
- Permissions:
2. Writing the Bot Code
Setting up .env file
Create a .env file in the project directory and add:
DISCORD_TOKEN = your_discord_bot_token_here
GOOGLE_API_KEY = your_google_studio_API_key_here
Installing Required Dependencies
Run the following command to install necessary libraries:
pip install discord.py google-generativeai PyPDF2 requests beautifulsoup4 python-dotenv
Prerequisites
The following code serves as the core structure for our AI-powered trivia bot. Let’s break down each section and its purpose:
Importing required libraries
# Import required libraries
import os
import discord
from discord.ext import commands
import google.generativeai as genai
import PyPDF2
import requests
from bs4 import BeautifulSoup
from dotenv import load_dotenv
import asyncio
This block imports necessary libraries. We’ll be using discord.ext for bot commands, google.generativeai for integrating Gemini, and requests, BeautifulSoup and PyPDF2 for scraping and file handling.
Configure the Bot Environment
# Load environment variables
load_dotenv()
# Configure Gemini
genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
model = genai.GenerativeModel('gemini-pro')
This code loads environment variables and configures the Gemini model using the API key stored in a .env file. Make sure to create and store your keys securely.
3. Creating a Knowledge Base
Our bot needs a knowledge base from which it will generate trivia questions. The KnowledgeBase class stores text, PDFs, and website data.
Add Text, Website, and PDF Content
class KnowledgeBase:
def __init__(self):
self.content = []
async def add_text(self, text):
"""Add raw text to knowledge base"""
self.content.append({"type": "text", "content": text})
async def add_website(self, url):
"""Scrape and add website content"""
try:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# Extract text content from paragraphs
text = ' '.join([p.text for p in soup.find_all('p')])
self.content.append({"type": "website", "content": text, "source": url})
return True
except Exception as e:
print(f"Error processing website: {e}")
return False
async def add_pdf(self, file_path):
"""Extract and add PDF content"""
try:
with open(file_path, 'rb') as file:
reader = PyPDF2.PdfReader(file)
text = ''
for page in reader.pages:
text += page.extract_text()
self.content.append({"type": "pdf", "content": text, "source": file_path})
return True
except Exception as e:
print(f"Error processing PDF: {e}")
return False
These functions add content to the knowledge base by scraping websites, extracting text from PDFs, or directly accepting text input.
Retrieve, update, delete content and get combined content
async def get_content(self):
"""Get all content"""
return self.content
async def update_content(self, index, new_content):
"""Update content at a specific index"""
if index < len(self.content):
self.content[index]["content"] = new_content
return True
else:
return False
async def delete_content(self, index):
"""Delete content at a specific index"""
if index < len(self.content):
del self.content[index]
return True
else:
return False
def get_combined_content(self):
"""Get all content combined"""
return ' '.join([item['content'] for item in self.content])
4. Generating Trivia Questions
The trivia bot uses Google’s Gemini model to generate questions based on the knowledge base’s contents. Initialize the bot, and using prompt engineering to get back the desired result in a format that we can extract the data from.
class TriviaBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
super().__init__(command_prefix='!', intents=intents)
self.knowledge_base = KnowledgeBase()
self.current_questions = {}
self.scores = {}
async def generate_question(self, context):
"""Generate a question using Gemini based on knowledge base"""
try:
prompt = f"""
Based on the following content, generate a trivia question with 4 multiple choice options (A, B, C, D) and indicate the correct answer. Always respond with the same format, as spacing and new line matters.
Format: Question
A)
B)
C)
D)
Correct Answer: X being either A or B or C or D
Content: {self.knowledge_base.get_combined_content()[:10000]} # Limit content length
"""
response = model.generate_content(prompt)
response_text = response.text
# Parse response to extract question, options, and answer
lines = response_text.strip().split('\n')
question = lines[0]
options = lines[1:5]
correct_answer = lines[-1].split()[-1]
return {
'question': question,
'options': options,
'correct_answer': correct_answer
}
except Exception as e:
print(f"Error generating question: {e}")
return None
This function sends the combined knowledge base content as a prompt to the Gemini API, which returns a trivia question with multiple-choice options. And we extract the data into variables
5. Setting Up Bot Commands
Here we set up the bot’s commands, which allow users to interact with the bot on Discord.
# Set up bot commands
def setup_bot():
bot = TriviaBot()
@bot.event
async def on_ready():
print(f'{bot.user} has connected to Discord!')
@bot.command(name='addtext')
async def add_text(ctx, *, text):
"""Add text to knowledge base"""
await bot.knowledge_base.add_text(text)
await ctx.send("Text added to knowledge base!")
@bot.command(name='addwebsite')
async def add_website(ctx, url):
"""Add website content to knowledge base"""
success = await bot.knowledge_base.add_website(url)
if success:
await ctx.send("Website content added to knowledge base!")
else:
await ctx.send("Error processing website!")
@bot.command(name='addpdf')
async def add_pdf(ctx):
"""Add PDF content to knowledge base"""
if len(ctx.message.attachments) == 0:
await ctx.send("Please attach a PDF file!")
return
attachment = ctx.message.attachments[0]
if not attachment.filename.endswith('.pdf'):
await ctx.send("Please attach a PDF file!")
return
# Download and save PDF temporarily
await attachment.save(attachment.filename)
success = await bot.knowledge_base.add_pdf(attachment.filename)
os.remove(attachment.filename) # Clean up
if success:
await ctx.send("PDF content added to knowledge base!")
else:
await ctx.send("Error processing PDF!")
@bot.command(name='view')
async def view_knowledge_base(ctx):
"""View the current knowledge base content"""
content = await bot.knowledge_base.get_content()
if not content:
await ctx.send("Knowledge base is empty.")
return
response = "Current Knowledge Base:\n\n"
for i, item in enumerate(content):
response += f"{i}. {item['type']}: {item['content'][:100]}{'...' if len(item['content']) > 100 else ''}\n"
await ctx.send(response)
@bot.command(name='update')
async def update_knowledge_base(ctx, index: int, *, new_content):
"""Update content in the knowledge base"""
success = await bot.knowledge_base.update_content(index, new_content)
if success:
await ctx.send("Knowledge base content updated.")
else:
await ctx.send("Invalid index. Unable to update content.")
@bot.command(name='delete')
async def delete_knowledge_base(ctx, index: int):
"""Delete content from the knowledge base"""
success = await bot.knowledge_base.delete_content(index)
if success:
await ctx.send("Knowledge base content deleted.")
else:
await ctx.send("Invalid index. Unable to delete content.")
@bot.command(name='trivia')
async def trivia(ctx):
"""Start a trivia question"""
if not bot.knowledge_base.content:
await ctx.send("No content in knowledge base! Add some content first.")
return
question_data = await bot.generate_question(ctx)
if not question_data:
await ctx.send("Error generating question!")
return
# Format and send question
question_msg = f"**{question_data['question']}**\n\n"
for i, option in enumerate(question_data['options']):
question_msg += f"{option}\n"
await ctx.send(question_msg)
bot.current_questions[ctx.channel.id] = question_data
# Wait for answer
def check(m):
return m.channel == ctx.channel and m.content.upper() in ['A', 'B', 'C', 'D']
try:
answer = await bot.wait_for('message', timeout=30.0, check=check)
if answer.content.upper() == question_data['correct_answer']:
# Update score
if answer.author.id not in bot.scores:
bot.scores[answer.author.id] = 0
bot.scores[answer.author.id] += 1
await ctx.send(f"🎉 Correct, {answer.author.mention}! Your score: {bot.scores[answer.author.id]}")
else:
await ctx.send(f"❌ Wrong! The correct answer was {question_data['correct_answer']}")
except asyncio.TimeoutError:
await ctx.send(f"Time's up! The correct answer was {question_data['correct_answer']}")
del bot.current_questions[ctx.channel.id]
@bot.command(name='score')
async def score(ctx):
"""Check your score"""
score = bot.scores.get(ctx.author.id, 0)
await ctx.send(f"{ctx.author.mention}, your score is: {score}")
return bot
These commands allow users to add content to the bot’s knowledge base, generate trivia questions, and respond with multiple-choice questions on the Discord channel:
- addText : allows users to add plain text to the knowledge base.
- addWebsite : lets users add website content.
- addPdf : lets users add pdf to the knowledge base.
- view: lets users view the current knowledge base.
- update: allows users to update certain index from the knowledge base.
- delete: allows users to delete certain index from the knowledge base.
- trivia : generates a trivia question and sends it to the Discord channel.
6. Putting It All Together and Running the Bot
# Main execution
def main():
# Create and set up bot
bot = setup_bot()
# Run bot
bot.run(os.getenv('DISCORD_TOKEN'))
if __name__ == "__main__":
main()
This is the main execution block. Make sure to set up your Discord token and Google Studio AI token in the .env file before running the bot.
Interactive Trivia Bot Showcase
This showcase demonstrates a custom-built trivia bot in action, featuring real-time knowledge base updates and dynamic trivia generation. Users can add, view, and delete knowledge entries, with the bot generating engaging trivia questions from the stored data. Through interactive commands, see how the bot handles correct, incorrect, and timed-out answers while providing an intuitive knowledge management experience. Note: This demo is a simplified example and not a fully production-ready implementation.
1. Adding and Viewing Text Content
Demonstrates the !view command to check the current knowledge base, initially showing an empty state. Then, the !addtext command is used to add content about fascinating wildlife facts. The command is issued again, showing the newly added text in the knowledge base.
2. Trivia Gameplay with Answer Feedback
The !trivia command triggers the bot to ask a question based on the knowledge base. This image demonstrates responses to correct, incorrect, and timed-out answers, showing how users can engage with the trivia questions and track their scores.
3. Adding Website Content and Viewing the Knowledge Base
The !addwebsite command adds content from the specified URL (e.g., information about the iPhone 16 Pro) to the knowledge base. Using !view the bot displays the website content, highlighting its ability to retrieve and incorporate online information for trivia generation.
4. Trivia Based on Website Content
After adding website content, !trivia is used to generate a question based on that information, such as features of the iPhone 16 Pro. This shows the bot's flexibility in generating trivia from various content types.
5. Adding PDF Content
Shows how users can upload PDF files to the knowledge base using !addpdf followed by !view to confirm that the content has been added. This demonstrates how the bot supports trivia generation from PDF content.
6. Trivia Based on PDF Content
Example of !trivia questions generated from the Pokémon facts PDF. The questions illustrate the bot’s ability to parse and generate relevant trivia based on PDF information, enhancing the knowledge base.
Conclusion
Developing a custom trivia bot that integrates AI-driven question generation and answer validation demonstrates the potential of intelligent systems to enhance engagement and interactivity. This bot leverages a blend of innovative technologies and techniques to deliver meaningful, dynamic experiences that can be adapted for various knowledge bases and user requirements. By providing capabilities like real-time updates, content versatility (text, web pages, PDFs), and flexible knowledge management, this bot exemplifies the benefits of merging knowledge retention with interactive entertainment. Ultimately, this project serves as a foundation for creating even more sophisticated bots that can drive user engagement, support learning, and deliver seamless, AI-driven interactions across multiple use cases.