Last active
January 22, 2023 03:41
-
-
Save TheBrokenRail/4b37e7c44e8f721d8bd845050d034c16 to your computer and use it in GitHub Desktop.
ShakespeareBot
import { ChatGPTAPIBrowser, ChatResponse, SendMessageOptions } from 'chatgpt'; | |
import { Client, GatewayIntentBits, Events, PermissionsBitField, WebhookCreateMessageOptions, MessageType, MessageFlags, TextChannel, ThreadChannel, WebhookEditMessageOptions, ForumChannel, Webhook } from 'discord.js'; | |
import { RateLimiter } from 'limiter'; | |
// Login To ChatGPT | |
const api = new ChatGPTAPIBrowser({ | |
email: '<Your Email>', | |
password: '<Your Password>', | |
isGoogleLogin: true | |
}); | |
await api.initSession(); | |
// Create Discord Client | |
const client = new Client({ | |
intents: [ | |
GatewayIntentBits.Guilds, | |
GatewayIntentBits.GuildMessages, | |
GatewayIntentBits.MessageContent | |
] | |
}); | |
// Login To Discord | |
const TOKEN = '<Your Token>'; | |
client.once(Events.ClientReady, c => { | |
console.log(`Ready! Logged in as ${c.user.tag}`); | |
}); | |
client.login(TOKEN); | |
// Rate Limiter | |
const limiter = new RateLimiter({tokensPerInterval: 10, interval: 'minute'}); | |
// Prevent ChatGPT Message Interleaving | |
let lastChatPromise: Promise<ChatResponse | string | null> = Promise.resolve(null); | |
function sendMessage(api: ChatGPTAPIBrowser, prompt: string, options: SendMessageOptions): Promise<ChatResponse | string | null> { | |
lastChatPromise = lastChatPromise.then(async () => { | |
try { | |
await limiter.removeTokens(1); | |
return await api.sendMessage(prompt, options); | |
} catch (e) { | |
return String(e); | |
} | |
}); | |
return lastChatPromise; | |
} | |
async function sendMessageSafe(api: ChatGPTAPIBrowser, prompt: string, options: SendMessageOptions): Promise<ChatResponse | null> { | |
const result = await sendMessage(api, prompt, options); | |
if (typeof result === 'string') { | |
throw result; | |
} | |
return result; | |
} | |
// Message Handler | |
client.on(Events.MessageCreate, async message => { | |
// Check Thread | |
let channel: TextChannel | ForumChannel | null = null; | |
let thread: ThreadChannel | null = null; | |
if (message.channel instanceof ThreadChannel) { | |
const parent = message.channel.parent | |
if (parent instanceof TextChannel || parent instanceof ForumChannel) { | |
channel = parent; | |
thread = message.channel; | |
} | |
} else if (message.channel instanceof TextChannel) { | |
channel = message.channel; | |
} | |
// Check Role | |
if (!channel || message.system || !message.deletable || !message.member || !message.member.roles.cache.has('<Target Role>')) { | |
return; | |
} | |
// Check Permission | |
if (!channel.permissionsFor(client.user!)?.has(PermissionsBitField.Flags.SendMessages)) { | |
return; | |
}; | |
// Fake User | |
const webhookName = 'ShakespeareBot'; | |
let webhook: Webhook | null = null; | |
const webhooks = (await channel.fetchWebhooks()).values(); | |
for (const potentialWebhook of webhooks) { | |
if (potentialWebhook.name === webhookName) { | |
webhook = potentialWebhook; | |
break; | |
} | |
} | |
if (!webhook) { | |
webhook = await channel.createWebhook({ | |
name: webhookName | |
}); | |
} | |
// Send Temporary Message | |
const newMessage: WebhookCreateMessageOptions = { | |
content: '*Translating message...*', | |
files: Array.from(message.attachments.values()), | |
embeds: message.embeds, | |
tts: message.tts, | |
avatarURL: message.member.displayAvatarURL(), | |
username: message.member.displayName | |
}; | |
if (message.flags.has(MessageFlags.SuppressEmbeds)) { | |
newMessage.flags = MessageFlags.SuppressEmbeds; | |
} | |
if (thread) { | |
newMessage.threadId = thread.id; | |
} | |
const sendPromise = webhook.send(newMessage); | |
// Delete Old Message | |
const deletePromise = message.delete(); | |
// Wait | |
await Promise.all([sendPromise, deletePromise]); | |
// Get New Message | |
const prompt = 'Rewrite the following message in the style of Shakespeare.\n\n' + message.content; | |
const timeout = 2 * 60 * 1000; // 2 minutes | |
let response: string | null = null; | |
try { | |
let result = await sendMessageSafe(api, prompt, {timeoutMs: timeout}); | |
// Remove Quotes | |
result = await sendMessageSafe(api, 'Remove extra quotation marks if present.', { | |
conversationId: result!.conversationId, | |
parentMessageId: result!.messageId, | |
timeoutMs: timeout | |
}); | |
// Store | |
response = result!.response; | |
} catch (e) { | |
response = '**ChatGPT Error:** ' + e + '\n**Original Message:** ' + message.content; | |
} | |
// Edit Message | |
const editedMessage: WebhookEditMessageOptions = { | |
content: response.trim(), | |
files: newMessage.files, | |
embeds: newMessage.embeds, | |
threadId: newMessage.threadId | |
}; | |
if (message.type == MessageType.Reply) { | |
editedMessage.content = '*Replying to <https://discord.com/channels/' + message.reference?.guildId! + '/' + message.reference?.channelId! + '/' + message.reference?.messageId! + '>*\n\n' + editedMessage.content; | |
} | |
await webhook.editMessage((await sendPromise).id, editedMessage); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment