Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 release: v3.3.0 #102

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
DISCORD_BOT_TOKEN=<discord_bot_token>
DISCORD_SUPPORT_ROLE_ID=<role_id>,<role_id>
CONTEXT_ID=<use_context_id>
ASKAI_CHANNEL=<channel_id_for_askai_bot>
ASKAI_CHANNELS=<channel_id_for_askai_bot>
REDIS_SERVER_URL=<REDIS_SERVER_DETAILS>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "thirdweb-support-discord-bot",
"version": "3.2.0",
"version": "3.3.0",
"description": "A self-hosted dedicated forum-based support Discord bot for the thirdweb community.",
"main": "src/bot.ts",
"author": "Waren Gonzaga",
Expand Down
44 changes: 30 additions & 14 deletions src/bot.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const fs = require("fs");
const path = require("node:path");
const { Client, GatewayIntentBits, Partials } = require("discord.js");
const { serverTime } = require("./utils/core");
const redis = require("./events/database");

// dot env
require("dotenv").config();

// discord bot environment vars
const { DISCORD_BOT_TOKEN } = process.env;
const { serverTime, localMode, debugMode } = require("./utils/core");
const redis = require("./utils/database");
const {
discord_bot_token,
discord_support_role,
context_id,
askai_channels
} = require("./utils/env");
const config = require("./config.json");

// discord bot instents and partials
const client = new Client({
Expand Down Expand Up @@ -41,10 +42,25 @@ for (const file of eventFiles) {
}
}

// check if the Redis is ready then log in the bot to Discord
redis.on("ready", () => {
console.log(`[${serverTime()}][log]: Redis is ready!`);

// check if the bot is in local development mode ignoring redis connection
if (localMode()) {
// inform the admin about the mode
console.log(`[${serverTime()}][WARNING]: This bot is in local mode, this means it will not connect to Redis server.`);
if(debugMode()) {
console.log(`[${serverTime()}][INFO]: Debug mode enabled!\n======\nDetails Loaded...\n\nDISCORD SUPPORT ROLES: ${discord_support_role}\nDISCORD ASK CHANNELS: ${askai_channels}\nCONTEXT ID: ${context_id}\n\nLOCAL: ${config.local.toString()}\nDEBUG: ${config.debug.toString()}\n======`);
}
// log in to Discord with your client's token
client.login(DISCORD_BOT_TOKEN);
});
client.login(discord_bot_token);
} else {
// check if the Redis is ready then log in the bot to Discord
redis.on("ready", () => {
console.log(`[${serverTime()}][LOG]: Redis is ready!`);

if(debugMode()) {
console.log(`[${serverTime()}][INFO]: Debug mode enabled!\n======\nDetails Loaded...\n\nDISCORD SUPPORT ROLES: ${discord_support_role}\nDISCORD ASK CHANNELS: ${askai_channels}\nCONTEXT ID: ${context_id}\n\nLOCAL: ${config.local.toString()}\nDEBUG: ${config.debug.toString()}\n======`);
}

// log in to Discord with your client's token
client.login(discord_bot_token);
});
}
8 changes: 6 additions & 2 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
"command_prefix": "!",
"utc_offset": -8,
"ai_thinking_message": "**🤖 Beep Boop Boop Beep:** <a:load:1210497921158619136> thinking...",
"getting_started_ai_message": "Hello, kindly use \\`!ask\\` or \\`!askai\\` followed by your question to get started.",
"getting_started_ai_message": "Hello, kindly use `!ask` or `!askai` followed by your question to get started.",
"helpful_message": "Thank you so much for your feedback!",
"not_helpful_messsage": "Thank you for your valuable feedback, this will help us improve the responses of our AI assistant.\n\nIn the meantime, would you like to contact a human customer success agent? Just click the link or the button below to submit a ticket.",
"reminder_mention": "Hey there! If you need assistance, please don't hesitate to reach out on our official support platform and create a ticket: https://thirdweb.com/support. Our dedicated team is always ready to help you out. Thank you for choosing to build with us!"
"reminder_outside_channel": "You can ask me all things thirdweb in the <#1214948528334311464> channel. Just type your question after the command \\`!askai\\` or \\`!ask\\` to get started.",
"reminder_mention": "Hey there! \n\nKindly use `!ask` or `!askai` followed by your question and I'll help you the best I can.\n\nIf you need assistance, please don't hesitate to reach out on our official support platform and create a ticket: https://thirdweb.com/support. Our dedicated team is always ready to help you out. Thank you for choosing to build with us!",
"response_team_mention": "We have moved to a community driven discord support model.\n\nYou can ask me all things thirdweb in the <#1214948528334311464> channel. Use the command \\`!askai\\` or \\`!ask\\` followed by your question to get started.",
"local": false,
"debug": false
}

21 changes: 0 additions & 21 deletions src/events/database.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/events/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ module.exports = {
name: Events.Error,
once: false,
execute(error) {
console.log(`[${serverTime()}][error]: ${error}`);
console.log(`[${serverTime()}][ERROR]: ${error}`);
},
};
20 changes: 7 additions & 13 deletions src/events/interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ const {
sendEmbedMessage,
serverTime,
CloseButtonComponent } = require("../utils/core");
const { ContextSDK } = require("@context-labs/sdk");
const redis = require("./database");
const redis = require("../utils/database");
const config = require("../config.json");
const context = new ContextSDK({});
const context = require("../utils/ai");
const { setQueryFeedback } = require("../utils/ai");

module.exports = {
name: Events.InteractionCreate,
Expand All @@ -27,17 +27,14 @@ module.exports = {
if (err) {
console.error(err);
} else {
await context.setQueryFeedback({
queryId: result,
helpful: true,
});
setQueryFeedback(result, true);
}
});
await interaction.message.edit({ components: [] });
await redis.del(messageId);

// log the feedback
console.log(`[${serverTime()}][log]: User sent a "Helpful" feedback!`);
console.log(`[${serverTime()}][LOG]: User sent a "Helpful" feedback!`);
}

if (interaction.customId === "not-helpful") {
Expand All @@ -51,17 +48,14 @@ module.exports = {
if (err) {
console.error(err);
} else {
await context.setQueryFeedback({
queryId: result,
helpful: false,
});
setQueryFeedback(result, false);
}
});
await interaction.message.edit({ components: [] });
await redis.del(messageId);

// log the feedback
console.log(`[${serverTime()}][log]: User sent a "Not Helpful" feedback!`);
console.log(`[${serverTime()}][LOG]: User sent a "Not Helpful" feedback!`);
}
}
}
Expand Down
66 changes: 38 additions & 28 deletions src/events/message.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
const { Events } = require("discord.js");
const {
sendEmbedMessage,
FeedbackButtonComponent,
serverTime,
FeedbackButtonComponent } = require("../utils/core");
localMode,
} = require("../utils/core");
const { version } = require("../../package.json");
const config = require("../config.json");
const redis = require("./database");
const { ContextSDK } = require("@context-labs/sdk");
const redis = require("../utils/database");
const { context, contextID } = require("../utils/ai");
const { discord_support_role, askai_channels } = require("../utils/env");

// discord bot env
const {
DISCORD_SUPPORT_ROLE_ID,
ASKAI_CHANNEL,
CONTEXT_ID } = process.env;
const roleIDs = DISCORD_SUPPORT_ROLE_ID.split(",");

const context = new ContextSDK({});
const roleIDs = discord_support_role.split(",");
const askChannelIDs = askai_channels.split(",");

module.exports = {
name: Events.MessageCreate,
Expand All @@ -38,15 +35,15 @@ module.exports = {
message.reply({
embeds: [sendEmbedMessage(`Latency is ${Date.now() - message.createdTimestamp}ms.`)],
});
console.log(`[${serverTime()}][log]: responded to ping command`);
console.log(`[${serverTime()}][LOG]: responded to ping command`);
}

// check version
if (message.content === "!!version") {
message.reply({
embeds: [sendEmbedMessage(`Version: ${version}`)],
});
console.log(`[${serverTime()}][log]: responded to version command in version ${version}`);
console.log(`[${serverTime()}][LOG]: responded to version command in version ${version}`);
}

/**
Expand All @@ -64,28 +61,41 @@ module.exports = {
embeds: [sendEmbedMessage(config.getting_started_ai_message)],
});
} else {
if (message.channel.id === ASKAI_CHANNEL) {
if (askChannelIDs.includes(message.channel.id)) {
let aiMessageLoading = await message.channel.send({
embeds: [sendEmbedMessage(config.ai_thinking_message)],
});

await context.query({
botId: CONTEXT_ID,
botId: contextID,
query: question,
onComplete: async (query) => {
// respond to the user with the answer from the AI
await message.channel.messages.fetch(aiMessageLoading.id).then((msg) => {
msg.edit({
content: `Hey <@${message.author.id}> 👇`,
embeds: [
sendEmbedMessage(`**Response:**\n${query.output.toString()}`),
],
components: [FeedbackButtonComponent()],

})
redis.set(msg.id, query._id);
// check if local mode is active or not
if(!localMode()) {
// respond to the user with the answer from the AI
await message.channel.messages.fetch(aiMessageLoading.id).then((msg) => {
msg.edit({
content: `Hey <@${message.author.id}> 👇`,
embeds: [
sendEmbedMessage(`**Response:**\n${query.output.toString()}`),
],
components: [FeedbackButtonComponent()],

})
redis.set(msg.id, query._id);
});
} else {
// respond to the user with the answer from the AI
await message.channel.messages.fetch(aiMessageLoading.id).then((msg) => {
msg.edit({
content: `Hey <@${message.author.id}> 👇`,
embeds: [
sendEmbedMessage(`**Response:**\n${query.output.toString()}`),
]
})
});
}
);

},
onError: async (error) => {
Expand All @@ -109,7 +119,7 @@ module.exports = {
// if the command is not from the channel
message.reply({
content: `Hey <@${message.author.id}> 👇`,
embeds: [sendEmbedMessage(`You can ask me all things thirdweb in the <#${ASKAI_CHANNEL}> channel. Just type your question after the command \`!askai\` or \`!ask\` to get started.`)],
embeds: [sendEmbedMessage(config.reminder_outside_channel)],
});
}
}
Expand All @@ -131,7 +141,7 @@ module.exports = {
let mentioned = message.guild.members.cache.get(mention.users.first().id)
if (mentioned.roles.cache.hasAny(...roleIDs) && !member.roles.cache.hasAny(...roleIDs)) {
message.reply({
embeds: [sendEmbedMessage(`We have moved to a community driven discord support model.\n\nYou can ask me all things thirdweb in the <#${ASKAI_CHANNEL}> channel. Use the command \`!askai\` or \`!ask\` followed by your question to get started.`)],
embeds: [sendEmbedMessage(config.response_team_mention)],
}).then(msg => {
setTimeout(() => msg.delete(), 60000)
})
Expand Down
2 changes: 1 addition & 1 deletion src/events/ready.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ module.exports = {

});

console.log(`[${serverTime()}][online]: logged in as ${bot.user.tag} @ v${packageJSON.version}`);
console.log(`[${serverTime()}][ONLINE]: logged in as ${bot.user.tag} @ v${packageJSON.version}`);
},
};
14 changes: 14 additions & 0 deletions src/utils/ai.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { ContextSDK } = require("@context-labs/sdk");
const { context_id } = require("./env");

const context = new ContextSDK({});
const contextID = context_id;

const setQueryFeedback = (queryId, helpful) => {
context.setQueryFeedback({
queryId: queryId,
helpful: helpful,
});
}

module.exports = { context, contextID, setQueryFeedback };
37 changes: 33 additions & 4 deletions src/utils/core.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require('discord.js');

const {
EmbedBuilder,
ButtonBuilder,
ButtonStyle,
ActionRowBuilder } = require('discord.js');
const moment = require('moment');
const config = require('../config.json');
const packageJSON = require('../../package.json');

/**
* This function determines the current mode of the bot.
* @returns {string} The mode of the bot.
*/

const mode = () => localMode() ? (debugMode() ? "LOCAL-DEBUG" : "LOCAL") : (debugMode() ? "BUILD-DEBUG" : "BUILD");

/**
* send embed message
Expand All @@ -16,7 +27,7 @@ const sendEmbedMessage = (message) => {
{ name: 'Need Help?', value: 'Submit a ticket here: https://thirdweb.com/support', inline: false}
)
.setTimestamp()
.setFooter({ text: 'thirdweb', iconURL: 'https://ipfs.io/ipfs/QmTWMy6Dw1PDyMxHxNcmDmPE8zqFCQMfD6m2feHVY89zgu/Icon/Favicon-01.png' });
.setFooter({ text: `thirdweb @ ${packageJSON.version} ${mode()}`, iconURL: 'https://ipfs.io/ipfs/QmTWMy6Dw1PDyMxHxNcmDmPE8zqFCQMfD6m2feHVY89zgu/Icon/Favicon-01.png' });

}
/**
Expand Down Expand Up @@ -75,10 +86,28 @@ const serverTime = () => {
return moment.utc().utcOffset(config.utc_offset).format('M/DD/YYYY HH:mm:ss');
}

/**
* check if the bot is in local mode or not
* @returns {boolean}
*/
const localMode = () => {
return config.local ? true : false;
}

/**
* check if the bot is in debug mode or not
* @returns {boolean}
*/
const debugMode = () => {
return config.debug ? true : false;
}

module.exports = {
sendEmbedMessage,
CloseButtonComponent,
FeedbackButtonComponent,
formatTime,
serverTime
serverTime,
localMode,
debugMode
}
Loading
Loading