Разработка бота


Это часть серии статей, посвященной созданию исходящего обзвона с использованием CAILA.

  1. Настройка подключения
  2. Разработка бота (вы находитесь здесь)
  3. Запуск обзвона
  4. Аналитика по диалогам
  5. Расширение сценария
  6. Тестирование

На данном этапе создадим сценарий бота. В скриптовых вставках мы будем обращаться к различным методам объекта $dialer для взаимодействия с телефонией. Для понимания естественного языка воспользуемся CAILA.

Конфигурационный файл

Перейдите в Редактор и создайте стандартный для проектов на CAILA конфигурационный файл chatbot.yaml:

name: call-campaign
entryPoint: main.sc

botEngine: v2
language: ru

sts:
    noMatchThreshold: 0.2
nlp:
    intentNoMatchThresholds:
        phrases: 0.2
        patterns: 0.2

Основная часть сценария

Создайте файл src/main.sc и поместите в корневую тему theme основную логику сценария:

theme: /

    state: Start
        q!: $regex</start>
        script:
            $jsapi.startSession();
            $session.userName = $dialer.getPayload().name || "незнакомец";
            $dialer.setCallResult("Приветствие");

        a: Приветствую вас, {{$session.userName}}!
        a: В связ+и с пандемией коронавируса, мировое правительство проводит информирование граждан.
        go!: /Симптомы

    state: Симптомы
        a: Скажите, наблюдаете ли вы за собой высокую температуру т+ела, сухой кашель, быструю утомляемость?

        state: Есть
            intent: /Согласие
            intent: /Болен
            a: В таком случае вам нужна срочная медицинская помощь! Немедленно обратитесь к врачу.
            script:
                $dialer.reportData("Анамнез", "положительный");
                $dialer.setCallResult("Состояние известно");
            go!: /Прощание

        state: Нет
            intent: /Отказ
            intent: /Здоров
            a: Очень рада, что всё в порядке! Тем не менее, не забывайте мыть руки и носить маски и перчатки.
            script:
                $dialer.reportData("Анамнез", "отрицательный");
                $dialer.setCallResult("Состояние известно");
            go!: /Прощание

        state: Ответ
            event!: noMatch
            a: Так и записала: {{$parseTree.text}}. Помните о гигиене и о средствах индивидуальной защиты.
            script:
                $dialer.reportData("Анамнез", $parseTree.text);
                $dialer.setCallResult("Состояние известно");
            go!: /Прощание

    state: Прощание
        event!: hangup
        a: Будьте здоровы! До свидания!
        script:
            $dialer.hangUp();

    state: NoInput || noContext = true
        event!: speechNotRecognized
        script:
            $session.noInputCounter = $session.noInputCounter || 0;
            $session.noInputCounter++;
        if: $session.noInputCounter >= 3
            a: Кажется, проблемы со связью.
            script:
                $dialer.setCallResult("Плохое качество связи");
            go!: /Прощание
        else:
            a: Вас плохо слышно. Повторите, пожалуйста!

Создайте также файл test/test.xml, но пока оставьте его пустым:

<test>
  <test-case/>
</test>

Начало диалога

Технический запуск бота при дозвоне происходит по команде /start, которую можно обработать паттерном для регулярных выражений. В обработчике данного активатора бот:

Используйте спецсимвол + в словах, которые могут читаться по-разному, для корректной постановки ударения в контексте фразы: В связ+и.

  1. Помечает сессию как новую и очищает данные предыдущих сессий, если они были.
  2. Извлекает имя клиента из списка клиентов и сохраняет его в хранилище сессионных данных.
  3. Устанавливает результат звонка, соответствующий текущему шагу диалога.

Если информация об имени клиента отсутствует, используется нейтральное обращение.

state: Start
    q!: $regex</start>
    script:
        $jsapi.startSession();
        $session.userName = $dialer.getPayload().name || "незнакомец";
        $dialer.setCallResult("Приветствие");

    a: Приветствую вас, {{$session.userName}}!
    a: В связ+и с пандемией коронавируса, мировое правительство проводит информирование граждан.
    go!: /Симптомы

Подробнее о методах $jsapi.startSession, $dialer.getPayload и $dialer.setCallResult

Запись ответа от клиента в отчет

В стейтах, вложенных в стейт /Симптомы, обрабатываются различные ответы на вопрос о самочувствии — положительный, отрицательный и нераспознанный. В каждом случае бот записывает ответ клиента в отчет по обзвону в колонку Анамнез. В случае нераспознанного ответа он будет записан в отчет как есть.

state: Симптомы
    a: Скажите, наблюдаете ли вы за собой высокую температуру т+ела, сухой кашель, быструю утомляемость?

    state: Есть
        intent: /Согласие
        intent: /Болен
        a: В таком случае вам нужна срочная медицинская помощь! Немедленно обратитесь к врачу.
        script:
            $dialer.reportData("Анамнез", "положительный");
            $dialer.setCallResult("Состояние известно");
        go!: /Прощание

    state: Нет
        intent: /Отказ
        intent: /Здоров
        a: Очень рада, что всё в порядке! Тем не менее, не забывайте мыть руки и носить маски и перчатки.
        script:
            $dialer.reportData("Анамнез", "отрицательный");
            $dialer.setCallResult("Состояние известно");
        go!: /Прощание

    state: Ответ
        event!: noMatch
        a: Так и записала: {{$parseTree.text}}. Помните о гигиене и о средствах индивидуальной защиты.
        script:
            $dialer.reportData("Анамнез", $parseTree.text);
            $dialer.setCallResult("Состояние известно");
        go!: /Прощание

Подробнее о методе $dialer.reportData

Окончание диалога

На последнем шаге бот прощается и завершает звонок.

state: Прощание
    event!: hangup
    a: Будьте здоровы! До свидания!
    script:
        $dialer.hangUp();

Клиент также попадет в этот стейт, если повесит трубку без ответа на вопрос. Информация о статусе звонка и состоянии здоровья клиента в таком случае обновлена не будет.

Обработка нераспознанных фраз

Технический стейт NoInput обрабатывает ситуации, когда запрос клиента распознать невозможно. Если попаданий в этот стейт больше порогового значения, бот вешает трубку.

state: NoInput || noContext = true
    event!: speechNotRecognized
    script:
        $session.noInputCounter = $session.noInputCounter || 0;
        $session.noInputCounter++;
    if: $session.noInputCounter >= 3
        a: Кажется, проблемы со связью.
        script:
            $dialer.setCallResult("Плохое качество связи");
        go!: /Прощание
    else:
        a: Вас плохо слышно. Повторите, пожалуйста!

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

hangup и speechNotRecognized — одни из системных событий, поддерживаемых для телефонии.

Настройка интентов

Перейдите на вкладку CAILA > Интенты и создайте интенты, которые мы использовали в сценарии: /Согласие, /Отказ, /Здоров и /Болен. Наполните их тренировочными фразами, передающими соответствующий смысл, например:

Согласие да ага очень даже наблюдаю
Отказ неа отнюдь вовсе нет не наблюдаю
Здоров я здорова проблем нет мы в порядке все слава богу
Болен болею я больна высокая температура у меня коронавирус

Тренировочные фразы для интента /Здоров

После заполнения интентов нажмите на кнопку Тестировать, чтобы обучить классификатор новым интентам.


Теперь все готово для того, чтобы создать и запустить обзвон.