Ответ: umbot — это мультиплатформенный фреймворк на TypeScript, который позволяет писать логику один раз и
запускать её на 7+ платформах: Алиса, Маруся, Сбер, Telegram, VK, Viber, MAX.
Преимущества перед нативными SDK:
umbot — это мультиплатформенный фреймворк на TypeScript для создания навыков для голосовых платформ и чат-ботов.
Позволяет писать код один раз и запускать на 7+ платформах: Алиса, Маруся, Сбер, Telegram, VK, Viber, MAX.
this.userCommand автоматически приводится к нижнему регистру. Ваши слоты тоже должны быть в нижнем
регистре.includes(). Если нужно точное совпадение, используйте регулярное
выражение (например, /^привет$/i).addCommand и интентом из platformParams?addCommand — основной способ регистрации команд. Поддерживает callback, асинхронность и специфичную логику.
Выполняется до проверки интентов.platformParams используются для базовых действий (приветствие, помощь) и обрабатываются, только если
ни одна команда не подошла.Рекомендация: всю бизнес-логику реализуйте через addCommand, а интенты оставьте для стандартных текстов (welcome,
help).
Используйте this.userData или this.state:
// Шаг 1: сохраняем ввод
ctx.userData.name = ctx.userCommand;
ctx.thisIntentName = 'step2';
// Шаг 2: читаем
ctx.text = `Привет, ${ctx.userData.name}!`;
userData сохраняется между сессиями (в БД или локальном хранилище).state хранится только в рамках текущей сессии (поддерживается не всеми платформами).Плагин в umbot — это модуль расширения функциональности, который регистрируется в контексте приложения (AppContext)
и позволяет добавлять новую логику без изменения ядра фреймворка.
Интерфейс: Плагин может быть реализован как класс с методом init(appContext) или как функция со свойством
isPlugin = true.
Регистрация: Плагины подключаются через метод bot.use(plugin).
Встроенные типы: В системе зарезервированы слоты для системных плагинов:
i18n — локализация;nlu — обработка естественного языка;regExp — кастомная реализация регулярных выражений.
Адаптеры: Платформы (Алиса, Telegram, VK и др.) и базы данных (MongoDB, файловая) в версии 3.0.0 также реализованы
через архитектуру плагинов/адаптеров.Подключение происходит в точке входа приложения через цепочку методов use().
Пример кода:
import { Bot } from 'umbot';
import { fullPlatforms, MongoAdapter } from 'umbot/plugins';
const bot = new Bot();
// 1. Подключение готовых плагинов (платформы и БД)
bot.use(fullPlatforms);
bot.use(
new MongoAdapter({
/* конфиг */
}),
);
// 2. Подключение кастомного плагина (пример)
const myPlugin = (appContext) => {
appContext.plugins['myPlugin'] = {
getData: (key) => `Value: ${key}`,
};
};
myPlugin.isPlugin = true; // Маркер, что это плагин
bot.use(myPlugin);
bot.start('localhost', 3000);
Плагин — это механизм расширения функциональности фреймворка без изменения его ядра. Он позволяет инкапсулировать логику в отдельные модули, которые можно подключать только когда это нужно.
Сценарий 1: Модульная архитектура большого проекта Проблема: У вас есть приложение с разными функциями (статистика, задачи, админка), и весь код находится в одном файле → сложно поддерживать. Решение: Каждая функция оформляется как отдельный плагин.
// plugins/statistics.ts
import { AppContext, Bot } from 'umbot';
export class StatisticsPlugin {
init(appContext: AppContext, bot: Bot): void {
// Плагин регистрирует свои команды
bot.addCommand('stats', ['статистика', 'статы'], (_, controller) => {
controller.text = '📊 Статистика приложения...';
});
bot.addCommand('stats_reset', ['сброс статистики'], (_, controller) => {
controller.text = 'Статистика сброшена';
});
}
destroy(bot: Bot): void {
// При удалении плагина очищаем его команды
bot.removeCommand('stats');
bot.removeCommand('stats_reset');
}
}
// plugins/tasks.ts
export class TasksPlugin {
init(appContext: AppContext, bot: Bot): void {
bot.addCommand('task_add', ['добавить задачу'], (_, controller) => {
controller.text = '📝 Новая задача создана';
});
bot.addCommand('task_list', ['список задач'], (_, controller) => {
controller.text = '📋 Список задач...';
});
}
destroy(bot: Bot): void {
bot.removeCommand('task_add');
bot.removeCommand('task_list');
}
}
Главное преимущество: Вы можете собирать разные версии приложения из одних и тех же плагинов:
// index-lite.ts — только статистика
import { Bot } from 'umbot';
import { StatisticsPlugin } from './plugins/statistics';
const bot = new Bot();
bot.use(new StatisticsPlugin()); // Только статистика
bot.start('localhost', 3000);
// index-full.ts — статистика + задачи
import { Bot } from 'umbot';
import { StatisticsPlugin } from './plugins/statistics';
import { TasksPlugin } from './plugins/tasks';
const bot = new Bot();
bot.use(new StatisticsPlugin());
bot.use(new TasksPlugin()); // + Задачи
bot.start('localhost', 3000);
// index-admin.ts — всё + админка
import { Bot } from 'umbot';
import { StatisticsPlugin } from './plugins/statistics';
import { TasksPlugin } from './plugins/tasks';
import { AdminPlugin } from './plugins/admin';
const bot = new Bot();
bot.use(new StatisticsPlugin());
bot.use(new TasksPlugin());
bot.use(new AdminPlugin()); // + Админка
bot.start('localhost', 3000);
Сценарий 2: Переиспользование кода между проектами Проблема: У вас 5 разных платформ, и в каждом нужна одинаковая логика (например, команда /help или обработка платежей). Решение: Создаёте плагин один раз → подключаете везде.
// plugins/help-system.ts
import { AppContext, Bot, HELP_INTENT_NAME } from 'umbot';
export class HelpPlugin {
init(appContext: AppContext, bot: Bot): void {
bot.addCommand(HELP_INTENT_NAME, ['помощь', 'help', 'справка'], (_, controller) => {
controller.text =
'🤖 Доступные команды:\n' +
'• /stats — статистика\n' +
'• /tasks — задачи\n' +
'• /settings — настройки';
controller.buttons.addBtn('📊 Статистика').addBtn('⚙️ Настройки');
});
}
destroy(bot: Bot): void {
bot.removeCommand(HELP_INTENT_NAME);
}
}
// Проект 1: Бот для Telegram
import { Bot } from 'umbot';
import { HelpPlugin } from './plugins/help-system';
import { TelegramAdapter } from 'umbot/plugins';
const bot = new Bot();
bot.use(new TelegramAdapter());
bot.use(new HelpPlugin()); // ✅ Готовая помощь
bot.start('localhost', 3000);
// Проект 2: Навык для Алисы
import { Bot } from 'umbot';
import { HelpPlugin } from './plugins/help-system';
import { AlisaAdapter } from 'umbot/plugins';
const bot = new Bot();
bot.use(new AlisaAdapter());
bot.use(new HelpPlugin()); // ✅ Та же помощь, работает везде
bot.start('localhost', 3000);
Сценарий 3: Динамическое включение/выключение функций Проблема: Нужно временно отключить функционал (например, на время технических работ). Решение: Плагин можно удалить из приложения.
import { Bot } from 'umbot';
import { PaymentPlugin } from './plugins/payment';
import { MaintenancePlugin } from './plugins/maintenance';
const bot = new Bot();
bot.use(new PaymentPlugin());
// Во время технических работ:
bot.clearUse(); // Удаляем все плагины
bot.use(new MaintenancePlugin()); // Добавляем заглушку
// После восстановления:
bot.clearUse();
bot.use(new PaymentPlugin()); // Возвращаем функционал
Сценарий 4: Интеграция со сторонними сервисами Проблема: Нужно подключить внешнее API (например, CRM, базу знаний, платежную систему). Решение: Плагин инкапсулирует всю логику интеграции.
// plugins/crm-integration.ts
import { AppContext, Bot } from 'umbot';
export class CrmPlugin {
private crmClient: any;
init(appContext: AppContext, bot: Bot): void {
// Инициализация клиента CRM
this.crmClient = new CrmClient(appContext.appConfig.crm);
// Регистрируем команды для работы с CRM
bot.addCommand('crm_client', ['клиент', 'карточка клиента'], async (_, controller) => {
const client = await this.crmClient.getClient(controller.userId);
controller.text = `👤 Клиент: ${client.name}`;
});
bot.addCommand('crm_order', ['заказ', 'история заказов'], async (_, controller) => {
const orders = await this.crmClient.getOrders(controller.userId);
controller.text = `📦 Заказы: ${orders.length}`;
});
}
destroy(bot: Bot): void {
bot.removeCommand('crm_client');
bot.removeCommand('crm_order');
this.crmClient?.disconnect();
}
}
| Критерий | Без плагинов | С плагинами |
|---|---|---|
| Структура кода | Всё в одном файле | Модульная, по функциям |
| Повторное использование | Копипаст между проектами | Один плагин → много проектов |
| Тестирование | Тестировать всё вместе | Тестировать каждый плагин отдельно |
| Масштабирование | Сложно добавлять новое | Просто подключить новый плагин |
| Отключение функций | Нужно комментировать код | bot.clearUse() + новый плагин |
| Командная разработка | Конфликты в одном файле | Каждый работает в своём плагине |
| Ситуация | Использовать плагин |
|---|---|
| Большая кодовая база (>1000 строк) | ✅ Да |
| Несколько проектов с общей логикой | ✅ Да |
| Нужно включать/выключать функции | ✅ Да |
| Интеграция со сторонними API | ✅ Да |
| Командная разработка | ✅ Да |
Плагины превращают разработку приложения в конструктор: вы подключаете только те функции, которые нужны конкретному продукту, и можете легко переиспользовать код между проектами.
npm install umbot
npx umbot create my-bot
cd my-bot
npm install
npm run start
Сохраните токены в .env файл:
TELEGRAM_TOKEN=your-token
VK_TOKEN=your-token
VK_CONFIRMATION_TOKEN=your-token
YANDEX_TOKEN=your-token
# ... и другие токены
Затем укажите путь в конфигурации:
bot.setAppConfig({
env: './.env',
});
Проблема: В версии 3.0 произошел переход на плагинную архитектуру. Работа с платформами теперь осуществляется через адаптеры. Было (2.2.x):
import { Bot } from 'umbot';
const bot = new Bot();
bot.setPlatformParams(params);
bot.start('localhost', 3000);
Стало (3.0):
import { Bot } from 'umbot';
import { fullPlatforms, FileAdapter } from 'umbot/plugins';
const bot = new Bot()
.use(fullPlatforms) // Подключаем платформы как плагин
.use(new FileAdapter()) // Подключаем адаптер БД
.setPlatformParams(params)
.start('localhost', 3000);
Подробнее об изменениях можно прочитать тут
Важно: Версия 2.1.x содержит критическую архитектурную проблему. Обязательно обновитесь! Обновите пакет:
npm install umbot@2.2
Проверьте код на использование устаревших методов (они были удалены в 2.2.x)
npm list umbot
umbot в состоянии обработать любое количество команд, но важно понимать что большое количество команд, как правило,
говорит о не оптимальной архитектуре приложения.
Также при большом количестве команд, время ответа приложения будет увеличиваться.
Рекомендуется не использовать более 1000 команд в своем приложении.
| Количество команд | Время обработки (с re2) | Рекомендация |
|---|---|---|
| 50 | 0.06 мс | ✅ Отлично |
| 500 | 0.26 мс | ✅ Отлично |
| 1000 | < 30 мс | ✅ Хорошо |
| 10000 | < 1 сек | ⚠️ Проверьте сервер |
| 20000 | 22.44 мс | ⚠️ Используйте re2 |
re2 — это библиотека для работы с регулярными выражениями, которая:
Установка:
npm install --save re2
После установки umbot автоматически начнет использовать re2.
Node.js на Windows работает менее эффективно, чем на Unix-системах (Linux/macOS). Это может приводить к высокому потреблению памяти (до 4ГБ против 400МБ на Linux). Рекомендация: Для продакшена используйте Linux-сервер.
Не рекомендуется. Файловая БД (FileAdapter) хранит данные в оперативной памяти. При большом количестве записей (>10000) возможен Out of Memory и падение приложения.
Рекомендация: Используйте MongoAdapter или создайте свой адаптер:
import { MongoAdapter } from 'umbot/adapters';
bot.use(
new MongoAdapter({
host: 'mongodb://localhost:27017/my-bot',
database: 'bot_db',
user: 'user',
pass: '***',
}),
);
BaseDbAdapterisConnected, _select, _insert, _update, _removeuse:bot.use(new MyCustomAdapter(config));
Да, можно одновременно хранить данные как в локальном хранилище платформы, так и в вашей базе данных. Сделать это можно следующим образом:
import { Bot } from 'umbot';
import { FileAdapter } from 'umbot/plugins';
const bot = new Bot();
bot.use(new FileAdapter());
bot.addCommand('test', ['сохранить'], (_, cBot) => {
cBot.userData = {}; // Сохраняем данные в базу данных.
cBot.state = {}; // Сохраняем данные в локальное хранилище платформы.
// Ваша логика
});
Далее, при повторном запросе, данные из базы данных будут лежать в userData, а данные из платформы — в state.
При этом, важно учитывать тот факт, что логика с локальным хранилищем будет работать только в том случае, если сама
платформа поддерживает такое поведение.
Подобное сделать можно. Для этого напишите следующий код:
import { Bot } from 'umbot';
const bot = new Bot();
bot.setAppConfig({
isLocalStorage: true, // говорим что данные сохраняются в локальное хранилище платформы
});
bot.addCommand('test', ['сохранить'], (_, ctx) => {
ctx.userData = {}; // Сохраняем данные в хранилище платформы.
// Ваша логика
});
Обратите внимание, что используется userData, данная механика реализована для удобства работы в сценариях, когда не
подразумевается использование базы данных.
Также важно учитывать что задан isLocalStorage, без его указания, механика работать не будет.
Информация только для базовых адаптеров платформ. При использовании сторонних адаптеров, поведение может отличаться.
В случае, если происходит попытка записать данные в userData и в state, то поведение может быть следующим:
userData, будут сохранены в базу, а в локальное
хранилище запишется state.state.BasePlatformAdapterisPlatformOnQuery, setQueryData, getContentbot.use(new MyPlatformAdapter(token));
По умолчанию рекомендуется использовать fullPlatforms, который подключает все платформы. Для подключения конкретных
платформ выполните следующие действия:
import { TelegramPlatform, VkPlatform } from 'umbot/plugins';
// Подключаем телеграм и вк
bot.use(new TelegramPlatform(telegramToken)).use(new VkPlatform(vkToken));
Также не стоит забывать о том, что можно подключить только голосовые платформы(voicePlatforms), либо только платформы
для чат-ботов(botPlatforms)
Проверьте:
Да, и вот почему.
umbot — это не «мультиплатформенная надстройка», а полноценный фреймворк, который даёт преимущества уже на первом
проекте, даже если вы никогда не планируете добавлять другие каналы.
Что вы получите, используя umbot для одной платформы:
Пример для одной платформы (только Алиса):
import { Bot, BotController } from 'umbot';
import { AlisaAdapter } from 'umbot/plugins'; // адаптер для Алисы
const bot = new Bot();
bot.use(new AlisaAdapter()); // вместо fullPlatforms
// ... вся остальная логика остаётся без изменений
Никакого оверхеда — вы используете ровно то, что нужно. Фреймворк не заставляет вас подключать лишние платформы.
Итог: umbot не только подходит для одной платформы, но и делает разработку на одной платформе более структурированной, безопасной и готовой к масштабированию. Попробуйте — и вы увидите, что код стал чище, а времени на рутину уходит меньше.
Используйте класс BotTest:
import { BotTest } from 'umbot/test';
import { fullPlatforms } from 'umbot/plugins';
const bot = new BotTest();
bot.use(fullPlatforms);
bot.test(); // Запускает интерактивный режим в консоли
Логи сохраняются в директорию, указанную в error_log:
bot.setAppConfig({
error_log: './logs',
});
В режиме разработки (dev) ошибки также выводятся в консоль.
bot.setAppMode('dev');
Это означает, что входящий текст не совпал ни с одним слотом или командой. Проверьте:
Проблема: Файловая БД переполняется, из-за чего приложение в какой-то момент может упасть с ошибкой. Решение:
Платформы (Алиса, Сбер и др.) дают максимум 3 секунды на ответ. Оптимизация:
Проблема: В ваших регулярных выражениях обнаружена потенциальная уязвимость. Решение:
bot.setAppMode('strict_prod')Фреймворк автоматически проверяет регулярные выражения на уязвимости. В режиме strict_prod такие команды не регистрируются. Чтобы исправить:
Проверьте, что вы подключили нужные адаптеры (bot.use(new TelegramAdapter()) и т.д.).
Убедитесь, что запрос приходит на правильный URL и содержит корректные заголовки (например, X-Telegram-Bot-Api-Secret-Token для Telegram).
Для локального тестирования используйте BotTest — он автоматически подставляет тестовые данные.
Иногда может возникнуть ситуация, когда фреймворк не смог корректно определить тип платформы, либо вам необходимо
самостоятельно определять тип платформы.
В таком случае можно использовать bot.setPlatformResolver(...), метод позволит зарегистрировать кастомный обработчик
для определения типа платформы.
Как использовать:
bot.setPlatformResolver((query, headers, detect) => {
const platform = detect?.();
if (platform === 'telegram' && headers?.['x-force-vk']) {
return 'vk';
}
return platform;
});
Первым аргументом придет сам запрос от платформы, вторым заголовок, третьим придет функция обработчик со стандартной механикой определения платформы.
В случае если платформа определилась не корректно, рекомендуется использовать данную механику для проставления корректной платформы, после чего выписать bug-report с ошибкой, чтобы мы смогли оперативно ее поправить.
umbot автоматически проверяет регулярные выражения на уязвимости.
В строгом режиме все потенциально опасные RegExp будут отклоняться.
bot.getAppContext().httpClient = async (url, options) => {
// Ваша реализация
return fetch(url, options);
};
Да, через метод webhookHandle:
app.post('/webhook', (req, res) => {
bot.webhookHandle(req, res);
});
Это позволяет интегрировать приложение в существующее webhook.
// Вариант 1: объект
class MyI18nPlugin implements IPlugin {
init(appContext: AppContext<IDatabaseInfo>) {
appContext.plugins['i18n'] = {
getData(key: string, ...params: unknown[]): string {
return `Translated: ${key}`;
},
};
}
}
// Вариант 2: функция
const myNluPlugin: IPluginFn = (appContext: AppContext) => {
appContext.plugins['i18n'] = (input: string, ctx?: unknown) => ({
intent: 'default',
entities: {},
});
};
myNluPlugin.isPlugin = true; // маркер обязательного наличия
bot.use(i18n);