From 1ca5dbf98766e59b5c41e5a48d28e2d01a4dc237 Mon Sep 17 00:00:00 2001 From: atridadl Date: Fri, 10 Nov 2023 18:36:44 -0700 Subject: [PATCH] Updated image gen --- src/commands/betapic.ts | 93 ----------------------------- src/commands/fancypic.ts | 124 ++++++++++----------------------------- src/commands/pic.ts | 51 ++++------------ 3 files changed, 43 insertions(+), 225 deletions(-) delete mode 100644 src/commands/betapic.ts diff --git a/src/commands/betapic.ts b/src/commands/betapic.ts deleted file mode 100644 index 31ad0b6..0000000 --- a/src/commands/betapic.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Args, BucketScope, Command } from '@sapphire/framework'; -import { AttachmentBuilder, Message } from 'discord.js'; -import OpenAI from 'openai'; - -const openai = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY -}); - -// @ts-ignore -@ApplyOptions({ - description: 'Shhhh!', - options: ['prompt'], - // 10mins - cooldownDelay: 400_000, - cooldownLimit: 1, - // Yes... I did hardcode myself. - cooldownFilteredUsers: ['83679718401904640'], - cooldownScope: BucketScope.User -}) -export class UserCommand extends Command { - // Register Chat Input and Context Menu command - public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => - builder - .setName(this.name) - .setDescription(this.description) - .addStringOption((option) => - option.setName('prompt').setDescription('The prompt you will use to generate an image!').setRequired(true) - ) - ); - } - - // Message command - public async messageRun(message: Message, args: Args) { - return this.pic(message, args.getOption('prompt') || 'Scold me for not passing any prompt in.'); - } - - // Chat Input (slash) command - public async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - return this.pic(interaction, interaction.options.getString('prompt') || 'NOTHING'); - } - - private async pic(interactionOrMessage: Message | Command.ChatInputCommandInteraction | Command.ContextMenuCommandInteraction, prompt: string) { - const askMessage = - interactionOrMessage instanceof Message - ? await interactionOrMessage.channel.send({ content: 'šŸ¤” Thinking... šŸ¤”' }) - : await interactionOrMessage.reply({ content: 'šŸ¤” Thinking... šŸ¤”', fetchReply: true }); - - const response = await openai.images.generate({ - model: 'dall-e-3', - prompt, - n: 1, - size: '1024x1024' - }); - - const imageUrl = response.data[0].url || ''; - // get an array buffer - const imageBuffer = await fetch(imageUrl).then((r) => r.arrayBuffer()); - - if (response.data.length === 0) { - const content = `Sorry, I can't complete the prompt for: ${prompt}`; - - if (interactionOrMessage instanceof Message) { - return askMessage.edit({ content }); - } - - return interactionOrMessage.editReply({ - content: content - }); - } else { - const imageAttachment: AttachmentBuilder[] = []; - - imageAttachment.push( - new AttachmentBuilder(Buffer.from(new Uint8Array(imageBuffer)), { - name: 'response.jpg', - description: "Himbot's Response" - }) - ); - - const content = `Prompt: ${prompt}:`; - - if (interactionOrMessage instanceof Message) { - return askMessage.edit({ content, files: imageAttachment }); - } - - return interactionOrMessage.editReply({ - content, - files: imageAttachment - }); - } - } -} diff --git a/src/commands/fancypic.ts b/src/commands/fancypic.ts index b391820..e478a9e 100644 --- a/src/commands/fancypic.ts +++ b/src/commands/fancypic.ts @@ -1,15 +1,18 @@ import { ApplyOptions } from '@sapphire/decorators'; import { Args, BucketScope, Command } from '@sapphire/framework'; import { AttachmentBuilder, Message } from 'discord.js'; +import OpenAI from 'openai'; -// This is literally the worlds messiest TS code. Please don't judge me... +const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY +}); // @ts-ignore @ApplyOptions({ - description: 'Make a picture... but high res!', - options: ['prompt', 'number of pictures'], + description: 'Pic... but better!', + options: ['prompt'], // 10mins - cooldownDelay: 300_000, + cooldownDelay: 400_000, cooldownLimit: 1, // Yes... I did hardcode myself. cooldownFilteredUsers: ['83679718401904640'], @@ -25,85 +28,38 @@ export class UserCommand extends Command { .addStringOption((option) => option.setName('prompt').setDescription('The prompt you will use to generate an image!').setRequired(true) ) - .addStringOption((option) => - option - .setName('amount') - .setDescription('The number of images you would like to generate. Maximum 2.') - .setChoices( - ...[ - { name: '1', value: '1' }, - { name: '2', value: '2' } - ] - ) - ) ); } // Message command public async messageRun(message: Message, args: Args) { - const amount = Math.abs(Number(args.getOption('amount'))); - return this.picHr(message, args.getOption('prompt') || 'Scold me for not passing any prompt in.', amount <= 2 ? amount : 1); + return this.pic(message, args.getOption('prompt') || 'NOTHING'); } // Chat Input (slash) command public async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const amount = Number(interaction.options.getString('amount')); - return this.picHr(interaction, interaction.options.getString('prompt') || 'NOTHING', amount || 1); + return this.pic(interaction, interaction.options.getString('prompt') || 'NOTHING'); } - private async picHr( - interactionOrMessage: Message | Command.ChatInputCommandInteraction | Command.ContextMenuCommandInteraction, - prompt: string, - amount: number - ) { + private async pic(interactionOrMessage: Message | Command.ChatInputCommandInteraction | Command.ContextMenuCommandInteraction, prompt: string) { const askMessage = interactionOrMessage instanceof Message ? await interactionOrMessage.channel.send({ content: 'šŸ¤” Thinking... šŸ¤”' }) : await interactionOrMessage.reply({ content: 'šŸ¤” Thinking... šŸ¤”', fetchReply: true }); - const creditCountResponse = await fetch(`https://api.stability.ai/v1/user/balance`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${process.env.STABILITY_API_KEY}` - } - }); - - const balance = (await creditCountResponse.json()).credits || 0; - - if (balance > 5) { - const imageGenResponse = await fetch(`https://api.stability.ai/v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - Authorization: `Bearer ${process.env.STABILITY_API_KEY}` - }, - body: JSON.stringify({ - text_prompts: [ - { - text: prompt - } - ], - cfg_scale: 6, - clip_guidance_preset: 'FAST_BLUE', - height: 1024, - width: 1024, - samples: amount, - steps: 32, - seed: Number(String(interactionOrMessage.member?.user.id).substring(0, 5)) || 0 - }) + try { + const response = await openai.images.generate({ + model: 'dall-e-3', + prompt, + n: 1, + size: '1024x1024' }); - interface GenerationResponse { - artifacts: Array<{ - base64: string; - seed: number; - finishReason: string; - }>; - } + const imageUrl = response.data[0].url || ''; + // get an array buffer + const imageBuffer = await fetch(imageUrl).then((r) => r.arrayBuffer()); - if (!imageGenResponse.ok) { + if (response.data.length === 0) { const content = `Sorry, I can't complete the prompt for: ${prompt}`; if (interactionOrMessage instanceof Message) { @@ -114,34 +70,16 @@ export class UserCommand extends Command { content: content }); } else { - const responseJSON = (await imageGenResponse.json()) as GenerationResponse; const imageAttachment: AttachmentBuilder[] = []; - for (let i = 0; i < responseJSON.artifacts.length; i++) { - imageAttachment.push( - new AttachmentBuilder(Buffer.from(responseJSON.artifacts[i].base64, 'base64'), { - name: 'response.jpg', - description: "Himbot's Response" - }) - ); - } + imageAttachment.push( + new AttachmentBuilder(Buffer.from(new Uint8Array(imageBuffer)), { + name: 'himbot_response.jpg', + description: `An image generated by Himbot using the prompt: ${prompt}` + }) + ); - const newCreditCountResponse = await fetch(`https://api.stability.ai/v1/user/balance`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${process.env.STABILITY_API_KEY}` - } - }); - - const newBalance = (await newCreditCountResponse.json()).credits || 0; - - const content = - `Credits Used: ${balance - newBalance}\nPrompt: ${prompt}${ - balance <= 300 - ? `\n\nāš ļøI am now at ${balance} credits. If you'd like to help fund this command, please type "/support" for details!` - : '' - }` || 'ERROR!'; + const content = `Prompt: ${prompt}:`; if (interactionOrMessage instanceof Message) { return askMessage.edit({ content, files: imageAttachment }); @@ -152,16 +90,14 @@ export class UserCommand extends Command { files: imageAttachment }); } - } else { - const content = `Oops! We're out of credits for this. If you'd like to help fund this command, please type "/support" for details!`; + } catch (error) { + const content = "Sorry, I can't complete the prompt for: " + prompt + '\n' + 'Error: ' + error; if (interactionOrMessage instanceof Message) { return askMessage.edit({ content }); } - return interactionOrMessage.editReply({ - content: content - }); + return interactionOrMessage.editReply({ content }); } } } diff --git a/src/commands/pic.ts b/src/commands/pic.ts index 3d19064..5fee092 100644 --- a/src/commands/pic.ts +++ b/src/commands/pic.ts @@ -2,14 +2,14 @@ import { ApplyOptions } from '@sapphire/decorators'; import { Args, BucketScope, Command } from '@sapphire/framework'; import { AttachmentBuilder, Message } from 'discord.js'; -// This is literally the worlds messiest TS code. Please don't judge me... +// This is literally the world's messiest Typescript code. Please don't judge me... // @ts-ignore @ApplyOptions({ - description: 'Make a picture!', - options: ['prompt', 'amount'], + description: 'Make a picture... but high res!', + options: ['prompt'], // 10mins - cooldownDelay: 100_000, + cooldownDelay: 300_000, cooldownLimit: 1, // Yes... I did hardcode myself. cooldownFilteredUsers: ['83679718401904640'], @@ -25,39 +25,20 @@ export class UserCommand extends Command { .addStringOption((option) => option.setName('prompt').setDescription('The prompt you will use to generate an image!').setRequired(true) ) - .addStringOption((option) => - option - .setName('amount') - .setDescription('The number of images you would like to generate. Maximum 4.') - .setChoices( - ...[ - { name: '1', value: '1' }, - { name: '2', value: '2' }, - { name: '3', value: '3' }, - { name: '4', value: '4' } - ] - ) - ) ); } // Message command public async messageRun(message: Message, args: Args) { - const amount = Math.abs(Number(args.getOption('amount'))); - return this.pic(message, args.getOption('prompt') || 'Scold me for not passing any prompt in.', amount <= 4 ? amount : 1); + return this.picHr(message, args.getOption('prompt') || 'Scold me for not passing any prompt in.'); } // Chat Input (slash) command public async chatInputRun(interaction: Command.ChatInputCommandInteraction) { - const amount = Number(interaction.options.getString('amount')); - return this.pic(interaction, interaction.options.getString('prompt') || 'NOTHING', amount || 1); + return this.picHr(interaction, interaction.options.getString('prompt') || 'NOTHING'); } - private async pic( - interactionOrMessage: Message | Command.ChatInputCommandInteraction | Command.ContextMenuCommandInteraction, - prompt: string, - amount: number - ) { + private async picHr(interactionOrMessage: Message | Command.ChatInputCommandInteraction | Command.ContextMenuCommandInteraction, prompt: string) { const askMessage = interactionOrMessage instanceof Message ? await interactionOrMessage.channel.send({ content: 'šŸ¤” Thinking... šŸ¤”' }) @@ -74,7 +55,7 @@ export class UserCommand extends Command { const balance = (await creditCountResponse.json()).credits || 0; if (balance > 5) { - const imageGenResponse = await fetch(`https://api.stability.ai/v1/generation/stable-diffusion-xl-beta-v2-2-2/text-to-image`, { + const imageGenResponse = await fetch(`https://api.stability.ai/v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -89,9 +70,8 @@ export class UserCommand extends Command { ], cfg_scale: 6, clip_guidance_preset: 'FAST_BLUE', - height: 512, - width: 512, - samples: amount, + height: 1024, + width: 1024, steps: 32, seed: Number(String(interactionOrMessage.member?.user.id).substring(0, 5)) || 0 }) @@ -122,8 +102,8 @@ export class UserCommand extends Command { for (let i = 0; i < responseJSON.artifacts.length; i++) { imageAttachment.push( new AttachmentBuilder(Buffer.from(responseJSON.artifacts[i].base64, 'base64'), { - name: 'response.jpg', - description: "Himbot's Response" + name: 'himbot_response.jpg', + description: `An image generated by Himbot using the prompt: ${prompt}` }) ); } @@ -138,12 +118,7 @@ export class UserCommand extends Command { const newBalance = (await newCreditCountResponse.json()).credits || 0; - const content = - `Credits Used: ${balance - newBalance}\nPrompt: ${prompt}${ - balance <= 300 - ? `\n\nāš ļøI am now at ${balance} credits. If you'd like to help fund this command, please type "/support" for details!` - : '' - }` || 'ERROR!'; + const content = `Credits Used: ${balance - newBalance}\nPrompt: ${prompt}` || 'ERROR!'; if (interactionOrMessage instanceof Message) { return askMessage.edit({ content, files: imageAttachment });