bump libs

migrate to typescript 6
remove ytdl feature
This commit is contained in:
2026-05-01 07:05:17 +03:00
parent ac51702f00
commit 13b41c3026
56 changed files with 1069 additions and 1857 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ export class AdminsAdd extends Command {
);
async execute(msg: Message): Promise<void> {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
const id = msg.reply_to_message.from.id;
const text = fullName(msg.reply_to_message.from);
+1 -1
View File
@@ -18,7 +18,7 @@ export class AdminsRemove extends Command {
);
async execute(msg: Message): Promise<void> {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
const id = msg.reply_to_message.from.id;
const text = fullName(msg.reply_to_message.from);
+2 -2
View File
@@ -13,7 +13,7 @@ export class Ae extends Command {
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, params?: RegExpExecArray) {
const match = params?.[3];
const match = params?.[3] || "";
try {
let e = eval(match);
@@ -21,7 +21,7 @@ export class Ae extends Command {
e = ((typeof e == "string") ? e : JSON.stringify(e));
await oldSendMessage(msg, e).catch(async () => await errorPlaceholder(msg));
} catch (e) {
} catch (e: any) {
const text = e.message.toString();
if (text.includes("is not defined")) {
+1 -1
View File
@@ -19,7 +19,7 @@ export class Ban extends Command {
);
async execute(msg: Message) {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.from || ! msg.reply_to_message.from) return;
const user = msg.reply_to_message.from;
const userId = user.id;
+1 -1
View File
@@ -12,7 +12,7 @@ export class Choice extends Command {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
const payload = match[3];
const payload = match?.[3] || "";
const re =
/\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^,]+?))\s*(?:,|$)/g;
+2 -2
View File
@@ -11,8 +11,8 @@ export class Dice extends Command {
description = "Sends random or specific dice";
async execute(msg: Message): Promise<void> {
const split = msg.text.split("/dice ");
const secondPart = split[1]?.trim();
const split = msg.text?.split("/dice ");
const secondPart = split?.[1]?.trim() || "";
const emojiIndex = emojis.indexOf(secondPart);
const emojiToDice: DiceEmoji = (emojiIndex >= 0 ? emojis[emojiIndex] : randomValue(emojis)) as DiceEmoji;
+2 -2
View File
@@ -47,14 +47,14 @@ export class Distort extends Command {
const inputBuf = await downloadTelegramFile(file.file_path);
const outBuf = await waveDistortSharp(inputBuf, amp, wavelength);
const outBuf = await waveDistortSharp(<Buffer>inputBuf, amp, wavelength);
await bot.sendPhoto({
chat_id: chatId,
photo: outBuf,
caption: `Искажение готово ✅ (amp=${amp}, wavelength=${wavelength})`,
});
} catch (e) {
} catch (e: any) {
await oldReplyToMessage(
msg, `Не получилось исказить изображение: ${e?.message ?? String(e)}`
).catch(logError);
+22 -17
View File
@@ -4,7 +4,7 @@ import {bot, googleAi} from "../index";
import {MessageStore} from "../common/message-store";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {ApiError} from "@google/genai";
import {
collectReplyChainText,
escapeMarkdownV2Text,
@@ -14,6 +14,7 @@ import {
startIntervalEditor
} from "../util/utils";
import {ChatCommand} from "../base/chat-command";
import {ApiError} from "@google/genai";
export class GeminiChat extends ChatCommand {
command = "gemini";
@@ -26,11 +27,11 @@ export class GeminiChat extends ChatCommand {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
return this.executeGemini(msg, match?.[3]);
return this.executeGemini(msg, match?.[3] || "");
}
async executeGemini(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
if (!text || !text.trim().length) return;
const chatId = msg.chat.id;
@@ -77,7 +78,7 @@ export class GeminiChat extends ChatCommand {
});
}
let waitMessage: Message;
let waitMessage: Message | null = null;
const startTime = Date.now();
@@ -95,7 +96,7 @@ export class GeminiChat extends ChatCommand {
const stream = await googleAi.interactions.create({
model: Environment.GEMINI_MODEL,
input: input,
input: input as any,
stream: true
});
@@ -109,7 +110,7 @@ export class GeminiChat extends ChatCommand {
await bot.editMessageText(
{
chat_id: chatId,
message_id: waitMessage.message_id,
message_id: <number>waitMessage?.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "MarkdownV2"
}
@@ -117,9 +118,11 @@ export class GeminiChat extends ChatCommand {
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
if (waitMessage) {
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
}
},
onStop: async () => {
}
@@ -175,17 +178,19 @@ export class GeminiChat extends ChatCommand {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
} catch (e: any) {
logError(e);
if (error instanceof ApiError) {
if (error.status === 429) {
await oldReplyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
return;
if (waitMessage) {
if (e instanceof ApiError) {
if (e.status === 429) {
await oldReplyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
return;
}
}
}
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
}
}
}
}
+11 -9
View File
@@ -18,14 +18,14 @@ export class GeminiGenerateImage extends Command {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
const prompt = match?.[3];
const prompt = match?.[3] || "";
return this.executeGenImage(msg, prompt);
}
async executeGenImage(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
if (!text || !text.trim().length) return;
let waitMessage: Message;
let waitMessage: Message | null = null;
try {
waitMessage = await replyToMessage({
@@ -47,14 +47,16 @@ export class GeminiGenerateImage extends Command {
console.log(`Output ${index + 1}: ${output}`);
}
});
} catch (e) {
} catch (e: any) {
logError(e);
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${e.toString()}`,
link_preview_options: {is_disabled: true}
}).catch(logError);
if (waitMessage) {
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${e.toString()}`,
link_preview_options: {is_disabled: true}
}).catch(logError);
}
}
}
}
+2 -2
View File
@@ -20,9 +20,9 @@ export class GeminiGetModel extends Command {
return {
vision: {supported: true},
ocr: null,
ocr: undefined,
thinking: {supported: info.thinking},
tools: null
tools: undefined
};
} catch (e) {
logError(e);
+1 -1
View File
@@ -17,7 +17,7 @@ export class GeminiListModels extends Command {
console.log(listResponse);
const modelsString = listResponse.page
.sort((a, b) => a.name.localeCompare(b.name))
.sort((a, b) => (a.name || "").localeCompare((b.name || "")))
.map(e => `${e.name}`)
.join("\n");
+1
View File
@@ -11,6 +11,7 @@ export class Help extends Command {
description = "Show list of commands";
async execute(msg: Message) {
if (!msg.from) return;
let text = "Commands:\n\n";
commands.forEach(c => {
+2 -2
View File
@@ -7,9 +7,9 @@ export class Id extends Command {
description = "ID of chat, user and reply (if replied to any message)";
async execute(msg: Message): Promise<void> {
let text = `chat id: \n\`\`\`${msg.chat.id}\`\`\` \nfrom id: \n\`\`\`${msg.from.id}\`\`\``;
let text = `chat id: \n\`\`\`${msg.chat.id}\`\`\` \nfrom id: \n\`\`\`${msg.from?.id}\`\`\``;
if (msg.reply_to_message) {
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from.id}\`\`\``;
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from?.id}\`\`\``;
}
await oldReplyToMessage(msg, text, "MarkdownV2").catch(logError);
+1 -1
View File
@@ -19,7 +19,7 @@ export class Ignore extends Command {
);
async execute(msg: Message) {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
const id = msg.reply_to_message.from.id;
const text = fullName(msg.reply_to_message.from);
+6 -6
View File
@@ -16,7 +16,7 @@ export class Info extends Command {
async execute(msg: Message): Promise<void> {
const aiProvider = Environment.DEFAULT_AI_PROVIDER;
const aiModel = getCurrentModel();
let aiModelCapabilities: AiModelCapabilities = {};
let aiModelCapabilities: AiModelCapabilities | null = {};
try {
aiModelCapabilities = await getCurrentModelCapabilities();
@@ -33,11 +33,11 @@ export class Info extends Command {
`provider: ${aiProvider.toLowerCase()}\n` +
`model: ${aiModel}\n\n` +
`vision${aiModelCapabilities.vision?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.vision?.supported)}\n` +
`ocr${aiModelCapabilities.ocr?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.ocr?.supported)}\n` +
`thinking${aiModelCapabilities.thinking?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.thinking?.supported)}\n` +
`tools${aiModelCapabilities.tools?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.tools?.supported)}\n` +
`audio${aiModelCapabilities.audio?.external ? "(ext)": ""}: ${boolToEmoji(aiModelCapabilities.audio?.supported)}` +
`vision${aiModelCapabilities?.vision?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.vision?.supported)}\n` +
`ocr${aiModelCapabilities?.ocr?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.ocr?.supported)}\n` +
`thinking${aiModelCapabilities?.thinking?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.thinking?.supported)}\n` +
`tools${aiModelCapabilities?.tools?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.tools?.supported)}\n` +
`audio${aiModelCapabilities?.audio?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.audio?.supported)}` +
"```";
const cmds = commands.filter(c => !(c instanceof ChatCommand));
+16 -11
View File
@@ -26,11 +26,11 @@ export class MistralChat extends ChatCommand {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
return this.executeMistral(msg, match?.[3]);
return this.executeMistral(msg, match?.[3] || "");
}
async executeMistral(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
if (!text || !text.trim().length) return;
const chatId = msg.chat.id;
@@ -63,7 +63,7 @@ export class MistralChat extends ChatCommand {
chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
}
let waitMessage: Message;
let waitMessage: Message | null = null;
const startTime = Date.now();
@@ -74,7 +74,7 @@ export class MistralChat extends ChatCommand {
if (imagesCount) {
try {
const modelInfo = await commands.find(c => c instanceof MistralGetModel).getModelCapabilities();
const modelInfo = await commands.find(c => c instanceof MistralGetModel)?.getModelCapabilities();
if (modelInfo) {
if (!modelInfo.vision?.supported) {
await replyToMessage({
@@ -117,7 +117,7 @@ export class MistralChat extends ChatCommand {
await bot.editMessageText(
{
chat_id: chatId,
message_id: waitMessage.message_id,
message_id: <number>waitMessage?.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "MarkdownV2"
}
@@ -125,9 +125,11 @@ export class MistralChat extends ChatCommand {
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
if (waitMessage) {
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
}
},
onStop: async () => {
}
@@ -172,9 +174,12 @@ export class MistralChat extends ChatCommand {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
} catch (e: any) {
logError(e);
if (waitMessage) {
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
}
}
}
}
+2 -3
View File
@@ -6,7 +6,6 @@ import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {mistralAi} from "../index";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
import {BaseModelCard} from "@mistralai/mistralai/models/components/basemodelcard";
export class MistralGetModel extends Command {
title = "/mistralGetModel";
@@ -20,13 +19,13 @@ export class MistralGetModel extends Command {
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
try {
const info: BaseModelCard = await mistralAi.models.retrieve({modelId: Environment.MISTRAL_MODEL}) as BaseModelCard;
const info = await mistralAi.models.retrieve({modelId: Environment.MISTRAL_MODEL}) as any;
console.log(info);
return {
vision: {supported: info.capabilities.vision},
ocr: {supported: info.capabilities.ocr},
thinking: null,
thinking: undefined,
tools: {supported: info.capabilities.functionCalling},
audio: {supported: info.capabilities.audioTranscription}
};
+40 -3
View File
@@ -4,7 +4,6 @@ import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {mistralAi} from "../index";
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
import {BaseModelCard} from "@mistralai/mistralai/models/components/basemodelcard";
export class MistralListModels extends Command {
title = "/mistralListModels";
@@ -21,7 +20,7 @@ export class MistralListModels extends Command {
console.log(listResponse);
const modelsString = listResponse.data
.sort((a, b) => a.name.localeCompare(b.name))
.sort((a, b) => a?.name?.localeCompare(b.name || "") || -1)
.map(e => `${e.id}`)
.join("\n");
@@ -37,4 +36,42 @@ export class MistralListModels extends Command {
await oldReplyToMessage(msg, "Не получилось загрузить список моделей").catch(logError);
}
}
}
}
type BaseModelCard = {
id: string;
object: string;
created?: number | undefined;
ownedBy: string;
/**
* This is populated by Harmattan, but some fields have a name
*
* @remarks
* that we don't want to expose in the API.
*/
capabilities: ModelCapabilities;
name?: string | null | undefined;
description?: string | null | undefined;
maxContextLength: number;
aliases?: Array<string> | undefined;
deprecation?: Date | null | undefined;
deprecationReplacementModel?: string | null | undefined;
defaultModelTemperature?: number | null | undefined;
type: "base";
};
type ModelCapabilities = {
completionChat: boolean;
functionCalling: boolean;
reasoning: boolean;
completionFim: boolean;
fineTuning: boolean;
vision: boolean;
ocr: boolean;
classification: boolean;
moderation: boolean;
audio: boolean;
audioTranscription: boolean;
audioTranscriptionRealtime: boolean;
audioSpeech: boolean;
};
+27 -22
View File
@@ -28,11 +28,12 @@ export class OllamaChat extends ChatCommand {
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
console.log("match", match);
return this.executeOllama(msg, match?.[3], match?.[1]?.toLowerCase()?.startsWith("ollamathink"));
return this.executeOllama(msg, match?.[3] || "", match?.[1]?.toLowerCase()?.startsWith("ollamathink"));
}
async executeOllama(msg: Message, text: string, think: boolean = false, voiceB64?: string): Promise<void> {
if ((!text || text.trim().length === 0) && !voiceB64) return;
async executeOllama(msg: Message, text: string, think: boolean = false, voiceB64?: string | null): Promise<void> {
if (!msg.from) return;
if ((!text || !text.trim().length) && !voiceB64) return;
const chatId = msg.chat.id;
@@ -66,7 +67,7 @@ export class OllamaChat extends ChatCommand {
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
}
let waitMessage: Message;
let waitMessage: Message | null = null;
const startTime = Date.now();
@@ -77,7 +78,7 @@ export class OllamaChat extends ChatCommand {
if (!think && imagesCount) {
try {
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadImageModelInfo();
const modelInfo = await commands.find(c => c instanceof OllamaGetModel)?.loadImageModelInfo();
if (modelInfo) {
if (!modelInfo.vision?.supported) {
await replyToMessage({
@@ -94,7 +95,7 @@ export class OllamaChat extends ChatCommand {
if (think) {
try {
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadThinkModelInfo();
const modelInfo = await commands.find(c => c instanceof OllamaGetModel)?.loadThinkModelInfo();
if (modelInfo) {
if (!modelInfo.thinking?.supported) {
await replyToMessage({
@@ -131,11 +132,11 @@ export class OllamaChat extends ChatCommand {
}
const stream = await ollama.chat({
model: think ? Environment.OLLAMA_THINK_MODEL : imagesCount ? Environment.OLLAMA_IMAGE_MODEL : Environment.OLLAMA_MODEL,
model: <string>(think ? Environment.OLLAMA_THINK_MODEL : imagesCount ? Environment.OLLAMA_IMAGE_MODEL : Environment.OLLAMA_MODEL),
stream: true,
think: think,
messages: chatMessages,
options: options
options: <Partial<Options>>options
});
const newRequest = {
@@ -170,7 +171,7 @@ export class OllamaChat extends ChatCommand {
try {
await bot.editMessageText({
chat_id: chatId,
message_id: waitMessage.message_id,
message_id: <number>waitMessage?.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "MarkdownV2",
reply_markup: cancelMarkup
@@ -178,9 +179,11 @@ export class OllamaChat extends ChatCommand {
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
if (waitMessage) {
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
}
} catch (e) {
logError(e);
}
@@ -225,7 +228,7 @@ export class OllamaChat extends ChatCommand {
shouldBreak = true;
}
if (getOllamaRequest(uuid).done) {
if (getOllamaRequest(uuid)?.done) {
shouldBreak = true;
}
@@ -266,17 +269,19 @@ export class OllamaChat extends ChatCommand {
}).catch(logError);
console.log(`aborted request ${uuid}:`, abortOllamaRequest(uuid));
}
} catch (error) {
if (error.message.toLowerCase().includes("aborted")) return;
} catch (e: any) {
if (e.message.toLowerCase().includes("aborted")) return;
logError(e);
await bot.editMessageReplyMarkup({
chat_id: chatId,
message_id: waitMessage.message_id,
reply_markup: {inline_keyboard: []}
}).catch(logError);
if (waitMessage) {
await bot.editMessageReplyMarkup({
chat_id: chatId,
message_id: waitMessage.message_id,
reply_markup: {inline_keyboard: []}
}).catch(logError);
logError(error);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
}
}
}
}
+10 -8
View File
@@ -56,22 +56,24 @@ export class OllamaGetModel extends Command {
parse_mode: "Markdown"
}).catch(logError);
} catch (e) {
} catch (e: any) {
logError(e);
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
}
}
private getModelText(model: string, info: AiModelCapabilities): string {
private getModelText(model: string | undefined, info: AiModelCapabilities | null): string {
return `model: ${model}\n\n` +
`vision: ${boolToEmoji(info.vision?.supported)}\n` +
`ocr: ${boolToEmoji(info.ocr?.supported)}\n` +
`thinking: ${boolToEmoji(info.thinking?.supported)}\n` +
`tools: ${boolToEmoji(info.tools?.supported)}\n` +
`audio: ${boolToEmoji(info.audio?.supported)}`;
`vision: ${boolToEmoji(info?.vision?.supported)}\n` +
`ocr: ${boolToEmoji(info?.ocr?.supported)}\n` +
`thinking: ${boolToEmoji(info?.thinking?.supported)}\n` +
`tools: ${boolToEmoji(info?.tools?.supported)}\n` +
`audio: ${boolToEmoji(info?.audio?.supported)}`;
}
async getModelCapabilities(model: string = Environment.OLLAMA_MODEL): Promise<AiModelCapabilities | null> {
async getModelCapabilities(model: string | undefined = Environment.OLLAMA_MODEL): Promise<AiModelCapabilities | null> {
if (!model) return null;
try {
const info = await ollama.show({model: model});
console.log(info);
+24 -18
View File
@@ -20,14 +20,16 @@ export class OllamaPrompt extends Command {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
return this.executeOllama(msg, match?.[3]);
return this.executeOllama(msg, match?.[3] || "");
}
async executeOllama(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
if (!text || !text.trim().length) return;
if (!msg.from) return;
const chatId = msg.chat.id;
let waitMessage: Message;
let waitMessage: Message | null = null;
const startTime = Date.now();
@@ -45,7 +47,7 @@ export class OllamaPrompt extends Command {
});
const stream = await ollama.generate({
model: Environment.OLLAMA_MODEL,
model: <string>Environment.OLLAMA_MODEL,
stream: true,
think: false,
prompt: text
@@ -83,7 +85,7 @@ export class OllamaPrompt extends Command {
try {
await bot.editMessageText({
chat_id: chatId,
message_id: waitMessage.message_id,
message_id: <number>waitMessage?.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "Markdown",
reply_markup: cancelMarkup
@@ -91,9 +93,11 @@ export class OllamaPrompt extends Command {
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
if (waitMessage) {
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
}
} catch (e) {
logError(e);
}
@@ -138,7 +142,7 @@ export class OllamaPrompt extends Command {
shouldBreak = true;
}
if (getOllamaRequest(uuid).done) {
if (getOllamaRequest(uuid)?.done) {
shouldBreak = true;
}
@@ -173,17 +177,19 @@ export class OllamaPrompt extends Command {
reply_markup: {inline_keyboard: []}
}).catch(logError);
}
} catch (error) {
if (error.message.toLowerCase().includes("aborted")) return;
} catch (e: any) {
if (e.message.toLowerCase().includes("aborted")) return;
logError(e);
await bot.editMessageReplyMarkup({
chat_id: chatId,
message_id: waitMessage.message_id,
reply_markup: {inline_keyboard: []}
}).catch(logError);
if (waitMessage) {
await bot.editMessageReplyMarkup({
chat_id: chatId,
message_id: waitMessage.message_id,
reply_markup: {inline_keyboard: []}
}).catch(logError);
logError(error);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
}
}
}
}
+6 -2
View File
@@ -4,7 +4,7 @@ import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {bot, ollama} from "../index";
import {WebSearchResponse} from "../model/web-search-response";
import {oldEditMessageText, logError} from "../util/utils";
import {logError, oldEditMessageText} from "../util/utils";
import {Environment} from "../common/environment";
export class OllamaSearch extends Command {
@@ -18,6 +18,10 @@ export class OllamaSearch extends Command {
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
console.log("match", match);
const query = match?.[3] || "";
if (!query || !query.length) return;
const chatId = msg.chat.id;
try {
@@ -31,7 +35,7 @@ export class OllamaSearch extends Command {
parse_mode: "Markdown"
});
const results = await ollama.webSearch({query: match?.[3]});
const results = await ollama.webSearch({query: query});
console.log("results", results);
let message = "Результаты:\n\n";
+4 -3
View File
@@ -15,18 +15,19 @@ export class OllamaSetModel extends Command {
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
const newModel = match?.[3];
const newModel = match?.[3] || "";
if (!newModel || !newModel.length) return;
try {
await ollama.show({model: newModel});
Environment.setOllamaModel(newModel || Environment.OLLAMA_MODEL);
Environment.setOllamaModel(newModel || <string>Environment.OLLAMA_MODEL);
const text = newModel ? `Выбрана модель "${newModel}"`
: `Модель не задана. Будет использоваться стандартная модель "${Environment.OLLAMA_MODEL}".`;
await replyToMessage({message: msg, text: text}).catch(logError);
} catch (e) {
} catch (e: any) {
logError(e);
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
}
+18 -13
View File
@@ -24,11 +24,11 @@ export class OpenAIChat extends ChatCommand {
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("OpenAI Chat: ", match);
return this.executeOpenAI(msg, match?.[3]);
return this.executeOpenAI(msg, match?.[3] || "");
}
async executeOpenAI(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
if (!text || !text.trim().length) return;
const chatId = msg.chat.id;
@@ -67,7 +67,7 @@ export class OpenAIChat extends ChatCommand {
});
}
let waitMessage: Message;
let waitMessage: Message | null = null;
const startTime = Date.now();
@@ -98,7 +98,7 @@ export class OpenAIChat extends ChatCommand {
await bot.editMessageText(
{
chat_id: chatId,
message_id: waitMessage.message_id,
message_id: <number>waitMessage?.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "MarkdownV2"
}
@@ -106,9 +106,11 @@ export class OpenAIChat extends ChatCommand {
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
if (waitMessage) {
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
}
},
onStop: async () => {
}
@@ -156,12 +158,15 @@ export class OpenAIChat extends ChatCommand {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${error.toString()}`
}).catch(logError);
} catch (e: any) {
logError(e);
if (waitMessage) {
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${e.toString()}`
}).catch(logError);
}
}
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ export class OpenAIGetModel extends Command {
try {
return {
vision: {supported: true},
ocr: null,
ocr: undefined,
thinking: {supported: true},
tools: {supported: true},
};
+1 -1
View File
@@ -61,7 +61,7 @@ export class Qr extends Command {
},
parse_mode: "HTML"
});
} catch (e) {
} catch (e: any) {
await replyToMessage({
message: msg,
text: `Не получилось сгенерировать QR: ${e?.message ?? String(e)}`
+7 -4
View File
@@ -48,6 +48,7 @@ export class Quote extends Command {
async execute(msg: Message): Promise<void> {
const chatId = msg.chat.id;
const reply = msg.reply_to_message;
if (!reply) return;
try {
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
@@ -97,7 +98,9 @@ function twemojiUrl(emoji: string) {
return `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/${code}.png`;
}
async function loadEmoji(emoji: string): Promise<CanvasImage> {
async function loadEmoji(emoji: string | undefined): Promise<CanvasImage | null> {
if (!emoji) return null;
const downloadAndCache = async (url: string): Promise<Image> => {
const res = await axios.get<ArrayBuffer>(url, {responseType: "arraybuffer"});
const img = await loadImage(Buffer.from(res.data));
@@ -491,7 +494,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
try {
const img = await loadEmoji(seg.v);
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
} catch (e) {
logError(e);
ctx.fillText(seg.v, cx, baselineY);
@@ -506,7 +509,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
} else {
const img = await loadEmoji("😥");
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
}
} catch (e) {
console.warn("Failed to draw custom emoji:", e);
@@ -514,7 +517,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
try {
const img = await loadEmoji("😥");
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
} catch (e) {
logError(e);
+3
View File
@@ -9,6 +9,9 @@ export class RandomInt extends Command {
description = "Ranged random integer from parameters";
async execute(msg: Message) {
// TODO: 01/05/2026, Danil Nikolaev: improve
if (!msg.text) return;
const split = msg.text.split(" ");
const min = parseInt(split[1]);
const max = parseInt(split[2]);
+3
View File
@@ -9,6 +9,9 @@ export class RandomString extends Command {
description = "literally random string (up to 4096 symbols)";
async execute(msg: Message) {
// TODO: 01/05/2026, Danil Nikolaev: improve
if (!msg.text) return;
const split = msg.text.split(" ");
const l = parseInt(split.length > 1 ? split[1] : "1");
+1 -1
View File
@@ -8,6 +8,6 @@ export class Start extends Command {
description = "Start the bot";
async execute(msg: Message): Promise<void> {
await commands.find(e => e instanceof Help).execute(msg);
await commands.find(e => e instanceof Help)?.execute(msg);
}
}
+3 -1
View File
@@ -81,12 +81,14 @@ export class Transliteration extends Command {
description = "Transliteration EN <--> RU";
async execute(msg: Message): Promise<void> {
if (!msg.text && !msg.caption) return;
let text: string = "";
if (msg.reply_to_message) {
text = (msg.reply_to_message.text || msg.reply_to_message.caption || "");
} else {
const split = (msg.text || msg.caption).split("/tr ");
const split = (<string>(msg.text || msg.caption)).split("/tr ");
if (split.length > 1) {
text = split[1].trim();
}
+2 -2
View File
@@ -19,7 +19,7 @@ export class Unban extends Command {
);
async execute(msg: Message) {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
const user = msg.reply_to_message.from;
const userId = user.id;
@@ -34,7 +34,7 @@ export class Unban extends Command {
return;
}
if (msg.from.id !== Environment.CREATOR_ID && Environment.ADMIN_IDS.has(userId)) {
if (msg.from?.id !== Environment.CREATOR_ID && Environment.ADMIN_IDS.has(userId)) {
await oldReplyToMessage(msg, "Админимтраторы бота и так не в бане.").catch(logError);
return;
}
+1 -1
View File
@@ -18,7 +18,7 @@ export class Unignore extends Command {
);
async execute(msg: Message) {
if (!msg.reply_to_message) return;
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
const id = msg.reply_to_message.from.id;
const text = fullName(msg.reply_to_message.from);
-66
View File
@@ -1,66 +0,0 @@
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {editMessageText, logError, replyToMessage} from "../util/utils";
import {bot, botUser} from "../index";
import {DownloadOptions, downloadVideoFromYouTube, getYouTubeVideoId} from "../util/ytdl";
import {Environment} from "../common/environment";
import {TryAgain} from "../callback_commands/try-again";
export class YouTubeDownload extends Command {
command = ["ytdl", "youtube"];
argsMode = "required" as const;
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
const url = match?.[3];
return this.downloadYouTubeVideo(msg, {url: url});
}
async downloadYouTubeVideo(msg: Message, options: DownloadOptions): Promise<void> {
// TODO: 02.03.2026, Danil Nikolaev: add check for date
let waitMessage: Message | null = (msg.from.id === botUser.id) ? msg : null;
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
try {
if (!waitMessage) {
waitMessage = await replyToMessage({message: msg, text: "⏳ Скачиваю видео..."});
} else {
await editMessageText({message: msg, text: "⏳ Скачиваю видео..."});
}
const {time, exists, buffer} = await downloadVideoFromYouTube({videoId: videoId});
if (buffer) {
const start = Date.now();
waitMessage = await bot.editMessageMedia({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
media: {
type: "video",
media: buffer
}
}) as Message;
const diff = Date.now() - start;
waitMessage = await bot.editMessageCaption({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
caption: "✅ Видео" + (exists ? " загружено из кэша" : " успешно скачано") + " за " + (time + diff) + "мс",
}) as Message;
}
} catch (e) {
logError(e);
if (waitMessage && "text" in waitMessage) {
await bot.editMessageText({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
text: Environment.errorText,
reply_markup: {
inline_keyboard: [[
TryAgain.withData("/ytdl " + videoId).asButton()
]]
}
});
}
}
}
}