diff --git a/app/db.ts b/app/db.ts index 880f04b..194fd79 100644 --- a/app/db.ts +++ b/app/db.ts @@ -1,4 +1,4 @@ -import { KVFS } from "../deps.ts"; +import { KvFs } from "kvfs"; export const db = await Deno.openKv("./app.db"); -export const fs = new KVFS.KvFs(db); +export const fs = new KvFs(db); diff --git a/app/generationQueue.ts b/app/generationQueue.ts index 7a5ff71..75faf5c 100644 --- a/app/generationQueue.ts +++ b/app/generationQueue.ts @@ -1,25 +1,23 @@ +import { promiseState } from "async"; +import { Chat, Message, User } from "grammy_types"; +import { JobData, Queue, Worker } from "kvmq"; +import createOpenApiClient from "openapi_fetch"; +import { delay } from "std/async"; +import { decode, encode } from "std/encoding/base64"; +import { getLogger } from "std/log"; +import { ulid } from "ulid"; import { bot } from "../bot/mod.ts"; +import { SdError } from "../sd/SdError.ts"; import { PngInfo } from "../sd/parsePngInfo.ts"; import * as SdApi from "../sd/sdApi.ts"; +import { formatOrdinal } from "../utils/formatOrdinal.ts"; import { formatUserChat } from "../utils/formatUserChat.ts"; import { getConfig, SdInstanceData } from "./config.ts"; import { db, fs } from "./db.ts"; import { SdGenerationInfo } from "./generationStore.ts"; -import { - Async, - AsyncX, - Base64, - createOpenApiClient, - GrammyTypes, - KVMQ, - Log, - ULID, -} from "../deps.ts"; -import { formatOrdinal } from "../utils/formatOrdinal.ts"; -import { SdError } from "../sd/SdError.ts"; import { uploadQueue } from "./uploadQueue.ts"; -const logger = () => Log.getLogger(); +const logger = () => getLogger(); interface GenerationJob { task: @@ -32,17 +30,17 @@ interface GenerationJob { params: Partial; fileId: string; }; - from: GrammyTypes.User; - chat: GrammyTypes.Chat; - requestMessage: GrammyTypes.Message; - replyMessage: GrammyTypes.Message; + from: User; + chat: Chat; + requestMessage: Message; + replyMessage: Message; sdInstanceId?: string; progress?: number; } -export const generationQueue = new KVMQ.Queue(db, "jobQueue"); +export const generationQueue = new Queue(db, "jobQueue"); -export const activeGenerationWorkers = new Map>(); +export const activeGenerationWorkers = new Map>(); /** * Initializes queue workers for each SD instance when they become online. @@ -104,7 +102,7 @@ export async function processGenerationQueue() { activeGenerationWorkers.set(sdInstance.id, newWorker); logger().info(`Started worker ${sdInstance.id}`); } - await Async.delay(60_000); + await delay(60_000); } } @@ -113,7 +111,7 @@ export async function processGenerationQueue() { */ async function processGenerationJob( state: GenerationJob, - updateJob: (job: Partial>) => Promise, + updateJob: (job: Partial>) => Promise, sdInstance: SdInstanceData, ) { const startDate = new Date(); @@ -185,7 +183,7 @@ async function processGenerationJob( ? state.task.params.negative_prompt : config.defaultParams?.negative_prompt, init_images: [ - Base64.encode( + encode( await fetch( `https://api.telegram.org/file/bot${bot.token}/${await bot.api.getFile( state.task.fileId, @@ -229,8 +227,8 @@ async function processGenerationJob( { maxAttempts: 1 }, ).catch(() => undefined); - await Promise.race([Async.delay(3000), responsePromise]).catch(() => undefined); - } while (await AsyncX.promiseState(responsePromise) === "pending"); + await Promise.race([delay(3000), responsePromise]).catch(() => undefined); + } while (await promiseState(responsePromise) === "pending"); // check response const response = await responsePromise; @@ -247,8 +245,8 @@ async function processGenerationJob( // save images to db const imageKeys: Deno.KvKey[] = []; for (const imageBase64 of response.data.images) { - const imageBuffer = Base64.decode(imageBase64); - const imageKey = ["images", "upload", ULID.ulid()]; + const imageBuffer = decode(imageBase64); + const imageKey = ["images", "upload", ulid()]; await fs.set(imageKey, imageBuffer, { expireIn: 30 * 60 * 1000 }); imageKeys.push(imageKey); } @@ -301,6 +299,6 @@ export async function updateGenerationQueue() { { maxAttempts: 1 }, ).catch(() => undefined); } - await Async.delay(3000); + await delay(3000); } } diff --git a/app/generationStore.ts b/app/generationStore.ts index fce3234..d5d79df 100644 --- a/app/generationStore.ts +++ b/app/generationStore.ts @@ -1,9 +1,10 @@ -import { GrammyTypes, IKV } from "../deps.ts"; +import { Chat, User } from "grammy_types"; +import { Store } from "indexed_kv"; import { db } from "./db.ts"; export interface GenerationSchema { - from: GrammyTypes.User; - chat: GrammyTypes.Chat; + from: User; + chat: Chat; sdInstanceId?: string; info?: SdGenerationInfo; startDate?: Date; @@ -49,7 +50,7 @@ type GenerationIndices = { chatId: number; }; -export const generationStore = new IKV.Store( +export const generationStore = new Store( db, "generations", { diff --git a/app/uploadQueue.ts b/app/uploadQueue.ts index 3344828..c63a2ea 100644 --- a/app/uploadQueue.ts +++ b/app/uploadQueue.ts @@ -1,16 +1,22 @@ +import { fileTypeFromBuffer } from "file_type"; +import { InputFile, InputMediaBuilder } from "grammy"; +import { bold, fmt } from "grammy_parse_mode"; +import { Chat, Message, User } from "grammy_types"; +import { Queue } from "kvmq"; +import { format } from "std/fmt/duration"; +import { getLogger } from "std/log"; import { bot } from "../bot/mod.ts"; import { formatUserChat } from "../utils/formatUserChat.ts"; import { db, fs } from "./db.ts"; import { generationStore, SdGenerationInfo } from "./generationStore.ts"; -import { FileType, FmtDuration, Grammy, GrammyParseMode, GrammyTypes, KVMQ, Log } from "../deps.ts"; -const logger = () => Log.getLogger(); +const logger = () => getLogger(); interface UploadJob { - from: GrammyTypes.User; - chat: GrammyTypes.Chat; - requestMessage: GrammyTypes.Message; - replyMessage: GrammyTypes.Message; + from: User; + chat: Chat; + requestMessage: Message; + replyMessage: Message; sdInstanceId: string; startDate: Date; endDate: Date; @@ -18,7 +24,7 @@ interface UploadJob { info: SdGenerationInfo; } -export const uploadQueue = new KVMQ.Queue(db, "uploadQueue"); +export const uploadQueue = new Queue(db, "uploadQueue"); /** * Initializes queue worker for uploading images to Telegram. @@ -37,7 +43,6 @@ export async function processUploadQueue() { // const detailedReply = Object.keys(job.value.params).filter((key) => key !== "prompt").length > 0; const detailedReply = true; const jobDurationMs = Math.trunc((Date.now() - state.startDate.getTime()) / 1000) * 1000; - const { bold, fmt } = GrammyParseMode; const caption = fmt([ `${state.info.prompt}\n`, ...detailedReply @@ -51,7 +56,7 @@ export async function processUploadQueue() { fmt`${bold("Seed:")} ${state.info.seed}, `, fmt`${bold("Size")}: ${state.info.width}x${state.info.height}, `, fmt`${bold("Worker")}: ${state.sdInstanceId}, `, - fmt`${bold("Time taken")}: ${FmtDuration.format(jobDurationMs, { ignoreZero: true })}`, + fmt`${bold("Time taken")}: ${format(jobDurationMs, { ignoreZero: true })}`, ] : [], ]); @@ -61,10 +66,10 @@ export async function processUploadQueue() { state.imageKeys.map(async (fileKey, idx) => { const imageBuffer = await fs.get(fileKey).then((entry) => entry.value); if (!imageBuffer) throw new Error("File not found"); - const imageType = await FileType.fileTypeFromBuffer(imageBuffer); + const imageType = await fileTypeFromBuffer(imageBuffer); if (!imageType) throw new Error("Image has unknown type"); - return Grammy.InputMediaBuilder.photo( - new Grammy.InputFile(imageBuffer, `image${idx}.${imageType.ext}`), + return InputMediaBuilder.photo( + new InputFile(imageBuffer, `image${idx}.${imageType.ext}`), // if it can fit, add caption for first photo idx === 0 && caption.text.length <= 1024 ? { caption: caption.text, caption_entities: caption.entities } diff --git a/bot/cancelCommand.ts b/bot/cancelCommand.ts index b63633e..6a1236b 100644 --- a/bot/cancelCommand.ts +++ b/bot/cancelCommand.ts @@ -1,7 +1,7 @@ import { generationQueue } from "../app/generationQueue.ts"; -import { Context } from "./mod.ts"; +import { ErisContext } from "./mod.ts"; -export async function cancelCommand(ctx: Context) { +export async function cancelCommand(ctx: ErisContext) { const jobs = await generationQueue.getAllJobs(); const userJobs = jobs .filter((job) => job.lockUntil < new Date()) diff --git a/bot/img2imgCommand.ts b/bot/img2imgCommand.ts index c7d0a70..50a195f 100644 --- a/bot/img2imgCommand.ts +++ b/bot/img2imgCommand.ts @@ -1,11 +1,13 @@ -import { Collections, Grammy, GrammyStatelessQ } from "../deps.ts"; -import { formatUserChat } from "../utils/formatUserChat.ts"; -import { parsePngInfo, PngInfo } from "../sd/parsePngInfo.ts"; -import { Context, logger } from "./mod.ts"; -import { generationQueue } from "../app/generationQueue.ts"; +import { CommandContext } from "grammy"; +import { StatelessQuestion } from "grammy_stateless_question"; +import { maxBy } from "std/collections"; import { getConfig } from "../app/config.ts"; +import { generationQueue } from "../app/generationQueue.ts"; +import { parsePngInfo, PngInfo } from "../sd/parsePngInfo.ts"; +import { formatUserChat } from "../utils/formatUserChat.ts"; +import { ErisContext, logger } from "./mod.ts"; -export const img2imgQuestion = new GrammyStatelessQ.StatelessQuestion( +export const img2imgQuestion = new StatelessQuestion( "img2img", async (ctx, state) => { // todo: also save original image size in state @@ -13,12 +15,12 @@ export const img2imgQuestion = new GrammyStatelessQ.StatelessQuestion( }, ); -export async function img2imgCommand(ctx: Grammy.CommandContext) { +export async function img2imgCommand(ctx: CommandContext) { await img2img(ctx, ctx.match, true); } async function img2img( - ctx: Context, + ctx: ErisContext, match: string | undefined, includeRepliedTo: boolean, fileId?: string, @@ -57,7 +59,7 @@ async function img2img( if (includeRepliedTo && repliedToMsg?.photo) { const photos = repliedToMsg.photo; - const biggestPhoto = Collections.maxBy(photos, (p) => p.width * p.height); + const biggestPhoto = maxBy(photos, (p) => p.width * p.height); if (!biggestPhoto) throw new Error("Message was a photo but had no photos?"); fileId = biggestPhoto.file_id; params.width = biggestPhoto.width; @@ -66,7 +68,7 @@ async function img2img( if (ctx.message.photo) { const photos = ctx.message.photo; - const biggestPhoto = Collections.maxBy(photos, (p) => p.width * p.height); + const biggestPhoto = maxBy(photos, (p) => p.width * p.height); if (!biggestPhoto) throw new Error("Message was a photo but had no photos?"); fileId = biggestPhoto.file_id; params.width = biggestPhoto.width; diff --git a/bot/mod.ts b/bot/mod.ts index 2c1c1d5..c4c56f9 100644 --- a/bot/mod.ts +++ b/bot/mod.ts @@ -1,52 +1,53 @@ -import { Grammy, GrammyAutoQuote, GrammyFiles, GrammyParseMode, Log } from "../deps.ts"; +import { Api, Bot, Context, RawApi, session, SessionFlavor } from "grammy"; +import { autoQuote } from "grammy_autoquote"; +import { FileFlavor, hydrateFiles } from "grammy_files"; +import { hydrateReply, ParseModeFlavor } from "grammy_parse_mode"; +import { getLogger } from "std/log"; +import { getConfig, setConfig } from "../app/config.ts"; import { formatUserChat } from "../utils/formatUserChat.ts"; +import { cancelCommand } from "./cancelCommand.ts"; +import { img2imgCommand, img2imgQuestion } from "./img2imgCommand.ts"; +import { pnginfoCommand, pnginfoQuestion } from "./pnginfoCommand.ts"; import { queueCommand } from "./queueCommand.ts"; import { txt2imgCommand, txt2imgQuestion } from "./txt2imgCommand.ts"; -import { pnginfoCommand, pnginfoQuestion } from "./pnginfoCommand.ts"; -import { img2imgCommand, img2imgQuestion } from "./img2imgCommand.ts"; -import { cancelCommand } from "./cancelCommand.ts"; -import { getConfig, setConfig } from "../app/config.ts"; -export const logger = () => Log.getLogger(); +export const logger = () => getLogger(); interface SessionData { - chat: ChatData; - user: UserData; + chat: ErisChatData; + user: ErisUserData; } -interface ChatData { +interface ErisChatData { language?: string; } -interface UserData { +interface ErisUserData { params?: Record; } -export type Context = - & GrammyFiles.FileFlavor> - & Grammy.SessionFlavor; +export type ErisContext = + & FileFlavor> + & SessionFlavor; -type WithRetryApi = { +type WithRetryApi = { [M in keyof T]: T[M] extends (args: infer P, ...rest: infer A) => infer R ? (args: P extends object ? P & { maxAttempts?: number; maxWait?: number } : P, ...rest: A) => R : T[M]; }; -type Api = Grammy.Api>; +type ErisApi = Api>; -export const bot = new Grammy.Bot( +export const bot = new Bot( Deno.env.get("TG_BOT_TOKEN")!, { client: { timeoutSeconds: 20 }, }, ); -bot.use(GrammyAutoQuote.autoQuote); -bot.use(GrammyParseMode.hydrateReply); -bot.use(Grammy.session< - SessionData, - Grammy.Context & Grammy.SessionFlavor ->({ +bot.use(autoQuote); +bot.use(hydrateReply); +bot.use(session({ type: "multi", chat: { initial: () => ({}), @@ -57,7 +58,7 @@ bot.use(Grammy.session< }, })); -bot.api.config.use(GrammyFiles.hydrateFiles(bot.token)); +bot.api.config.use(hydrateFiles(bot.token)); // Automatically retry bot requests if we get a "too many requests" or telegram internal error bot.api.config.use(async (prev, method, payload, signal) => { diff --git a/bot/pnginfoCommand.ts b/bot/pnginfoCommand.ts index ca0f108..589886a 100644 --- a/bot/pnginfoCommand.ts +++ b/bot/pnginfoCommand.ts @@ -1,19 +1,21 @@ -import { Grammy, GrammyParseMode, GrammyStatelessQ } from "../deps.ts"; +import { CommandContext } from "grammy"; +import { bold, fmt } from "grammy_parse_mode"; +import { StatelessQuestion } from "grammy_stateless_question"; import { getPngInfo, parsePngInfo } from "../sd/parsePngInfo.ts"; -import { Context } from "./mod.ts"; +import { ErisContext } from "./mod.ts"; -export const pnginfoQuestion = new GrammyStatelessQ.StatelessQuestion( +export const pnginfoQuestion = new StatelessQuestion( "pnginfo", async (ctx) => { await pnginfo(ctx, false); }, ); -export async function pnginfoCommand(ctx: Grammy.CommandContext) { +export async function pnginfoCommand(ctx: CommandContext) { await pnginfo(ctx, true); } -async function pnginfo(ctx: Context, includeRepliedTo: boolean): Promise { +async function pnginfo(ctx: ErisContext, includeRepliedTo: boolean): Promise { const document = ctx.message?.document || (includeRepliedTo ? ctx.message?.reply_to_message?.document : undefined); @@ -30,8 +32,6 @@ async function pnginfo(ctx: Context, includeRepliedTo: boolean): Promise { const buffer = await fetch(file.getUrl()).then((resp) => resp.arrayBuffer()); const params = parsePngInfo(getPngInfo(new Uint8Array(buffer)) ?? ""); - const { bold, fmt } = GrammyParseMode; - const paramsText = fmt([ `${params.prompt}\n`, params.negative_prompt ? fmt`${bold("Negative prompt:")} ${params.negative_prompt}\n` : "", diff --git a/bot/queueCommand.ts b/bot/queueCommand.ts index e296674..ef3cbb9 100644 --- a/bot/queueCommand.ts +++ b/bot/queueCommand.ts @@ -1,10 +1,11 @@ -import { Grammy, GrammyParseMode } from "../deps.ts"; -import { Context } from "./mod.ts"; -import { getFlagEmoji } from "../utils/getFlagEmoji.ts"; -import { activeGenerationWorkers, generationQueue } from "../app/generationQueue.ts"; +import { CommandContext } from "grammy"; +import { bold, fmt } from "grammy_parse_mode"; import { getConfig } from "../app/config.ts"; +import { activeGenerationWorkers, generationQueue } from "../app/generationQueue.ts"; +import { getFlagEmoji } from "../utils/getFlagEmoji.ts"; +import { ErisContext } from "./mod.ts"; -export async function queueCommand(ctx: Grammy.CommandContext) { +export async function queueCommand(ctx: CommandContext) { let formattedMessage = await getMessageText(); const queueMessage = await ctx.replyFmt(formattedMessage, { disable_notification: true }); handleFutureUpdates().catch(() => undefined); @@ -18,7 +19,6 @@ export async function queueCommand(ctx: Grammy.CommandContext) { .filter((job) => job.lockUntil <= new Date()) .map((job, index) => ({ ...job, index: index + 1 })); const jobs = [...processingJobs, ...waitingJobs]; - const { bold, fmt } = GrammyParseMode; return fmt([ "Current queue:\n", diff --git a/bot/txt2imgCommand.ts b/bot/txt2imgCommand.ts index c3e48da..535ccad 100644 --- a/bot/txt2imgCommand.ts +++ b/bot/txt2imgCommand.ts @@ -1,11 +1,12 @@ -import { Grammy, GrammyStatelessQ } from "../deps.ts"; -import { formatUserChat } from "../utils/formatUserChat.ts"; -import { getPngInfo, parsePngInfo, PngInfo } from "../sd/parsePngInfo.ts"; -import { Context, logger } from "./mod.ts"; -import { generationQueue } from "../app/generationQueue.ts"; +import { CommandContext } from "grammy"; +import { StatelessQuestion } from "grammy_stateless_question"; import { getConfig } from "../app/config.ts"; +import { generationQueue } from "../app/generationQueue.ts"; +import { getPngInfo, parsePngInfo, PngInfo } from "../sd/parsePngInfo.ts"; +import { formatUserChat } from "../utils/formatUserChat.ts"; +import { ErisContext, logger } from "./mod.ts"; -export const txt2imgQuestion = new GrammyStatelessQ.StatelessQuestion( +export const txt2imgQuestion = new StatelessQuestion( "txt2img", async (ctx) => { if (!ctx.message.text) return; @@ -13,11 +14,11 @@ export const txt2imgQuestion = new GrammyStatelessQ.StatelessQuestion( }, ); -export async function txt2imgCommand(ctx: Grammy.CommandContext) { +export async function txt2imgCommand(ctx: CommandContext) { await txt2img(ctx, ctx.match, true); } -async function txt2img(ctx: Context, match: string, includeRepliedTo: boolean): Promise { +async function txt2img(ctx: ErisContext, match: string, includeRepliedTo: boolean): Promise { if (!ctx.message?.from?.id) { await ctx.reply("I don't know who you are"); return; diff --git a/deno.jsonc b/deno.jsonc index 7556d45..3cdfde7 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -4,5 +4,27 @@ }, "fmt": { "lineWidth": 100 + }, + "imports": { + "std/log": "https://deno.land/std@0.201.0/log/mod.ts", + "std/async": "https://deno.land/std@0.201.0/async/mod.ts", + "std/fmt/duration": "https://deno.land/std@0.202.0/fmt/duration.ts", + "std/collections": "https://deno.land/std@0.202.0/collections/mod.ts", + "std/encoding/base64": "https://deno.land/std@0.202.0/encoding/base64.ts", + "async": "https://deno.land/x/async@v2.0.2/mod.ts", + "ulid": "https://deno.land/x/ulid@v0.3.0/mod.ts", + "indexed_kv": "https://deno.land/x/indexed_kv@v0.4.0/mod.ts", + "kvmq": "https://deno.land/x/kvmq@v0.2.0/mod.ts", + "kvfs": "https://deno.land/x/kvfs@v0.1.0/mod.ts", + "grammy": "https://lib.deno.dev/x/grammy@1/mod.ts", + "grammy_types": "https://lib.deno.dev/x/grammy_types@3/mod.ts", + "grammy_autoquote": "https://lib.deno.dev/x/grammy_autoquote@1/mod.ts", + "grammy_parse_mode": "https://lib.deno.dev/x/grammy_parse_mode@1/mod.ts", + "grammy_stateless_question": "https://lib.deno.dev/x/grammy_stateless_question_alpha@3/mod.ts", + "grammy_files": "https://lib.deno.dev/x/grammy_files@1/mod.ts", + "file_type": "https://esm.sh/file-type@18.5.0", + "png_chunks_extract": "https://esm.sh/png-chunks-extract@1.0.0", + "png_chunk_text": "https://esm.sh/png-chunk-text@1.0.0", + "openapi_fetch": "https://esm.sh/openapi-fetch@0.7.6" } } diff --git a/deps.ts b/deps.ts deleted file mode 100644 index c90b40f..0000000 --- a/deps.ts +++ /dev/null @@ -1,20 +0,0 @@ -export * as Log from "https://deno.land/std@0.201.0/log/mod.ts"; -export * as Async from "https://deno.land/std@0.201.0/async/mod.ts"; -export * as FmtDuration from "https://deno.land/std@0.202.0/fmt/duration.ts"; -export * as Collections from "https://deno.land/std@0.202.0/collections/mod.ts"; -export * as Base64 from "https://deno.land/std@0.202.0/encoding/base64.ts"; -export * as AsyncX from "https://deno.land/x/async@v2.0.2/mod.ts"; -export * as ULID from "https://deno.land/x/ulid@v0.3.0/mod.ts"; -export * as IKV from "https://deno.land/x/indexed_kv@v0.4.0/mod.ts"; -export * as KVMQ from "https://deno.land/x/kvmq@v0.2.0/mod.ts"; -export * as KVFS from "https://deno.land/x/kvfs@v0.1.0/mod.ts"; -export * as Grammy from "https://deno.land/x/grammy@v1.18.3/mod.ts"; -export * as GrammyTypes from "https://deno.land/x/grammy_types@v3.2.2/mod.ts"; -export * as GrammyAutoQuote from "https://deno.land/x/grammy_autoquote@v1.1.2/mod.ts"; -export * as GrammyParseMode from "https://deno.land/x/grammy_parse_mode@1.8.1/mod.ts"; -export * as GrammyStatelessQ from "https://deno.land/x/grammy_stateless_question_alpha@v3.0.4/mod.ts"; -export * as GrammyFiles from "https://deno.land/x/grammy_files@v1.0.4/mod.ts"; -export * as FileType from "https://esm.sh/file-type@18.5.0"; -export { default as pngChunksExtract } from "https://esm.sh/png-chunks-extract@1.0.0"; -export { decode as pngChunkTextDecode } from "https://esm.sh/png-chunk-text@1.0.0"; -export { default as createOpenApiClient } from "https://esm.sh/openapi-fetch@0.7.6"; diff --git a/main.ts b/main.ts index 4866c58..1c37ebc 100644 --- a/main.ts +++ b/main.ts @@ -1,11 +1,11 @@ import "https://deno.land/std@0.201.0/dotenv/load.ts"; -import { Log } from "./deps.ts"; -import { bot } from "./bot/mod.ts"; +import { handlers, setup } from "std/log"; import { runAllTasks } from "./app/mod.ts"; +import { bot } from "./bot/mod.ts"; -Log.setup({ +setup({ handlers: { - console: new Log.handlers.ConsoleHandler("DEBUG"), + console: new handlers.ConsoleHandler("DEBUG"), }, loggers: { default: { level: "DEBUG", handlers: ["console"] }, diff --git a/sd/parsePngInfo.ts b/sd/parsePngInfo.ts index 17aaee6..dfd693b 100644 --- a/sd/parsePngInfo.ts +++ b/sd/parsePngInfo.ts @@ -1,9 +1,10 @@ -import { pngChunksExtract, pngChunkTextDecode } from "../deps.ts"; +import { decode } from "png_chunk_text"; +import extractChunks from "png_chunks_extract"; export function getPngInfo(pngData: Uint8Array): string | undefined { - return pngChunksExtract(pngData) + return extractChunks(pngData) .filter((chunk) => chunk.name === "tEXt") - .map((chunk) => pngChunkTextDecode(chunk.data)) + .map((chunk) => decode(chunk.data)) .find((textChunk) => textChunk.keyword === "parameters") ?.text; } diff --git a/utils/formatUserChat.ts b/utils/formatUserChat.ts index 65b45cc..41d8219 100644 --- a/utils/formatUserChat.ts +++ b/utils/formatUserChat.ts @@ -1,7 +1,7 @@ -import { GrammyTypes } from "../deps.ts"; +import { Chat, User } from "grammy_types"; export function formatUserChat( - ctx: { from?: GrammyTypes.User; chat?: GrammyTypes.Chat; sdInstanceId?: string }, + ctx: { from?: User; chat?: Chat; sdInstanceId?: string }, ) { const msg: string[] = []; if (ctx.from) {