Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes and enhancements #122

Merged
merged 3 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bilderberg_butler",
"version": "2.57.0",
"version": "2.58.0",
"description": "Discord bot for bilderberg club",
"main": "index.js",
"scripts": {
Expand Down
25 changes: 6 additions & 19 deletions telegram/command-handlers/help-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@
* @returns {[null, String | null]}
*/

async function help() {
let message = `Вот список доступных команд:
/help - список команд
/ping - pong
/info - получить информацию о чате
/calc {математическое выражение} - получить информацию о чате
/cur {число} {валюта1} {валюта2} - конвертор валют
/wiki {запрос} - возвращает подходящие страницы из Википедии
/answer {текст?} - при реплае использует текст оригинального сообщения для запроса к GPT, также использует текст переданный вместе с командой если таковой есть
/urban {слово?} - определение из <a href="https://www.urbandictionary.com/">Urban Dictionary</>
/set {название} - сохранить содержимое сообщения
/get {название} - вызвать контент, сохранённый командой /set
/get_list - показать список гетов, доступных в этом чате
/del {название} - удалить гет
/ahegao - получить случайное ахегао
/curl {ссылка} - возвращает результат запроса к указанной ссылке
/deep {запрос} - генерирует изображение по запросу с помощью DeepAI
/0o0 {текст} - превращает текст в ТеКсТ
`;
async function help({}, interaction) {
let message = 'Вот список доступных команд:\n';
interaction.registered_commands.forEach((help, command_name) => {
if (!help?.length) return;
message += `/${command_name} — ${help.join(' ')}\n`;
});
return [null, message];
}

Expand Down
4 changes: 2 additions & 2 deletions telegram/gpt-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const { OpenAIApi, Configuration } = require('openai');

const CHAT_MODEL_NAME = 'gpt-4';

const DEFAULT_SYSTEM_PROMPT = 'you are a chat-assistant\nanswer in english and/or russian languages\nanswer should not exceed 3000 characters\nyou can mention users by `@<username>` and call them by name';
const DEFAULT_SYSTEM_PROMPT = `you are a chat-assistant\nanswer should not exceed 3000 characters\neach message starts with user's name and username, username is mentionable with @`;
/**
@param {String} input
@return {String}
Expand Down Expand Up @@ -379,7 +379,7 @@ class ChatGPTHandler{
const context_tree = this._getContextTree(context.chat.id);

if (!new_system_prompt) {
[`Нужен не пустой системный промпт.\nПо умолчанию: <code>${DEFAULT_SYSTEM_PROMPT}</code>\nСейчас: <code>${context_tree.root_node.content}</code>`];
return [`Нужен не пустой системный промпт.\nПо умолчанию: <code>${DEFAULT_SYSTEM_PROMPT}</code>\nСейчас: <code>${context_tree.root_node.content}</code>`];
}

context_tree.root_node.content = new_system_prompt;
Expand Down
2 changes: 1 addition & 1 deletion telegram/presence-subscriber.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class PresenceNotification {
}

getNotificationText() {
let text = 'Активность';
let text = '\nАктивность';
for (const [{}, { member_name, activity, call_me_by = null }] of this.presence_collection.entries()) {
if (activity) text += `\n${call_me_by || member_name} — ${activity}`;
}
Expand Down
90 changes: 59 additions & 31 deletions telegram/telegram-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const { commands, conditions, definitions, handlers } = require('../commands/han
const ChatGPTHandler = require('./gpt-handler');
const { isNotificationMessage: isChannelNotificationMessage } = require('./channel-subscriber.js');
const { isNotificationMessage: isEventNotificationMessage } = require('./event-subscriber.js');
// const { isNotificationMessage: isPresenceNotificationMessage } = require('./presence-subscriber.js');

const no_tags_regex = /<\/?[^>]+(>|$)/g;

Expand Down Expand Up @@ -110,6 +109,13 @@ class TelegramInteraction {
return this.client.inline_commands;
}

/**
* @returns {Map<'string', 'string'[]>}
*/
get registered_commands() {
return this.client.registered_commands;
}

/**
* @returns {Telegram}
*/
Expand Down Expand Up @@ -301,14 +307,14 @@ class TelegramInteraction {
* @returns {undefined | Promise}
*/
reply() {
if (typeof this.handler[this.command_name] !== 'function') {
if (typeof this.handler[this.command_name]?.handler !== 'function') {
this.logger.warn(`Received nonsense, how did it get here???`);
return;
}

this.logger.info(`Received command: ${this.command_name}`);

this.handler[this.command_name](this.context, this).then(([err, response, callback = () => {}, overrides]) => {
this.handler[this.command_name].handler(this.context, this).then(([err, response, callback = () => {}, overrides]) => {
if (err) {
return this._reply(err, overrides).catch((err) => {
this.logger.error(`Error while replying with an error message to [${this.command_name}]`, { error: err.stack || err });
Expand Down Expand Up @@ -454,25 +460,20 @@ class TelegramInteraction {
if (matching_command_names.length > 0 && !this.inline_commands.includes(command_name)) {
let results = [];
for (const matching_command_name of matching_command_names) {
if (commands.includes(matching_command_name)) {
const index = commands.indexOf(matching_command_name);
let line = `/${matching_command_name} `;
if (definitions[index].args && definitions[index].args.length) {
for (const arg of definitions[index].args) {
line += `{${arg.name}${arg.optional ? '?' : ''}} `;
}
}
this.registered_commands.forEach((help, command_name) => {
if (command_name !== matching_command_name || !help.length) return;
let line = `/${command_name} ${help.length > 1 ? help.slice(0, -1).join(' ') : ''}`;
results.push(
this._generateInlineText(
line,
{
description: definitions[index].description,
description: help.slice(-1)[0],
id: `${matching_command_name}${require('../package.json').version}${process.env.ENV}`,
message_text: `<code>@${this.context.me.username} ${line}</code>\n<i>${definitions[index].description}</i>`,
message_text: `<code>@${this.context.me.username} ${line}</code>\n<i>${help.slice(-1)[0]}</i>`,
}
)
);
}
});
}

if (!results.length) {
Expand Down Expand Up @@ -509,8 +510,8 @@ class TelegramInteraction {
this.logger.info(`Received eligible inline query, parsed context [${JSON.stringify(parsed_context)}]`);

(async () => {
if (this.handler[command_name]) {
return this.handler[command_name](parsed_context, this);
if (this.handler[command_name]?.handler) {
return this.handler[command_name].handler(parsed_context, this);
}
const common_command_index = commands.indexOf(command_name);
if (common_command_index >= 0) {
Expand Down Expand Up @@ -562,6 +563,7 @@ class TelegramClient {
this.logger = require('../logger').child(this.log_meta);
this.handler = new TelegramHandler(this);
this.inline_commands = [];
this.registered_commands = new Map();
}

/**
Expand All @@ -572,20 +574,14 @@ class TelegramClient {
* @param {String?} handle_function_name {command_name} which function from TelegramHandler handles this command
*/
_registerTelegramCommand(command_name, condition = false, is_inline = false, handle_function_name = command_name) {
if (!command_name) {
return;
}

if (typeof condition === 'function') {
condition = condition();
if (!condition()) return;
}
else if (!condition) return;

if (!condition) {
return;
}
this.handler[handle_function_name]?.help && this.registered_commands.set(command_name, this.handler[handle_function_name].help);

this.client.command(command_name, async (ctx) => new TelegramInteraction(this, handle_function_name, ctx).reply());

if (is_inline) {
this.inline_commands.push(command_name);
}
Expand Down Expand Up @@ -624,21 +620,53 @@ class TelegramClient {
// Registering common commands
commands.forEach((command_name, index) => {
if (typeof conditions[index] === 'function') {
if (!conditions[index]()) {
return;
}
if (!conditions[index]()) return;
}
else if (!conditions[index]) {
return;
else if (!conditions[index]) return;

let args = [];
if (definitions?.[index]?.args?.length) {
for (const arg of definitions[index].args) {
args.push(`{${arg.name}${arg.optional ? '?' : ''}}`);
}
}
this.registered_commands.set(command_name, [args.join(' '), definitions[index].description]);

this.client.command(command_name, async (ctx) => handleCommand(ctx, handlers[index], definitions[index]));

if (definitions[index].is_inline) {
this.inline_commands.push(command_name);
}
});

this.client.api.setMyCommands(
[...this.registered_commands.entries()]
.reduce((acc, [command_name, help]) => {
if (help?.length) {
acc.push({command: command_name, description: help.join(' ')});
}
return acc;
}, []),
{
scope: {
type: 'default'
}
}
)
.catch(err => {
this.logger.error('Error while registering commands', { error: err.stack || err });
})
.then(registered => {
if (registered) this.logger.debug('Received successful response for commands registering');
return this.client.api.getMyCommands({ scope: { type: 'default' } });
})
.catch(err => {
this.logger.error('Error while getting registered commands', { error: err.stack || err });
})
.then(commands => {
this.logger.debug(`Received following registered commands: ${JSON.stringify(commands)}`);
})
;

this.client.on('inline_query', async (ctx) => new TelegramInteraction(this, 'inline_query', ctx).answer());
}

Expand Down
53 changes: 28 additions & 25 deletions telegram/telegram-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,48 +32,51 @@ class TelegramHandler {
return args;
}

/**
* `/start` command handler
* @returns {[null, String]}
*/
async start() {
let message = 'Этот бот что-то может, чтобы узнать что, воспользуйся командой /help';
return [null, message];
}
start = {
/**
* `/start` command handler
* @returns {[null, String]}
*/
handler: async () => {
let message = 'Этот бот что-то может, чтобы узнать что, воспользуйся командой /help';
return [null, message];
},
help: []
}

fizzbuzz = fizzbuzz.bind(this);
fizzbuzz = { handler: fizzbuzz.bind(this), help: [] };

get = get.bind(this);
get = { handler: get.bind(this), help: ['{название}', 'Вызвать контент, сохранённый командой /set'] };

set = set.bind(this);
set = { handler: set.bind(this), help: ['{название}', 'Сохранить содержимое сообщения']};

get_list = getList.bind(this);
get_list = { handler: getList.bind(this), help: ['Вызвать список гетов, доступных в этом чате'] };

del = del.bind(this);
del = { handler: del.bind(this), help: ['{название}', 'Удалить гет, доступно только владельцу (если он есть)'] };

gh = gh.bind(this);
gh = { handler: gh.bind(this), help: [] };

help = help;
help = { handler: help, help: ['Вызвать список доступных команд']};

html = html.bind(this);
html = { handler: html.bind(this), help: [] };

deep = generateImage.bind(this);
deep = { handler: generateImage.bind(this), help: ['{описание}', 'Генерирует 4 картинки по описанию (DeepAI)'] };

info = info.bind(this);
info = { handler: info.bind(this), help: ['Вызвать информацию о чате и отправителе'] };

ytdl = require('./command-handlers/ytdl-handler').ytdl.bind(this);
ytdl = { handler: require('./command-handlers/ytdl-handler').ytdl.bind(this), help: [] };

webapp = require('./command-handlers/webapp-handler').webapp.bind(this);
webapp = { handler: require('./command-handlers/webapp-handler').webapp.bind(this), help: [] };

roundit = require('./command-handlers/roundit-handler').roundit.bind(this);
roundit = { handler: require('./command-handlers/roundit-handler').roundit.bind(this), help: ['Превратить видео в кружок'] };

imagine = require('./command-handlers/imagine-handler').imagine.bind(this);
imagine = { handler: require('./command-handlers/imagine-handler').imagine.bind(this), help: ['{описание}', 'Генерирует 4 картинки по описанию (DALL-E)'] };

new_system_prompt = ChatGPTHandler.handleAdjustSystemPrompt.bind(ChatGPTHandler);
new_system_prompt = { handler: ChatGPTHandler.handleAdjustSystemPrompt.bind(ChatGPTHandler), help: ['{промпт}', 'Задать новый системный промпт для ChatGPT и/или проверить, установленный сейчас'] };

answer = ChatGPTHandler.handleAnswerCommand.bind(ChatGPTHandler);
answer = { handler: ChatGPTHandler.handleAnswerCommand.bind(ChatGPTHandler), help: ['{запрос?}', 'Спросить у ChatGPT, можно использовать как реплай'] };

tree = ChatGPTHandler.handleTreeRequest.bind(ChatGPTHandler);
tree = { handler: ChatGPTHandler.handleTreeRequest.bind(ChatGPTHandler), help: ['Запросить контекстное дерево ChatGPT'] };
}

module.exports = TelegramHandler;