Skip to content

Building a Comedy Set Bot : Using Savage Bot AI Template

Build using Savage Bot AI template by Metaschool

Hey Everyone, as you have stumbled on this blog I am pretty much sure that you were checking out the Build with AI section on Metaschool and looking at those cool AI templates that the team has built. A lot of you reached out to us. before, saying that you have got a bunch of project ideas while exploring the AI templates and want to build on top of it, but don’t know how to start. And so why not make it a bit easy for you?

Get ready with your ideas, while show you how I build mine using our AI templates. But for those who don’t know what AI templates are? We have worked on some really interesting projects like DSAGPT Tutor, Story Generator GPT, Finance GPT, and so on and provided the entire code along with the steps to integrate them and build something even better. For this article, we will be using the Savage bot template which is an AI-powered Discord bot that delivers savage, witty, and hilariously brutal responses.

Comedy Bot - built with Savage Bot AI Template by Metaschool

Prerequisites

  • Node.js installed on your system
  • Basic knowledge of TypeScript and React
  • Discord Developer account
  • OpenAI API key
  • Clone of Savage Bot Template by Metaschool

Figuring out an idea

As a developer, we all think that coding is the toughest part as all of us have a bunch of ideas we want to build on. But while you start working on a side project as much as the idea matters, figuring out how to proceed next is important. With AI it is the opposite, we bring you the best templates to build upon but what are the most relevant and fun ideas associated with that template that you can build? If you have figured it out already, skip to the next section but if not, let’s go to Claude and ask:

This is the prompt I gave:

I have a savage discord bot template by Metaschool, it is AI powered and it provides really savage replies very fun and simple to use. I want some product ideas that can be built using this template, in which we can integrate the use of savage bot.

That’s it, Claude will give you a bunch of ideas. For this prompt, it gave me the following ideas:

  1. “Savage Social Media Manager” – A social media management tool that generates witty, sharp-tongued responses to comments and messages across platforms.
  2. “Roast Battle Training Arena” – A platform where users can practice comebacks and witty banter with the AI bot in a safe environment. C
  3. “Savage Writing Assistant” – A writing tool that helps add humor and edge to content like marketing copy, scripts, or social posts.
  4. “Comedy Open Mic Simulator” – An app that acts as a virtual audience/heckler to help comedians practice their material and improve their crowd work.
  5. “Savage Customer Service Training” – A tool for training customer service reps to handle difficult customers with wit and grace.

Interesting isn’t it? I picked No. 4 – because I love jokes! Which one did you pick?
Once you have decided on the idea, don’t wait Fork and Clone the repository now! (Give it a Star too! We love stars, that is our source of validation, that you love what we are doing)

Part 1: Setting Up the Project

1.1 Getting Started

First, fork the Savage Bot template from Metaschool’s repository and clone it to your local machine. You will find this set of instructions on the README page as well.

git clone <https://github.com/your-username/savage-bot.git>
cd savage-bot
npm install

Create a .env file in the root directory:

DISCORD_TOKEN=your_discord_bot_token
OPENAI_API_KEY=your_openai_api_key

As you clone the project and open the folder in your VS Code. Understanding the project structure before you proceed with the coding part is very important. Let us move to the next section, to see what is the significance of each file.

1.2 Understanding the Project Structure

The template provides the implementation of the bot where each file has a significant role to play. Understanding it is important so that when you play around with the code trying to build on top of it, you don’t mess with the wrong file.

Heads Up: Even if you, it is fine. Code errors can be fixed.

savage-bot/
├── app/                           # Next.js app directory containing frontend code
│ ├── components/                  # React components folder
│ │ └── Footer.tsx                # Footer component with Metaschool branding and social links
│ ├── globals.css                 # Global styles and Tailwind CSS configuration
│ ├── layout.tsx                  # Root layout component with fonts and common structure
│ └── page.tsx                    # Main comedy club interface with chat and commands
├── bot/                          # Discord bot related files
│ ├── bot.js                      # Main Discord bot setup with OpenAI integration
│ └── comedy-mic.js               # Comedy-specific logic and slash commands
├── public/                       # Static assets directory
├── .env                         # Environment variables (Discord token, OpenAI key)
├── next.config.ts               # Next.js configuration file
├── package.json                 # Project dependencies and scripts
├── tailwind.config.ts           # Tailwind CSS configuration
└── tsconfig.json                # TypeScript configuration

Now that we have understood what each file does, let’s start coding. While we implement new features we will simultaneously look into what’s written in each of these files.

Part 2: Building the Discord Bot

Understanding the Base Bot Logic

Before we start building our comedy features, let’s understand what’s already set up in bot.js. This is crucial because it serves as the foundation for our comedy bot.

Core Components in bot.js

const { Client, GatewayIntentBits } = require('discord.js');
const dotenv = require('dotenv');
const { ChatOpenAI } = require("@langchain/openai");
const { HumanMessage, SystemMessage } = require("@langchain/core/messages");

These imports set up:

  • Discord.js client for bot functionality
  • Environment variables management
  • LangChain’s OpenAI integration for AI responses
  • Message types for AI interactions

Bot Configuration

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

The intent tell Discord what events our bot needs access to:

  • Guilds: Access to server information
  • GuildMessages: Ability to read messages
  • MessageContent: Access to message content

OpenAI Setup

const chatModel = new ChatOpenAI({
  openAIApiKey: process.env.OPENAI_API_KEY,
  modelName: 'gpt-4',
  temperature: 1,
  maxTokens: 50, // Limit response length
});

This configuration:

  • Uses GPT-4 model
  • Sets high temperature (1) for more creative responses
  • Limits response length to keep roasts concise

System Prompt

const PLAYFUL_PROMPT = `You are a savage, sarcastic roast bot. STRICT RULES:
- Maximum 1 sentence response
- Brutally witty
- No filters
- Pure savage energy
- Destroy their ego instantly
- Make it sharp, short, and hilarious`;

This defines the bot’s personality and response style. The template already gives us a roast-oriented personality, which is perfect for our comedy bot.

Message Handling

client.on('messageCreate', async (message) => {
  if (message.author.bot) return;

  try {
    message.channel.sendTyping();

    // Check fixed responses first
    const normalizedMessage = message.content.toLowerCase().trim();
    if (FIXED_RESPONSES.hasOwnProperty(normalizedMessage)) {
      await message.reply(FIXED_RESPONSES[normalizedMessage]);
      return;
    }

    // Use AI for other responses
    const response = await chatModel.invoke([
      new SystemMessage(PLAYFUL_PROMPT),
      new HumanMessage(message.content)
    ]);

    const savageResponse = response.content.split('.')[0].trim();
    await message.reply(savageResponse);
  } catch (error) {
    console.error('Error:', error);
    await message.reply("Even my wit buffer is overloaded by this conversation!");
  }
});

This code:

  1. Listens for new messages
  2. Ignores messages from other bots
  3. Shows typing indicator for better UX
  4. Checks for pre-defined responses
  5. Falls back to AI-generated responses
  6. Handles errors gracefully

Now that we have understood the core logic of the bot.js file we will add respective modifications in it to extend it as Comedy Club Bot.

Extending for Comedy Club Features

A comedy club isn’t just about random roasts – it needs structure, timing, and a sense of performance. This is where our extensions come in. Through comedy-mic.js, we’ll transform our savage bot into a full-fledged comedy club host. We need to create an environment where users can take the stage, perform their sets, and receive feedback while maintaining the bot’s signature savage style. You can add as many creative features as you want.

The challenge lies in organizing these performances. We need to track who’s on stage, manage the flow of jokes, and ensure the bot responds appropriately at each step of a comedy set. It’s like turning our basic roast bot into a seasoned comedy club manager who knows exactly when to introduce performers, when to heckle, and when to wrap up a set.

Let’s look at how we’ll implement these features by building our comedy club bot.

2.1 Setting Up the Bot Logic

First, let’s implement the comedy bot functionality in comedy-mic.js:

class ComedyMicExtension {
    constructor(client, openAIApiKey) {
        this.client = client;
        this.chatModel = new ChatOpenAI({
            openAIApiKey: openAIApiKey,
            modelName: 'gpt-4',
            temperature: 1,
        });

        this.activePerformances = new Map();
    }

    get COMEDY_PROMPT() {
        return `You are a savage comedy club host and heckler with the following traits:
- You maintain a brutal yet entertaining presence
- Your responses are short, witty, and cutting
- You stay in character as a comedy club host/heckler
- You provide brief but insightful feedback on performances
Current setting: You're hosting an open mic night at the Savage Comedy Club.`;
    }

    async startSet(interaction) {
        // Implementation details shown in comedy-mic.js
    }

    async processJoke(interaction) {
        // Implementation details shown in comedy-mic.js
    }

    async endSet(interaction) {
        // Implementation details shown in comedy-mic.js
    }

    registerCommands() {
        return [
            {
                name: 'startset',
                description: 'Start your comedy set',
            },
            {
                name: 'joke',
                description: 'Tell a joke during your set',
                options: [{
                    name: 'joke',
                    type: 3,
                    description: 'Your joke/bit',
                    required: true
                }]
            },
            {
                name: 'endset',
                description: 'End your comedy set and get feedback',
            }
        ];
    }
}

Let’s look into how we transform our basic roast bot into a comedy club host through comedy-mic.js. The implementation creates a structured performance environment while maintaining the bot’s savage personality.

The ComedyMicExtension Class

class ComedyMicExtension {
    constructor(client, openAIApiKey) {
        this.client = client;
        this.chatModel = new ChatOpenAI({
            openAIApiKey: openAIApiKey,
            modelName: 'gpt-4',
            temperature: 1,
        });

        this.activePerformances = new Map();
    }

The constructor sets up two essential elements:

  1. A connection to our Discord client
  2. An OpenAI chat model configured for creative responses
  3. A Map to track active performances in different channels

Defining the Comedy Club Host Personality

get COMEDY_PROMPT() {
    return `You are a savage comedy club host and heckler with the following traits:
- You maintain a brutal yet entertaining presence
- Your responses are short, witty, and cutting
- You stay in character as a comedy club host/heckler
- You provide brief but insightful feedback on performances
Current setting: You're hosting an open mic night at the Savage Comedy Club.`;
}

This prompt transforms our basic bot into a comedy club host. It defines the personality and behavior our AI should maintain throughout the performance.

Managing the Stage: startSet

async startSet(interaction) {
    await interaction.deferReply();

    if (this.activePerformances.has(interaction.channelId)) {
        return interaction.reply("There's already someone bombing on stage. Wait your turn!");
    }

    const performance = {
        comedian: interaction.user.id,
        startTime: Date.now(),
        jokes: [],
        heckles: [],
        feedback: null
    };

    this.activePerformances.set(interaction.channelId, performance);

    const response = await this.chatModel.invoke([
        new SystemMessage(this.COMEDY_PROMPT),
        new HumanMessage("Introduce the next comedian in a savage way")
    ]);

    return interaction.editReply(`đŸŽ€ ${response.content}`);
}

The startSet method handles the beginning of a performance by:

  • Checking if someone is already performing
  • Creating a new performance record
  • Generating a savage introduction for the comedian

Handling Jokes: processJoke

async processJoke(interaction) {
    await interaction.deferReply();

    const performance = this.activePerformances.get(interaction.channelId);
    if (!performance || performance.comedian !== interaction.user.id) {
        return interaction.reply("You're not the one on stage, heckle them instead!");
    }

    const joke = interaction.options.getString('joke');
    performance.jokes.push(joke);

    const response = await this.chatModel.invoke([
        new SystemMessage(this.COMEDY_PROMPT),
        new HumanMessage(`Comedian's joke: "${joke}"\\\\nRespond with a brutal heckle or savage commentary`)
    ]);

    performance.heckles.push(response.content);
    return interaction.editReply(response.content);
}

During the performance, processJoke:

  • Verifies the right person is telling the joke
  • Records the joke in the performance history
  • Generates and stores a savage heckle response

Wrapping Up: endSet

async endSet(interaction) {
    await interaction.deferReply();

    const performance = this.activePerformances.get(interaction.channelId);
    if (!performance || performance.comedian !== interaction.user.id) {
        return interaction.reply("You can't end a set you never started!");
    }

    const duration = (Date.now() - performance.startTime) / 1000 / 60;

    const feedback = await this.chatModel.invoke([
        new SystemMessage(this.COMEDY_PROMPT),
        new HumanMessage(`The comedian just finished their ${duration.toFixed(1)} minute set.
            Jokes performed: ${performance.jokes.join(' | ')}
            Provide a brutal but slightly constructive wrap-up of their performance.`)
    ]);

    this.activePerformances.delete(interaction.channelId);

    return interaction.editReply(`🎭 ${feedback.content}`);
}

The endSet method concludes the performance by:

  • Calculating the set duration
  • Providing AI-generated feedback based on the full set
  • Cleaning up the performance record

Command Registration

registerCommands() {
    return [
        {
            name: 'startset',
            description: 'Start your comedy set',
        },
        {
            name: 'joke',
            description: 'Tell a joke during your set',
            options: [{
                name: 'joke',
                type: 3,
                description: 'Your joke/bit',
                required: true
            }]
        },
        {
            name: 'endset',
            description: 'End your comedy set and get feedback',
        }
    ];
}

This method defines the slash commands that users can use to interact with our comedy bot in Discord.

Each of these components works together to create a structured comedy club experience, where users can perform their sets, receive instant feedback, and get roasted by our AI host.

2.2 Configuring the Discord Bot

In bot.js, we set up the Discord client and integrated OpenAI:

const { Client, GatewayIntentBits } = require('discord.js');
const dotenv = require('dotenv');
const { ChatOpenAI } = require("@langchain/openai");
const { HumanMessage, SystemMessage } = require("@langchain/core/messages");
const ComedyMicExtension = require('./comedy-mic');

dotenv.config();

const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
    ],
});

const comedyMic = new ComedyMicExtension(client, process.env.OPENAI_API_KEY);

// Register commands and handle interactions as shown in bot.js

Part 3: Developing the Web Interface

3.1 Implementing the Comedy Club Page

In page.tsx, we create an interactive comedy club interface. You can always play around with the user interface, add as many designs, colors and animation to it.

'use client'
import React, { useState } from 'react';
import { Mic, MessageCircle, Star, ArrowRight } from 'lucide-react';

const ComedyClubPage = () => {
    const [currentStep, setCurrentStep] = useState('welcome');
    const [isPerforming, setIsPerforming] = useState(false);
    const [showJokeOptions, setShowJokeOptions] = useState(false);

    // State and handlers implementation as shown in page.tsx

    return (
        // JSX implementation as shown in page.tsx
    );
};

export default ComedyClubPage;

3.2 Styling with Tailwind CSS

In globals.css, we define our theme, and experiment with as many color combinations as you want before you decide on that final theme for your interface.

@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
    --background: #ffffff;
    --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
    :root {
        --background: #0a0a0a;
        --foreground: #ededed;
    }
}

body {
    color: var(--foreground);
    background: var(--background);
    font-family: Arial, Helvetica, sans-serif;
}

Part 4: Connecting Everything

4.1 Setting Up OAuth2 for Discord

  1. Go to the Discord Developer Portal
  2. Create a new application
  3. Add bot permissions
  4. Generate OAuth2 URL with required scopes
  5. Replace the client ID in your frontend code
const addBotToDiscord = () => {
    window.open('<https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&permissions=8&scope=bot%20applications.commands>', '_blank');
};

4.2 Deploying the Bot

That was a lot of work, but don’t worry all we have to do now is to deploy the bot on a hosting platform. We prefer Vercel, very straightforward to use. But before that don’t forget to run it locally and test if everything works fine.

  1. Set up your hosting platform (e.g., Heroku, Vercel)
  2. Configure environment variables
  3. Deploy the Discord bot and frontend separately
# Deploy Discord bot
npm run deploy-bot

# Deploy frontend
npm run deploy

Wrap Up

You now have a fully functional Savage Comedy Bot with both Discord integration and a web interface. I have only added a guided mock performance on the web interface as a Discord bot, is well suited in Discord but you can always have it on the website too. As of now, a user can perform these actions:

  1. Add it to their Discord server
  2. Use slash commands for comedy interactions
  3. Get roasted by AI-powered responses

What’s Next?

There are tonnes of more features that you can add to the bot. I will make it easier for you with a few potential ideas which I wanted to implement but because we have quite a few more interesting templates I will experiment with those while you build on this.

  1. Add user authentication
  2. Implement performance history
  3. Add more interactive features like Performance feedback, set sequences for multiple comedians
  4. Enhance the AI responses with more context
  5. Add analytics for tracking usage

Remember to maintain your API keys securely and monitor your OpenAI API usage to manage costs effectively.

Did we forget errors?

Bugs are a common occurrence while you are coding, doesn’t matter with AI or without AI. A lot of times it is the same set of errors that we all encounter. So in order to make it a bit easier for you (although I highly recommend debugging it on its own, and not using AI) I will list a few common issues and potential hints around its solution.

  1. Discord commands not registering: Check your bot permissions
  2. OpenAI API errors: Verify your API key and usage limits
  3. Frontend not connecting: Check your OAuth2 configuration
  4. Deployment issues: Verify environment variables and build scripts
  5. Hydration Error(this was the most common one)- Check your client-side and server-side rendering components.

Conclusion

Wow, that was a long read! But don’t worry once you have built a few projects on your own, you would not need these blogs(that would be sad for us, but we would still want that for you.) Once you are done building this, submit your project to the attached form link on the template page, to get your project featured. Write to us if you are facing any issues, or have any suggestions. And do try our other templates and build on them. Don’t forget to give us a STAR on GitHub.

Frequently Asked Questions

What can you build using these AI templates?

Absolutely anything, just pick up a template that resonates with your project idea and you can build on top of it. For example: Savage Bot had witty replies, best for building a Comedy Set-related application.

Are these AI Templates free to use?

Yes, all these templates whether AI or Web3 are free to use, if you love them please don’t forget to give us a STAR ⭐ on Github