
- README.md
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
- AirCode An online platform for Building and hosting Node.js Apps.
- discord.js discord-interactions Api and library types.
- OpenAI Send messages to ChatGPT.
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:
- 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"
- Copy your Public Key and Application ID, and put them somewhere locally (we'll need these later)
- 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.
- Go to this Discord ChatGPT Bot Demo. Click on the "Get a copy" button.
- 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
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
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
- Node.js versionnode/v16
- Function execution timeout90 s
- Dependencies
- aircode0.4.1
- axios1.4.0
- discord-interactions3.4.0
- discord.js14.11.0
- openai3.2.1
- tweetnacl1.0.3
- Environments
- DISCORD_BOT_TOKEN
- DISCORD_PUBLIC_KEY
- DISCORD_APP_ID
- OPENAI_KEY