umbot
    Preparing search index...

    Class BaseBotController<TUserData, TPlatformState>

    Контроллер для обработки запросов приложения по умолчанию. Используется в качестве контроллера по умолчанию, и позволяет не создавать свой контроллер, если вся обработка команд или шагов осуществляется через bot.addCommand или bot.addStep.

    Стандартные команды (приветствие и помощь) обрабатываются конвейером BotController (тексты welcome_text/help_text и интенты welcome/help), а не этим action(). Обработка в action происходит только в том случае, если не была обработана ни одна команда или шаг.

    Type Parameters

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    appContext: AppContext

    Контекст приложения.

    appeal: "official" | "no_official" | null = null

    Стиль обращения к пользователю. Определяет формальность общения, используется для платформ, которые поддерживают данное поведение.

    Возможные значения:

    • 'official': официальное обращение
    • 'no_official': неофициальное обращение
    • null: стиль не определен
    this.appeal = 'official'; // официальное обращение
    
    appType: string | null = null

    Платформа, от которой был получен запрос.

    emotion: string | null = null

    Эмоция для голосового ответа. Используется для платформ, которые поддерживают данное поведение.

    this.emotion = 'good';
    
    eventType: TEventType = 'message'

    Универсальный тип события, вызвавшего запрос ('message', 'photo', 'callback', …).

    Заполняется адаптером платформы. Позволяет различать не-текстовые апдейты (фото, голосовые, нажатия кнопок) без ручного разбора requestObject. Если платформа не проставила событие, значение — 'message'.

    // В action() или обработчике команды:
    if (this.eventType === 'photo') {
    this.text = 'Отличное фото!';
    }
    isAuth: boolean = false

    Флаг необходимости авторизации. Определяет, требуется ли авторизация пользователя или нет.

    this.isAuth = true; // требуется авторизация
    
    isEnd: boolean = false

    Флаг, определяющий необходимость завершения диалога. Актуально когда необходимо принудительно завершить диалог с пользователем. Поддержка работы флага зависит от платформы.

    this.isEnd = true; // завершить диалог
    
    isScreen: boolean = false

    Определяет, запущено ли приложение с колонки или с устройства с экраном.

    this.isScreen = true; // экран доступен
    
    isSendRating: boolean = false

    Флаг отправки запроса на оценку. Определяет, нужно ли запросить оценку у пользователя. Используется для платформ, которые поддерживают данное поведение.

    this.isSendRating = true; // запросить оценку
    
    messageId: string | number | null = null

    ID сообщения. На голосовых платформах (Алиса, Маруся) messageId === 0 означает начало нового диалога — по этому признаку срабатывает welcome-интент. На чат-платформах (Telegram, VK, Max, Viber) это ID конкретного сообщения, и поле может быть null.

    this.messageId = 12345;
    
    oldIntentName: string | null = null

    Название предыдущего интента/команды, полученное из userData.oldIntentName (а при включённом локальном хранилище и пустом userData — из state.oldIntentName). Используется для отслеживания контекста диалога.

    КАК ЭТО РАБОТАЕТ:

    1. В конце обработки каждого запроса this.thisIntentName сохраняется: при включённом isLocalStorage и пустом userData — в state.oldIntentName, иначе — в userData.oldIntentName
    2. При следующем запросе это значение копируется в this.oldIntentName
    3. Используется для определения, с какого шага продолжить диалог

    ТИПИЧНОЕ ИСПОЛЬЗОВАНИЕ:

    • Возврат к предыдущему шагу
    • Многошаговые формы ("вернуться назад")
    • Диалоги с контекстом
    • Использование в шагах 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;
    }
    }
    originalUserCommand: string | null = null

    Оригинальный запрос пользователя. Текст запроса без изменений, включая регистр и знаки препинания.

    this.originalUserCommand = 'Привет, мир!';
    
    payload: string | Record<string, unknown> | null | undefined = null

    Дополнительные параметры запроса. Может содержать любые дополнительные данные, полученные от платформы.

    this.payload = {
    source: 'mobile',
    version: '1.0'
    };
    platformOptions: IPlatformOptions = {}

    Дополнительные опции платформы. ⚠️ Внутреннее свойство. Заполняется адаптером платформы. Не предназначено для прямого использования в пользовательском коде.

    requestObject: unknown = null

    Полученный запрос от платформы. Содержит оригинальный объект запроса.

    this.requestObject = {
    command: 'start',
    payload: { source: 'mobile' }
    };
    skipAutoReply: boolean = false

    Флаг, указывающий, что ответ уже отправлен через API и не требуется автоматическая отправка. Как правило, данный флаг стоит использовать для платформ, которые не ждут ответ в виде возвращаемого содержимого, а ожидают что к самой платформе будет отправлен запрос. Например, чат-бот для Telegram, для отображения результата пользователю, отправляется запрос к платформе с нужным содержимым.

    Если указано true, значит все необходимые запросы уже отправлены в логике приложения, и дополнительно пользователю ничего отправлять не нужно.

    this.skipAutoReply = true; // запросы уже отправлены
    
    state: TPlatformState | null = null

    Пользовательское локальное хранилище. Используется для временного хранения данных, специфичных для текущего диалога. Работает только при включённой опции isLocalStorage: true в конфигурации. bot.setAppConfig({ isLocalStorage: true, });

    Правила синхронизации с базой данных (если подключена):

    • Если заполнены и userData, и state: userData сохраняется в БД, а state — в локальное хранилище платформы.
    • Если заполнен только userDatastate пуст или совпадает с ним): при использовании локального хранилища данные уходят только в него (в БД не сохраняются), без локального хранилища — только в БД.
    • Если заполнен только state (userData пуст): перед формированием ответа userData подменяется на state, поэтому state уходит в локальное хранилище платформы, а без него — в БД.

    При загрузке данных:

    1. Если используется локальное хранилище платформы, его запись сразу записывается и в userData, и в state (у Алисы и Маруси это один и тот же объект); данные из БД при этом не читаются.
    2. Без локального хранилища данные пользователя читаются из БД в userData; state остаётся тем, что прислала платформа (у чат-платформ — null).

    userData — для постоянного хранения данных пользователя.

    this.state = {
    lastIntent: 'greeting',
    step: 1
    };
    text: string = ''

    Текст, который будет отображен пользователю. Основной способ коммуникации с пользователем, так как именно этот текст пользователь увидит в интерфейсе.

    this.text = 'Привет! Чем могу помочь?';
    
    thisIntentName: string | null = null

    Название текущего интента. Определяет следующий шаг диалога.

    this.thisIntentName = 'help';
    
    tts: string | null = null

    Текст, который пользователь может услышать. Для голосовых платформ, озвучка будет произведена силами самой платформы, для не голосовых платформ, поведение зависит непосредственно от реализации адаптера. Так для некоторых стандартных адаптеров, в случае заполнения поля и указания токена yandex SpeechKit, будет отправлен запрос на преобразование текста в аудиофайл, после чего аудиофайл будет отправлен пользователю.

    this.tts = 'Привет! Я голосовой ассистент.';
    
    userCommand: string | null = null

    Запрос пользователя в нижнем регистре.

    this.userCommand = 'привет мир';
    
    userData: TUserData = ...

    Пользовательские данные, которые были сохранены.

    ⚠️ Мутируйте отдельные поля (this.userData.name = ...), а не переприсваивайте объект целиком (this.userData = {...}) — фреймворк хранит ссылку на исходный объект, и переприсваивание разрывает её.

    // Тип контроллера с дженериком:
    // class MyController extends BotController<MyUserData> { ... }
    this.userData.name = 'John';
    this.userData.score += 1;
    this.userData.preferences = { language: 'ru' };
    userEvents: IUserEvent | null = null

    Пользовательские события. Содержит информацию об авторизации или оценке.

    IUserEvent

    this.userEvents = {
    auth: { status: true },
    rating: { status: true, value: 5 }
    };
    userId: string | number | null = null

    Уникальный идентификатор пользователя.

    this.userId = 'user_123';    // Telegram (string)
    this.userId = 123456789; // VK (number)
    this.userId = null; // не удалось получить информацию
    userMeta: unknown = null

    Дополнительная информация о пользователе.

    this.userMeta = {
    timezone: 'Europe/Moscow',
    locale: 'ru-RU'
    };
    userToken: string | null = null

    Пользовательский токен авторизации. Заполняется адаптером Алисы (access_token из account linking после авторизации пользователя). Читайте его для запросов к внешним API, требующим авторизации пользователя.

    this.userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
    

    Accessors

    • get api(): IControllerApi | null

      API активной платформы: отправка медиа и ответов на callback-кнопки без ручного конструирования платформенных Request-классов.

      Доступно на чат-платформах (Telegram, VK, MAX, Viber с оговорками); на голосовых (Алиса, Маруся, SmartApp) — null: их ответ формируется телом webhook, используйте card/sound.

      Returns IControllerApi | null

      bot.addEvent('photo', async (ctx) => {
      await ctx.api?.sendPhoto('answer.jpg', { caption: 'Вот ваш отчёт' });
      ctx.skipAutoReply = true; // ответ уже отправлен вручную
      });
    • get buttons(): Buttons

      Компонент для отображения различных кнопок пользователю. Позволяет создавать интерактивные элементы управления в приложении.

      Returns Buttons

      • Навигация по меню
      • Быстрые ответы (Да/Нет)
      • Выбор из вариантов
      • Быстрое действие/команда

      Buttons

      this.buttons
      .addBtn('Помощь')
      .addBtn('Выход');
    • get card(): Card

      Компонент для отображения карточек пользователю. Позволяет создавать визуальные элементы с изображениями и текстом. Также при указании нескольких изображений, они автоматически преобразуются в карточку.

      Returns Card

      • Каталог товаров/услуг
      • Галерея изображений
      • Карточки статей/новостей
      • Навигация

      Card

      // КАТАЛОГ ТОВАРОВ (интернет-магазин):
      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'
      }
      )
    • get match(): RegExpExecArray | null

      Результат совпадения команды с регулярным выражением.

      Заполняется лениво при первом обращении: фреймворк запоминает регулярку сработавшей команды (RegExp-слот, isPattern-паттерн или группу регулярок) и прогоняет её по тексту только если обработчик реально читает match. Содержит RegExpExecArray совпавшей регулярки — группы доступны как this.match[1], this.match.groups. Для строковых команд и событий — null.

      Returns RegExpExecArray | null

      bot.addCommand('order', [/(?:заказ|купить)\s+(\d+)/], (_, ctx) => {
      ctx.text = `Оформляю заказ №${ctx.match?.[1]}`;
      });
    • get nlu(): Nlu

      Обработанный NLU (Natural Language Understanding). Содержит результаты обработки естественного языка, как правило, данные заполняются самой платформой.

      Returns Nlu

      Nlu

    • get sound(): Sound

      Компонент для работы со звуками. Позволяет добавлять звуковые эффекты и музыку. Используется вместе с tts.

      Returns Sound

      Sound

    Methods

    • Запуск обработки пользовательских команд с учетом метрик.

      Parameters

      • commandName: string | null

        Имя команды

      • isCommand: boolean = false

        Является ли обработка командой (а не шагом)

      • isStep: boolean = false

        Является ли обработка шагом диалога

      Returns void

    • Извлекает нужную команду из запроса.

      Returns void | Promise<void | null> | null

      результат выполнения обработчика найденной команды или null, если подходящая команда не найдена

    • Находит нужный интент по тексту запроса.

      Parameters

      • text: string | null

        Текст запроса

      Returns string | null

      Название интента или null

    • Обработка запроса по умолчанию. Вызывается фреймворком последним, после поиска команд и шагов. Если команда или шаг уже обработали запрос (isCommand/isStep = true), метод просто применяет i18n и выходит. Если ничего не подошло — устанавливает текст из platformParams.empty_text (только если text пуст, if (!this.text)), затем применяет i18n.

      Parameters

      • intentName: string | null

        Имя сработавшего интента/команды/шага. null если ничего не найдено.

      • OptionalisCommand: boolean

        true если запрос обработан командой из addCommand

      • OptionalisStep: boolean

        true если запрос обработан шагом из addStep

      Returns void

    • Полностью сбрасывает состояние контроллера, включая текст ответа, пользовательские данные, состояние диалога и внутренние флаги.

      Returns void

      // Вызывается фреймворком автоматически перед следующим запросом;
      // вручную — чтобы переиспользовать контроллер в тестах:
      controller.clearStoreData();
      console.log(controller.text); // ''
    • Флаг возвращающий информацию о том, были ли инициализированы кнопки или нет

      Returns boolean

      true если кнопки были инициализированы

    • Флаг возвращающий информацию о том, были ли инициализированы карточки или нет

      Returns boolean

      true если карточки были инициализированы

    • Метод: возвращает true, только если объект Nlu уже создан (было обращение к геттеру nlu). Вызов setThisUser сам по себе объекта не создаёт: при неинициализированном Nlu данные буферизуются в #thisUserBuffer и применятся при первом же обращении к геттеру.

      Returns boolean

      true если объект NLU был инициализирован

    • Флаг возвращающий информацию о том, были ли инициализированы звуки или нет

      Returns boolean

      true если звуки были инициализированы

    • Основной метод обработки запроса, вызываемый автоматически фреймворком.

      Returns void | Promise<void>

      Может быть асинхронным

      Как это работает:

      1. Пользователь отправляет сообщение → платформа → Bot.run()
      2. run() определяет тип запроса (команда/интент/шаг)
      3. Вызывается ваш метод action() с результатом
      4. Вы заполняете поля ответа (text, buttons, card)
      5. Bot отправляет ответ пользователю

      Не вызывайте 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).

      Parameters

      • appContext: AppContext

        Контекст приложения

      Returns this

      Текущий экземпляр для цепочки вызовов

    • Записывает данные отправителя сообщения (username/имя/фамилия) в NLU.

      Используется адаптерами чат-платформ (через хелпер setThisUserToNlu из pUtils). Значение сначала держится в приватном буфере: если логика приложения ни разу не обратится к nlu, объект Nlu и его кэш не создаются вовсе. При первом обращении буфер переносится в Nlu (nlu.getUserName() возвращает переданные данные).

      Parameters

      • thisUser: INluThisUser

        Данные отправителя; пустые поля интерпретируются как отсутствие данных

      Returns this

      Текущий экземпляр для цепочки вызовов

      // Внутри адаптера платформы:
      controller.setThisUser({ username: 'ivan', first_name: 'Иван', last_name: null });
      // ...позже в бизнес-логике:
      const name = this.nlu.getUserName()?.first_name;