forked from pinks/eris
1
0
Fork 0
eris/bot/img2imgCommand.ts

136 lines
4.3 KiB
TypeScript
Raw Permalink Normal View History

2023-09-24 13:08:35 +00:00
import { CommandContext } from "grammy";
import { StatelessQuestion } from "grammy_stateless_question";
2023-09-26 10:43:36 +00:00
import { maxBy } from "std/collections/max_by.ts";
2023-10-15 19:13:38 +00:00
import { debug } from "std/log/mod.ts";
2023-09-23 18:49:05 +00:00
import { getConfig } from "../app/config.ts";
2023-09-24 13:08:35 +00:00
import { generationQueue } from "../app/generationQueue.ts";
import { formatUserChat } from "../utils/formatUserChat.ts";
2023-10-15 19:13:38 +00:00
import { ErisContext } from "./mod.ts";
2023-09-26 10:43:36 +00:00
import { parsePngInfo, PngInfo } from "./parsePngInfo.ts";
2023-09-12 01:57:44 +00:00
type QuestionState = { fileId?: string; params?: Partial<PngInfo> };
2023-09-24 13:08:35 +00:00
export const img2imgQuestion = new StatelessQuestion<ErisContext>(
2023-09-12 01:57:44 +00:00
"img2img",
async (ctx, stateString) => {
const state: QuestionState = JSON.parse(stateString);
2023-09-12 01:57:44 +00:00
await img2img(ctx, ctx.message.text, false, state);
},
);
2023-09-24 13:08:35 +00:00
export async function img2imgCommand(ctx: CommandContext<ErisContext>) {
2023-09-12 01:57:44 +00:00
await img2img(ctx, ctx.match, true);
}
async function img2img(
2023-09-24 13:08:35 +00:00
ctx: ErisContext,
2023-09-12 01:57:44 +00:00
match: string | undefined,
includeRepliedTo: boolean,
state: QuestionState = {},
2023-09-12 01:57:44 +00:00
): Promise<void> {
2023-10-15 19:47:08 +00:00
if (!ctx.from || !ctx.message) {
return;
}
if (ctx.from.is_bot) {
2023-09-12 01:57:44 +00:00
return;
}
2023-09-22 02:59:22 +00:00
const config = await getConfig();
if (config.pausedReason != null) {
2023-09-24 19:58:09 +00:00
await ctx.reply(`I'm paused: ${config.pausedReason || "No reason given"}`, {
reply_to_message_id: ctx.message?.message_id,
});
2023-09-12 01:57:44 +00:00
return;
}
2023-09-22 02:59:22 +00:00
const jobs = await generationQueue.getAllJobs();
if (jobs.length >= config.maxJobs) {
2023-09-24 19:58:09 +00:00
await ctx.reply(`The queue is full. Try again later. (Max queue size: ${config.maxJobs})`, {
reply_to_message_id: ctx.message?.message_id,
});
2023-09-12 01:57:44 +00:00
return;
}
2023-09-22 02:59:22 +00:00
const userJobs = jobs.filter((job) => job.state.from.id === ctx.message?.from?.id);
if (userJobs.length >= config.maxUserJobs) {
2023-10-05 09:00:51 +00:00
await ctx.reply(`You already have ${userJobs.length} jobs in queue. Try again later.`, {
2023-09-24 19:58:09 +00:00
reply_to_message_id: ctx.message?.message_id,
});
2023-09-12 01:57:44 +00:00
return;
}
const repliedToMsg = ctx.message.reply_to_message;
if (includeRepliedTo && repliedToMsg?.photo) {
const photos = repliedToMsg.photo;
2023-09-24 13:08:35 +00:00
const biggestPhoto = maxBy(photos, (p) => p.width * p.height);
2023-09-12 01:57:44 +00:00
if (!biggestPhoto) throw new Error("Message was a photo but had no photos?");
state.fileId = biggestPhoto.file_id;
if (!state.params) state.params = {};
state.params.width = biggestPhoto.width;
state.params.height = biggestPhoto.height;
2023-09-12 01:57:44 +00:00
}
if (ctx.message.photo) {
const photos = ctx.message.photo;
2023-09-24 13:08:35 +00:00
const biggestPhoto = maxBy(photos, (p) => p.width * p.height);
2023-09-12 01:57:44 +00:00
if (!biggestPhoto) throw new Error("Message was a photo but had no photos?");
state.fileId = biggestPhoto.file_id;
if (!state.params) state.params = {};
state.params.width = biggestPhoto.width;
state.params.height = biggestPhoto.height;
2023-09-12 01:57:44 +00:00
}
const repliedToText = repliedToMsg?.text || repliedToMsg?.caption;
if (includeRepliedTo && repliedToText) {
// TODO: remove bot command from replied to text
state.params = parsePngInfo(repliedToText, state.params);
2023-09-12 01:57:44 +00:00
}
if (match) {
state.params = parsePngInfo(match, state.params);
}
2023-09-12 01:57:44 +00:00
if (!state.fileId) {
2023-09-12 01:57:44 +00:00
await ctx.reply(
"Please show me a picture to repaint." +
img2imgQuestion.messageSuffixMarkdown(JSON.stringify(state satisfies QuestionState)),
2023-09-24 19:58:09 +00:00
{
reply_markup: { force_reply: true, selective: true },
parse_mode: "Markdown",
reply_to_message_id: ctx.message?.message_id,
},
2023-09-12 01:57:44 +00:00
);
return;
}
if (!state.params?.prompt) {
2023-09-12 01:57:44 +00:00
await ctx.reply(
"Please describe the picture you want to repaint." +
img2imgQuestion.messageSuffixMarkdown(JSON.stringify(state satisfies QuestionState)),
2023-09-24 19:58:09 +00:00
{
reply_markup: { force_reply: true, selective: true },
parse_mode: "Markdown",
reply_to_message_id: ctx.message?.message_id,
},
2023-09-12 01:57:44 +00:00
);
return;
}
2023-09-24 19:58:09 +00:00
const replyMessage = await ctx.reply("Accepted. You are now in queue.", {
reply_to_message_id: ctx.message?.message_id,
});
2023-09-12 01:57:44 +00:00
2023-09-22 02:59:22 +00:00
await generationQueue.pushJob({
task: { type: "img2img", fileId: state.fileId, params: state.params },
2023-09-12 01:57:44 +00:00
from: ctx.message.from,
chat: ctx.message.chat,
2023-09-22 02:59:22 +00:00
requestMessage: ctx.message,
replyMessage: replyMessage,
2023-11-17 23:50:34 +00:00
}, { priority: 0, retryCount: 3, repeatDelayMs: 10_000 });
2023-09-12 01:57:44 +00:00
2023-10-15 19:13:38 +00:00
debug(`Generation (img2img) enqueued for ${formatUserChat(ctx.message)}`);
2023-09-12 01:57:44 +00:00
}