Skip to content
Задание для сертификации партнеров JAICP
Share
Explore
Разработка

icon picker
Сценарий чат-бота

Приветствие.

Начало общения пользователя с туристическим ботом Мария реализовано в стейте Welcome , в папке main.sc.
При помощи созданного командой разработки именованного паттерна $greeting чат-бот готов распознать большинство приветственных фраз:
Далее происходит проверка имени пользователя при помощи переменной $client.name. В случае, если человек уже обращался, ответное приветствие будет по имени. Если написал новый пользователь представление чат-бота не будет персонализировано.
Далее бот переходит в тему /Menu.

Входной сценарий.

Блок входного сценария отвечает за глобальные стейты и интенты, в нем содержится тема Menu.
Стейт CatchAll регулирует работу чат-бота с нераспознанными репликами пользователя (noMatch).
Реализовано две возможности в любом месте диалога. Если фраза непонятна боту:
а) чат-бот переспрашивает;
б) просит перефразировать вопрос.
Глобальный стейт отказа Cancel или отмены
позволяет отказаться и выйти из диалога при помощи следующих фраз, прописанных в паттернах и интентах:
Стейт Bye срабатывает, когда пользователь хочет попрощаться:
для этого собраны самые популярные слова прощания в паттерне $goodbye:
В стейтах Bye и CatchAll проставляется через двойную черту флаг noContext = true, чтобы при переходе в стейт для обработки нераспознанных ответов система не переключалась на контекст этого стейта и была возможность вернуться в контекст предыдущего стейта.
Прощание разделено на два стейта - по инициативе пользователя - Exit и после оправки заявки в турагенство “Just tour” - End. В обоих случаях происходит завершение диалога и выбор пользователя удаляется из переменной $session.
Во входном блоке содержится тема /Menu, которая разделяется на два крупных стейта - Begin и Choose. Begin представляет туристического бота “Just tour” и рассказывает о нем, а в стейте Choose пользователь может выбрать оформление тура (переход к теме /trip) или прогнозу погоды (переход к теме /Weather). Отдельным стейтом NoSure отрабатываются сомнения неопределившихся пользователей, переводя их в начало оформления заявки на тур.
Переменная {Session.place.name} позволяет записывать координаты города, для последующей отправки по API в сервис погоды для точного прогноза.

Дальнейшее общение с пользователем переходит в одну из двух веток - запрос погоды или оформления тура.

Запрос погоды.

В файле weather.sc находится тема Weather. Для того, чтобы попасть в начальное состояние Begin, пользователь может задать вопрос о погоде из любого места сценария:
Снимок экрана 2022-12-07 в 23.54.16.png
Если в запросе пользователя есть сущность место, сверяем со справочниками Города и Страны. Справочники находятся в отдельных документах cities.csv и countries.csv в папке dicts. В файле localPatterns.sc в паттерны $Сity и $Country подгружаются значения из словарей.
Если есть совпадение, сохраняем название и координаты:
Снимок экрана 2022-12-08 в 0.11.27.png
Функция getLocation, которая находится в файле func.js, извлекает название города или страны и их координаты и сохраняет в сессионные переменные
Снимок экрана 2022-12-08 в 0.18.32.png
Если город или страна записаны в сессионные переменные, идем в состояние AskCityInCountry. Если нет, то проверяем есть ли город или страна в заявке на тур в сессионной переменной session.tripPlace. Если там есть значение, то сохраняем значение в сессионную переменную session.place и переходим в состояние AskCityInCountry. Если ни город, ни страна неизвестны, спрашиваем, где нужно посмотреть погоду.
Снимок экрана 2022-12-08 в 20.08.49.png
В состоянии AskCityInCountry проверяется, страна или город введены в запросе и нужно ли уточнить город. Если сохранён город, идем на шаг 2 запрашивать дату. Если страна, то просим назвать город и переходим в состояние AskCity. Для названия страны используется переменная session.place.nameSC, а не session.place.name, чтобы из справочника стран взять название страны в предложном падеже.
Снимок экрана 2022-12-08 в 20.16.19.png
Если в ответе пользователя есть город переходим к шагу 2, если он называет страну, спрашиваем про город. Если звучит отказ, выходим из программы. А если программа не смогла распознать фразу, возвращаемся снова к началу, чтобы спросить про город или страну:
Снимок экрана 2022-12-08 в 0.39.36.png
Далее состояние AskCity - обработка запроса города, если известна только страна. Если пользователь назвал город, переходим на шаг 2 для уточнения даты. Если на вопрос “Можете назвать город?” - “да”, просим назвать город и возвращаемся в начало состояния AskCity. Если ответ “нет” или любой другой, сообщаем, что будем смотреть прогноз по стране и переходим на шаг 2.
Снимок экрана 2022-12-08 в 0.45.16.png
В состоянии Step 2 (шаг 2), запрашиваем дату, на которую нужно уточнить погоду. Если дата уже есть в сессионной переменной, переходим к шагу 3 - проверка даты. Если нет, то запрашиваем дату. Если пользователь называет дату, сохраняем и идем на шаг 3, в случае отказа выходим из программы. Любой другой ответ - даем подсказку и возвращаемся к началу шага 2:
Снимок экрана 2022-12-08 в 0.52.54.png
В шаге 3 (Step 3) проверяем дату, названную пользователем в предыдущем шаге. Для этого уточняем текущую дату. Если дата в интервале от сегодняшней и на 16 дней вперед, то переходим в state ForecastStep4 запрашивать погоду. Если нет, то сообщаем пользователю, что можем посмотреть погоду только на 16 дней вперед и уточняем хочет ли он узнать историческую информацию о погоде на эту дату год назад. Такое решение было разработано, так как в сервисах, предоставляющих прогноз погоды есть доступ к прогнозу только на 16 дней. В некоторых случаях на месяц вперед, но по платной подписке. Так как пользователь запрашивает погоду, с целью понять какая обычно погода в том месте, куда он поедет, если даты не попадают в указанный выше интервал, мы предлагаем узнать какая погода была год назад, чтобы он смог составить своё представление о примерном климате в выбранной стране или городе.
Для перевода месяца из цифрового формата в название месяца используется словарь months.yaml, который хранится в папке dicts.
На этом шаге пользователь также видит кнопки "Да, узнать" и "Нет, не надо"
Снимок экрана 2022-12-08 в 20.25.05.png
Если пользователь согласен, переходим в состояние для запроса исторических данных о погоде в прошлом году HistoryStep4. Если нет, то удаляем значение даты из сессионной переменной и возвращаемся на шаг 2, чтобы заново запросить дату
Снимок экрана 2022-12-08 в 20.38.20.png
Состояние ForecastStep4 запрашиваем погоду по API и сохраняем значение температуры в сессионную переменную session.temperature:
Снимок экрана 2022-12-08 в 20.41.08.png
В файле func.js можно увидеть как реализован запрос.
В качестве третьей системы, способной предоставить информацию о погоде на конкретную дату в городах и странах, был использован ресурс weatherbit.io и Rest API запросы к нему.
Следующая функция запрашивает прогноз погоды и возвращает параметры прогноза либо ответ о неудаче:
Снимок экрана 2022-12-07 в 23.19.43.png
Характеристики погоды записываются каждая в свою переменную. В переменные сохраняются значение температуры (градус по шкале цельсия) скорость ветра (м/c), порывы ветра (м/с), описание погоды (ясно, пасмурно, облачно, осадки, туман и т.д.).
Снимок экрана 2022-12-07 в 23.19.53.png
Подобная функция реализована и для запроса исторических данных о погоде. Она также возвращает параметры прогноза либо ответ о неудаче:
Снимок экрана 2022-12-07 в 23.20.59.png
Если ответ пришёл, отправляем информацию пользователю и переходим в шаг 5, уточнять информацию про климат. Если ответ не пришел, сообщаем, что запрос не получен по техническим причинам и возвращаемся в главное меню.
Снимок экрана 2022-12-08 в 23.15.31.png
Похожим образом реализован и запрос исторических данных о погоде в состоянии HistotyStep4. Только в начале формируем для запроса входную и выходную дату в прошлом году. Затем запрашиваем погоду по API c помощью функции для запроса исторических данных о погоде getHistoricalWeather, упомянутой выше. Сохраняем температуру. Если ответ получен, отправляем информацию пользователю и переходим в раздел, где спрашиваем про климат Step5. Если ответ не пришел сообщаем об этом и возвращаемся в главное меню.
Снимок экрана 2022-12-08 в 23.20.03.png
В состоянии Step5 проверяем в какой диапазон входит температура, полученная на предыдущем шаге и в зависимости от результата спрашиваем пользователя планирует ли он поездку в страну с умеренным, холодным или жарким климатом. Выводим кнопки "Да, планирую" и "Нет, не планирую"
Снимок экрана 2022-12-08 в 20.58.10.png
Если он вводит название города или страны, идем смотреть погоду для этого места - возвращаемся в состояние Begin. Если вводит дату, то запоминаем её и идём проверять на шаг 3.
Снимок экрана 2022-12-08 в 21.00.41.png
Если пользователь отвечает отрицательно, переходим к шагу 6, чтобы предложить посмотреть погоду в другом месте.
Если он согласен, то предлагаем оформить заявку на тур. В этом случае проверяем есть ли данные о заявке на тур и месте путешествия, указанной там. Если место в заявке не совпадает с местом запроса погоды, уточняем продолжить ли оформление старой заявки или начать оформлять новую. Выводим кнопки "Продолжим", "Начнём новую" и "Нет, ни то, ни другое не надо". Если есть данные, что пользователь начал оформление заявки, предлагаем продолжить и выводим кнопки "Да, продолжим" и "Нет, не надо".
Если данных о заявке на тур нет, то предлагаем оформить заявку в город или страну, указанные в запросе погоды и выводим кнопки "Да, оформим" и "Нет, не надо":
Снимок экрана 2022-12-08 в 23.26.42.png
Если получаем согласие оформить заявку или продолжить оформление заявки, то переходим к оформлению заявки:
Снимок экрана 2022-12-08 в 21.27.16.png
В случае отказа переходим на шаг 6, чтобы предложить посмотреть климат в другом месте. Если получаем ответ начать новую заявку (в случае если была начата ранее заявка, но в другое место), то переходим в шаг 3 оформления заявки:
Снимок экрана 2022-12-08 в 21.28.52.png
В шаг 6 предлагаем посмотреть климат в другом месте, если пользователь не хочет оформлять тур в место, где он смотрел прогноз погоды ранее. Выводим кнопки "Прогноз в другом месте" и "Не нужен прогноз". Если пользователь выбирает просмотр погоды в другом месте, то переходим в состояние ChangePlaceDate, удаляем информацию в сессионных переменных с местом и датой для предыдущего прогноза и направляемся в состояние Begin. Если прогноз не нужен, то выходим из программы.
Снимок экрана 2022-12-08 в 21.41.01.png

Запрос тура:

В сценарий оформления заявки пользователь может попасть из нескольких мест:
- Находясь в главном меню выбрать пункт “Оформить заявку на тур”
04.jpg
и после этого ответить на вопросы бота о городе или стране. Если пользователь не определился со страной, бот начинает заполнение заявки, объявив клиенту, что с выбором направления ему поможет менеджер. Предусмотрены паттерны пользователя Не знаю/нужна консультация и любой другой вид реакции.
05.jpg
Также из Запросов о погоде (файл weather.sc) можно попасть в сценарий оформления заявки. Если пользователь прервал оформление заявки вопросом о погоде, то в программе реализована возможность вернуться к прерванному шагу заявки. За это отвечает сессионная переменная $session.tripStep, через которую срабатывает метод $reactions.transition
изображение.png
Начинаем заполнять заявку. Бот предупреждает, что обязательными полями являются только Имя и Номер телефона. Если бот уже знает имя пользователя, он переходит к следующему шагу (Step2)
08.jpg
Если бот не знает имени пользователя, то предлагает ввести его. Стейт AskName запроса имени модальный, несмотря на это из него можно выйти: либо командой покинуть диалог, либо по запросу погоды. За это, соответственно, отвечают стейты GoExit и GoWeather
09.jpg
10.jpg
При нежелании ввести имя, бот предупреждает, что в этом случае не сможет принять заявку. Чтобы не попасть в бесконечный цикл, на втором отказе бот предложит ввести имя или отменить заявку.
11.jpg
Пользователи с необычными именами также могут его ввести, или проверить, не написано ли имя с ошибкой.
12.jpg
Имя введено, теперь бот просит ввести номер телефона. Если номер известен, то пропускаем этот шаг. Выйти из диалога можно либо командой покинуть диалог, либо по запросу погоды. За это отвечают глобальные стейты отказа и погоды.
изображение.png
Проверку номера телефона проверяет паттерн $phone с регулярным выражением внутри него: $phone = $regexp<((8|[+]7)[\- ]?)?\(?\d{3}\)?[\- ]?\d{1}[\- ]?\d{1}[\- ]?\d{1}[\- ]?\d{1}[\- ]?\d{1}[\- ]?\d{1}?[\- ]?\d{1}> Это регулярное выражение позволяет принять телефонный номер с любой группировкой цифр, что удобно для пользователей “красивых” номеров и номеров с кодами городов, состоящими иногда из 4-х и 5-ти цифр.
изображение.png
Если пользователь не хочет ввести номер, то бот выводит два предупреждения
изображение.png
Если пользователь запутался - выводим еще одну подсказку.
изображение.png
Номер телефона введен, переходим к остальным пунктам заявки.
Запрашиваем дату в стейте Step3. Для тех, кто еще не определился с датой для удобства выводится кнопка “Еще не знаю”. Дата начала поездки – проверяется сущностью duckling.date, также нельзя указать даты, ставшие историческими.
изображение.png
Запрашиваем длительность путешествия в стейте Step4. Для удобства выводятся кнопки с подсказками. Взяты примерные диапазоны длительности поездок от турфирм.
изображение.png
Длительность поездки проверяется сущностью duckling.duration.
изображение.png
Интересуемся количеством путешественников в стейте Step5, если участников больше 1 (стейт Number), то уточняем сколько из них детей младше 14лет (стейт Children). Возраст детей взят на усмотрение разработчика (получение паспорта), т.к. задачей установлен не был. Если меньше или равно 1 либо введено любое другое значение - вопрос про детей не задается, чтоб не было ситуации, когда за ответом “не знаю” последовал вопрос “сколько из них детей”.
изображение.png
Количество детей из ответа берет сущность duckling.number
изображение.png
Нескромный вопрос про бюджет в стейте Step6, есть кнопки-подсказки, чтобы пользователю было проще сориентироваться.
изображение.png
В зависимости от вида валюты формируются динамические подсказки в кнопках:
изображение.png
Вопрос про звезды отеля в стейте Step7. Больше семи не “звездим” (меньше ноля тоже).
изображение.png
Если у пользователя остались пожелания или вопросы, то стейт NoMatch в Step8 запомнит их все. Это модальный стейт, что позволяет пользователю написать буквально любое сообщение, в том числе и содержащее триггеры для интента Погоды и некоторых паттернов. Например: “хочу чтобы всегда была хорошая погода”, “всего доброго!”, “привет ему передайте”, “подберите тур с отличной погодой!”. Реализовано на $caila.checkVocabulary. Проверяет каждое слово из массива аргументов (фразы пользователя) на вхождение в словарь указанного движка NLU (pymorphy.)
изображение.png
Пользователь ответил на все вопросы, формируем заявку. Выводим ее на экран. Перенос строки /n был взят как работающий в обычных мессенджерах. Для вывода заявки в HTML-среде его нужно заменить на <br>
изображение.png
Оставляем за пользователем возможность внести поправки в Имя и Номер телефона. А также отменить заявку, если он передумал. И, конечно, подтвердить правильность своей заявки.
изображение.png
При желании изменить Имя, пользователь возвращается в стейт AskName. При желании изменить Номер телефона, пользователь возвращается в стейт AskPhone. Работа этих стейтов описана выше.
В случае, если пользователь отвечает, что заявка не верная, то получает подсказку и возможность изменить Имя или Номер телефона.
изображение.png
Были введены дополнительные проверки на каждом шаге заполнения заявки на релевантность. На каждом шаге пользователю дается право на несколько ошибок.
«Назойливость» чат-бота настраивается в конфигурационном файле chatbot.yaml переменной sens_bot:, значение по умолчанию-1, что соответствует переходу к следующему пункту заявки после 3-й ошибки (0 - 2; 1 - 3; 2 - 4 ошибки).
изображение.png
При переполнении счетчика ошибок в данном пункте заявки будет указано “данных нет”.
изображение.png
Заявка заполнена и верна. Бот оправляет ее в стейт отправки почты.
изображение.png

Оправка заявки на электронную почту

Заявка пользователя с собранными данными отправляется на почтовый ящик, специально созданный для этого проекта. Для отправки письма используется smtp-сервер почтового клиента mail.ru.    - если письмо отправлено успешно, пользователю сообщается, что в ближайшее время с ним свяжется менеджер компании. После этого бот прощается, переходя в стейт End. - если при отправке письма возникли неполадки, бот информирует пользователя об этом. Клиенту предлагается обратиться за подбором тура в компанию по телефону 8-812-000-00-00.  
изображение.png
отправку почты осуществляет функция email() из файла (funcs.js): в первой части собранные данные пользователя формируются в заявку для менеджера. Вторая часть функции использует встроенный сервис JAICP для отправки электронных писем $mail.send
изображение.png
Ответы сервиса обрабатываются в стейте /SendMail/Mail
Если заявка была отправлена и получен ответ {”status” : “OK”}, информируем пользователя об успешной отправке заявки, говорим, что с ним в ближайшее время свяжется менеджер компании, далее бот завершает чат.
Если при отправке от сервиса был получен ответ {”status” : “UNABLE_TO_CONNECT”} или {”status” : “INCORRECT_ADDRESS”}, то бот выводит номер телефона туроператора, и завершает чат.






Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.