Skip to content

Commit 184aa7c

Browse files
committed
Fix bug with components staying when they shouldn't, introduce queueitem types, variant support
1 parent 679135f commit 184aa7c

File tree

7 files changed

+143
-35
lines changed

7 files changed

+143
-35
lines changed

src/embeds/imageSelectPrompt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function(queueItem: QueueItem): BotEmbed {
1515
new ActionRowBuilder()
1616
.addComponents([
1717
new SelectMenuBuilder()
18-
.setCustomId('image-select-prompt')
18+
.setCustomId(`image-select-prompt-${queueItem.type}`)
1919
.setPlaceholder('Select an image')
2020
.addOptions(
2121
{

src/events/buttonImagineRegenerate.ts

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,58 @@
11
import { Interaction } from 'discord.js'
22
import { isNil } from 'ramda'
33
import { Bot } from '../bot'
4-
import { BotEvent, QueueItem } from '../types'
4+
import { BotEvent, QueueItem, QueueItemType } from '../types'
55
import { getRandomInt } from '../utils'
66
import { v4 as uuidv4 } from 'uuid'
7-
import addedToQueue from '../embeds/addedToQueue'
8-
import addedToQueueNoWait from '../embeds/addedToQueueNoWait'
7+
import addedToQueue, { QueueType } from '../embeds/addedToQueue'
98

109
const botEvent: BotEvent = {
11-
name: 'Command Handler - Ping',
10+
name: 'Button Handler - Imagine Regenerate',
1211
event: 'interactionCreate',
1312
once: false,
1413
async execute(bot: Bot, interaction: Interaction) {
1514
if (!interaction.isButton()) return
1615
if (interaction.customId !== 'button-imagine-result-regenerate') return
1716

18-
const referenceQueueItem = bot.findQueueItemReferenceByMessageID(interaction.message.id)
17+
const referenceQueueItem = bot.findLatestQueueItemReferenceByMessageID(interaction.message.id)
1918
if (isNil(referenceQueueItem)) {
2019
await interaction.reply({
2120
ephemeral: true,
2221
content: 'There is no reference of this image generation. Most likely, this generation is too old to modify.'
23-
}).then(message => {
24-
// TODO: Remove message after 5 seconds
25-
// setTimeout(async () => {
26-
// if (!message.interaction.isRepliable) return
27-
// const msg = await message.awaitMessageComponent()
28-
// await msg.deleteReply()
29-
// }, 5000)
3022
})
23+
3124
return
3225
}
3326

3427
const queueItem: QueueItem = {
3528
...referenceQueueItem,
29+
type: QueueItemType.Regenerated,
3630
discordCaller: interaction.user.id.toString(),
3731
seed: getRandomInt(1, 99999999),
3832
uuid: uuidv4()
3933
}
4034

41-
bot.log.debug(`isProcessing: ${bot.stableDiffusion.isProcessing()} hasQueue: ${bot.hasQueue()} queueLength: ${bot.queue.length}`)
42-
4335
// Remove old attachment
4436
await interaction.message.removeAttachments()
4537

4638
await interaction.reply({
4739
ephemeral: true,
4840
content: 'Your images are being regenerated. The original message will be updated once complete.'
49-
}).then(message => {
50-
// TODO: Remove message after 5 seconds
51-
// setTimeout(async () => {
52-
// if (!message.interaction.isRepliable) return
53-
// const msg = await message.awaitMessageComponent()
54-
// await msg.deleteReply()
55-
// }, 5000)
5641
})
5742

58-
5943
if (bot.stableDiffusion.isProcessing() || bot.hasQueue()) {
6044
const queuePos = bot.addQueue(queueItem)
6145

6246
await referenceQueueItem.interaction.editReply({
63-
embeds: addedToQueue(queuePos, queueItem).embeds
47+
embeds: addedToQueue(QueueType.Queued, queueItem, queuePos).embeds,
48+
components: []
6449
})
6550
} else {
6651
bot.addQueue(queueItem)
6752

6853
await referenceQueueItem.interaction.editReply({
69-
embeds: addedToQueueNoWait(queueItem).embeds
54+
embeds: addedToQueue(QueueType.Instant, queueItem).embeds,
55+
components: []
7056
})
7157
}
7258
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Interaction } from "discord.js"
2+
import { isEmpty, isNil } from "ramda"
3+
import { Bot } from '../bot'
4+
import { BotEvent, QueueItem, QueueItemType } from '../types'
5+
import imageSelectPrompt from '../embeds/imageSelectPrompt'
6+
import { v4 as uuidv4 } from 'uuid'
7+
import addedToQueue, { QueueType } from "../embeds/addedToQueue"
8+
9+
const botEvent: BotEvent = {
10+
name: 'Button Handler - Imagine Variant Of',
11+
event: 'interactionCreate',
12+
once: false,
13+
async execute(bot: Bot, interaction: Interaction) {
14+
if (!interaction.isButton() && !interaction.isSelectMenu()) return
15+
if (interaction.customId === 'image-select-prompt-variant' && interaction.isSelectMenu()) {
16+
// TODO: Lock this action to user who triggered prompt?
17+
18+
const referenceQueueItem = bot.findLatestQueueItemReferenceByMessageID(interaction.message.id)
19+
if (isNil(referenceQueueItem) || isNil(referenceQueueItem.imageData) || isEmpty(referenceQueueItem.imageData)) {
20+
await interaction.reply({
21+
ephemeral: true,
22+
content: 'There is no reference of this image generation. Most likely, this generation is too old to modify.'
23+
})
24+
return
25+
}
26+
27+
// Ensure PNG
28+
const selectedImageB64 = `data:image/png;base64,${referenceQueueItem.imageData[0].toString('base64')}`
29+
const queueItem: QueueItem = {
30+
...referenceQueueItem,
31+
type: QueueItemType.Variant,
32+
prediction: {
33+
prompt: referenceQueueItem.prediction.prompt,
34+
promptStrength: 0.8,
35+
initImage: selectedImageB64,
36+
numOutputs: 4,
37+
height: referenceQueueItem.prediction.height,
38+
width: referenceQueueItem.prediction.width,
39+
guidanceScale: referenceQueueItem.prediction.guidanceScale,
40+
mask: referenceQueueItem.prediction.mask,
41+
numInferenceSteps: referenceQueueItem.prediction.numInferenceSteps
42+
},
43+
discordCaller: interaction.user.id.toString(),
44+
uuid: uuidv4()
45+
}
46+
47+
// Remove old attachment
48+
await interaction.message.removeAttachments()
49+
50+
await interaction.reply({
51+
ephemeral: true,
52+
content: 'Your image variants are being generated. The original message will be updated once complete.'
53+
})
54+
55+
if (bot.stableDiffusion.isProcessing() || bot.hasQueue()) {
56+
const queuePos = bot.addQueue(queueItem)
57+
await referenceQueueItem.interaction.editReply({
58+
embeds: addedToQueue(QueueType.Queued, queueItem, queuePos).embeds,
59+
components: []
60+
})
61+
} else {
62+
bot.addQueue(queueItem)
63+
await referenceQueueItem.interaction.editReply({
64+
embeds: addedToQueue(QueueType.Instant, queueItem).embeds,
65+
components: []
66+
})
67+
}
68+
} else if (interaction.customId === 'button-imagine-result-variant-of' && interaction.isButton()) {
69+
const referenceQueueItem = bot.findLatestQueueItemReferenceByMessageID(interaction.message.id)
70+
if (isNil(referenceQueueItem)) {
71+
await interaction.reply({
72+
ephemeral: true,
73+
content: 'There is no reference of this image generation. Most likely, this generation is too old to modify.'
74+
})
75+
return
76+
}
77+
78+
const imageSelectPromptEmbed = imageSelectPrompt({...referenceQueueItem, type: QueueItemType.Variant})
79+
80+
await referenceQueueItem.interaction.editReply({
81+
embeds: imageSelectPromptEmbed.embeds,
82+
components: imageSelectPromptEmbed.components
83+
})
84+
}
85+
return
86+
}
87+
}
88+
89+
export default botEvent

src/events/queueProcessor.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async function tick(bot: Bot) {
2121
if (bot.stableDiffusion.isProcessing() || tickLock) return
2222
if (isNil(bot.queue) || isEmpty(bot.queue)) return
2323
tickLock = true
24-
bot.log.debug(`isProcessing ; queueLength: ${bot.queue.length}`)
24+
bot.log.debug(`isProcessing ; queueLength: ${bot.queue.length - 1}`)
2525
const queueItem = bot.queue[0]
2626

2727
try {
@@ -53,6 +53,8 @@ async function tick(bot: Bot) {
5353
const file = new AttachmentBuilder(buf, {
5454
name: `stable-confusion_${queueItem.uuid}.jpeg`
5555
})
56+
57+
queueItem.imageData = [buf]
5658

5759
await queueItem.interaction.editReply({
5860
embeds: imageResultEmbed.embeds,
@@ -105,6 +107,7 @@ async function tick(bot: Bot) {
105107
name: `stable-confusion_${queueItem.uuid}_collage.png`
106108
})
107109

110+
queueItem.imageData = imageBuffers
108111

109112
await queueItem.interaction.editReply({
110113
embeds: imageResultEmbed.embeds,

src/modules/stableDiffusion.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { QueueItem, } from "../types"
1+
import { QueueItem, QueueItemType } from "../types"
22
import axios from 'axios'
33
import { isNil } from "ramda"
44

@@ -17,6 +17,8 @@ export default class StableDiffusion {
1717

1818
public async processRequest(queueItem: QueueItem): Promise<false | string[]> {
1919
if (this.processing) return false
20+
if (queueItem.type === QueueItemType.Variant) return this.processVariantRequest(queueItem)
21+
2022
this.abortController = new AbortController()
2123
this.processing = true
2224

@@ -46,6 +48,33 @@ export default class StableDiffusion {
4648
return results.data.output as string[]
4749
}
4850

51+
private async processVariantRequest(queueItem: QueueItem): Promise<false | string[]> {
52+
if (this.processing) return false
53+
this.abortController = new AbortController()
54+
this.processing = true
55+
56+
const body = {
57+
input: {
58+
prompt: queueItem.prediction.prompt,
59+
width: queueItem.prediction.width,
60+
height: queueItem.prediction.height,
61+
"init_image": queueItem.prediction.initImage,
62+
"prompt_strength": queueItem.prediction.promptStrength,
63+
"num_outputs": queueItem.prediction.numOutputs
64+
}
65+
}
66+
67+
const results = await axios.post(`${this.host}:${this.port ?? 5000}/predictions`, body, {
68+
headers: {'Content-Type': 'application/json'}
69+
}).catch(e => {
70+
return null
71+
})
72+
73+
this.processing = false
74+
if (isNil(results) || isNil(results.data)) return false
75+
return results.data.output as string[]
76+
}
77+
4978
public cancelRequest(): boolean | undefined {
5079
if (!this.abortController) throw new Error('No active abort controller')
5180
if (!this.processing) return false

src/types.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,18 @@ export interface BotEvent {
2323
}
2424

2525
export enum QueueItemType {
26-
Default,
27-
Quick,
28-
Regenerated,
29-
Variant,
30-
Upscaled
26+
Default = 'default',
27+
Quick = 'quick',
28+
Regenerated = 'regenerated',
29+
Variant = 'variant',
30+
Upscaled = 'upscaled'
3131
}
3232

3333
export interface QueueItem {
3434
uuid: string // Unique queue uuid
3535
seed: number // RNG
3636
type: QueueItemType
37+
imageData?: Buffer[] // Array of generated image buffers for request
3738
messageId?: string // Discord main message snowflake ID.
3839
interaction: ChatInputCommandInteraction
3940
discordCaller: string // Snowflake of caller for command
@@ -44,8 +45,8 @@ export interface QueueItem {
4445
initImage: string | undefined // Starter image to generate from
4546
mask: string | undefined // Mask image to generate with
4647
promptStrength: number // 0 - 1 float value, default 0.8
47-
numOutputs: number // Number of images to generate, default 1
48+
numOutputs: number // Number of images to generate, default 1
4849
numInferenceSteps: number // Number of steps, default 50
4950
guidanceScale: number // Default 7.5
5051
}
51-
}
52+
}

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ export const getImageAttachmentURL = (attachment: Attachment | null): string | u
2222
if (isNil(attachment) || isNil(attachment.contentType)) return
2323
if (!imageMimes.includes(attachment.contentType)) return
2424
return attachment.url
25-
}
25+
}

0 commit comments

Comments
 (0)