update regex matching - now bot responds only for base commands (like /ping) and with mention (like /ping@panfilovi4_bot) and ignores command if it mentions other bot;
Add ability to see, change and list gemini, mistral and ollama models
This commit is contained in:
@@ -1,15 +1,58 @@
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {Requirements} from "./requirements";
|
import {Requirements} from "./requirements";
|
||||||
|
|
||||||
|
export type ArgsMode = "none" | "optional" | "required";
|
||||||
|
|
||||||
export abstract class ChatCommand {
|
export abstract class ChatCommand {
|
||||||
|
|
||||||
abstract regexp: RegExp;
|
regexp?: RegExp | null;
|
||||||
|
command?: string | string[];
|
||||||
|
argsMode: ArgsMode = "none";
|
||||||
|
|
||||||
requirements?: Requirements = null;
|
requirements?: Requirements = null;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
get finalRegexp(): RegExp {
|
||||||
|
if (!this.regexp) {
|
||||||
|
const inferred = name(this.constructor.name);
|
||||||
|
const names = this.command ?? inferred;
|
||||||
|
this.regexp = createCommandRegExp(names, this.argsMode);
|
||||||
|
}
|
||||||
|
return this.regexp;
|
||||||
|
}
|
||||||
|
|
||||||
abstract execute(
|
abstract execute(
|
||||||
msg: Message,
|
msg: Message,
|
||||||
match?: RegExpExecArray
|
match?: RegExpExecArray
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function name(s: string) {
|
||||||
|
return s
|
||||||
|
.replace(/Command$/, "")
|
||||||
|
.replace(/([a-z0-9])([A-Z])/g, "$1$2")
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRe(s: string) {
|
||||||
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCommandRegExp(
|
||||||
|
names: string | string[],
|
||||||
|
argsMode: ArgsMode = "optional",
|
||||||
|
) {
|
||||||
|
const list = Array.isArray(names) ? names : [names];
|
||||||
|
const group = list.map(escapeRe).join("|");
|
||||||
|
|
||||||
|
const base = `^\\/(${group})(?:@([\\w_]+))?`; // (1)=cmd, (2)=bot
|
||||||
|
const tail =
|
||||||
|
argsMode === "none"
|
||||||
|
? "\\s*$"
|
||||||
|
: argsMode === "required"
|
||||||
|
? "\\s+([\\s\\S]+)\\s*$" // (3)=args обязателен
|
||||||
|
: "(?:\\s+([\\s\\S]+))?\\s*$"; // (3)=args опционален
|
||||||
|
|
||||||
|
return new RegExp(base + tail, "i");
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {Environment} from "../common/environment";
|
|||||||
import {botUser} from "../index";
|
import {botUser} from "../index";
|
||||||
|
|
||||||
export class AdminsAdd extends ChatCommand {
|
export class AdminsAdd extends ChatCommand {
|
||||||
regexp = /^\/addadmin/i;
|
command = "addAdmin";
|
||||||
title = "/addAdmin";
|
title = "/addAdmin";
|
||||||
description = "Add user to admins";
|
description = "Add user to admins";
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {Environment} from "../common/environment";
|
|||||||
import {botUser} from "../index";
|
import {botUser} from "../index";
|
||||||
|
|
||||||
export class AdminsRemove extends ChatCommand {
|
export class AdminsRemove extends ChatCommand {
|
||||||
regexp = /^\/removeadmin/i;
|
command = "removeAdmin";
|
||||||
title = "/removeAdmin";
|
title = "/removeAdmin";
|
||||||
description = "Remove user from admins";
|
description = "Remove user from admins";
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -4,15 +4,16 @@ import {errorPlaceholder, logError, oldSendMessage} from "../util/utils";
|
|||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
|
|
||||||
export class Ae implements ChatCommand {
|
export class Ae extends ChatCommand {
|
||||||
regexp = /^\/ae\s([^]+)/i;
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/ae";
|
title = "/ae";
|
||||||
description = "evaluation";
|
description = "evaluation";
|
||||||
|
|
||||||
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
async execute(msg: Message, params: string[]) {
|
async execute(msg: Message, params?: RegExpExecArray) {
|
||||||
const match = params[1];
|
const match = params?.[3];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let e = eval(match);
|
let e = eval(match);
|
||||||
|
|||||||
+4
-5
@@ -3,11 +3,10 @@ import {Requirements} from "../base/requirements";
|
|||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {bot, botUser} from "../index";
|
import {bot, botUser} from "../index";
|
||||||
import {fullName, logError, oldSendMessage, replyToMessage} from "../util/utils";
|
import {fullName, logError, oldSendMessage, oldReplyToMessage} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class Ban extends ChatCommand {
|
export class Ban extends ChatCommand {
|
||||||
regexp = /^\/ban/i;
|
|
||||||
title = "/ban [reply]";
|
title = "/ban [reply]";
|
||||||
description = "ban user from chat";
|
description = "ban user from chat";
|
||||||
|
|
||||||
@@ -25,17 +24,17 @@ export class Ban extends ChatCommand {
|
|||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
|
|
||||||
if (userId === botUser.id) {
|
if (userId === botUser.id) {
|
||||||
await replyToMessage(msg, "Используй /leave").catch(logError);
|
await oldReplyToMessage(msg, "Используй /leave").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userId === Environment.CREATOR_ID) {
|
if (userId === Environment.CREATOR_ID) {
|
||||||
await replyToMessage(msg, "Бот не будет банить своего создателя.").catch(logError);
|
await oldReplyToMessage(msg, "Бот не будет банить своего создателя.").catch(logError);
|
||||||
return;
|
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 replyToMessage(msg, "Бот не будет банить своих администраторов.").catch(logError);
|
await oldReplyToMessage(msg, "Бот не будет банить своих администраторов.").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {logError, randomValue, replyToMessage} from "../util/utils";
|
import {logError, oldReplyToMessage, randomValue} from "../util/utils";
|
||||||
|
|
||||||
export class Choice extends ChatCommand {
|
export class Choice extends ChatCommand {
|
||||||
regexp = /^\/choice\b\s*(.*)$/i;
|
command = "choice";
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/choice a, b, ..., c";
|
title = "/choice a, b, ..., c";
|
||||||
description = "Выбор случайного значения";
|
description = "Выбор случайного значения";
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
|
|
||||||
const payload = match[1];
|
const payload = match[3];
|
||||||
|
|
||||||
const re =
|
const re =
|
||||||
/\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^,]+?))\s*(?:,|$)/g;
|
/\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^,]+?))\s*(?:,|$)/g;
|
||||||
@@ -32,6 +34,6 @@ export class Choice extends ChatCommand {
|
|||||||
|
|
||||||
const random = randomValue(out);
|
const random = randomValue(out);
|
||||||
|
|
||||||
await replyToMessage(msg, `Выбрал *${random}*`, "Markdown").catch(logError);
|
await oldReplyToMessage(msg, `Выбрал *${random}*`, "Markdown").catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {getRangedRandomInt, logError, replyToMessage} from "../util/utils";
|
import {getRangedRandomInt, logError, oldReplyToMessage} from "../util/utils";
|
||||||
|
|
||||||
export class Coin extends ChatCommand {
|
export class Coin extends ChatCommand {
|
||||||
regexp = /^\/coin$/i;
|
|
||||||
title = "/coin";
|
title = "/coin";
|
||||||
description = "Heads or tails";
|
description = "Heads or tails";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
const random = getRangedRandomInt(0, 2);
|
const random = getRangedRandomInt(0, 2);
|
||||||
const headsOrTails = random === 1 ? "Выпал *Орёл* 🪙" : "Выпала *Решка* 🪙";
|
const headsOrTails = random === 1 ? "Выпал *Орёл* 🪙" : "Выпала *Решка* 🪙";
|
||||||
await replyToMessage(msg, headsOrTails, "Markdown").catch(logError); }
|
await oldReplyToMessage(msg, headsOrTails, "Markdown").catch(logError); }
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,7 @@ type DiceEmoji = "🎲" | "🎯" | "🏀" | "⚽" | "🎳" | "🎰";
|
|||||||
const emojis = ["🎲", "🎯", "🏀", "⚽", "🎳", "🎰"];
|
const emojis = ["🎲", "🎯", "🏀", "⚽", "🎳", "🎰"];
|
||||||
|
|
||||||
export class Dice extends ChatCommand {
|
export class Dice extends ChatCommand {
|
||||||
regexp = /^\/dice/i;
|
title = "/dice";
|
||||||
title = "/dice [emoji]";
|
|
||||||
description = "Sends random or specific dice";
|
description = "Sends random or specific dice";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
|
|||||||
+11
-7
@@ -1,10 +1,12 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {downloadTelegramFile, extractImageFileId, logError, replyToMessage, waveDistortSharp} from "../util/utils";
|
import {downloadTelegramFile, extractImageFileId, logError, oldReplyToMessage, waveDistortSharp} from "../util/utils";
|
||||||
import {bot} from "../index";
|
import {bot} from "../index";
|
||||||
|
|
||||||
export class Distort extends ChatCommand {
|
export class Distort extends ChatCommand {
|
||||||
regexp = /^\/distort(?:@[\w_]+)?(?:\s+(\d+))?(?:\s+(\d+))?\s*$/i;
|
command = "distort";
|
||||||
|
argsMode = "optional" as const;
|
||||||
|
|
||||||
title = "/distort [amp] [wavelength]";
|
title = "/distort [amp] [wavelength]";
|
||||||
description = "Distortion of picture";
|
description = "Distortion of picture";
|
||||||
|
|
||||||
@@ -13,7 +15,7 @@ export class Distort extends ChatCommand {
|
|||||||
|
|
||||||
const reply = msg.reply_to_message;
|
const reply = msg.reply_to_message;
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
await replyToMessage(
|
await oldReplyToMessage(
|
||||||
msg,
|
msg,
|
||||||
"Ответь командой /distort на сообщение с картинкой (фото, документ или стикер).\n" + "Пример: /distort 16 80"
|
"Ответь командой /distort на сообщение с картинкой (фото, документ или стикер).\n" + "Пример: /distort 16 80"
|
||||||
);
|
);
|
||||||
@@ -22,15 +24,17 @@ export class Distort extends ChatCommand {
|
|||||||
|
|
||||||
const fileId = extractImageFileId(reply);
|
const fileId = extractImageFileId(reply);
|
||||||
if (!fileId) {
|
if (!fileId) {
|
||||||
await replyToMessage(
|
await oldReplyToMessage(
|
||||||
msg,
|
msg,
|
||||||
"В реплае не вижу картинку. Пришли фото или файл-изображение."
|
"В реплае не вижу картинку. Пришли фото или файл-изображение."
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const amp = match?.[1] ? parseInt(match[1], 10) : 14;
|
const args = (match?.[3] ?? "").trim();
|
||||||
const wavelength = match?.[2] ? parseInt(match[2], 10) : 72;
|
const [a, b] = args ? args.split(/\s+/) : [];
|
||||||
|
const amp = a ? Number(a) : 14;
|
||||||
|
const wavelength = b ? Number(b) : 72;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await bot.sendChatAction({chat_id: chatId, action: "upload_photo"});
|
await bot.sendChatAction({chat_id: chatId, action: "upload_photo"});
|
||||||
@@ -48,7 +52,7 @@ export class Distort extends ChatCommand {
|
|||||||
caption: `Искажение готово ✅ (amp=${amp}, wavelength=${wavelength})`,
|
caption: `Искажение готово ✅ (amp=${amp}, wavelength=${wavelength})`,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await replyToMessage(
|
await oldReplyToMessage(
|
||||||
msg, `Не получилось исказить изображение: ${e?.message ?? String(e)}`
|
msg, `Не получилось исказить изображение: ${e?.message ?? String(e)}`
|
||||||
).catch(logError);
|
).catch(logError);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-14
@@ -3,30 +3,31 @@ import {Message} from "typescript-telegram-bot-api";
|
|||||||
import {
|
import {
|
||||||
collectReplyChainText,
|
collectReplyChainText,
|
||||||
editMessageText,
|
editMessageText,
|
||||||
escapeMarkdownV2Text, extractText,
|
escapeMarkdownV2Text,
|
||||||
|
extractText,
|
||||||
logError,
|
logError,
|
||||||
replyToMessage,
|
oldReplyToMessage,
|
||||||
startIntervalEditor
|
startIntervalEditor
|
||||||
} from "../util/utils";
|
} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
import {bot} from "../index";
|
import {bot, googleAi} from "../index";
|
||||||
import {MessageStore} from "../common/message-store";
|
import {MessageStore} from "../common/message-store";
|
||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {ApiError, GoogleGenAI} from "@google/genai";
|
import {ApiError} from "@google/genai";
|
||||||
|
|
||||||
export class GeminiChat extends ChatCommand {
|
export class GeminiChat extends ChatCommand {
|
||||||
regexp = /^\/gemini\s([^]+)/i;
|
command = "gemini";
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/gemini";
|
title = "/gemini";
|
||||||
description = "Chat with AI (Gemini)";
|
description = "Chat with AI (Gemini)";
|
||||||
|
|
||||||
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
private googleAi = new GoogleGenAI({apiKey: Environment.GEMINI_API_KEY});
|
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeGemini(msg, match?.[1]);
|
return this.executeGemini(msg, match?.[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeGemini(msg: Message, text: string): Promise<void> {
|
async executeGemini(msg: Message, text: string): Promise<void> {
|
||||||
@@ -67,8 +68,8 @@ export class GeminiChat extends ChatCommand {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const stream = await this.googleAi.models.generateContentStream({
|
const stream = await googleAi.models.generateContentStream({
|
||||||
model: Environment.GEMINI_MODEL || "gemini-2.5-flash",
|
model: Environment.GEMINI_MODEL,
|
||||||
contents: chatContent,
|
contents: chatContent,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,6 +86,7 @@ export class GeminiChat extends ChatCommand {
|
|||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
await editor.tick();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
@@ -123,21 +125,21 @@ export class GeminiChat extends ChatCommand {
|
|||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
waitMessage.reply_to_message = msg;
|
||||||
waitMessage.text = messageText;
|
waitMessage.text = messageText;
|
||||||
MessageStore.put(waitMessage);
|
await MessageStore.put(waitMessage);
|
||||||
|
|
||||||
await replyToMessage(waitMessage, `⏱️ ${diff}s`);
|
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
||||||
if (error instanceof ApiError) {
|
if (error instanceof ApiError) {
|
||||||
if (error.status === 429) {
|
if (error.status === 429) {
|
||||||
await replyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
|
await oldReplyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await replyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
|
export class GeminiGetModel extends ChatCommand {
|
||||||
|
title = "/geminiGetModel";
|
||||||
|
description = "Get current Gemini model";
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
await replyToMessage({message: msg, text: `Текущая модель: "${Environment.GEMINI_MODEL}"`}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {googleAi} from "../index";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
|
||||||
|
export class GeminiListModels extends ChatCommand {
|
||||||
|
title = "/geminiListModels";
|
||||||
|
description = "List all Gemini models";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
try {
|
||||||
|
const listResponse = await googleAi.models.list();
|
||||||
|
console.log(listResponse);
|
||||||
|
|
||||||
|
const modelsString = listResponse.page
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map(e => `\`${e.name}\``)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
const text = "Доступные модели:\n\n" + modelsString;
|
||||||
|
|
||||||
|
await replyToMessage({
|
||||||
|
message: msg,
|
||||||
|
text: text,
|
||||||
|
parse_mode: "Markdown"
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
await replyToMessage({message: msg, text: "Не получилось загрузить список моделей"}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
|
||||||
|
export class GeminiSetModel extends ChatCommand {
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
|
title = "/geminiSetModel";
|
||||||
|
description = "Set Gemini model";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
|
const newModel = match?.[1];
|
||||||
|
Environment.setGeminiModel(newModel || Environment.GEMINI_MODEL);
|
||||||
|
|
||||||
|
const text = newModel ? `Выбрана модель "${newModel}"`
|
||||||
|
: `Модель не задана. Будет использоваться стандартная модель "${Environment.GEMINI_MODEL}".`;
|
||||||
|
|
||||||
|
await replyToMessage({message: msg, text: text}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,9 @@ import {ChatCommand} from "../base/chat-command";
|
|||||||
import {chatCommands} from "../index";
|
import {chatCommands} from "../index";
|
||||||
import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
|
import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
|
||||||
|
|
||||||
export class Help implements ChatCommand {
|
export class Help extends ChatCommand {
|
||||||
regexp = /^\/(h|help)/i;
|
command = ["h", "help"];
|
||||||
|
|
||||||
title = "/help";
|
title = "/help";
|
||||||
description = "Show list of commands";
|
description = "Show list of commands";
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ export class Help implements ChatCommand {
|
|||||||
text += `${chatCommandToString(c)}\n`;
|
text += `${chatCommandToString(c)}\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
await sendMessage({chatId: msg.from.id, text: text})
|
await sendMessage({chat_id: msg.from.id, text: text})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
if (msg.chat.type !== "private") {
|
if (msg.chat.type !== "private") {
|
||||||
await sendMessage({message: msg, text: "Отправил команды в ЛС 😎"}).catch(logError);
|
await sendMessage({message: msg, text: "Отправил команды в ЛС 😎"}).catch(logError);
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {logError, replyToMessage} from "../util/utils";
|
import {logError, oldReplyToMessage} from "../util/utils";
|
||||||
|
|
||||||
export class Id extends ChatCommand {
|
export class Id extends ChatCommand {
|
||||||
regexp = /^\/id/i;
|
|
||||||
title = "/id";
|
title = "/id";
|
||||||
description = "ID of chat, user and reply (if replied to any message)";
|
description = "ID of chat, user and reply (if replied to any message)";
|
||||||
|
|
||||||
@@ -13,6 +12,6 @@ export class Id extends ChatCommand {
|
|||||||
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from.id}\`\`\``;
|
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from.id}\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
await replyToMessage(msg, text, "MarkdownV2").catch(logError);
|
await oldReplyToMessage(msg, text, "MarkdownV2").catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,6 @@ import {Requirement} from "../base/requirement";
|
|||||||
import {bot} from "../index";
|
import {bot} from "../index";
|
||||||
|
|
||||||
export class Leave extends ChatCommand {
|
export class Leave extends ChatCommand {
|
||||||
regexp = /^\/leave/i;
|
|
||||||
title = "/leave";
|
title = "/leave";
|
||||||
description = "Bot will leave current chat";
|
description = "Bot will leave current chat";
|
||||||
|
|
||||||
|
|||||||
@@ -7,31 +7,27 @@ import {
|
|||||||
editMessageText,
|
editMessageText,
|
||||||
escapeMarkdownV2Text,
|
escapeMarkdownV2Text,
|
||||||
extractText,
|
extractText,
|
||||||
getPhotoMaxSize,
|
|
||||||
logError,
|
logError,
|
||||||
replyToMessage,
|
oldReplyToMessage,
|
||||||
startIntervalEditor
|
startIntervalEditor
|
||||||
} from "../util/utils";
|
} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
import {bot} from "../index";
|
import {bot, mistralAi} from "../index";
|
||||||
import {MessageStore} from "../common/message-store";
|
import {MessageStore} from "../common/message-store";
|
||||||
import {Mistral} from "@mistralai/mistralai";
|
|
||||||
import path from "node:path";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export class MistralChat extends ChatCommand {
|
export class MistralChat extends ChatCommand {
|
||||||
regexp = /^\/mistral\s([^]+)/i;
|
command = "mistral";
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/mistral";
|
title = "/mistral";
|
||||||
description = "Chat with AI (Mistral)";
|
description = "Chat with AI (Mistral)";
|
||||||
|
|
||||||
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
private mistralAi = new Mistral({apiKey: Environment.MISTRAL_API_KEY});
|
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeMistral(msg, match?.[1]);
|
return this.executeMistral(msg, match?.[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeMistral(msg: Message, text: string): Promise<void> {
|
async executeMistral(msg: Message, text: string): Promise<void> {
|
||||||
@@ -39,41 +35,18 @@ export class MistralChat extends ChatCommand {
|
|||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
let imageFilePath: string | null = null;
|
|
||||||
|
|
||||||
const maxSize = await getPhotoMaxSize(msg.photo);
|
|
||||||
if (maxSize) {
|
|
||||||
const imagePath = path.join(Environment.DATA_PATH, "temp");
|
|
||||||
if (!fs.existsSync(imagePath)) {
|
|
||||||
fs.mkdirSync(imagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
|
|
||||||
if (!fs.existsSync(imageFilePath)) {
|
|
||||||
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
|
|
||||||
const src = Buffer.from(res.data);
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.writeFileSync(imageFilePath, src);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
imageFilePath = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageParts = await collectReplyChainText(msg, "/mistral");
|
const messageParts = await collectReplyChainText(msg, "/mistral");
|
||||||
console.log("MESSAGE PARTS", messageParts);
|
console.log("MESSAGE PARTS", messageParts);
|
||||||
|
|
||||||
const chatMessages = messageParts.map((part, i) => {
|
const chatMessages = messageParts.map(part => {
|
||||||
const content = [];
|
const content = [];
|
||||||
content.push({
|
content.push({
|
||||||
type: "text",
|
type: "text",
|
||||||
text: (Environment.USE_NAMES_IN_PROMPT && !part.bot ? `MESSAGE FROM USER "${part.name}":\n` : "") + extractText(part.content, Environment.BOT_PREFIX),
|
text: (Environment.USE_NAMES_IN_PROMPT && !part.bot ? `MESSAGE FROM USER "${part.name}":\n` : "") + extractText(part.content, Environment.BOT_PREFIX),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (imageFilePath && i === 0) {
|
if (part.images && part.images.length > 0) {
|
||||||
const base64Image = Buffer.from(fs.readFileSync(imageFilePath)).toString("base64");
|
const base64Image = Buffer.from(fs.readFileSync(part.images[0])).toString("base64");
|
||||||
content.push({
|
content.push({
|
||||||
type: "image_url",
|
type: "image_url",
|
||||||
imageUrl: "data:image/jpeg;base64," + base64Image
|
imageUrl: "data:image/jpeg;base64," + base64Image
|
||||||
@@ -102,8 +75,8 @@ export class MistralChat extends ChatCommand {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const stream = await this.mistralAi.chat.stream({
|
const stream = await mistralAi.chat.stream({
|
||||||
model: Environment.MISTRAL_MODEL || "mistral-small-latest",
|
model: Environment.MISTRAL_MODEL,
|
||||||
messages: chatMessages as any
|
messages: chatMessages as any
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,14 +93,13 @@ export class MistralChat extends ChatCommand {
|
|||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
await editor.tick();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
// const text = chunk.text;
|
|
||||||
const text = chunk.data.choices[0].delta.content;
|
const text = chunk.data.choices[0].delta.content;
|
||||||
console.log("chunk", chunk);
|
console.log("chunk", chunk);
|
||||||
|
|
||||||
// const text = "";
|
|
||||||
const length = (messageText + text).length;
|
const length = (messageText + text).length;
|
||||||
if (length > 4096) {
|
if (length > 4096) {
|
||||||
messageText = messageText.slice(0, 4093) + "...";
|
messageText = messageText.slice(0, 4093) + "...";
|
||||||
@@ -163,7 +135,7 @@ export class MistralChat extends ChatCommand {
|
|||||||
waitMessage.text = messageText;
|
waitMessage.text = messageText;
|
||||||
MessageStore.put(waitMessage);
|
MessageStore.put(waitMessage);
|
||||||
|
|
||||||
await replyToMessage(waitMessage, `⏱️ ${diff}s`);
|
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -175,7 +147,7 @@ export class MistralChat extends ChatCommand {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
await replyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
|
||||||
|
export class MistralGetModel extends ChatCommand {
|
||||||
|
title = "/mistralGetModel";
|
||||||
|
description = "Get current Mistral model";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
await replyToMessage({message: msg, text: `Текущая модель: "${Environment.MISTRAL_MODEL}"`}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {mistralAi} from "../index";
|
||||||
|
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
|
||||||
|
|
||||||
|
export class MistralListModels extends ChatCommand {
|
||||||
|
title = "/mistralListModels";
|
||||||
|
description = "List all Mistral models";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
try {
|
||||||
|
const listResponse = await mistralAi.models.list();
|
||||||
|
console.log(listResponse);
|
||||||
|
|
||||||
|
const modelsString = listResponse.data
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map(e => `\`${e.name}\``)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
const text = "Доступные модели:\n\n" + modelsString;
|
||||||
|
|
||||||
|
await replyToMessage({
|
||||||
|
chat_id: msg.chat.id,
|
||||||
|
text: text,
|
||||||
|
parse_mode: "Markdown",
|
||||||
|
message: msg
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
await oldReplyToMessage(msg, "Не получилось загрузить список моделей").catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
|
||||||
|
export class MistralSetModel extends ChatCommand {
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
|
title = "/mistralSetModel";
|
||||||
|
description = "Set Mistral model";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
|
const newModel = match?.[1];
|
||||||
|
Environment.setMistralModel(newModel || Environment.MISTRAL_MODEL);
|
||||||
|
|
||||||
|
const text = newModel ? `Выбрана модель "${newModel}"`
|
||||||
|
: `Модель не задана. Будет использоваться стандартная модель "${Environment.MISTRAL_MODEL}".`;
|
||||||
|
|
||||||
|
await replyToMessage({message: msg, text: text}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,7 @@ import {fullName, logError, oldSendMessage} from "../util/utils";
|
|||||||
import {botUser} from "../index";
|
import {botUser} from "../index";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class Mute implements ChatCommand {
|
export class Mute extends ChatCommand {
|
||||||
regexp = /^\/mute/i;
|
|
||||||
title = "/mute";
|
title = "/mute";
|
||||||
description = "Bot will ignore user";
|
description = "Bot will ignore user";
|
||||||
|
|
||||||
|
|||||||
+21
-44
@@ -6,27 +6,25 @@ import {
|
|||||||
editMessageText,
|
editMessageText,
|
||||||
escapeMarkdownV2Text,
|
escapeMarkdownV2Text,
|
||||||
extractText,
|
extractText,
|
||||||
getPhotoMaxSize,
|
|
||||||
logError,
|
logError,
|
||||||
replyToMessage,
|
oldReplyToMessage,
|
||||||
startIntervalEditor
|
startIntervalEditor
|
||||||
} from "../util/utils";
|
} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
import {MessageStore} from "../common/message-store";
|
import {MessageStore} from "../common/message-store";
|
||||||
import axios from "axios";
|
|
||||||
import * as fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
import {Cancel} from "../callback_commands/cancel";
|
import {Cancel} from "../callback_commands/cancel";
|
||||||
import {OllamaCancel} from "../callback_commands/ollama-cancel";
|
import {OllamaCancel} from "../callback_commands/ollama-cancel";
|
||||||
|
|
||||||
export class OllamaChat extends ChatCommand {
|
export class OllamaChat extends ChatCommand {
|
||||||
regexp = /^\/ollama\s([^]+)/;
|
command = "ollama";
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/ollama";
|
title = "/ollama";
|
||||||
description = "talk to AI (Ollama)";
|
description = "Chat with AI (Ollama)";
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeOllama(msg, match?.[1]);
|
return this.executeOllama(msg, match?.[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeOllama(msg: Message, text: string): Promise<void> {
|
async executeOllama(msg: Message, text: string): Promise<void> {
|
||||||
@@ -34,41 +32,18 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
let imageFilePath: string | null = null;
|
|
||||||
|
|
||||||
const maxSize = await getPhotoMaxSize(msg.photo);
|
|
||||||
if (maxSize) {
|
|
||||||
const imagePath = path.join(Environment.DATA_PATH, "temp");
|
|
||||||
if (!fs.existsSync(imagePath)) {
|
|
||||||
fs.mkdirSync(imagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
|
|
||||||
if (!fs.existsSync(imageFilePath)) {
|
|
||||||
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
|
|
||||||
const src = Buffer.from(res.data);
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.writeFileSync(imageFilePath, src);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
imageFilePath = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageParts = await collectReplyChainText(msg);
|
const messageParts = await collectReplyChainText(msg);
|
||||||
console.log("MESSAGE PARTS", messageParts);
|
console.log("MESSAGE PARTS", messageParts);
|
||||||
|
|
||||||
const chatMessages = messageParts.map((part, i) => {
|
const chatMessages = messageParts.map(part => {
|
||||||
return {
|
return {
|
||||||
role: part.bot ? "assistant" : "user",
|
role: part.bot ? "assistant" : "user",
|
||||||
content: (Environment.USE_NAMES_IN_PROMPT && !part.bot ? `MESSAGE FROM USER "${part.name}":\n` : "") + extractText(part.content, Environment.BOT_PREFIX),
|
content: (Environment.USE_NAMES_IN_PROMPT && !part.bot ? `MESSAGE FROM USER "${part.name}":\n` : "") + extractText(part.content, Environment.BOT_PREFIX),
|
||||||
images: imageFilePath && i === 0 ? [imageFilePath] : null
|
images: part.images
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
chatMessages.reverse();
|
chatMessages.reverse();
|
||||||
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: null});
|
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message;
|
||||||
|
|
||||||
@@ -81,7 +56,8 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
waitMessage = await bot.sendMessage({
|
waitMessage = await bot.sendMessage({
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
text: maxSize !== null ? `🔍 Внимательно изучаю изображение...\n🤓 ${maxSize.width}x${maxSize.height}px` : Environment.waitText,
|
text: Environment.waitText,
|
||||||
|
// text: maxSize !== null ? `🔍 Внимательно изучаю изображение...\n🤓 ${maxSize.width}x${maxSize.height}px` : Environment.waitText,
|
||||||
reply_parameters: {
|
reply_parameters: {
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: msg.message_id
|
message_id: msg.message_id
|
||||||
@@ -117,17 +93,18 @@ export class OllamaChat extends ChatCommand {
|
|||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
await editor.tick();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
if (!getOllamaRequest(uuid).done) {
|
currentText += chunk.message.content;
|
||||||
currentText += chunk.message.content;
|
|
||||||
|
|
||||||
if (currentText.length > 4096) {
|
if (currentText.length > 4096) {
|
||||||
currentText = currentText.slice(0, 4093) + "...";
|
currentText = currentText.slice(0, 4093) + "...";
|
||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
if (getOllamaRequest(uuid).done) {
|
||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +131,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
waitMessage.text = currentText;
|
waitMessage.text = currentText;
|
||||||
await MessageStore.put(waitMessage);
|
await MessageStore.put(waitMessage);
|
||||||
|
|
||||||
await replyToMessage(waitMessage, `⏱️ ${diff}s` + (maxSize !== null ? `\n🤓 ${maxSize.width}x${maxSize.height}px` : ""));
|
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s` /*+ (maxSize !== null ? `\n🤓 ${maxSize.width}x${maxSize.height}px` : "")*/);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +150,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
}).catch(logError);
|
}).catch(logError);
|
||||||
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
await replyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {boolToEmoji, logError, replyToMessage} from "../util/utils";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
import {ollama} from "../index";
|
||||||
|
|
||||||
|
export class OllamaGetModel extends ChatCommand {
|
||||||
|
title = "/ollamaGetModel";
|
||||||
|
description = "Ollama model info";
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
|
||||||
|
const showResponse = await ollama.show({model: Environment.OLLAMA_MODEL});
|
||||||
|
console.log(showResponse);
|
||||||
|
|
||||||
|
const caps = showResponse.capabilities;
|
||||||
|
|
||||||
|
const text = "```ollama\n" +
|
||||||
|
`model: ${Environment.OLLAMA_MODEL}\n\n` +
|
||||||
|
`vision: ${boolToEmoji(caps.includes("vision"))}\n` +
|
||||||
|
`thinking: ${boolToEmoji(caps.includes("thinking"))}\n` +
|
||||||
|
`tools: ${boolToEmoji(caps.includes("tools"))}`
|
||||||
|
+ "```";
|
||||||
|
|
||||||
|
await replyToMessage({message: msg, text: text, parse_mode: "Markdown"}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {ollama} from "../index";
|
||||||
|
import {logError, oldReplyToMessage, sendMessage} from "../util/utils";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
|
||||||
|
export class OllamaListModels extends ChatCommand {
|
||||||
|
title = "/ollamaListModels";
|
||||||
|
description = "List all Ollama models";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message): Promise<void> {
|
||||||
|
try {
|
||||||
|
const listResponse = await ollama.list();
|
||||||
|
|
||||||
|
const modelsString = listResponse.models
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map(e => `\`${e.model}\``)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
const message = "Доступные модели:\n\n" + modelsString;
|
||||||
|
|
||||||
|
await sendMessage({
|
||||||
|
chat_id: msg.chat.id,
|
||||||
|
text: message,
|
||||||
|
parse_mode: "Markdown",
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
await oldReplyToMessage(msg, "Не получилось загрузить список моделей").catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {bot, ollama} from "../index";
|
import {bot, ollama} from "../index";
|
||||||
import {editMessageText, ignore, replyToMessage} from "../util/utils";
|
import {editMessageText, ignore, oldReplyToMessage} from "../util/utils";
|
||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class OllamaPrompt extends ChatCommand {
|
export class OllamaPrompt extends ChatCommand {
|
||||||
regexp = /^\/ollamaprompt\s([^]+)/i;
|
command = "ollamaPrompt";
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/ollamaPrompt";
|
title = "/ollamaPrompt";
|
||||||
description = "Custom prompt for AI (Ollama)";
|
description = "Custom prompt for AI (Ollama)";
|
||||||
|
|
||||||
@@ -86,7 +88,7 @@ export class OllamaPrompt extends ChatCommand {
|
|||||||
messageText += `\n\nДумал ${diff}s`;
|
messageText += `\n\nДумал ${diff}s`;
|
||||||
|
|
||||||
await editMessageText(chatId, waitMessage.message_id, messageText);
|
await editMessageText(chatId, waitMessage.message_id, messageText);
|
||||||
await replyToMessage(waitMessage, "Закончил лишь часть 😉");
|
await oldReplyToMessage(waitMessage, "Закончил лишь часть 😉");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +103,7 @@ export class OllamaPrompt extends ChatCommand {
|
|||||||
messageText += `\n\nДумал ${diff}s`;
|
messageText += `\n\nДумал ${diff}s`;
|
||||||
|
|
||||||
await editMessageText(chatId, waitMessage.message_id, messageText);
|
await editMessageText(chatId, waitMessage.message_id, messageText);
|
||||||
await replyToMessage(waitMessage, "Закончил 😉");
|
await oldReplyToMessage(waitMessage, "Закончил 😉");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import {editMessageText} from "../util/utils";
|
|||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class OllamaSearch extends ChatCommand {
|
export class OllamaSearch extends ChatCommand {
|
||||||
regexp = /^\/(s|search)\s([^]+)/;
|
command = ["s", "search"];
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/search";
|
title = "/search";
|
||||||
description = "Web search via Ollama";
|
description = "Web search via Ollama";
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ export class OllamaSearch extends ChatCommand {
|
|||||||
parse_mode: "Markdown"
|
parse_mode: "Markdown"
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await ollama.webSearch({query: match?.[2]});
|
const results = await ollama.webSearch({query: match?.[3]});
|
||||||
console.log("results", results);
|
console.log("results", results);
|
||||||
|
|
||||||
let message = "Результаты:\n\n";
|
let message = "Результаты:\n\n";
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {Environment} from "../common/environment";
|
||||||
|
import {logError, replyToMessage} from "../util/utils";
|
||||||
|
import {Requirements} from "../base/requirements";
|
||||||
|
import {Requirement} from "../base/requirement";
|
||||||
|
|
||||||
|
export class OllamaSetModel extends ChatCommand {
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
|
title = "/ollamaSetModel";
|
||||||
|
description = "Set Ollama model";
|
||||||
|
|
||||||
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
|
const newModel = match?.[1];
|
||||||
|
Environment.setOllamaModel(newModel || Environment.OLLAMA_MODEL);
|
||||||
|
|
||||||
|
const text = newModel ? `Выбрана модель "${newModel}"`
|
||||||
|
: `Модель не задана. Будет использоваться стандартная модель "${Environment.OLLAMA_MODEL}".`;
|
||||||
|
|
||||||
|
await replyToMessage({message: msg, text: text}).catch(logError);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,7 @@ import {logError, oldSendMessage} from "../util/utils";
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
|
||||||
export class Ping implements ChatCommand {
|
export class Ping extends ChatCommand {
|
||||||
regexp = /^\/ping/i;
|
|
||||||
title = "/ping";
|
title = "/ping";
|
||||||
description = "Ping between received and sent message";
|
description = "Ping between received and sent message";
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {logError, randomValue, replyToMessage} from "../util/utils";
|
import {logError, randomValue, oldReplyToMessage} from "../util/utils";
|
||||||
import {prefixAnswers} from "../db/database";
|
import {prefixAnswers} from "../db/database";
|
||||||
|
|
||||||
export class PrefixResponse extends ChatCommand {
|
export class PrefixResponse extends ChatCommand {
|
||||||
regexp: RegExp;
|
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
await replyToMessage(msg, randomValue(prefixAnswers)).catch(logError);
|
await oldReplyToMessage(msg, randomValue(prefixAnswers)).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-4
@@ -5,7 +5,6 @@ import {bot} from "../index";
|
|||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
|
||||||
export class Qr extends ChatCommand {
|
export class Qr extends ChatCommand {
|
||||||
regexp = /^\/qr/i;
|
|
||||||
title = "/qr";
|
title = "/qr";
|
||||||
description = "Generates QR-code from text you sent or replied to.";
|
description = "Generates QR-code from text you sent or replied to.";
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ export class Qr extends ChatCommand {
|
|||||||
const payload = extractMessagePayload(msg, matchText);
|
const payload = extractMessagePayload(msg, matchText);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
await sendMessage({
|
await sendMessage({
|
||||||
chatId: chatId,
|
chat_id: chatId,
|
||||||
text: "Отправь: /qr <текст или ссылка>\n" + "или ответь командой /qr на сообщение, из которого взять текст."
|
text: "Отправь: /qr <текст или ссылка>\n" + "или ответь командой /qr на сообщение, из которого взять текст."
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -26,7 +25,7 @@ export class Qr extends ChatCommand {
|
|||||||
|
|
||||||
if (payload.length > 1500) {
|
if (payload.length > 1500) {
|
||||||
await sendMessage({
|
await sendMessage({
|
||||||
chatId: chatId,
|
chat_id: chatId,
|
||||||
text: `Слишком длинный текст для QR (${payload.length} символов). Максимум 1500 символов.`
|
text: `Слишком длинный текст для QR (${payload.length} символов). Максимум 1500 символов.`
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -51,7 +50,7 @@ export class Qr extends ChatCommand {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await sendMessage({chatId: chatId, text: `Не получилось сгенерировать QR: ${e?.message ?? String(e)}`}).catch(logError);
|
await sendMessage({chat_id: chatId, text: `Не получилось сгенерировать QR: ${e?.message ?? String(e)}`}).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,8 @@ import {
|
|||||||
getUserAvatar,
|
getUserAvatar,
|
||||||
logError,
|
logError,
|
||||||
makeDarkGradientBgFancy,
|
makeDarkGradientBgFancy,
|
||||||
oldSendMessage,
|
oldReplyToMessage,
|
||||||
replyToMessage
|
oldSendMessage
|
||||||
} from "../util/utils";
|
} from "../util/utils";
|
||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
@@ -34,7 +34,9 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Quote extends ChatCommand {
|
export class Quote extends ChatCommand {
|
||||||
regexp = /^\/(cit|q|quote)$/i;
|
command = ["cit", "citation", "q", "quote"];
|
||||||
|
argsMode = "none" as const;
|
||||||
|
|
||||||
title = "/quote";
|
title = "/quote";
|
||||||
description = "Make quote from text (or quote)";
|
description = "Make quote from text (or quote)";
|
||||||
|
|
||||||
@@ -45,14 +47,14 @@ export class Quote extends ChatCommand {
|
|||||||
const reply = msg.reply_to_message;
|
const reply = msg.reply_to_message;
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
await replyToMessage(msg, "Сделай /quote реплаем на сообщение 🙂").catch(logError);
|
await oldReplyToMessage(msg, "Сделай /quote реплаем на сообщение 🙂").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
|
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
|
||||||
if (quoteRaw.length === 0) {
|
if (quoteRaw.length === 0) {
|
||||||
await replyToMessage(msg, "Не нашёл в сообщении текста 😢").catch(logError);
|
await oldReplyToMessage(msg, "Не нашёл в сообщении текста 😢").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {getRandomInt, getRangedRandomInt, logError, oldSendMessage} from "../uti
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
|
||||||
export class RandomInt extends ChatCommand {
|
export class RandomInt extends ChatCommand {
|
||||||
regexp = /^\/randomInt/i;
|
|
||||||
title = "/randomInt [min] [max]";
|
title = "/randomInt [min] [max]";
|
||||||
description = "Ranged random integer from parameters";
|
description = "Ranged random integer from parameters";
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import {ChatCommand} from "../base/chat-command";
|
|||||||
import {getRandomInt, logError, oldSendMessage} from "../util/utils";
|
import {getRandomInt, logError, oldSendMessage} from "../util/utils";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
|
||||||
export class RandomString implements ChatCommand {
|
export class RandomString extends ChatCommand {
|
||||||
regexp = /^\/randomString/i;
|
|
||||||
title = "/randomString [length]";
|
title = "/randomString [length]";
|
||||||
description = "literally random string (up to 4096 symbols)";
|
description = "literally random string (up to 4096 symbols)";
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const timings = [1500, 2500];
|
|||||||
const timer = [3, 2, 1];
|
const timer = [3, 2, 1];
|
||||||
|
|
||||||
export class Shutdown extends ChatCommand {
|
export class Shutdown extends ChatCommand {
|
||||||
regexp = /^\/shutdown/i;
|
|
||||||
title = "/shutdown";
|
title = "/shutdown";
|
||||||
description = "Self-destruction sequence for bot (shutdown)";
|
description = "Self-destruction sequence for bot (shutdown)";
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {chatCommands} from "../index";
|
|||||||
import {Help} from "./help";
|
import {Help} from "./help";
|
||||||
|
|
||||||
export class Start extends ChatCommand {
|
export class Start extends ChatCommand {
|
||||||
regexp = /^\/start/i;
|
|
||||||
title = "/start";
|
title = "/start";
|
||||||
description = "Start the bot";
|
description = "Start the bot";
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import {logError, oldSendMessage} from "../util/utils";
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {systemInfoText} from "../index";
|
import {systemInfoText} from "../index";
|
||||||
|
|
||||||
export class SystemSpecs implements ChatCommand {
|
export class SystemSpecs extends ChatCommand {
|
||||||
regexp = /^\/systeminfo/i;
|
|
||||||
title = "/systemInfo";
|
title = "/systemInfo";
|
||||||
description = "System information";
|
description = "System information";
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {logError, randomValue, replyToMessage} from "../util/utils";
|
import {logError, randomValue, oldReplyToMessage} from "../util/utils";
|
||||||
import {testAnswers} from "../db/database";
|
import {testAnswers} from "../db/database";
|
||||||
|
|
||||||
export class Test implements ChatCommand {
|
export class Test extends ChatCommand {
|
||||||
regexp = /^(test|тест|еуые|ntcn|инноке(нтий|ш|нтич))/i;
|
regexp = /^(test|тест|еуые|ntcn|инноке(нтий|ш|нтич))/i;
|
||||||
title = "тест";
|
title = "тест";
|
||||||
description = "System functionality check";
|
description = "System functionality check";
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
await replyToMessage(msg, randomValue(testAnswers) || "а").catch(logError);
|
await oldReplyToMessage(msg, randomValue(testAnswers) || "а").catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,14 @@ import {ChatCommand} from "../base/chat-command";
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {logError, replyToMessage} from "../util/utils";
|
import {logError, oldReplyToMessage} from "../util/utils";
|
||||||
import {bot} from "../index";
|
import {bot} from "../index";
|
||||||
|
|
||||||
export class Title extends ChatCommand {
|
export class Title extends ChatCommand {
|
||||||
regexp = /^\/title\s([^]+)/;
|
command = "title";
|
||||||
title = "/title [title]";
|
argsMode = "required" as const;
|
||||||
|
|
||||||
|
title = "/title";
|
||||||
description = "Change group title";
|
description = "Change group title";
|
||||||
|
|
||||||
requirements = Requirements.Build(
|
requirements = Requirements.Build(
|
||||||
@@ -19,7 +21,7 @@ export class Title extends ChatCommand {
|
|||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
const title = (match?.[1] ?? "").trim();
|
const title = (match?.[1] ?? "").trim();
|
||||||
if (title.length === 0) {
|
if (title.length === 0) {
|
||||||
await replyToMessage(msg, "Не нашёл название...").catch(logError);
|
await oldReplyToMessage(msg, "Не нашёл название...").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {logError, replyToMessage} from "../util/utils";
|
import {logError, oldReplyToMessage} from "../util/utils";
|
||||||
|
|
||||||
const EN =
|
const EN =
|
||||||
"`qwertyuiop[]asdfghjkl;'zxcvbnm,./" +
|
"`qwertyuiop[]asdfghjkl;'zxcvbnm,./" +
|
||||||
@@ -98,7 +98,6 @@ export function fixLayoutAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Transliteration extends ChatCommand {
|
export class Transliteration extends ChatCommand {
|
||||||
regexp = /^\/tr/i;
|
|
||||||
title = "/tr [text or reply]";
|
title = "/tr [text or reply]";
|
||||||
description = "Transliteration EN <--> RU";
|
description = "Transliteration EN <--> RU";
|
||||||
|
|
||||||
@@ -120,6 +119,6 @@ export class Transliteration extends ChatCommand {
|
|||||||
|
|
||||||
const newText = fixLayoutAuto(text, toRuLayout, toEnLayout);
|
const newText = fixLayoutAuto(text, toRuLayout, toEnLayout);
|
||||||
|
|
||||||
await replyToMessage(msg, newText).catch(logError);
|
await oldReplyToMessage(msg, newText).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,10 @@ import {Requirements} from "../base/requirements";
|
|||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {bot, botUser} from "../index";
|
import {bot, botUser} from "../index";
|
||||||
import {fullName, logError, oldSendMessage, replyToMessage} from "../util/utils";
|
import {fullName, logError, oldSendMessage, oldReplyToMessage} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class Unban extends ChatCommand {
|
export class Unban extends ChatCommand {
|
||||||
regexp = /^\/unban/i;
|
|
||||||
title = "/unban [reply]";
|
title = "/unban [reply]";
|
||||||
description = "unban user from chat";
|
description = "unban user from chat";
|
||||||
|
|
||||||
@@ -25,17 +24,17 @@ export class Unban extends ChatCommand {
|
|||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
|
|
||||||
if (userId === botUser.id) {
|
if (userId === botUser.id) {
|
||||||
await replyToMessage(msg, "Бот и так не в бане сам у себя.").catch(logError);
|
await oldReplyToMessage(msg, "Бот и так не в бане сам у себя.").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userId === Environment.CREATOR_ID) {
|
if (userId === Environment.CREATOR_ID) {
|
||||||
await replyToMessage(msg, "Создатель бота и так не в бане и никогда не будет.").catch(logError);
|
await oldReplyToMessage(msg, "Создатель бота и так не в бане и никогда не будет.").catch(logError);
|
||||||
return;
|
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 replyToMessage(msg, "Админимтраторы бота и так не в бане.").catch(logError);
|
await oldReplyToMessage(msg, "Админимтраторы бота и так не в бане.").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import {Message} from "typescript-telegram-bot-api";
|
|||||||
import {botUser} from "../index";
|
import {botUser} from "../index";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class Unmute implements ChatCommand {
|
export class Unmute extends ChatCommand {
|
||||||
regexp = /^\/unmute/i;
|
|
||||||
title = "/unmute";
|
title = "/unmute";
|
||||||
description = "Bot will start responding to the user";
|
description = "Bot will start responding to the user";
|
||||||
requirements = Requirements.Build(Requirement.BOT_ADMIN, Requirement.CHAT, Requirement.REPLY);
|
requirements = Requirements.Build(Requirement.BOT_ADMIN, Requirement.CHAT, Requirement.REPLY);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {Message} from "typescript-telegram-bot-api";
|
|||||||
import {getUptime, logError, oldSendMessage} from "../util/utils";
|
import {getUptime, logError, oldSendMessage} from "../util/utils";
|
||||||
|
|
||||||
export class Uptime extends ChatCommand {
|
export class Uptime extends ChatCommand {
|
||||||
regexp = /^\/uptime/i;
|
|
||||||
title = "/uptime";
|
title = "/uptime";
|
||||||
description = "Bot's uptime";
|
description = "Bot's uptime";
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {logError, randomValue, oldSendMessage} from "../util/utils";
|
import {logError, oldSendMessage, randomValue} from "../util/utils";
|
||||||
import {betterAnswers} from "../db/database";
|
import {betterAnswers} from "../db/database";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
|
||||||
export class WhatBetter extends ChatCommand {
|
export class WhatBetter extends ChatCommand {
|
||||||
regexp = /^\/(what|что)\s(better|лучше)\s([^]+)\s(or|или)\s([^]+)/i;
|
command = ["what", "что"];
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/what better [a] or [b]";
|
title = "/what better [a] or [b]";
|
||||||
description = "either a or b randomly (50% chance)";
|
description = "either a or b randomly (50% chance)";
|
||||||
|
|
||||||
|
private argsRe = /^(better|лучше)\s+([\s\S]+?)\s+(or|или)\s+([\s\S]+)$/i;
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray) {
|
async execute(msg: Message, match?: RegExpExecArray) {
|
||||||
const a = match[3];
|
const args = (match?.[3] ?? "").trim();
|
||||||
const b = match[5].trimStart();
|
const m = this.argsRe.exec(args);
|
||||||
|
if (!m) return;
|
||||||
|
const a = m[2].trim();
|
||||||
|
const b = m[4].trim();
|
||||||
|
|
||||||
const text = `${randomValue(betterAnswers)} ${randomValue([a, b])}`;
|
const text = `${randomValue(betterAnswers)} ${randomValue([a, b])}`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {getRandomInt, getRangedRandomInt, logError, replyToMessage} from "../util/utils";
|
import {getRandomInt, getRangedRandomInt, logError, oldReplyToMessage} from "../util/utils";
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
|
|
||||||
export class When extends ChatCommand {
|
export class When extends ChatCommand {
|
||||||
regexp = /^\/(when|когда)\s([^]+)/i;
|
command = ["when", "когда"];
|
||||||
|
argsMode = "required" as const;
|
||||||
|
|
||||||
title = "/when [value]";
|
title = "/when [value]";
|
||||||
description = "random date";
|
description = "random date";
|
||||||
|
|
||||||
@@ -85,6 +87,6 @@ export class When extends ChatCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await replyToMessage(msg, text).catch(logError);
|
await oldReplyToMessage(msg, text).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,10 +30,10 @@ export class Environment {
|
|||||||
static OLLAMA_API_KEY?: string;
|
static OLLAMA_API_KEY?: string;
|
||||||
|
|
||||||
static GEMINI_API_KEY?: string;
|
static GEMINI_API_KEY?: string;
|
||||||
static GEMINI_MODEL?: string;
|
static GEMINI_MODEL: string;
|
||||||
|
|
||||||
static MISTRAL_API_KEY?: string;
|
static MISTRAL_API_KEY?: string;
|
||||||
static MISTRAL_MODEL?: string;
|
static MISTRAL_MODEL: string;
|
||||||
|
|
||||||
static waitText = "⏳ Дайте-ка подумать...";
|
static waitText = "⏳ Дайте-ка подумать...";
|
||||||
|
|
||||||
@@ -64,10 +64,10 @@ export class Environment {
|
|||||||
Environment.OLLAMA_API_KEY = process.env.OLLAMA_API_KEY;
|
Environment.OLLAMA_API_KEY = process.env.OLLAMA_API_KEY;
|
||||||
|
|
||||||
Environment.GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
Environment.GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
||||||
Environment.GEMINI_MODEL = process.env.GEMINI_MODEL;
|
Environment.GEMINI_MODEL = process.env.GEMINI_MODEL || "gemini-2.5-flash";
|
||||||
|
|
||||||
Environment.MISTRAL_API_KEY = process.env.MISTRAL_API_KEY;
|
Environment.MISTRAL_API_KEY = process.env.MISTRAL_API_KEY;
|
||||||
Environment.MISTRAL_MODEL = process.env.MISTRAL_MODEL;
|
Environment.MISTRAL_MODEL = process.env.MISTRAL_MODEL || "mistral-small-latest";
|
||||||
}
|
}
|
||||||
|
|
||||||
static setAdmins(admins: Set<number>) {
|
static setAdmins(admins: Set<number>) {
|
||||||
@@ -93,4 +93,16 @@ export class Environment {
|
|||||||
|
|
||||||
return has;
|
return has;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static setOllamaModel(newModel: string) {
|
||||||
|
Environment.OLLAMA_MODEL = newModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static setGeminiModel(newModel: string) {
|
||||||
|
Environment.GEMINI_MODEL = newModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static setMistralModel(newModel: string) {
|
||||||
|
Environment.MISTRAL_MODEL = newModel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,5 @@ export type MessagePart = {
|
|||||||
bot: boolean;
|
bot: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
images: string[];
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ export class MessageStore {
|
|||||||
static async put(m: Message, prefix: string = Environment.BOT_PREFIX) {
|
static async put(m: Message, prefix: string = Environment.BOT_PREFIX) {
|
||||||
const msg: StoredMessage = {
|
const msg: StoredMessage = {
|
||||||
chatId: m.chat.id,
|
chatId: m.chat.id,
|
||||||
messageId: m.message_id,
|
id: m.message_id,
|
||||||
replyToMessageId: m.reply_to_message?.message_id ?? null,
|
replyToMessageId: m.reply_to_message?.message_id ?? null,
|
||||||
fromId: m.from.id,
|
fromId: m.from.id,
|
||||||
text: extractTextMessage(m, prefix),
|
text: extractTextMessage(m, prefix),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {messagesTable} from "./schema";
|
import {MessageInsert, messagesTable} from "./schema";
|
||||||
import {DatabaseManager} from "./database-manager";
|
import {DatabaseManager} from "./database-manager";
|
||||||
import {StoredMessage} from "../model/stored-message";
|
import {StoredMessage} from "../model/stored-message";
|
||||||
import {and, eq} from "drizzle-orm";
|
import {and, eq} from "drizzle-orm";
|
||||||
@@ -66,7 +66,7 @@ export class MessageDao extends Dao<StoredMessage> {
|
|||||||
return this.mapFrom(messages);
|
return this.mapFrom(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
async insert(values: typeof messagesTable.$inferInsert[]): Promise<true> {
|
async insert(values: MessageInsert[]): Promise<true> {
|
||||||
const then = Date.now();
|
const then = Date.now();
|
||||||
const r = await DatabaseManager.db
|
const r = await DatabaseManager.db
|
||||||
.insert(messagesTable)
|
.insert(messagesTable)
|
||||||
@@ -82,7 +82,7 @@ export class MessageDao extends Dao<StoredMessage> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapTo(messages: Message[]): typeof messagesTable.$inferInsert[] {
|
mapTo(messages: Message[]): MessageInsert[] {
|
||||||
return messages.map(msg => {
|
return messages.map(msg => {
|
||||||
return {
|
return {
|
||||||
chatId: msg.chat.id,
|
chatId: msg.chat.id,
|
||||||
@@ -95,15 +95,16 @@ export class MessageDao extends Dao<StoredMessage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mapFrom(messages: typeof messagesTable.$inferInsert[]): StoredMessage[] {
|
mapFrom(messages: MessageInsert[]): StoredMessage[] {
|
||||||
return messages.map(m => {
|
return messages.map(m => {
|
||||||
return {
|
return {
|
||||||
chatId: m.chatId,
|
chatId: m.chatId,
|
||||||
messageId: m.id,
|
id: m.id,
|
||||||
replyToMessageId: m.replyToMessageId,
|
replyToMessageId: m.replyToMessageId,
|
||||||
fromId: m.fromId,
|
fromId: m.fromId,
|
||||||
text: m.text,
|
text: m.text,
|
||||||
date: m.date
|
date: m.date,
|
||||||
|
photoMaxSizeFilePath: m.photoMaxSizeFilePath
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const messagesTable = sqliteTable("messages", {
|
|||||||
fromId: int().notNull(),
|
fromId: int().notNull(),
|
||||||
text: text(),
|
text: text(),
|
||||||
date: int().notNull(),
|
date: int().notNull(),
|
||||||
|
photoMaxSizeFilePath: text(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type MessageInsert = typeof messagesTable.$inferInsert;
|
export type MessageInsert = typeof messagesTable.$inferInsert;
|
||||||
|
|||||||
+44
-5
@@ -7,6 +7,7 @@ import {
|
|||||||
executeChatCommand,
|
executeChatCommand,
|
||||||
extractTextMessage,
|
extractTextMessage,
|
||||||
findAndExecuteCallbackCommand,
|
findAndExecuteCallbackCommand,
|
||||||
|
ignore,
|
||||||
initSystemSpecs,
|
initSystemSpecs,
|
||||||
logError,
|
logError,
|
||||||
randomValue,
|
randomValue,
|
||||||
@@ -57,6 +58,17 @@ import {CallbackCommand} from "./base/callback-command";
|
|||||||
import {OllamaCancel} from "./callback_commands/ollama-cancel";
|
import {OllamaCancel} from "./callback_commands/ollama-cancel";
|
||||||
import {MistralChat} from "./commands/mistral-chat";
|
import {MistralChat} from "./commands/mistral-chat";
|
||||||
import {Transliteration} from "./commands/transliteration";
|
import {Transliteration} from "./commands/transliteration";
|
||||||
|
import {OllamaListModels} from "./commands/ollama-list-models";
|
||||||
|
import {OllamaGetModel} from "./commands/ollama-get-model";
|
||||||
|
import {OllamaSetModel} from "./commands/ollama-set-model";
|
||||||
|
import {Mistral} from "@mistralai/mistralai";
|
||||||
|
import {GoogleGenAI} from "@google/genai";
|
||||||
|
import {MistralGetModel} from "./commands/mistral-get-model";
|
||||||
|
import {MistralSetModel} from "./commands/mistral-set-model";
|
||||||
|
import {MistralListModels} from "./commands/mistral-list-models";
|
||||||
|
import {GeminiListModels} from "./commands/gemini-list-models";
|
||||||
|
import {GeminiGetModel} from "./commands/gemini-get-model";
|
||||||
|
import {GeminiSetModel} from "./commands/gemini-set-model";
|
||||||
|
|
||||||
process.setUncaughtExceptionCaptureCallback(console.error);
|
process.setUncaughtExceptionCaptureCallback(console.error);
|
||||||
|
|
||||||
@@ -69,6 +81,9 @@ export const userDao = new UserDao();
|
|||||||
export const bot = new TelegramBot({botToken: Environment.BOT_TOKEN, testEnvironment: Environment.TEST_ENVIRONMENT});
|
export const bot = new TelegramBot({botToken: Environment.BOT_TOKEN, testEnvironment: Environment.TEST_ENVIRONMENT});
|
||||||
export let botUser: User;
|
export let botUser: User;
|
||||||
|
|
||||||
|
export const googleAi = new GoogleGenAI({apiKey: Environment.GEMINI_API_KEY});
|
||||||
|
export const mistralAi = new Mistral({apiKey: Environment.MISTRAL_API_KEY});
|
||||||
|
|
||||||
export const ollama = new Ollama({
|
export const ollama = new Ollama({
|
||||||
host: Environment.OLLAMA_ADDRESS,
|
host: Environment.OLLAMA_ADDRESS,
|
||||||
headers: {"Authorization": `Bearer ${Environment.OLLAMA_API_KEY}`}
|
headers: {"Authorization": `Bearer ${Environment.OLLAMA_API_KEY}`}
|
||||||
@@ -148,7 +163,13 @@ export const callbackCommands: CallbackCommand[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL && Environment.SYSTEM_PROMPT) {
|
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL && Environment.SYSTEM_PROMPT) {
|
||||||
chatCommands.push(new OllamaChat(), new OllamaPrompt());
|
chatCommands.push(
|
||||||
|
new OllamaChat(),
|
||||||
|
new OllamaPrompt(),
|
||||||
|
new OllamaListModels(),
|
||||||
|
new OllamaGetModel(),
|
||||||
|
new OllamaSetModel()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Environment.OLLAMA_API_KEY) {
|
if (Environment.OLLAMA_API_KEY) {
|
||||||
@@ -156,18 +177,29 @@ if (Environment.OLLAMA_API_KEY) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Environment.GEMINI_API_KEY) {
|
if (Environment.GEMINI_API_KEY) {
|
||||||
chatCommands.push(new GeminiChat());
|
chatCommands.push(
|
||||||
|
new GeminiChat(),
|
||||||
|
new GeminiListModels(),
|
||||||
|
new GeminiGetModel(),
|
||||||
|
new GeminiSetModel()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Environment.MISTRAL_API_KEY) {
|
if (Environment.MISTRAL_API_KEY) {
|
||||||
chatCommands.push(new MistralChat());
|
chatCommands.push(
|
||||||
|
new MistralChat(),
|
||||||
|
new MistralListModels(),
|
||||||
|
new MistralGetModel(),
|
||||||
|
new MistralSetModel()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log(
|
console.log(
|
||||||
`TEST_ENVIRONMENT: ${Environment.TEST_ENVIRONMENT}\n` +
|
`TEST_ENVIRONMENT: ${Environment.TEST_ENVIRONMENT}\n` +
|
||||||
`DATA_PATH: ${Environment.DATA_PATH}\n` +
|
`DATA_PATH: ${Environment.DATA_PATH}\n` +
|
||||||
`MAX_PHOTO_SIZE: ${Environment.MAX_PHOTO_SIZE}`
|
`MAX_PHOTO_SIZE: ${Environment.MAX_PHOTO_SIZE}\n` +
|
||||||
|
`ONLY_FOR_CREATOR: ${Environment.ONLY_FOR_CREATOR_MODE}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const commands = chatCommands.filter(cmd => {
|
const commands = chatCommands.filter(cmd => {
|
||||||
@@ -214,7 +246,7 @@ bot.on("edited_message", async (msg) => {
|
|||||||
bot.on("message", async (msg) => {
|
bot.on("message", async (msg) => {
|
||||||
console.log("message", msg);
|
console.log("message", msg);
|
||||||
|
|
||||||
await Promise.all([MessageStore.put(msg), UserStore.put(msg.from)]);
|
Promise.all([MessageStore.put(msg), UserStore.put(msg.from)]).then(ignore);
|
||||||
|
|
||||||
if ((msg.new_chat_members?.length || 0 > 0)) {
|
if ((msg.new_chat_members?.length || 0 > 0)) {
|
||||||
await bot.sendMessage({chat_id: msg.chat.id, text: randomValue(inviteAnswers)}).catch(logError);
|
await bot.sendMessage({chat_id: msg.chat.id, text: randomValue(inviteAnswers)}).catch(logError);
|
||||||
@@ -232,8 +264,15 @@ bot.on("message", async (msg) => {
|
|||||||
|
|
||||||
const cmdText = msg.text || msg.caption || "";
|
const cmdText = msg.text || msg.caption || "";
|
||||||
|
|
||||||
|
const then = Date.now();
|
||||||
|
|
||||||
const cmd = searchChatCommand(chatCommands, cmdText);
|
const cmd = searchChatCommand(chatCommands, cmdText);
|
||||||
const executed = await executeChatCommand(cmd, msg, cmdText);
|
const executed = await executeChatCommand(cmd, msg, cmdText);
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const diff = now - then;
|
||||||
|
console.log("diff", diff);
|
||||||
|
|
||||||
if (executed || !cmdText) return;
|
if (executed || !cmdText) return;
|
||||||
|
|
||||||
const startsWithPrefix = cmdText.toLowerCase().startsWith(Environment.BOT_PREFIX.toLowerCase());
|
const startsWithPrefix = cmdText.toLowerCase().startsWith(Environment.BOT_PREFIX.toLowerCase());
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
export type StoredMessage = {
|
export type StoredMessage = {
|
||||||
chatId: number;
|
chatId: number;
|
||||||
messageId: number;
|
id: number;
|
||||||
replyToMessageId?: number | null;
|
replyToMessageId?: number | null;
|
||||||
fromId: number;
|
fromId: number;
|
||||||
text?: string;
|
text?: string;
|
||||||
date: number;
|
date: number;
|
||||||
|
photoMaxSizeFilePath?: string | null;
|
||||||
};
|
};
|
||||||
+102
-23
@@ -14,6 +14,7 @@ import {UserStore} from "../common/user-store";
|
|||||||
import * as orm from "drizzle-orm";
|
import * as orm from "drizzle-orm";
|
||||||
import {sql, type SQL} from "drizzle-orm";
|
import {sql, type SQL} from "drizzle-orm";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
export const ignore = () => {
|
export const ignore = () => {
|
||||||
};
|
};
|
||||||
@@ -38,12 +39,21 @@ export const errorPlaceholder = async (msg: Message) => {
|
|||||||
await sendErrorPlaceholder(msg).catch(logError);
|
await sendErrorPlaceholder(msg).catch(logError);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function searchChatCommand(commands: ChatCommand[], text: string): ChatCommand | null {
|
export function searchChatCommand(
|
||||||
for (let i = 0; i < commands.length; i++) {
|
commands: ChatCommand[],
|
||||||
const command = commands[i];
|
text: string,
|
||||||
if (command?.regexp.test(text)) {
|
botUsername: string = botUser.username
|
||||||
return command;
|
): ChatCommand | null {
|
||||||
|
for (const command of commands) {
|
||||||
|
const match = command.finalRegexp.exec(text);
|
||||||
|
if (!match) continue;
|
||||||
|
|
||||||
|
const mentioned = match[2]?.toLowerCase();
|
||||||
|
if (botUsername && mentioned && mentioned !== botUsername.toLowerCase()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -81,13 +91,13 @@ export async function checkRequirements(cmd: ChatCommand | null, msg: Message):
|
|||||||
|
|
||||||
if (reqs.isRequiresBotCreator() && fromId !== Environment.CREATOR_ID) {
|
if (reqs.isRequiresBotCreator() && fromId !== Environment.CREATOR_ID) {
|
||||||
console.log(`${cmd.title}: creatorId is bad`);
|
console.log(`${cmd.title}: creatorId is bad`);
|
||||||
await replyToMessage(msg, "Вы не являетесь создателем бота.");
|
await oldReplyToMessage(msg, "Вы не являетесь создателем бота.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reqs.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
|
if (reqs.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
|
||||||
console.log(`${cmd.title}: adminId is bad`);
|
console.log(`${cmd.title}: adminId is bad`);
|
||||||
await replyToMessage(msg, "Вы не являетесь администратором бота.");
|
await oldReplyToMessage(msg, "Вы не являетесь администратором бота.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,20 +107,20 @@ export async function checkRequirements(cmd: ChatCommand | null, msg: Message):
|
|||||||
|
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
console.log(`${cmd.title}: chatAdminId is bad`);
|
console.log(`${cmd.title}: chatAdminId is bad`);
|
||||||
await replyToMessage(msg, "Бот не является администратором чата.");
|
await oldReplyToMessage(msg, "Бот не является администратором чата.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reqs.isRequiresChat() && msg.chat.type === "private") {
|
if (reqs.isRequiresChat() && msg.chat.type === "private") {
|
||||||
console.log(`${cmd.title}: chatId is bad`);
|
console.log(`${cmd.title}: chatId is bad`);
|
||||||
await replyToMessage(msg, "Тут Вам не чат.");
|
await oldReplyToMessage(msg, "Тут Вам не чат.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reqs.isRequiresReply() && !msg.reply_to_message) {
|
if (reqs.isRequiresReply() && !msg.reply_to_message) {
|
||||||
console.log(`${cmd.title}: replyMessage is bad`);
|
console.log(`${cmd.title}: replyMessage is bad`);
|
||||||
await replyToMessage(msg, "Отсутствует ответ на сообщение.");
|
await oldReplyToMessage(msg, "Отсутствует ответ на сообщение.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,10 +189,11 @@ export async function editMessageText(chatId: number, messageId: number, message
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SendOptions = {
|
export type SendOptions = {
|
||||||
chatId?: number;
|
chat_id?: number;
|
||||||
message?: Message,
|
message?: Message,
|
||||||
|
message_id?: number;
|
||||||
text: string,
|
text: string,
|
||||||
parseMode?: ParseMode,
|
parse_mode?: ParseMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function oldSendMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
export async function oldSendMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
||||||
@@ -197,15 +208,28 @@ export async function oldSendMessage(message: Message, text: string, parseMode?:
|
|||||||
|
|
||||||
export async function sendMessage(options: SendOptions): Promise<Message> {
|
export async function sendMessage(options: SendOptions): Promise<Message> {
|
||||||
const response = await bot.sendMessage({
|
const response = await bot.sendMessage({
|
||||||
chat_id: options.chatId ?? options.message?.chat?.id,
|
chat_id: options.chat_id ?? options.message?.chat?.id,
|
||||||
text: options.text,
|
text: options.text,
|
||||||
parse_mode: options.parseMode
|
parse_mode: options.parse_mode
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve(response);
|
return Promise.resolve(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function replyToMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
export async function replyToMessage(options: SendOptions): Promise<Message> {
|
||||||
|
const response = await bot.sendMessage({
|
||||||
|
chat_id: options.chat_id ?? options.message?.chat?.id,
|
||||||
|
text: options.text,
|
||||||
|
parse_mode: options.parse_mode,
|
||||||
|
reply_parameters: {
|
||||||
|
message_id: options.message_id || options.message?.message_id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function oldReplyToMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
||||||
const response = await bot.sendMessage({
|
const response = await bot.sendMessage({
|
||||||
chat_id: message.chat.id,
|
chat_id: message.chat.id,
|
||||||
text: text,
|
text: text,
|
||||||
@@ -382,6 +406,7 @@ export function extractTextStored(msg: StoredMessage, prefix: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function extractText(text: string, prefix: string): string {
|
export function extractText(text: string, prefix: string): string {
|
||||||
|
if (!text) return "";
|
||||||
if (text.toLowerCase().startsWith(prefix.toLowerCase())) {
|
if (text.toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||||
text = text.substring(prefix.length).trim();
|
text = text.substring(prefix.length).trim();
|
||||||
}
|
}
|
||||||
@@ -389,17 +414,57 @@ export function extractText(text: string, prefix: string): string {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isStoredMessage(msg: Message | StoredMessage): msg is StoredMessage {
|
||||||
|
return "id" in msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadImageIfExists(msg: Message | StoredMessage): Promise<string | null> {
|
||||||
|
if (isStoredMessage(msg)) {
|
||||||
|
return msg.photoMaxSizeFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageFilePath: string | null = null;
|
||||||
|
|
||||||
|
const maxSize = await getPhotoMaxSize(msg.photo);
|
||||||
|
if (maxSize) {
|
||||||
|
const imagePath = path.join(Environment.DATA_PATH, "temp");
|
||||||
|
if (!fs.existsSync(imagePath)) {
|
||||||
|
fs.mkdirSync(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
|
||||||
|
if (!fs.existsSync(imageFilePath)) {
|
||||||
|
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
|
||||||
|
const src = Buffer.from(res.data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(imageFilePath, src);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
imageFilePath = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
export async function collectReplyChainText(triggerMsg: Message, prefix: string = Environment.BOT_PREFIX, limit: number = 40, includeTrigger = true): Promise<MessagePart[]> {
|
export async function collectReplyChainText(triggerMsg: Message, prefix: string = Environment.BOT_PREFIX, limit: number = 40, includeTrigger = true): Promise<MessagePart[]> {
|
||||||
const chatId = triggerMsg.chat.id as number;
|
const chatId = triggerMsg.chat.id as number;
|
||||||
|
|
||||||
const parts: MessagePart[] = [];
|
const parts: MessagePart[] = [];
|
||||||
if (includeTrigger) {
|
if (includeTrigger) {
|
||||||
const t = extractTextMessage(triggerMsg, prefix);
|
const t = extractTextMessage(triggerMsg, prefix);
|
||||||
if (t) parts.push({
|
const img = (await loadImageIfExists(triggerMsg)) /*|| triggerMsg.reply_to_message ?
|
||||||
bot: triggerMsg.from.id === botUser.id,
|
(await loadImageIfExists(triggerMsg.reply_to_message)) : null*/;
|
||||||
content: t,
|
if (t) {
|
||||||
name: triggerMsg.from.first_name
|
parts.push({
|
||||||
});
|
bot: triggerMsg.from.id === botUser.id,
|
||||||
|
content: t,
|
||||||
|
name: triggerMsg.from.first_name,
|
||||||
|
images: img ? [img] : []
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const first = triggerMsg.reply_to_message;
|
const first = triggerMsg.reply_to_message;
|
||||||
@@ -408,7 +473,15 @@ export async function collectReplyChainText(triggerMsg: Message, prefix: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
const firstText = extractTextMessage(first, prefix);
|
const firstText = extractTextMessage(first, prefix);
|
||||||
if (firstText) parts.push({bot: first.from.id === botUser.id, content: firstText, name: first.from.first_name});
|
if (firstText || first.photo) {
|
||||||
|
const img = await loadImageIfExists(first);
|
||||||
|
parts.push({
|
||||||
|
bot: first.from.id === botUser.id,
|
||||||
|
content: firstText,
|
||||||
|
name: first.from.first_name,
|
||||||
|
images: img ? [img] : []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let curId = first.message_id;
|
let curId = first.message_id;
|
||||||
|
|
||||||
@@ -418,14 +491,16 @@ export async function collectReplyChainText(triggerMsg: Message, prefix: string
|
|||||||
if (!parentId) break;
|
if (!parentId) break;
|
||||||
|
|
||||||
const parent = await messageDao.getById({chatId: chatId, id: parentId});
|
const parent = await messageDao.getById({chatId: chatId, id: parentId});
|
||||||
if (!parent?.text) break;
|
if (!parent?.text && !parent?.photoMaxSizeFilePath) break;
|
||||||
|
|
||||||
const user = await UserStore.get(parent.fromId);
|
const user = await UserStore.get(parent.fromId);
|
||||||
|
const img = await loadImageIfExists(parent);
|
||||||
|
|
||||||
parts.push({
|
parts.push({
|
||||||
bot: parent.fromId === botUser.id,
|
bot: parent.fromId === botUser.id,
|
||||||
content: extractTextStored(parent, prefix),
|
content: extractTextStored(parent, prefix),
|
||||||
name: user?.firstName
|
name: user?.firstName,
|
||||||
|
images: img ? [img] : []
|
||||||
});
|
});
|
||||||
curId = parentId;
|
curId = parentId;
|
||||||
}
|
}
|
||||||
@@ -807,3 +882,7 @@ export function ifTrue(exp?: never): boolean {
|
|||||||
|
|
||||||
return ["true", "t", "y", 1, "1"].includes(exp);
|
return ["true", "t", "y", 1, "1"].includes(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function boolToEmoji(bool: boolean): string {
|
||||||
|
return bool ? "✅" : "❌";
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user