logo
/
Discord ChatGPT
Get a copy
22
Building your first Discord ChatGPT Bot
  • README.md
    arrow

    Building your first Discord ChatGPT Bot

    What we'll be building

    In this tutorial, we will guide you through building your initial Discord app using JavaScript to interact with ChatGPT via slash commands.

    Here's what the finished app will look like:

    Resources used in this guide

    Step 1: Creating an App and Bot

    First, you'll need to create an app in the developer portal if you don't have one already:

    1. Go to Discord Developer Portal. (login using your discord account if required). Click on the "New Application" button at the top right. Give your application a name and click "Create"

    1. Copy your Public Key and Application ID, and put them somewhere locally (we'll need these later)

    1. Click on the "Bot" tab on the left side of the screen.Click on the "Add Bot" button on the right. After the bot is created, Reset the token for your bot, and store it somewhere safe as a secret.(we'll need these later)

    Once the application and bot is created, Here, you can customize them by adding an icon, description, etc.

    Step 2: Setting Scope and Authorization

    Click on OAuth2 in the left sidebar, then select URL Generator.

    Add two scopes:

    • applications.commands which allows your app to create commands. bot which adds your bot user.
    • After you select bot, you can also select different permissions for your bot. For now, just check Send Messages.

    Copy the GENERATED URL from above, and paste it into your browser. You'll be guided through the installation flow, where you should make sure you're installing your app on a server where you can develop and test it.

    After authorized your app, you can head over to your server and see that -> GPT hopped into the server. ✨

    Step 3: Get a copy and Deploy

    This guide uses AirCode to host code, Before we get a copy, make sure you have a AirCode account.

    1. Go to this Discord ChatGPT Bot Demo. Click on the "Get a copy" button.

    1. You'll be redirected to the Create app page, use the default name or type your own app name, then click "Create".

    Paste the Bot token、OpenAI Key、Public Key、Application ID、earlier save from platform into the Environment variables. Make sure they are in the right key value place.

    Click on the "Deploy" button to deploy all files, the env changes will take effect online after deployment.

    Step 4: Register Command

    The project contains a register command script you can use to install the commands, which is defined in register-command.js.

    Select register-command.js file, you will find a invoke url as following, Copy the URL and paste it into your browser URL address.

    You will register /chatgpt slash command into server.

    Step 5: Handling Interactivity

    To enable your app to receive slash command requests (and other interactions), Discord needs a public URL to send them.

    Select interactions.js file, you will find a invoke URL as following, copy the link.

    Back to Discord Applications, on your app's General Information page, there's an Interactive Endpoint URL option, where you can paste your interactions URL copied from AirCode.

    Click on the "Save changes" button, Make sure the save is successful.

    Test your ChatGPT bot by typing the command "/chatgpt".

    Feedback

    Join our Discord server for help and discussion.

  • interactions.js
    arrow
    1// @see https://docs.aircode.io/guide/functions/
    2const axios = require('axios');
    3const nacl = require('tweetnacl');
    4const { Configuration, OpenAIApi } = require('openai');
    5
    6const { EmbedBuilder } = require('discord.js');
    7
    8const {
    9  verifyKey,
    10  InteractionType,
    11  InteractionResponseType,
    12} = require('discord-interactions');
    13
    14const apiKey = process.env.OPENAI_KEY;
    15
    16const discordToken = process.env.DISCORD_BOT_TOKEN;
    17
    18// Your public key can be found on your application in the Developer Portal
    19const discordPublicKey = process.env.DISCORD_PUBLIC_KEY;
    20
    21// Slash command's name you use tointeract with bots on Discord after typing /
    22const slashCommandName = 'chatgpt';
    23
    24// Use openAI API to fetch ChatGPT completion
    25const getOpenAIChatCompletion = async (question) => {
    26  try {
    27    const configuration = new Configuration({
    28      apiKey,
    29    });
    30
    31    const openai = new OpenAIApi(configuration);
    32
    33    const completion = await openai.createChatCompletion({
    34      // OpenAI models https://platform.openai.com/docs/models
    35      model: 'gpt-3.5-turbo',
    36      messages: [{ role: 'assistant', content: question }],
    37    });
    38
    39    console.log(
    40      'ChatGPT completion data:',
    41      completion.data.choices[0].message.content.trim()
    42    );
    43    return {
    44      code: 0,
    45      data: completion.data.choices[0].message.content.trim(),
    46    };
    47  } catch (error) {
    48    console.error(`OpenAI api error: ${error.message}`);
    49    return {
    50      code: 1,
    51      message: `OpenAI api error: ${error.message}`,
    52    };
    53  }
    54};
    55
    56// Build an Embed (rich embed) object for replied message
    57const createResponseEmbed = (response) => {
    58  const embed = new EmbedBuilder().setColor('#37393E').setDescription(response);
    59
    60  return { embeds: [embed] };
    61};
    62
    63module.exports = async function (params, context) {
    64  console.log('params context', params);
    65
    66  // Get signature and timestamp from headers
    67  const signature = context.headers['X-Signature-Ed25519'];
    68  const timestamp = context.headers['X-Signature-Timestamp'];
    69  // Get rawBody content
    70  const body = context.rawBody;
    71
    72  // Verify whether the request from discord
    73  const isVerified = nacl.sign.detached.verify(
    74    Buffer.from(timestamp + body),
    75    Buffer.from(signature, 'hex'),
    76    Buffer.from(discordPublicKey, 'hex')
    77  );
    78
    79  if (!isVerified) {
    80    context.status(401);
    81    return 'Invalid request signature';
    82  }
    83
    84  // Interaction type and data
    85  const { type, id, data, token } = params;
    86
    87  console.log('params', params);
    88  // Handle verification requests reply with PONG
    89  if (type === InteractionType.PING) {
    90    return { type: InteractionResponseType.PONG };
    91  }
    92
    93  // Handle the user registered interaction command
    94  if (
    95    type === InteractionType.APPLICATION_COMMAND &&
    96    data.name === slashCommandName
    97  ) {
    98    const userInput = data.options[0].value;
    99
    100    // Immediately acknowledge the interaction
    101    try {
    102      await axios.post(
    103        `https://discord.com/api/v9/interactions/${id}/${token}/callback`,
    104        {
    105          type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
    106        }
    107      );
    108    } catch (error) {
    109      console.error('Error acknowledging the interaction:', error);
    110      return;
    111    }
    112
    113    const response = await getOpenAIChatCompletion(userInput);
    114    console.log('response form OpenAI ChatCompletion: ', response);
    115
    116    // Patch message
    117    if (response.code === 0) {
    118      try {
    119        await axios.patch(
    120          `https://discord.com/api/v9/webhooks/${process.env.DISCORD_APP_ID}/${token}/messages/@original`,
    121          {
    122            content: `> ${userInput} \n ${response.data}`,
    123          }
    124        );
    125      } catch (error) {
    126        console.error('Error editing the original response:', error.message);
    127        return;
    128      }
    129    }
    130  }
    131};
    132
  • register-command.js
    arrow
    1// @see https://docs.aircode.io/guide/functions/
    2const axios = require('axios');
    3const Discord = require('discord.js');
    4
    5async function registerCommands(appId, commands) {
    6	const { DISCORD_BOT_TOKEN } = process.env;
    7
    8  try {
    9    // Use discord sdk register chatgpt command
    10    const rest = new Discord.REST({ version: '10' }).setToken(
    11      DISCORD_BOT_TOKEN
    12    );
    13    const data = await rest.put(Discord.Routes.applicationCommands(appId), {
    14      body: commands,
    15    });
    16
    17    console.log('Command register response:', data);
    18
    19    if (data) {
    20      return {
    21        success: true,
    22        message: `WOW, slash command ${data
    23          .map((command) => `/${command.name}`)
    24          .join(' ')} registered`,
    25      };
    26    }
    27  } catch (err) {
    28    console.error('Error from registering commands:', err);
    29  }
    30}
    31
    32module.exports = async function (params, context) {
    33  console.log('Received params:', params);
    34  const slashCommandName = 'chatgpt';
    35
    36  const ChatGPTCommand = {
    37    name: slashCommandName,
    38    description: 'Interact with ChatGPT',
    39    options: [
    40      {
    41        name: 'prompt',
    42        type: 3,
    43        description: 'The message sending to ChatGPT',
    44        required: true,
    45      },
    46    ],
    47  };
    48
    49  const commands = [ChatGPTCommand];
    50  // Register ChatGPT command
    51  const res = await registerCommands(process.env.DISCORD_APP_ID, commands);
    52
    53  return res;
    54};
    55
  • Runtime
    arrow
    • Node.js versionnode/v16
    • Function execution timeout90 s
  • Dependencies
    arrow
    • aircode0.4.1
    • axios1.4.0
    • discord-interactions3.4.0
    • discord.js14.11.0
    • openai3.2.1
    • tweetnacl1.0.3
  • Environments
    arrow
    arrow
    • DISCORD_BOT_TOKEN
    • DISCORD_PUBLIC_KEY
    • DISCORD_APP_ID
    • OPENAI_KEY