AbstractСоздает новый экземпляр контроллера. UI-компоненты (кнопки, карточки, звуки, NLU) инициализируются лениво — при первом обращении через соответствующие геттеры.
OptionalappContext: AppContext<IDatabaseInfo, unknown>Контекст приложения. Если не передан, будет создан новый AppContext
Контекст приложения.
Стиль обращения к пользователю. Определяет формальность общения, используется для платформ, которые поддерживают данное поведение.
Платформа, от которой был получен запрос.
Эмоция для голосового ответа. Используется для платформ, которые поддерживают данное поведение.
Универсальный тип события, вызвавшего запрос ('message', 'photo', 'callback', …).
Заполняется адаптером платформы. Позволяет различать не-текстовые апдейты
(фото, голосовые, нажатия кнопок) без ручного разбора requestObject.
Если платформа не проставила событие, значение — 'message'.
Флаг необходимости авторизации. Определяет, требуется ли авторизация пользователя или нет.
Флаг, определяющий необходимость завершения диалога. Актуально когда необходимо принудительно завершить диалог с пользователем. Поддержка работы флага зависит от платформы.
Определяет, запущено ли приложение с колонки или с устройства с экраном.
Флаг отправки запроса на оценку. Определяет, нужно ли запросить оценку у пользователя. Используется для платформ, которые поддерживают данное поведение.
ID сообщения.
На голосовых платформах (Алиса, Маруся) messageId === 0 означает начало
нового диалога — по этому признаку срабатывает welcome-интент. На чат-платформах
(Telegram, VK, Max, Viber) это ID конкретного сообщения, и поле может быть null.
Название предыдущего интента/команды, полученное из userData.oldIntentName
(а при включённом локальном хранилище и пустом userData — из
state.oldIntentName).
Используется для отслеживания контекста диалога.
КАК ЭТО РАБОТАЕТ:
this.thisIntentName сохраняется:
при включённом isLocalStorage и пустом userData — в state.oldIntentName,
иначе — в userData.oldIntentNamethis.oldIntentNameТИПИЧНОЕ ИСПОЛЬЗОВАНИЕ:
bot.addStep()// Пример: Многошаговая регистрация
class RegistrationBot extends BotController {
public action(intentName: string | null): void {
// Определяем на каком шаге находимся
const previousStep = this.oldIntentName;
if (previousStep === 'enter_name') {
// Пользователь только что ввел имя, спрашиваем email
this.userData.name = this.userCommand;
this.text = 'Отлично! Теперь введите ваш email:';
this.thisIntentName = 'enter_email'; // Сохранится для следующего шага
} else if (previousStep === 'enter_email') {
// Пользователь ввел email, завершаем регистрацию
this.userData.email = this.userCommand;
this.text = 'Регистрация завершена!';
}
}
}
// Пример: Кнопка "Назад"
if (intentName === 'back') {
// Возвращаемся к предыдущему шагу
switch(this.oldIntentName) {
case 'product_list':
this.text = 'Выберите категорию:';
break;
case 'category_list':
this.text = 'Добро пожаловать!';
break;
}
}
Оригинальный запрос пользователя. Текст запроса без изменений, включая регистр и знаки препинания.
Дополнительные параметры запроса. Может содержать любые дополнительные данные, полученные от платформы.
Дополнительные опции платформы. ⚠️ Внутреннее свойство. Заполняется адаптером платформы. Не предназначено для прямого использования в пользовательском коде.
Полученный запрос от платформы. Содержит оригинальный объект запроса.
Флаг, указывающий, что ответ уже отправлен через API и не требуется автоматическая отправка. Как правило, данный флаг стоит использовать для платформ, которые не ждут ответ в виде возвращаемого содержимого, а ожидают что к самой платформе будет отправлен запрос. Например, чат-бот для Telegram, для отображения результата пользователю, отправляется запрос к платформе с нужным содержимым.
Пользовательское локальное хранилище.
Используется для временного хранения данных, специфичных для текущего диалога.
Работает только при включённой опции isLocalStorage: true в конфигурации.
bot.setAppConfig({
isLocalStorage: true,
});
Правила синхронизации с базой данных (если подключена):
userData, и state: userData сохраняется в БД,
а state — в локальное хранилище платформы.userData (а state пуст или совпадает с ним):
при использовании локального хранилища данные уходят только в него
(в БД не сохраняются), без локального хранилища — только в БД.state (userData пуст): перед формированием
ответа userData подменяется на state, поэтому state уходит
в локальное хранилище платформы, а без него — в БД.При загрузке данных:
userData, и в state (у Алисы и Маруси это
один и тот же объект); данные из БД при этом не читаются.userData;
state остаётся тем, что прислала платформа (у чат-платформ — null).userData — для постоянного хранения данных пользователя.
Текст, который будет отображен пользователю. Основной способ коммуникации с пользователем, так как именно этот текст пользователь увидит в интерфейсе.
Название текущего интента. Определяет следующий шаг диалога.
Текст, который пользователь может услышать. Для голосовых платформ, озвучка будет произведена силами самой платформы, для не голосовых платформ, поведение зависит непосредственно от реализации адаптера. Так для некоторых стандартных адаптеров, в случае заполнения поля и указания токена yandex SpeechKit, будет отправлен запрос на преобразование текста в аудиофайл, после чего аудиофайл будет отправлен пользователю.
Запрос пользователя в нижнем регистре.
Пользовательские данные, которые были сохранены.
⚠️ Мутируйте отдельные поля (this.userData.name = ...), а не
переприсваивайте объект целиком (this.userData = {...}) — фреймворк
хранит ссылку на исходный объект, и переприсваивание разрывает её.
Пользовательские события. Содержит информацию об авторизации или оценке.
Уникальный идентификатор пользователя.
Дополнительная информация о пользователе.
Пользовательский токен авторизации. Заполняется адаптером Алисы (access_token из account linking после авторизации пользователя). Читайте его для запросов к внешним API, требующим авторизации пользователя.
API активной платформы: отправка медиа и ответов на callback-кнопки без ручного конструирования платформенных Request-классов.
Доступно на чат-платформах (Telegram, VK, MAX, Viber с оговорками);
на голосовых (Алиса, Маруся, SmartApp) — null: их ответ формируется
телом webhook, используйте card/sound.
Компонент для отображения различных кнопок пользователю. Позволяет создавать интерактивные элементы управления в приложении.
Компонент для отображения карточек пользователю. Позволяет создавать визуальные элементы с изображениями и текстом. Также при указании нескольких изображений, они автоматически преобразуются в карточку.
// КАТАЛОГ ТОВАРОВ (интернет-магазин):
this.text = 'Популярные товары:';
this.card
.addImage(
'http://localhost/iphone.jpg',
'iPhone 15 Pro',
'99 990 ₽\nЭкран 6.1", процессор A17 Pro'
)
.addButton('Купить')
.addImage(
'http://localhost/macbook.jpg',
'MacBook Air M2',
'124 990 ₽\n13.6", 8ГБ RAM, 256ГБ SSD'
)
.addButton('Купить');
// ГАЛЕРЕЯ ФОТОГРАФИЙ:
this.text = 'Наши работы:';
this.card
.addImage('photo1.jpg', 'Свадьба', 'Иван и Мария')
.addImage('photo2.jpg', 'Выпускной', 'Школа №123')
.addImage('photo3.jpg', 'Корпоратив', 'Компания "Рога и копыта"');
// КАРТОЧКИ НОВОСТЕЙ:
this.card
.addImage(
'news1.jpg',
'Новое обновление',
'Добавлена оплата картой и доставка',
{
title: 'Перейти',
url: 'http://localhost/news/1'
}
)
Результат совпадения команды с регулярным выражением.
Заполняется лениво при первом обращении: фреймворк запоминает регулярку
сработавшей команды (RegExp-слот, isPattern-паттерн или группу регулярок)
и прогоняет её по тексту только если обработчик реально читает match.
Содержит RegExpExecArray совпавшей регулярки — группы доступны как
this.match[1], this.match.groups. Для строковых команд и событий — null.
Обработанный NLU (Natural Language Understanding). Содержит результаты обработки естественного языка, как правило, данные заполняются самой платформой.
Компонент для работы со звуками. Позволяет добавлять звуковые эффекты и музыку. Используется вместе с tts.
Protected_actionMetricЗапуск обработки пользовательских команд с учетом метрик.
Имя команды
Является ли обработка командой (а не шагом)
Является ли обработка шагом диалога
Protected_getCommandИзвлекает нужную команду из запроса.
результат выполнения обработчика найденной команды или null, если подходящая команда не найдена
Protected_getIntentНаходит нужный интент по тексту запроса.
Текст запроса
Название интента или null
Protected_intentsAbstractactionОсновной метод, в котором вы реализуете логику вашего голосового навыка или бота.
Этот метод вызывается фреймворком автоматически после того, как запрос пользователя
был распознан как команда, интент или шаг диалога.
В параметр intentName передаётся имя команды.
Флаги isCommand и isStep позволяют различить источник вызова.
Используется для более глубокой логики приложения, например можно использовать в качестве логирования, если все обработчики реализованы через команды.
Либо использовать в качестве обработки команд, что не рекомендуется, так как из-за подобного подхода, размер метода может быть большим.
Метод необходимо обязательно реализовать в дочерних классах.
⚠️ Метод вызывается синхронно: фреймворк не дожидается возвращаемого значения.
Не объявляйте его async — всё, что выполнится после первого await, не попадёт
в ответ пользователю. Если action() всё же вернёт Promise, фреймворк напишет
предупреждение в лог, а ошибки промиса будут залогированы вместо unhandledRejection.
Для асинхронной логики используйте addCommand/addStep — их колбэки фреймворк ожидает.
Название интента или команды
OptionalisCommand: booleanФлаг, указывающий что это команда
OptionalisStep: booleanФлаг, указывающий что это шаг
// Пример с обработкой интентов
class MyController extends BotController {
public action(intentName: string | null): void {
if (intentName === 'greeting') {
this.text = 'Привет!';
} else if (intentName === 'help') {
this.text = 'Помощь:';
this.buttons.addBtn('Назад');
}
}
}
// Пример с логированием
class MyController extends BotController {
public action(intentName: string | null, isCommand?: boolean, isStep?: boolean): void {
console.log(`Прошли по ${isCommand ? 'команде' : isStep ? 'шагу' : 'интенту'} с именем: ${intentName}`);
}
}
Полностью сбрасывает состояние контроллера, включая текст ответа, пользовательские данные, состояние диалога и внутренние флаги.
Флаг возвращающий информацию о том, были ли инициализированы кнопки или нет
true если кнопки были инициализированы
Флаг возвращающий информацию о том, были ли инициализированы карточки или нет
true если карточки были инициализированы
Метод: возвращает true, только если объект Nlu уже создан (было обращение
к геттеру nlu). Вызов setThisUser сам по себе объекта
не создаёт: при неинициализированном Nlu данные буферизуются в
#thisUserBuffer и применятся при первом же обращении к геттеру.
true если объект NLU был инициализирован
Флаг возвращающий информацию о том, были ли инициализированы звуки или нет
true если звуки были инициализированы
Основной метод обработки запроса, вызываемый автоматически фреймворком.
Может быть асинхронным
Как это работает:
run() определяет тип запроса (команда/интент/шаг)action() с результатомtext, buttons, card)Не вызывайте run() вручную и не переопределяйте его —
для своей логики переопределяйте только action().
Порядок обработки внутри run():
run()
├── Шаг 0: Вызывает событийные обработчики (bot.addEvent) по controller.eventType
│ → Обработчик не вернул false → обработка завершена (action(eventType))
├── Шаг 1: Проверяет есть ли активный шаг
│ → Если есть → вызывает action(stepName, false, true)
├── Шаг 2: Ищет команду
│ → Если нашел → вызывает action(commandName, true, false)
├── Шаг 3: Ищет интент (включая welcome/help)
│ → Если нашел → вызывает action(intentName, false, false)
│ → welcome-интент: messageId === 0 (начало диалога) и fallback-команда
│ не зарегистрирована
└── Шаг 4: Если интент не найден → fallback-команда ("*"), если зарегистрирована.
Fallback проверяется раньше welcome и имеет над ним приоритет —
welcome при messageId === 0 срабатывает, только если fallback не зарегистрирован
// ВАШ КОД (контроллер):
class MyController extends BotController {
public action(intentName: string | null): void {
// Ваша логика здесь
this.text = "Ответ пользователю";
}
}
// КОД ФРЕЙМВОРКА (не ваш):
// Когда приходит запрос от пользователя:
const controller = new MyController();
{...}; // Наполняет контроллер данными. Как правило, этим занимается адаптер платформы
await controller.run(); // Автоматически вызывает ваш action()
const response = ...; // Адаптер формирует ответ в зависимости от состояния контроллера
Устанавливает контекст приложения (обновляет контекст в уже созданных
компонентах buttons и card).
Контекст приложения
Текущий экземпляр для цепочки вызовов
Записывает данные отправителя сообщения (username/имя/фамилия) в NLU.
Используется адаптерами чат-платформ (через хелпер setThisUserToNlu
из pUtils). Значение сначала держится в приватном буфере: если логика
приложения ни разу не обратится к nlu, объект Nlu и его кэш
не создаются вовсе. При первом обращении буфер переносится в Nlu
(nlu.getUserName() возвращает переданные данные).
Данные отправителя; пустые поля интерпретируются как отсутствие данных
Текущий экземпляр для цепочки вызовов
Контроллер приложения – главный класс для реализации единой бизнес-логики вашего приложения. Именно в этом классе обрабатывается вся логика вашего приложения, которая потом передается в саму платформу, будь то голосовой навык для Алисы, либо чат-бот для VK.
Этот класс связывает входящие запросы от пользователя с вашей бизнес‑логикой. Вы наследуетесь от
BotController, переопределяете метод action и получаете доступ ко всем инструментам: кнопкам, карточкам, состоянию диалога, пользовательским данным, NLU и многому другому.Адаптеры платформ (например,
AlisaAdapter) автоматически наполняют контроллер данными, вызывают метод run (он вызывает вашaction()), а затем формируют ответ на основе заполненных вами полей (text,buttons,cardи т.д.).Ключевая особенность: вся логика вашего голосового навыка или бота описывается в одном месте – в методе
action(). Фреймворк сам позаботится о маршрутизации: команды, интенты, шаги диалога – всё придёт вactionс соответствующим флагом.Remarks
Основные возможности:
Example
See