Skip to content

Commit c21ca69

Browse files
committed
Create new imagine command, legacy imagine command, support quad image preview
1 parent 4ef4e3b commit c21ca69

File tree

8 files changed

+268
-60
lines changed

8 files changed

+268
-60
lines changed

src/commands/imagine.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,6 @@ export default function(): BotCommand {
88
option.setName('prompt')
99
.setDescription('The prompt to generate an image with')
1010
.setRequired(true))
11-
.addIntegerOption(option =>
12-
option.setName('width')
13-
.setMinValue(128)
14-
.setMaxValue(1024)
15-
.setDescription('The width of the generated image')
16-
.setChoices(
17-
{name: '128px', value: 128},
18-
{name: '256px', value: 256},
19-
{name: '512px', value: 512},
20-
{name: '768px', value: 768},
21-
{name: '1024px', value: 1024}
22-
))
23-
.addIntegerOption(option =>
24-
option.setName('height')
25-
.setMinValue(128)
26-
.setMaxValue(1024)
27-
.setDescription('The height of the generated image')
28-
.setChoices(
29-
{name: '128px', value: 128},
30-
{name: '256px', value: 256},
31-
{name: '512px', value: 512},
32-
{name: '768px', value: 768},
33-
{name: '1024px', value: 1024}
34-
))
3511
.addAttachmentOption(option =>
3612
option.setName('image')
3713
.setDescription('Inital jpg or png image to generate variations of. Will be resized to the specified width and height'))
@@ -43,11 +19,6 @@ export default function(): BotCommand {
4319
.setDescription('Prompt strength when using init image. 1.0 corresponds to full destruction of information in image')
4420
.setMinValue(0)
4521
.setMaxValue(1))
46-
.addIntegerOption(option =>
47-
option.setName('numout')
48-
.setDescription('How many images to generate with this prompt')
49-
.setMinValue(1)
50-
.setMaxValue(4))
5122
.addIntegerOption(option =>
5223
option.setName('numsteps')
5324
.setDescription('Number of denoising steps. Default 50')

src/commands/imagineLegacy.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { SlashCommandBuilder } from 'discord.js';
2+
import { BotCommand } from '../types';
3+
export default function(): BotCommand {
4+
const command = new SlashCommandBuilder()
5+
.setName('imagine-legacy')
6+
.setDescription('Generate images from prompts')
7+
.addStringOption(option =>
8+
option.setName('prompt')
9+
.setDescription('The prompt to generate an image with')
10+
.setRequired(true))
11+
.addIntegerOption(option =>
12+
option.setName('width')
13+
.setMinValue(128)
14+
.setMaxValue(1024)
15+
.setDescription('The width of the generated image')
16+
.setChoices(
17+
{name: '128px', value: 128},
18+
{name: '256px', value: 256},
19+
{name: '512px', value: 512},
20+
{name: '768px', value: 768},
21+
{name: '1024px', value: 1024}
22+
))
23+
.addIntegerOption(option =>
24+
option.setName('height')
25+
.setMinValue(128)
26+
.setMaxValue(1024)
27+
.setDescription('The height of the generated image')
28+
.setChoices(
29+
{name: '128px', value: 128},
30+
{name: '256px', value: 256},
31+
{name: '512px', value: 512},
32+
{name: '768px', value: 768},
33+
{name: '1024px', value: 1024}
34+
))
35+
.addAttachmentOption(option =>
36+
option.setName('image')
37+
.setDescription('Inital jpg or png image to generate variations of. Will be resized to the specified width and height'))
38+
.addAttachmentOption(option =>
39+
option.setName('mask')
40+
.setDescription('Black and white jpg or png image to use as mask for inpainting over init_image'))
41+
.addNumberOption(option =>
42+
option.setName('pstrength')
43+
.setDescription('Prompt strength when using init image. 1.0 corresponds to full destruction of information in image')
44+
.setMinValue(0)
45+
.setMaxValue(1))
46+
.addIntegerOption(option =>
47+
option.setName('numout')
48+
.setDescription('How many images to generate with this prompt')
49+
.setMinValue(1)
50+
.setMaxValue(4))
51+
.addIntegerOption(option =>
52+
option.setName('numsteps')
53+
.setDescription('Number of denoising steps. Default 50')
54+
.setMinValue(1)
55+
.setMaxValue(500))
56+
.addNumberOption(option =>
57+
option.setName('guidescale')
58+
.setDescription('Scale for classifier-free guidance. Default 7.5')
59+
.setMinValue(1)
60+
.setMaxValue(20))
61+
.addIntegerOption(option =>
62+
option.setName('seed')
63+
.setDescription('Generation seed. Randomized if not provided')
64+
.setMinValue(0)
65+
.setMaxValue(999999999))
66+
67+
return {
68+
command,
69+
commandJson: command.toJSON()
70+
}
71+
}

src/embeds/imageResult.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,43 @@
1-
import { EmbedBuilder, AttachmentBuilder } from 'discord.js'
2-
import { BotEmbed } from '../types'
1+
import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, codeBlock } from 'discord.js'
2+
import { BotEmbed, QueueItem } from '../types'
33

4-
export default function(): BotEmbed {
4+
export default function(queueItem: QueueItem): BotEmbed {
55

66
return {
77
embeds: [
88
new EmbedBuilder()
99
.setColor('#6aaa64')
1010
.setTitle('Processing Complete')
11-
.setImage(`attachment://stable-confusion.jpeg`)
11+
.setDescription('Result for parameters')
1212
.setTimestamp()
13-
14-
]
13+
.addFields([
14+
{name: 'Prompt', value: codeBlock(queueItem.prediction.prompt), inline: false},
15+
{name: 'Prompt Strength', value: queueItem.prediction.promptStrength.toString(), inline: true},
16+
{name: 'Steps', value: queueItem.prediction.numInferenceSteps.toString(), inline: true},
17+
{name: 'Guidance Scale', value: queueItem.prediction.guidanceScale.toString(), inline: true},
18+
{name: 'Has Mask', value: typeof queueItem.prediction.mask === 'undefined' ? 'No' : 'Yes', inline: true},
19+
{name: 'Has Base Image', value: typeof queueItem.prediction.initImage === 'undefined' ? 'No' : 'Yes', inline: true},
20+
{name: 'Seed', value: codeBlock(queueItem.seed.toString()), inline: false},
21+
{name: 'Prompt ID', value: codeBlock(queueItem.uuid), inline: false}
22+
])
23+
.setImage(`attachment://stable-confusion_${queueItem.uuid}_collage.png`)
24+
],
25+
components: [
26+
new ActionRowBuilder()
27+
.addComponents([
28+
new ButtonBuilder()
29+
.setCustomId('button-imagine-result-regenerate')
30+
.setLabel('🔁 Regenerate All')
31+
.setStyle(ButtonStyle.Primary),
32+
new ButtonBuilder()
33+
.setCustomId('button-imagine-result-upscale')
34+
.setLabel('⬆️ Upscale..')
35+
.setStyle(ButtonStyle.Primary),
36+
new ButtonBuilder()
37+
.setCustomId('button-imagine-result-variant-of')
38+
.setLabel('🆎 Variant of..')
39+
.setStyle(ButtonStyle.Primary),
40+
])
41+
]
1542
}
1643
}

src/embeds/imageResultLegacy.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, codeBlock } from 'discord.js'
2+
import { BotEmbed, QueueItem } from '../types'
3+
4+
export default function(queueItem: QueueItem): BotEmbed {
5+
6+
return {
7+
embeds: [
8+
new EmbedBuilder()
9+
.setColor('#6aaa64')
10+
.setTitle('Processing Complete')
11+
.setDescription('Result for parameters\n\nGenerated using the legacy imagine command. Check out `/imagine` for new features!')
12+
.setTimestamp()
13+
.addFields([
14+
{name: 'Prompt', value: codeBlock(queueItem.prediction.prompt), inline: false},
15+
{name: 'Width', value: queueItem.prediction.width.toString(), inline: true},
16+
{name: 'Height', value: queueItem.prediction.height.toString(), inline: true},
17+
{name: 'Prompt Strength', value: queueItem.prediction.promptStrength.toString(), inline: true},
18+
{name: 'Steps', value: queueItem.prediction.numInferenceSteps.toString(), inline: true},
19+
{name: 'Guidance Scale', value: queueItem.prediction.guidanceScale.toString(), inline: true},
20+
{name: 'Has Mask', value: typeof queueItem.prediction.mask === 'undefined' ? 'No' : 'Yes', inline: true},
21+
{name: 'Has Base Image', value: typeof queueItem.prediction.initImage === 'undefined' ? 'No' : 'Yes', inline: true},
22+
{name: 'Seed', value: codeBlock(queueItem.seed.toString()), inline: false},
23+
{name: 'Prompt ID', value: codeBlock(queueItem.uuid), inline: false}
24+
])
25+
.setImage(`attachment://stable-confusion_${queueItem.uuid}.jpeg`)
26+
],
27+
components: []
28+
}
29+
}

src/embeds/processingPrompt.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ export default function(queueItem: QueueItem): BotEmbed {
77
new EmbedBuilder()
88
.setColor('#030354')
99
.setTitle('Processing Prompt')
10-
.setDescription('Your image is being generated..')
10+
.setDescription('Your images are being generated..')
1111
.setThumbnail('https://i.gifer.com/2RNf.gif')
1212
.setTimestamp()
1313
.addFields([
1414
{name: 'Prompt', value: codeBlock(queueItem.prediction.prompt), inline: false},
15-
{name: 'Width', value: queueItem.prediction.width.toString(), inline: true},
16-
{name: 'Height', value: queueItem.prediction.height.toString(), inline: true},
1715
{name: 'Prompt Strength', value: queueItem.prediction.promptStrength.toString(), inline: true},
1816
{name: 'Steps', value: queueItem.prediction.numInferenceSteps.toString(), inline: true},
1917
{name: 'Guidance Scale', value: queueItem.prediction.guidanceScale.toString(), inline: true},

src/events/commandImagine.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { Attachment, Interaction } from 'discord.js'
1+
import { Interaction } from 'discord.js'
22
import { Bot } from '../bot'
33
import { BotEvent, QueueItem } from '../types'
44
import addedToQueue from '../embeds/addedToQueue'
5-
import { isNil } from 'ramda'
65
import { v4 as uuidv4 } from 'uuid'
76
import addedToQueueNoWait from '../embeds/addedToQueueNoWait'
87
import { getImageAttachmentURL, getRandomInt, validateHeight, validateWidth } from '../utils'
@@ -18,12 +17,9 @@ const botEvent: BotEvent = {
1817
await interaction.deferReply()
1918

2019
const prompt = interaction.options.getString('prompt', true)
21-
const width = validateWidth(interaction.options.getInteger('width'))
22-
const height = validateHeight(interaction.options.getInteger('height'))
2320
const initImage = getImageAttachmentURL(interaction.options.getAttachment('image'))
2421
const mask = getImageAttachmentURL(interaction.options.getAttachment('mask'))
2522
const promptStrength = interaction.options.getNumber('pstrength')
26-
const numOutputs = interaction.options.getInteger('numout')
2723
const numInferenceSteps = interaction.options.getInteger('numsteps')
2824
const guidanceScale = interaction.options.getNumber('guidancescale')
2925
const seed = interaction.options.getInteger('seed')
@@ -35,12 +31,12 @@ const botEvent: BotEvent = {
3531
interaction,
3632
prediction: {
3733
prompt,
38-
width,
39-
height,
34+
width: 512,
35+
height: 512,
4036
initImage,
4137
mask,
4238
promptStrength: promptStrength ?? 0.8,
43-
numOutputs: numOutputs ?? 1,
39+
numOutputs: 4,
4440
numInferenceSteps: numInferenceSteps ?? 50,
4541
guidanceScale: guidanceScale ?? 7.5
4642
}

src/events/commandImagineLegacy.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { Interaction } from 'discord.js'
2+
import { Bot } from '../bot'
3+
import { BotEvent, QueueItem } from '../types'
4+
import addedToQueue from '../embeds/addedToQueue'
5+
import { v4 as uuidv4 } from 'uuid'
6+
import addedToQueueNoWait from '../embeds/addedToQueueNoWait'
7+
import { getImageAttachmentURL, getRandomInt, validateHeight, validateWidth } from '../utils'
8+
9+
const botEvent: BotEvent = {
10+
name: 'Command Handler - Imagine Legacy',
11+
event: 'interactionCreate',
12+
once: false,
13+
async execute(bot: Bot, interaction: Interaction) {
14+
if (!interaction.isChatInputCommand()) return
15+
if (interaction.commandName !== 'imagine-legacy') return
16+
17+
await interaction.deferReply()
18+
19+
const prompt = interaction.options.getString('prompt', true)
20+
const width = validateWidth(interaction.options.getInteger('width'))
21+
const height = validateHeight(interaction.options.getInteger('height'))
22+
const initImage = getImageAttachmentURL(interaction.options.getAttachment('image'))
23+
const mask = getImageAttachmentURL(interaction.options.getAttachment('mask'))
24+
const promptStrength = interaction.options.getNumber('pstrength')
25+
const numOutputs = interaction.options.getInteger('numout')
26+
const numInferenceSteps = interaction.options.getInteger('numsteps')
27+
const guidanceScale = interaction.options.getNumber('guidancescale')
28+
const seed = interaction.options.getInteger('seed')
29+
30+
const queueItem: QueueItem = {
31+
discordCaller: interaction.user.id.toString(),
32+
seed: seed ?? getRandomInt(1, 99999999),
33+
uuid: uuidv4(),
34+
interaction,
35+
prediction: {
36+
isLegacy: true,
37+
prompt,
38+
width,
39+
height,
40+
initImage,
41+
mask,
42+
promptStrength: promptStrength ?? 0.8,
43+
numOutputs: numOutputs ?? 1,
44+
numInferenceSteps: numInferenceSteps ?? 50,
45+
guidanceScale: guidanceScale ?? 7.5
46+
}
47+
}
48+
49+
// bot.log.debug(`QueueItem: ${JSON.stringify(queueItem)}`)
50+
bot.log.debug(`isProcessing: ${bot.stableDiffusion.isProcessing()} hasQueue: ${bot.hasQueue()} queueLength: ${bot.queue.length}`)
51+
52+
if (bot.stableDiffusion.isProcessing() || bot.hasQueue()) {
53+
const queuePos = bot.addQueue(queueItem)
54+
55+
await interaction.editReply({
56+
embeds: addedToQueue(queuePos, queueItem).embeds
57+
})
58+
} else {
59+
bot.addQueue(queueItem)
60+
61+
await interaction.editReply({
62+
embeds: addedToQueueNoWait(queueItem).embeds
63+
})
64+
}
65+
}
66+
}
67+
68+
export default botEvent

0 commit comments

Comments
 (0)