diff --git a/package.json b/package.json index 0dcd5cf..02ef276 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,16 @@ { "name": "gptitor", - "version": "1.3.3", + "version": "1.4.0", "description": "", "main": "src/index.ts", + "type": "module", "scripts": { "dev": "ts-node src/index.ts", "dev:watch": "nodemon --exec ts-node src/index.ts", "build": "tsc", "lint": "tsc -noEmit && eslint src/**", "test": "jest", - "start": "ts-node src/index.ts" + "start": "node --loader ts-node/esm ./src/index.ts" }, "engines": { "node": "18.x" @@ -24,12 +25,13 @@ "fluent-ffmpeg": "^2.1.2", "midjourney": "^4.0.98", "node-fetch": "^2.6.11", - "openai": "^3.3.0", + "openai": "^4.24.1", "redis": "^4.6.7", "sharp": "^0.32.1", "telegraf": "^4.12.2", "ts-node": "^10.9.1", - "typescript": "^5.1.3" + "typescript": "^5.1.3", + "winston": "^3.11.0" }, "devDependencies": { "@jest/globals": "^29.5.0", diff --git a/src/bot.ts b/src/bot.ts index f8ddde9..6ae7c25 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,5 +1,5 @@ import { Telegraf, Context, Scenes, session } from "telegraf"; -import { Update, CallbackQuery } from 'typegram'; +import { Update, CallbackQuery } from "telegraf/types"; import ffmpeg from "fluent-ffmpeg"; import { definitions } from "./scenes/dialog/commands"; @@ -8,8 +8,8 @@ import antispamScene from "./scenes/antispam"; import dialogScene, { DIALOG_SCENE_ID } from "./scenes/dialog"; import { services, - Datastore, OpenAI, Quota, Settings, Translation, Conversation, Midjourney, - type UserQuota, type ChatSettings, type Translator + Datastore, OpenAI, Quota, Settings, Translation, Conversation, + type UserQuota, type ChatSettings, type Translator, type Midjourney, } from "./services"; export type SceneState = Scenes.SceneSessionData & { diff --git a/src/config.ts b/src/config.ts index 23eaf4c..52f7169 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,46 +1,57 @@ const prices = { - "gpt-3.5-turbo-16k-0613": 0.4, - "gpt-4-0613": 6, - "whisper-1": 0.6 + "gpt-4o": 1.5, + "gpt-4-vision-preview": 3, + "whisper-1": 0.6, + "dall-e-3": 4, } as const; export type ModelName = keyof typeof prices; const config = { models: { - "gpt-3.5-turbo-16k-0613": "GPT-3.5 Turbo", - "gpt-4-0613": "GPT-4" + "gpt-4o": "GPT-4o" } as Record, prices, modes: { "0.1": "Strict", "0.7": "Flexible", "1.2": "Creative", "1.7": "Extreme" }, systemMessage: [ - "You are an AI assistant who has access to all the knowledge of mankind. The user asks you to explain something. Always politely and briefly answer his questions. If the answer requires clarification, ask a question. Communicate in a friendly tone, but always short and to the point.", + "You are an AI assistant who has access to all the knowledge of mankind.", + "The user asks you to explain something.", + "Always politely and briefly answer his questions.", + "Do not repeat user's question at the start of the answer.", + "If the answer requires clarification, ask a question.", + "Communicate in a friendly tone, but always short and to the point.", "Generate code only if the user explicitly requested it, or if the code is an integral part of the explanation.", - "Always wrap code blocks with three backticks (`)" + "Always wrap code blocks with three backticks (`)", + "Use MarkdownV2 style for formatting messages.", + "To make bold text use single *asterisks*, to make italic use single _underscore_.", + "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.", ].join("\n"), translationRequest: "Translate following user's message into English", maxCompletions: 5, defaultSettings: { - model: "gpt-3.5-turbo-16k-0613" as ModelName, + model: "gpt-4o" as ModelName, temperature: 0.7, completions: 1, maxTokens: 4096 }, - functions: [ - // { - // name: "generateImage", - // description: "Generate an image from a user's prompt. Can be called only when user explicitly asks for an image", - // parameters: { - // type: "object", - // properties: { - // prompt: { - // type: "string", - // description: "Clear and concise prompt string in English language without verbs that describes the image to be generated" - // } - // }, - // required: ["prompt"] - // }, - // }, + tools: [ + { + type: "function" as const, + function: { + name: "generateImage", + description: "Generate an image from a user's prompt. Can be called only when user explicitly asks for an image", + parameters: { + type: "object", + properties: { + prompt: { + type: "string", + description: "Clear and concise prompt string in English language without verbs that describes the image to be generated" + } + }, + required: ["prompt"] + }, + } + }, // { // name: "describeImage", // description: "Describe in human readable format what is depicted on provided image", diff --git a/src/functions/index.ts b/src/functions/index.ts index d8b2051..167ba36 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -1,17 +1,33 @@ -import { type Message } from "typegram"; +import d from "debug"; +import { Markup } from "telegraf"; +import actions from "../scenes/dialog/actions"; +import { callUntil } from "../utils"; +import { type Message } from "telegraf/types"; import type { BotContext } from "../bot"; -import actions from "../scenes/dialog/actions"; + +const debug = d("bot:functions"); export type BotFunction = (ctx: BotContext, args: object) => Promise; export async function generateImage(ctx: BotContext, { prompt }: { prompt: string }) { - const hasNonAscii = prompt.split("").some((char) => char.charCodeAt(0) > 127) - if (hasNonAscii) { - prompt = await ctx.openai.translateMessage(prompt); + try { + debug(`generateImage: ${prompt}`); + await callUntil( + () => ctx.sendChatAction("upload_photo"), + async () => { + const { url, revised_prompt } = await ctx.openai.generateImage(prompt); + return ctx.sendPhoto(url!, { + caption: revised_prompt, + // ...Markup.inlineKeyboard([ + // Markup.button.callback(ctx.$t("action.fullsize"), `fullsize:${url}`) + // ]) + }); + } + ); + } catch (error: any) { + await ctx.sendMessage(error.message ?? ctx.$t("error.noimage")); } - - await actions.generate(ctx, prompt); } export async function describeImage(ctx: BotContext) { diff --git a/src/index.test.ts b/src/index.test.ts deleted file mode 100644 index b75f445..0000000 --- a/src/index.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import express from "express"; - -import Bot from "./bot"; - -const app = express(); -const bot = new Bot("test"); - -bot.telegram.callApi = function(method, payload): Promise { - console.log(method, payload); - return Promise.resolve(true); -} - -app.post("/bot", async (request, response, next) => { - await bot.handle(request, response, next); - response.status(200).json({ success: true }); -}); - -app.listen(3000, async () => { - await bot.run({ - domain: "localhost", - path: "/bot", - }); - - console.log("Server started on port 3000"); -}); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index ceef2ba..fdc9a33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,8 @@ import "dotenv/config"; -import * as fs from "fs"; import express from "express"; -import { type AxiosError } from 'axios'; import d from "debug"; import Bot from "./bot"; -import routes from "./routes"; const { BOT_TOKEN, NODE_ENV, PORT, RAILWAY_STATIC_URL } = process.env; @@ -13,7 +10,6 @@ const debug = d("bot:server"); const app = express(); const bot = new Bot(BOT_TOKEN!); const host = RAILWAY_STATIC_URL || process.argv[2]; -const log = fs.createWriteStream("./debug.log", { flags: "a" }); if (!host) { throw new Error("Missing host. Provide '-- ' as the last argument"); @@ -25,28 +21,25 @@ app.post("/bot", async (request, response, next) => { try { await bot.handle(request, response, next); } catch (error) { - debug( - "Error handle update: %s\n%s\n\n%o\n\n%o", - (error as Error).message, - (error as Error).stack, - request.body, - (error as AxiosError).response?.data - ); - log.write(`Error: ${JSON.stringify(error, null, 2)}\nRequest: ${request.body}`, "utf-8"); + console.error(`Error: ${JSON.stringify(error, null, 2)}\nRequest: ${request.body}`, "utf-8"); } }); -app.get("/file/:file.png", async (request, response) => { - const file = await bot.telegram.getFileLink(request.params.file); - const buffer = await fetch(file.href).then((result) => result.arrayBuffer()); - - response.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); - response.setHeader('Content-Type', 'image/png'); - response.setHeader('Content-Length', buffer.byteLength); - response.send(Buffer.from(buffer)); +app.use((request, response, next) => { + if (request.query.bot !== process.env.BOT_TOKEN) { + return response.status(418).json({ error: "I'm a teabot!" }); + } + next(); }); -app.use(routes(bot)); +app.get("/check", async (request, response) => { + response.status(200).json({ + env: process.env, + memory: process.memoryUsage(), + bot: await bot.telegram.getMe(), + webhook: await bot.telegram.getWebhookInfo() + }); +}); app.listen(PORT || 3000, async () => { await bot.run({ diff --git a/src/lang/en.ts b/src/lang/en.ts index 8b89e64..b4483ad 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -9,11 +9,13 @@ export default { "balance.message": "You have {{tokens}} tokens left. You receive {{dailyTokens}} tokens once in a day if your balance is less than {{startTokens}}.", + "error.chat": "An error occurred while generating the answer:\n{{error}}", "error.noimage": "No image provided", "error.image-not-found": "Image not found", "error.process-image-failed": "Failed to process image", "error.generate-image-failed": "Failed to generate image", + "action.fullsize": "🖼️ Full size", "action.split": "🔢 Split", "action.regenerate": "🔁 Regenerate", "action.variate": "🔄 Variate", diff --git a/src/lang/ru.ts b/src/lang/ru.ts index 3408e49..5ea2c7a 100644 --- a/src/lang/ru.ts +++ b/src/lang/ru.ts @@ -9,11 +9,13 @@ export default { "balance.message": "У вас осталось {{tokens}} токенов. Каждый день вы получете {{dailyTokens}} токенов если ваш баланс меньше чем {{startTokens}}.", + "error.chat": "Произошла ошибка при генерации ответа:\n{{error}}", "error.noimage": "Изображение не загружено", "error.image-not-found": "Изображение не найдено", "error.process-image-failed": "Ошибка при обработке изображения", "error.generate-image-failed": "Ошибка при генерации изображения", + "action.fullsize": "🖼️ Полный размер", "action.split": "🔢 Разделить", "action.regenerate": "🔁 Перерисовать", "action.variate": "🔄 Варианты", diff --git a/src/routes.ts b/src/routes.ts deleted file mode 100644 index 9e84bfc..0000000 --- a/src/routes.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as fs from "fs"; -import { Router } from "express"; - -import type Bot from "./bot"; - -export default function(bot: Bot) { - const router = Router(); - - router.use((request, response, next) => { - if (request.query.bot !== process.env.BOT_TOKEN) { - return response.status(418).json({ error: "I'm a teabot!" }); - } - next(); - }); - - router.get("/check", async (request, response) => { - response.status(200).json({ - env: process.env, - memory: process.memoryUsage(), - bot: await bot.telegram.getMe(), - webhook: await bot.telegram.getWebhookInfo() - }); - }); - - router.get("/debug", async (request, response) => { - fs.createReadStream("./debug.log").pipe(response); - }); - - return router; -} diff --git a/src/scenes/dialog/actions.ts b/src/scenes/dialog/actions.ts index 631e011..a9d1584 100644 --- a/src/scenes/dialog/actions.ts +++ b/src/scenes/dialog/actions.ts @@ -1,6 +1,6 @@ import { Markup } from "telegraf"; -import { type Message, type CallbackQuery, type InlineKeyboardMarkup, type InlineKeyboardButton } from "typegram"; +import { type Message, type CallbackQuery, type InlineKeyboardMarkup, type InlineKeyboardButton } from "telegraf/types"; import { type GeneratedImage } from "../../services/Midjourney"; import type { BotContext } from "../../bot"; import { format, callUntil } from "../../utils"; @@ -80,15 +80,24 @@ const trackProgress = async (ctx: BotContext, callback: (tracker: (progress: num }; export default { + async fullsize(ctx: BotContext, imageUrl: string) { + await callUntil( + () => ctx.sendChatAction("upload_photo"), + ctx.sendDocument(imageUrl) + ); + }, async generate(ctx: BotContext, prompt: string) { - await trackProgress(ctx, (setProgress) => { - const message = (ctx.message || ctx.callbackQuery?.message) as Message.PhotoMessage & Message.TextMessage; - if (message.photo) { - prompt = `${ctx.host}/file/${message.photo[0].file_id}.png ${prompt}`; - } + // await trackProgress(ctx, (setProgress) => { + // const message = (ctx.message || ctx.callbackQuery?.message) as Message.PhotoMessage & Message.TextMessage; + // if (message.photo) { + // prompt = `${ctx.host}/file/${message.photo[0].file_id}.png ${prompt}`; + // } - return sendImage(ctx, ctx.midjourney.generate(prompt, setProgress)); - }); + // return sendImage(ctx, ctx.midjourney.generate(prompt, setProgress)); + // }); + const message = (ctx.message || ctx.callbackQuery?.message) as Message.TextMessage; + + return sendImage(ctx, ctx.midjourney.generate(prompt)); }, async upscale(ctx: BotContext, payload: string) { diff --git a/src/scenes/dialog/handlers.ts b/src/scenes/dialog/handlers.ts index 3328950..5efba1e 100644 --- a/src/scenes/dialog/handlers.ts +++ b/src/scenes/dialog/handlers.ts @@ -1,12 +1,12 @@ -import type { Message } from "typegram"; -import { type ChatCompletionRequestMessage } from "openai"; +import type { Message } from "telegraf/types"; +import OpenAIApi from "openai"; import d from "debug"; import { type BotContext } from "../../bot"; import functions from "../../functions"; import { format, callUntil } from "../../utils"; -const debug = d("bot:dialog"); +const debug = d("bot:dialog:handlers"); export async function onPhoto(ctx: BotContext, next: () => Promise) { const message = ctx.message as Message.PhotoMessage & Message.TextMessage; @@ -31,7 +31,6 @@ export async function onVoice(ctx: BotContext, next: () => Promise) { .pipe() .on("data", (chunk: Buffer) => chunks.push(chunk)) .on("end", async () => { - debug(`Transcribe audio ${msg.voice.file_id} in ${url.toString()}`); msg.text = await ctx.openai.transcribeAudio(Buffer.concat(chunks), msg.voice.duration); resolve(true); }); @@ -43,7 +42,8 @@ export async function onVoice(ctx: BotContext, next: () => Promise) { } export async function onText(ctx: BotContext) { - const conversation = ctx.conversation.load(ctx.message as Message.TextMessage); + const message = ctx.message as Message.PhotoMessage & Message.TextMessage; + const conversation = ctx.conversation.load(message); if (conversation.length === 0) { return; } @@ -52,10 +52,19 @@ export async function onText(ctx: BotContext) { return ctx.sendMessage(ctx.$t('quota.exceed')); } + if (message.photo) { + const link = await ctx.telegram.getFileLink(message.photo[0].file_id); + const userMsg = conversation[conversation.length - 1]; + userMsg.content = [ + { type: "text", text: userMsg.content as string }, + { type: "image_url", image_url: { url: link.href } }, + ]; + } + return answer(ctx, conversation); } -async function answer(ctx: BotContext, conversation: ChatCompletionRequestMessage[]) { +async function answer(ctx: BotContext, conversation: OpenAIApi.ChatCompletionMessageParam[]) { const msg = ctx.message as Message.TextMessage; const choices = await callUntil( () => ctx.sendChatAction("typing"), @@ -63,35 +72,44 @@ async function answer(ctx: BotContext, conversation: ChatCompletionRequestMessag ); for (const choice of choices) { - const { content, function_call } = choice.message ?? {}; + const { content, tool_calls } = choice.message ?? {}; + // @ts-ignore if (choice.finish_reason === "error" && content) { - return ctx.replyWithMarkdownV2(format("`" + content + "`").join("")); + return ctx.replyWithMarkdownV2(ctx.$t("error.chat", { error: format("`" + content + "`").join("") })); } - if (function_call && functions[function_call.name!]) { - let args = {}; + if (tool_calls?.length) { try { - args = JSON.parse(function_call.arguments!); + debug(`Calling ${JSON.stringify(tool_calls, null, 2)} tools`); + + const calls = []; + for (const { id, function: fn } of tool_calls) { + if (functions[fn.name]) { + const result = await functions[fn.name](ctx, JSON.parse(fn.arguments)); + if (result) { + calls.push({ role: "tool" as "tool", tool_call_id: id, content: result }); + } + } + } + + if (calls.length) { + await answer(ctx, [ + ...conversation, + choice.message, + ...calls + ]); + } } catch (error) { - debug("Error parse function_call.arguments", function_call.arguments); - } - - debug(`Call function ${function_call.name} with args ${function_call.arguments}`); - const functionResult = await functions[function_call.name!](ctx, args); - if (typeof functionResult === "string") { - await answer(ctx, [ - ...conversation, - choice.message!, - { role: "function", name: function_call.name, content: functionResult } - ]); + console.error(`Error when calling a function: ${JSON.stringify(error, null, 2)}`); } } if (content) { for (const answer of format(content)) { const reply = await ctx.replyWithMarkdownV2(answer, { reply_to_message_id: msg.message_id }); - ctx.conversation.save(msg, reply, conversation[conversation.length - 1].content!, content); + const question = conversation[conversation.length - 1].content as string; + ctx.conversation.save(msg, reply, question, content); } } } diff --git a/src/scenes/dialog/middleware.ts b/src/scenes/dialog/middleware.ts index 6390157..5891031 100644 --- a/src/scenes/dialog/middleware.ts +++ b/src/scenes/dialog/middleware.ts @@ -1,4 +1,4 @@ -import type { Message } from "typegram"; +import type { Message } from "telegraf/types"; import d from "debug"; import { BotContext, BotUpdate } from "../../bot"; diff --git a/src/services/Conversation.ts b/src/services/Conversation.ts index 7efcf59..b353dff 100644 --- a/src/services/Conversation.ts +++ b/src/services/Conversation.ts @@ -1,5 +1,5 @@ import { type Message } from 'telegraf/types'; -import { type ChatCompletionRequestMessage } from "openai"; +import OpenAIApi from "openai"; import config from "../config"; @@ -25,7 +25,7 @@ export default class Conversation { } load(msg: Message.TextMessage) { - const conversation: ChatCompletionRequestMessage[] = []; + const conversation: OpenAIApi.ChatCompletionMessageParam[] = []; if (msg.reply_to_message) { let dialog = this.loadDialog(msg.chat.id, msg.reply_to_message.message_id); diff --git a/src/services/index.ts b/src/services/index.ts index fe3063e..973b868 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,11 +1,11 @@ import Bot, { type BotContext } from "../bot"; import config from "../config"; -import Datastore from "./Datastore"; +// import Datastore from "./Datastore"; import OpenAI from "./OpenAI"; import Quota from "./Quota"; import Settings from "./Settings"; -import Midjourney from "./Midjourney"; +//import Midjourney from "./Midjourney"; import { type LangName } from "./Translation"; export { default as Datastore } from "./Datastore"; @@ -25,7 +25,7 @@ export function services(bot: Bot) { ctx.openai = new OpenAI(OPENAI_KEY!, ctx); ctx.conversation = conversation; ctx.ffmpeg = ffmpeg; - ctx.midjourney = new Midjourney(ctx, new Datastore("generations")); + // ctx.midjourney = new Midjourney(ctx, new Datastore("generations")); ctx.quota = new Quota(ctx.session); ctx.settings = new Settings(ctx.session); diff --git a/src/services/openai.ts b/src/services/openai.ts index 2333d69..5880513 100644 --- a/src/services/openai.ts +++ b/src/services/openai.ts @@ -1,11 +1,4 @@ -import { - Configuration, - OpenAIApi, - ChatCompletionRequestMessage, - CreateChatCompletionResponseChoicesInner -} from "openai"; -import { type AxiosError } from 'axios'; -import { Readable } from "stream"; +import OpenAIApi, { toFile } from "openai"; import d from "debug"; import config, { type ModelName } from "../config"; @@ -17,49 +10,63 @@ export default class OpenAI { api: OpenAIApi; constructor (key: string, private ctx: BotContext) { - this.api = new OpenAIApi(new Configuration({ apiKey: key })); + this.api = new OpenAIApi({ apiKey: key }); } - async createChatCompletion(messages: ChatCompletionRequestMessage[]) - : Promise - { + async createChatCompletion(messages: OpenAIApi.ChatCompletionMessageParam[]) { const settings = this.ctx.settings.current; const request = { messages, model: settings.model, temperature: settings.temperature, n: settings.completions, - // max_tokens: settings.maxTokens - functions: config.functions + // max_tokens: settings.maxTokens, + tools: config.tools, }; try { - debug("createChatCompletion %o", request); - const { data } = await this.api.createChatCompletion(request); + debug(`createChatCompletion request: ${JSON.stringify(request, null, 2)}`); + const { choices, usage } = await this.api.chat.completions.create(request); + debug(`createChatCompletion response: ${JSON.stringify(choices, null, 2)}`); - debug("Chat completion result %o", data); - - if (data.usage?.total_tokens) { - this.ctx.quota.consume(settings.model, data.usage.total_tokens / 1000); + if (usage?.total_tokens) { + this.ctx.quota.consume(settings.model, usage.total_tokens / 1000); } - - return data.choices; + + return choices; } catch (error) { - debug("createChatCompletion error", (error as AxiosError).response?.data ?? (error as Error).message); + console.error(`createChatCompletion error: ${JSON.stringify(error, null, 2)}`); - const message = (error as AxiosError).response?.data?.error?.message; + const message = (error as Error)?.message; return message - ? [{ message: { content: message, role: "system" }, finish_reason: "error" }] + ? [ + { + message: { content: message, role: "system" }, + finish_reason: "error", + } as unknown as OpenAIApi.ChatCompletion.Choice + ] : []; } } + async generateImage(prompt: string) { + const { data } = await this.api.images.generate({ + prompt, + model: "dall-e-3", + quality: 'hd', + response_format: 'url', + size: '1024x1024', + }); + + return data[0]; + } + async transcribeAudio(buffer: Buffer, duration: number) { - const audio = Readable.from(buffer); - // @ts-expect-error path does not exist - audio.path = "conversation.mp3"; + const { text } = await this.api.audio.transcriptions.create({ + file: await toFile(buffer, "conversation.mp3", { type: "audio/mpeg" }), + model: "whisper-1", + }); - const { data: { text } } = await this.api.createTranscription(audio as unknown as File, "whisper-1"); this.ctx.quota.consume("whisper-1", duration / 60); return text; @@ -67,60 +74,54 @@ export default class OpenAI { async translateMessage(text: string) { const settings = this.ctx.settings.current; - const messages: ChatCompletionRequestMessage[] = [ + const messages: OpenAIApi.ChatCompletionMessageParam[] = [ { role: "system", content: config.translationRequest }, { role: "user", content: text } ]; - debug("translate message %o", messages); - const { data } = await this.api.createChatCompletion({ + const { choices, usage } = await this.api.chat.completions.create({ messages, model: settings.model, temperature: 0 }); - debug("Translation result %o", data); - - if (data.usage?.total_tokens) { - this.ctx.quota.consume(settings.model, data.usage.total_tokens / 1000); + if (usage?.total_tokens) { + this.ctx.quota.consume(settings.model, usage.total_tokens / 1000); } - return data.choices[0].message?.content ?? ""; + return choices[0].message?.content ?? ""; } async antispamPrompt() { - const { data } = await this.api.createChatCompletion({ + const { choices } = await this.api.chat.completions.create({ messages: [{ role: "system", content: this.ctx.$t("antispam.system") }], model: this.ctx.settings.current.model, temperature: 1.1 }); - debug("Antispam prompt %o", data.choices[0]); - - return data.choices[0].message?.content ?? ""; + return choices[0].message?.content ?? ""; } async checkAntispam(question: string, answer: string) { - const prompt: ChatCompletionRequestMessage[] = [ + const prompt: OpenAIApi.ChatCompletionMessageParam[] = [ { role: "system", content: this.ctx.$t("antispam.system") }, { role: "assistant", content: question }, { role: "user", content: answer } ]; - const { data } = await this.api.createChatCompletion({ + const { choices } = await this.api.chat.completions.create({ messages: prompt, model: this.ctx.settings.current.model, temperature: 0 }); - debug("Antispam check %o", data.choices[0]); - return data.choices[0].message?.content?.toLowerCase() === "yes"; + return choices[0].message?.content?.toLowerCase() === "yes"; } async getModels(returnAll = false) { - const response = await this.api.listEngines(); - return response.data.data - .filter(engine => engine.ready && (returnAll || config.models[engine.id as ModelName])) + const response = await this.api.models.list(); + return response.data + .filter(engine => returnAll || config.models[engine.id as ModelName]) .map(engine => engine.id); } } diff --git a/tsconfig.json b/tsconfig.json index c6f6c7d..3d223fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,20 @@ { + "extends": "ts-node/node16/tsconfig.json", + "compilerOptions": { - "module": "NodeNext", + "module": "ESNext", "target": "ESNext", "allowJs": true, "strict": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "isolatedModules": false, - "outDir": "./dist" + "isolatedModules": false }, "ts-node": { "files": true, - "esm": true + "esm": true, + "experimentalSpecifierResolution": "node" }, "include": ["src/**/*", "api/**/*"], "exclude": ["node_modules", "**/*.spec.ts"] diff --git a/yarn.lock b/yarn.lock index 780070a..144281f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -299,6 +299,11 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" @@ -306,6 +311,15 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -699,6 +713,11 @@ resolved "https://registry.npmjs.org/@telegraf/session/-/session-2.0.0-beta.6.tgz" integrity sha512-L4UqZDN797JRk2aplalmWW34D8GqpZEHEvfy8NBjylL8KzQFnCNzW+Ajnes090a7vTITB5YM70tgSjpnsr35KA== +"@telegraf/types@^6.9.1": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@telegraf/types/-/types-6.9.1.tgz#ee2d335164f582db55337d77cc440c1faeadd510" + integrity sha512-bzqwhicZq401T0e09tu8b1KvGfJObPmzKU/iKCT5V466AsAZZWQrBYQ5edbmD1VZuHLEwopoOVY5wPP4HaLtug== + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" @@ -851,17 +870,26 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node-fetch@^2.6.4": - version "2.6.4" - resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz" - integrity sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg== + version "2.6.9" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.9.tgz#15f529d247f1ede1824f7e7acdaa192d5f28071e" + integrity sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA== dependencies: "@types/node" "*" - form-data "^3.0.0" + form-data "^4.0.0" "@types/node@*", "@types/node@^20.3.3": - version "20.3.3" - resolved "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz" - integrity sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw== + version "20.10.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" + integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== + dependencies: + undici-types "~5.26.4" + +"@types/node@^18.11.18": + version "18.19.3" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz" + integrity sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg== + dependencies: + undici-types "~5.26.4" "@types/prettier@^2.1.5": version "2.7.3" @@ -904,6 +932,11 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" @@ -1002,7 +1035,7 @@ abort-controller@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" @@ -1030,6 +1063,13 @@ acorn@^8.4.1, acorn@^8.8.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +agentkeepalive@^4.2.1: + version "4.5.0" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -1106,23 +1146,16 @@ array-union@^2.1.0: resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -async@>=0.2.9: +async@>=0.2.9, async@^3.2.3: version "3.2.4" resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^0.26.0: - version "0.26.1" - resolved "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz" - integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== - dependencies: - follow-redirects "^1.14.8" - babel-jest@^29.5.0: version "29.5.0" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz" @@ -1188,6 +1221,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz" + integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -1261,12 +1299,12 @@ bser@2.1.1: buffer-alloc-unsafe@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" @@ -1274,7 +1312,7 @@ buffer-alloc@^1.2.0: buffer-fill@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== buffer-from@^1.0.0: @@ -1345,6 +1383,11 @@ char-regex@^1.0.2: resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + chownr@^1.1.1: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" @@ -1384,7 +1427,7 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1408,7 +1451,7 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.9.0: +color-string@^1.6.0, color-string@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== @@ -1416,6 +1459,14 @@ color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + color@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz" @@ -1424,9 +1475,17 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" @@ -1482,6 +1541,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -1525,7 +1589,7 @@ deepmerge@^4.2.2: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== depd@2.0.0: @@ -1558,6 +1622,14 @@ diff@^4.0.1: resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +digest-fetch@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz" + integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== + dependencies: + base-64 "^0.1.0" + md5 "^2.3.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" @@ -1597,6 +1669,11 @@ emoji-regex@^8.0.0: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" @@ -1758,7 +1835,7 @@ etag@~1.8.1: event-target-shim@^5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== eventemitter3@^4.0.4: @@ -1879,6 +1956,11 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" @@ -1943,29 +2025,33 @@ fluent-ffmpeg@^2.1.2: async ">=0.2.9" which "^1.1.1" -follow-redirects@^1.14.8: - version "1.15.2" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== form-data@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" mime-types "^2.1.12" +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" @@ -2144,6 +2230,13 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -2215,6 +2308,11 @@ is-arrayish@^0.3.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-core-module@^2.11.0: version "2.12.1" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz" @@ -2727,6 +2825,11 @@ kleur@^3.0.3: resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + leven@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" @@ -2769,6 +2872,18 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -2802,6 +2917,15 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -2850,7 +2974,7 @@ midjourney@^4.0.98: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: @@ -2899,7 +3023,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: mri@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== ms@2.0.0: @@ -2907,7 +3031,7 @@ ms@2.0.0: resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: +ms@2.1.2, ms@^2.0.0, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -2949,13 +3073,25 @@ node-addon-api@^6.1.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz" integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== -node-fetch@^2.6.11, node-fetch@^2.6.8: +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^2.6.11, node-fetch@^2.6.7: version "2.6.11" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz" integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.8: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" @@ -2997,6 +3133,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" @@ -3004,13 +3147,20 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -openai@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz" - integrity sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ== +openai@^4.24.1: + version "4.24.1" + resolved "https://registry.npmjs.org/openai/-/openai-4.24.1.tgz" + integrity sha512-ezm/O3eiZMnyBqirUnWm9N6INJU1WhNtz+nK/Zj/2oyKvRz9pgpViDxa5wYOtyGYXPn1sIKBV0I/S4BDhtydqw== dependencies: - axios "^0.26.0" - form-data "^4.0.0" + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + digest-fetch "^1.3.0" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" optionator@^0.9.1: version "0.9.1" @@ -3074,7 +3224,7 @@ p-timeout@^3.2.0: p-timeout@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-4.1.0.tgz#788253c0452ab0ffecf18a62dff94ff1bd09ca0a" integrity sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw== p-try@^2.0.0: @@ -3264,7 +3414,7 @@ react-is@^18.0.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -readable-stream@^3.1.1, readable-stream@^3.4.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -3347,11 +3497,16 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: safe-compare@^1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/safe-compare/-/safe-compare-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/safe-compare/-/safe-compare-1.1.4.tgz#5e0128538a82820e2e9250cd78e45da6786ba593" integrity sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ== dependencies: buffer-alloc "^1.2.0" +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" @@ -3359,7 +3514,7 @@ safe-compare@^1.1.4: sandwich-stream@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/sandwich-stream/-/sandwich-stream-2.0.2.tgz#6d1feb6cf7e9fe9fadb41513459a72c2e84000fa" integrity sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ== semver@^6.0.0, semver@^6.3.0: @@ -3502,6 +3657,11 @@ sprintf-js@~1.0.2: resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" @@ -3613,10 +3773,11 @@ tar-stream@^2.1.4: readable-stream "^3.1.1" telegraf@^4.12.2: - version "4.12.2" - resolved "https://registry.npmjs.org/telegraf/-/telegraf-4.12.2.tgz" - integrity sha512-PgwqI4wD86cMqVfFtEM9JkGGnMHgvgLJbReZMmwW4z35QeOi4DvbdItONld4bPnYn3A1jcO0SRKs0BXmR+x+Ew== + version "4.15.3" + resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.15.3.tgz#72e28e62c3cc7f97b88b5f1b04a0e0700a7df251" + integrity sha512-pm2ZQAisd0YlUvnq6xdymDfoQR++8wTalw0nfw7Tjy0va+V/0HaBLzM8kMNid8pbbt7GHTU29lEyA5CAAr8AqA== dependencies: + "@telegraf/types" "^6.9.1" abort-controller "^3.0.0" debug "^4.3.4" mri "^1.2.0" @@ -3624,7 +3785,6 @@ telegraf@^4.12.2: p-timeout "^4.1.0" safe-compare "^1.1.4" sandwich-stream "^2.0.2" - typegram "^4.3.0" test-exclude@^6.0.0: version "6.0.0" @@ -3635,6 +3795,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" @@ -3664,9 +3829,14 @@ toidentifier@1.0.1: tr46@~0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + ts-jest@^29.1.1: version "29.1.1" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz" @@ -3754,16 +3924,16 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typegram@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/typegram/-/typegram-4.3.0.tgz" - integrity sha512-pS4STyOZoJ++Mwa9GPMTNjOwEzMkxFfFt1By6IbMOJfheP0utMP/H1ga6J9R4DTjAYBr0UDn4eQg++LpWBvcAg== - typescript@^5.1.3: version "5.1.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz" integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" @@ -3820,14 +3990,24 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +web-streams-polyfill@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" @@ -3847,6 +4027,32 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +winston-transport@^4.5.0: + version "4.6.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz" + integrity sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@^3.11.0: + version "3.11.0" + resolved "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz" + integrity sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.5.0" + word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz"