Общее описание
Сценарии позволяют описывать диалоги системы autoFAQ с пользователями. Диалог может включать в себя переписку с пользователем, обращение к данным во внешних системах и обогащение ответов.
Система позволяет создавать сценарии диалогов произвольной сложности и прикреплять их напрямую к документам в базах знаний. В случае когда база знаний по запросу пользователя определяет документ, содержащий вместо ответа сценарий, бот начнет вести с пользователем описанный в сценарии диалог.
Описание сценариев в системе ведется при помощи языка DSL autoFAQ. Тело сценария состоит из последовательных операций. Каждая операция располагается в отдельной строке, для связи со следующей операцией в конце строки требуется указание символа "+". Некоторые операции могут содержать 1 или несколько опциональных модификаторов.
Системные переменные
Для работы с контекстом в сценариях доступны следующие системные переменные:
Code Block |
---|
{userFullName} - имя пользователя
{userLogin} - логин пользователя
{userEmail} - электронная почта пользователя
{userPayload.<название_даных>} - дополнительные данные о пользователе, полученные при идентификации пользователя во внешней системе
{platformInMessageQuery} - текст запроса пользователя
{http_code} - переменная содержит код статуса последнего запроса к API |
Пользовательские переменные
В сценариях возможно создавать и использовать для хранения данных любые пользовательские переменные. Значение переменной будет потеряно после завершения сценария.
Code Block |
---|
{userSaidYes} - пример пользовательской переменной |
Списки
Переменная attachments[] хранит не одно значение, а список значений, при записи новых значений в данную переменная они будут дописаны в конец списка.
Code Block |
---|
запроситьФайл("Приложите файл").сохранитьРезультат("file")+ - полученные данные перезапишут значение переменной
запроситьФайл("Приложите файл").сохранитьРезультат("files[]")+ - полученные данные будут дописаны в список |
Порядок выполнения шагов сценария
Все шаги сценария выполняются последовательно с первой до последней строки. Если вы хотите временно исключить одну из строк из процесса выполнения сценария - установите в начале данной строки символ //
Code Block |
---|
|
сообщениеПользователю.сШаблоном("Привет")+ - шаг будет выполнен
//сообщениеПользователю.сШаблоном("Привет, {userFullName}")+ - шаг не будет выполнен |
В конце сценария обязательно размещение одного из шагов завершения сценария:
Code Block |
---|
breakoutMode | wide |
---|
language | py |
---|
|
завершить - завершение сценария
завершитьСШаблоном("Пока!") - завершение сценария с выводом сообщения пользователю
завершитьСНовымЗапросом("Новый запрос") - завершение сценария и одновременный запуск в работу нового сообщения
завершитьИПеревестиНаОператора - звершение сценария и перевод диалога в очередь оператору
завершитьИЗакрытьДиалог() - завершение сценария и закрытие диалога, следующая реплика пользователя начнет новый диалог |
Если в условии сценария применен один из шагов завершения, то сценарий может завершить работу досрочно:
Code Block |
---|
|
если("{http_code} != 200").то(
комментарий("Данные пользователя не обновлены")+
завершитьИПеревестиНаОператора
)+
комментарий("Обовлены данные пользователя. Новые данные отправлены в CRM")+
завершить |
Список команд языка DSL
сообщениеПользователю.сШаблоном("сообщение")
Вывод простого текстового сообщения пользователю без ожидания ответной реакции.
Сообщение может содержать HTML форматирование, а также использовать вставку значений переменных. Сообщение будет передано в текущий открытый диалог, в тот же канал. Система самостоятельно проверит форматирование сообщения на соответствие требованиям канала.
Code Block |
---|
|
сообщениеПользователю.сШаблоном("Текст сообщения")+ вывод простого текстового сообщения
сообщениеПользователю.сШаблоном("Сообщение от {userFullName}")+ вывод текстового сообщения с использованием данных из переменной
сообщениеПользователю.сШаблоном("Пройдите по <a href='https://yandex.ru'>ссылке</a>")+ вывод HTML форматированного сообщения |
сообщениеПользователю.сФайлами(111).сШаблоном("сообщение")
Расширением предыдущей команды служит часть ".сФайлами", которая позволяет отправить пользователю файлы из текущего документа.
Code Block |
---|
|
сообщениеПользователю.сФайлами(523).сШаблоном("Высылаю файл") - отправка файла с идентификатором 523 пользователю вместе с сопровождающим текстом
сообщениеПользователю.сФайлами(523, 524, 525).сШаблоном("Высылаю файл") - отправка нескольких файлов пользователю
сообщениеПользователю.сФайлами(523).сШаблоном("") - отправка файла пользователю без сопровождающего текста |
Идентификатор файла копируется из формы прикладывания файла к документу.
Info |
---|
Передача файлов пользователю поддерживается только для сценариев в документах баз знаний и не поддерживается для сценариев приветствия и интеграций. |
задатьПользователюВопрос("сообщение")
Вывод текстовой информации и ожидание ввода пользователя. Поддерживает вывод форматированного сообщения с использованием переменных, получение и проверку данных на соответствие шаблону. Время ожидания ответа от пользователя устанавливается таймером сценариев в разделе Настройки - Запросы - Сценарии.
Code Block |
---|
|
задатьПользователюВопрос("На какую дату нужен пропуск ?").сохранитьРезультат("day)+ |
Система будет ожидать ответ пользователя все время жизни сценария. Время жизни сценария устанавливается в разделе Настройки - Запросы - Сценарии.
Функции операции:
.сВариантамиОтвета(варианты) - функция предоставляет пользователю варианты выбора из списка. В случае если канал позволяет отображать кнопки - варианты будет представлены кнопками, в противном случае варианты будут представлены автоматически сгенерированным списком. При этом пользователь сохраняет возможность написать ответ вручную минуя варианты выбора.
Code Block |
---|
|
задатьПользователюВопрос("На какую дату нужен пропуск ?").сВариантамиОтвета("Сегодня", "Завтра").сохранитьРезультат("day")+ |
.проверитьФормат(формат, сообщение) - функция проверяет полученные от пользователя данные на соответствие шаблону. Шаблон задается регулярным выражением. В случае соответствия ответной реплики пользователя шаблону шаг передает данные далее, в обратном случае - выводит текст сообщения и ожидает получения корректной информации без ограничений по количеству попыток ввода.
Code Block |
---|
|
// выражение для проверки, что введенная строка соотвествует формату даты вида 02.12.2021
задатьПользователюВопрос("Укажите дату").проверитьФормат("(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.](19|20)\\d\\d", "Не понял вас, повторите пожалуйста.").сохранитьРезультат("day")+
// выражение для проверки, что введенная строка содержит адрес электронной почты
задатьПользователюВопрос("Напишите email").проверитьФормат("^\\S+@\\S+\\.[a-z]{2,}$", "Пожалуйста, введите корректный email").сохранитьРезультат("_email")+ |
.сохранитьРезультат(переменная) - функция сохраняет полученные данные в переменную для дальнейшего использования в сценарии.
Code Block |
---|
|
задатьПользователюВопрос("Как дела?").сохранитьРезультат("what")+
если("{what} != Хорошо").то(
комментарий("А дела то не хорошо")+
завершитьИПеревестиНаОператора
)+
комментарий("Все отлично")+
завершить |
вызвать
Вызывает внешние команды и системы. В настоящее время поддерживается только к HTTP(REST и SOAP) сервисам, планируется подключение к почтовым , FTP и прочим сервисам
Функции операции:
.внешнийСервис(адрес, тип) - обязательная функция, которая формирует вызов API сервисов. В параметрах указывается адрес сервиса и тип запроса. Поддерживаются основные HTTP запросы - GET, POST, PUT.
Code Block |
---|
|
вызвать.внешнийСервис("https://api.autofaq.ai/v1/ping","GET").сохранитьРезультат("result")+ |
.сПараметрами() - необязательная функция, передает в запрос список параметров адресной строки, параметры будут собраны в соответствующий запросу формат
Code Block |
---|
|
вызвать.внешнийСервис("https://server.com/api","GET").сПараметрами(("foo","bar"),("user_token","1234567")).сохранитьРезультат("result")+ |
.сЗаголовками() - необязательная функция, передает в запрос список заголовков в формате пар ключ:значение
Code Block |
---|
|
вызвать.внешнийСервис("https://server.com/api", "POST").сЗаголовками(("Content-Type", "application/json"),("charset", "utf-8"),("Authorization","Bearer {user_token}")).сохранитьРезультат("result")+ |
.сТеломСообщения() - необязательная функция, передает тело запроса. Поддерживаются форматы x-www-form-urlencoded и json
Code Block |
---|
|
// передача JSON в виде строки
вызвать.внешнийСервис("https://server.com/api", "POST").сЗаголовками(("Content-Type", "application/json")).сТеломСообщения("{\"name\":\"new document\", \"question\":\"new question\"}")+
// передача x-www-form-urlencoded
вызвать.внешнийСервис("https://server.com/api", "POST").сЗаголовками(("Content-Type", "application/x-www-form-urlencoded")).сТеломСообщения("name=new document, question=new question")+ |
.сСоставнымТеломСообщения() - необязательная функция, передает multipart тело запроса для передачи файлов. При передаче файла можно указать либо полное название файла либо идентификатор файла в файловом хранилище диалога
Code Block |
---|
|
// передача файла через указание пути
вызвать.внешнийСервис("https://server.com/api", "POST").сСоставнымТеломСообщения(("content" -> "C:/docker.yml")).сохранитьРезультат("callRes")+
// передача файла через идентификатор в хранилище
вызвать.внешнийСервис("{post_url}", "POST").сЗаголовками(("apikey","{apikey_var}")).сСоставнымТеломСообщения(("content" -> "{fileId}"),("type" -> "addAttach")).сохранитьРезультатКакСтроку("callRes")+ |
.сохранитьРезультат() - функция обрабатывает полученный ответ в формате JSON, сохраняет значения указанных полей в переменные сценария. Функция обрабатывает каждое значение ключа ответа и сохраняет его в отдельной переменной. В качестве параметров команды указываются пары ключ ответа - переменная
Code Block |
---|
|
вызвать.внешнийСервис("{post_url}", "POST").сТеломСообщения("{query}").сохранитьРезультат(("message", "response_message"),("code", "response_code"))+ |
.сохранитьРезультатКакСтроку() - функция обрабатывает полученный ответ в формате JSON и сохраняет сериализованный в текст ответ целиком в переменную. Содержание переменной может быть разобрано далее по ходу сценария.
Code Block |
---|
|
// запрос и сохранение результата в строку
вызвать.внешнийСервис("{post_url}", "POST").сТеломСообщения("{query}").сохранитьРезультатКакСтроку("answer")+
// разбор ответа в JS коде (рассмотрено ниже)
выполнитьJs("""
try {
var answerParsed = JSON.parse(answer);
} catch(err) {
var answerParsed = {'results':[]};
}
var resultsLength = answerParsed.results.length;
var exit = {'resultsLength ':resultsLength};
exit;
""") + |
установитьПеременную(переменная, значение)
Операция установки значений переменной, старое значение будет затерто. При указании значения допускается использование переменных. Переменная будет доступна только в рамках выполняемого сценария.
Code Block |
---|
|
установитьПеременную("date", "Сегодня {new_date}")+ |
установитьПеременнуюВДиалог(*аргументы)
Операция установки переменной для всего диалога. При указании значения допускается использование переменных. Переменная диалога сохраняет свое значение на протяжении всего диалога, может быть создана и прочтена в рамках любого сценария. В новом диалоге будет отсуствоватьотсутствовать.
Может быть использована для хранения информации связанной с контекстом диалога, для хранения контекста пользователя в рамках всех диалогов необходимо воспользоваться созданием переменной пользователя.
Code Block |
---|
|
установитьПеременнуюВДиалог(
ключ = "priority", - системное название задаваемой переменной, любой текст
значение = "[\"v1\", \"v2\"]", - значение, может быть пустым
название = "Выберите критичность", - название, которое будет отображаться в интерфейсе, строка
редактируемое = true, - является ли поле редактируемым или нет, true/false
показыватьОператору = true, - показывать ли оператору в боковой панели, true/false
обязательное = true, - является ли обязательным для заполнения при закрытии диалога, true/false
множественныйВыбор = true, - можно ли выбрать несколько вариантов, применимо только для выпадающего списка, true/false
тип = "Выпадающий список", - тип задаваемой переменной, возможные значения в таблице ниже
варианты = "{\"v1\": \"High\", \"v2\": \"Medium\"}" - список возможных значений, применимо только для выпадающего списка, можно задать как с помощью другой переменной, так и напрямую
)+ |
Список возможных типов с примерами использования:
Тип | Пример использования |
---|
Текст | Code Block |
---|
установитьПеременнуюВДиалог(
ключ = "NonEditabletext",
значение = "Нередактируемый текст",
название = "Примечание",
показыватьОператору = true,
редактируемое = false,
обязательное = false,
тип = "Текст"
) |
Code Block |
---|
установитьПеременнуюВДиалог(
ключ = "textField",
значение = "г.Москва Ул.Тверская",
название = "Адрес",
показыватьОператору = true,
редактируемое = true,
обязательное = true,
тип = "Текст"
) |
|
Число | Code Block |
---|
установитьПеременнуюВДиалог(
ключ = "number",
значение = "",
название = "Возраст",
показыватьОператору = true,
редактируемое = true,
обязательное = true,
тип = "Число"
) |
|
Выпадающий список | Code Block |
---|
установитьПеременную("priority", "{\"v1\": \"Blocker\", \"v2\": \"Critical\", \"v3\": \"Major\", \"v4\": \"Minor\"}")+
установитьПеременнуюВДиалог(
ключ = "priority",
значение = "[\"v1\", \"v2\"]",
название = "Выберите критичность",
редактируемое = true,
показыватьОператору = true,
обязательное = true,
множественныйВыбор = true,
тип = "Выпадающий список",
варианты = "{priority}"
) |
Code Block |
---|
установитьПеременнуюВДиалог(
ключ = "severity",
значение = "",
название = "Выберите важность",
редактируемое = true,
показыватьОператору = true,
обязательное = true,
тип = "Выпадающий список",
варианты = "{\"v1\": \"High\", \"v2\": \"Medium\", \"v3\": \"Low\"}"
) |
|
Переключатель | Code Block |
---|
установитьПеременнуюВДиалог(
ключ = "switcher",
значение = "true",
название = "Активный?",
показыватьОператору = true,
редактируемое = true,
обязательное = true,
тип = "Переключатель"
) |
|
установитьПеременнуюПользователю(переменная, значение)
Операция установки переменной дляпользователядля пользователя. При указании значения допускается использование переменных. Переменная пользователя сохраняет свое значение до тех пор пока не будет очищена. Может быть создана и наполнена в любом сценарии. После создания переменная будет доступна в любом сенарии сценарии любого диалога.
Можно установить значение одной из фиксированных переменных пользователя или произвольной переменной в составе payload. Сохранение данных пользователя позволит передавать данные между разными диалогами.
Code Block |
---|
// установка фиксированной переменной
установитьПеременнуюПользователю("userEmail", "vasya@mail.ru")+
// установка переменной из payload
установитьПеременнуюПользователю("userPayload.lastLoginTS", "{nowTimeStamp}")+ |
если(условие)
Операция сравнения переменных. Доступны операции сравнения: равенство (==), больше (>), меньше (<), неравенство (!=).
Функции операции:
.то(список операций) - обязательный блок операций, которые будут выполнены в случае истинности проверки
Code Block |
---|
|
если("{error} == 1").то(сообщениеПользователю.сШаблоном("Система не работает"))+ |
Блок операций может состоять из нескольких операций, различные операции в блоке соединены знаком “+”, последняя операция в блоке не должна содержать “+“
Code Block |
---|
|
если("{when_error} == 1").то(
задатьПользователюВопрос("Не разобрал дату. Введи пожалуйста еще раз").сохранитьРезультат("when")+
вызвать.внешнийСервис("http://yandex.ru", "GET").сПараметрами(("text","{when}")).сЗаголовками().сохранитьРезультат(("name", "when"))
)+ |
.и(условие) - функция объединения условий
Code Block |
---|
|
если("{error} == 0").и("{connection_mistakes} == 0").то(сообщениеПользователю.сШаблоном("Система работает"))+ |
.или(условие) - функция выполняет дизъюнкцию условий
Code Block |
---|
|
если("{error} == 1").или("{connection_mistakes} == 1").то(сообщениеПользователю.сШаблоном("Система не отвечает"))+ |
запроситьФайл("сообщение")
Процедура получения файла и записи его в переменную. Пользователю будет выведен текст сообщения. Файл будет сохранен в хранилище файлов диалога.
Code Block |
---|
|
запроситьФайл("Приложите файл")+ |
Функции операции:
.можноПропустить(сообщение) - функция позволяет пользователю пропустить отправку файла
Code Block |
---|
|
запроситьФайл("Приложите файл").можноПропустить("Пропустить")+ |
.сохранитьРезультат(переменная) - функция сохраняет идентификатор полученного файла в переменную
Code Block |
---|
|
запроситьФайл("Приложи файл").сохранитьРезультат("file")+ |
установитьМетку()
Установка определенной метки в коде, чтобы потом в нее можно было перейти из любого места сценария.
Code Block |
---|
|
установитьМетку("раз")+лог |
перейтиНаМетку()
Осуществить переход на установленную метку в сценарии.
Code Block |
---|
|
// перети на метку не более 3 раз, на 4 раз шаг перехода не сработает
перейтиНаМетку("раз").неБольше(3)+
// переход на метку без указания лимита переходов, используется значение по-умолчанию 30
перейтиНаМетку("раз")+ |
запросВБазыЗнаний(вопрос, переменная)
Проверка наличия у системы автоматического ответа на указанный запрос. Если в базах знаний есть ответ, который удовлетворяет требованиям по точности, переменной будет присвоено значение true, если ответа нет - false.
Code Block |
---|
|
запросВБазыЗнаний("Как купить слона", "botKnows")+
если("{botKnows} == true").то(
сообщениеПользователю.сШаблоном("Ответ есть")
)+ |
назначитьТематику(ID базы знаний)
Шаг принудительного указания тематики диалога. Шаг замещает все автоматически определенные тематики и сохраняет значение тематики вне зависимости от того что пишет пользователь.
Для установки тематики требуется указать идентификатор базы знаний.
Code Block |
---|
назначитьТематику("1234")+
// диалог попадет на скилл группу операторов со специализацией на базе знаний с ID 1234
завершитьИПеревестиНаОператора |
Если база знаний с укзанным указанным идентификатором не будет найдена шаг не заменит тематику.
назначитьОператора(логин оператора)
Шаг указания оператора для диалога. Требуется указать логин оператора.
Code Block |
---|
|
назначитьОператора("vasya@mail.ru")+
//
// Сценарий не обязательно должен завершаться переводом на оператора завершитьИПеревестиНаОператора,
// можно просто завершить - назначенный оператор будет найден когда диалог попадет на операторов
завершить |
При попадании диалога с установленным оператором в процедуру назначения оператора система в первую очередь попытается назначить диалог на оператора с указанным логином. Если такой оператор существует и удовлетворяет всем требованиям автоназначения - система назначит диалог на данного оператора. Если оператора с таким логином не существует или он не удовлетворяет требованиям автоназначения система проведет назначение на другого оператора по стандартным правилам.
Info |
---|
Для корректного назначения на оператора следует проверить соответствие тематики диалога специализации оператора. Проще всего установить диалогу нужную тематику через шаг назначитьТематику() |
В последующем, данные оператор может перевести диалог на другого оператора или в другую группу - система больше не будет пытаться назначить диалог на него.
комментарий("сообщение")
Команда позволяет добавлять комментарий в диалог. Комментарий виден администраторам и операторам системы, пользователь не видит комментарии.
Code Block |
---|
|
комментарий("текст комментария")+ |
выполнитьJs(скрипт)
Выполнить произвольный скрипт на JavaScript. Шаг позволяет реализовать произвольную логику вычислений или разбор сложных объектов.
Info |
---|
Javascript VM сответствует соответствует ECMAScript 5.1 Используйте обычный синтаксис callback function поскольку не поддерживается синтаксис lambda функций ES6 |
JS скрипт имеет доступ ко всем переменным сценария. Результаты скрипта следует записать в JSON объект и передать его на выход, в DSL сценарии можно будет получить к ним доступ по названиям полей.
Code Block |
---|
|
выполнитьJs("""
var uids = JSON.parse(results);
var ln = uids.length;
if (ln == 0) {var uuid = '';} else {var uuid = uids[0]["UUID"];}
var exit = {'uuid':uuid, 'numberOfUids':ln};
exit;
""") +
завершитьСШаблоном("Заявка создана, всего создано полей {numberOfUids}, первый id - {uuid}.") |
Внутри JavaScript есть возможность получить данные об операторе для случая, когда запущен сценарий на интеграцию по кнопке. Название объекта - initByOperator
.
Пример использования:
Code Block |
---|
|
выполнитьJs("""
var initByOperator = JSON.parse(initByOperator);
var initByOperatorLogin = initByOperator.login;
var exit = {'operatorLogin ': initByOperatorLogin, 'operatorFIO': initByOperator.fullName, 'operatorEmail': initByOperator.email};
exit;
""")+
комментарий("ФИО оператора: {operatorFIO}") +
комментарий("Логин оператора: {operatorLogin}") +
комментарий("Email оператора: {operatorEmail}") + |
Весь список параметров, к которым можно получить доступ:
id: String, login: String, fullName: Option[String], isActive: Boolean, isNotify: Boolean, serviceId: String, actions: Seq[UserRoleType], email: Option[String], settings: UserSettings = UserSettings()
knowledgeBases: Seq[Long] = Seq.empty, autoAssignEnabled: Boolean = false
добавитьПолеВФормуОператора(*args)
Для конструирования формы, которая будет показана оператору в момент работы сценария интеграции, добавлена команда добавитьПолеВФормуОператора со следующими параметрами:
Code Block |
---|
|
форма: String, - имя формы - обязательный параметр
переменная: String, - имя переменнной, которая пойдет в сценарий и имя в html form - обязательный параметр
название: String - имя на форме,
тип: String - Тип HTML ввода - обязательный параметр, если не задано или неверное -> нередактируемый текст
описание: String - описание на форме,
значение: String - предопределенное значение,
обязательное: Boolean - обязательность - по-умолчанию - false,
варианты: String - варианы для выпадающих списков - пример - {\"v1\": \"l1\", \"v2\": \"l2\"} |
Пример:
Code Block |
---|
|
добавитьПолеВФормуОператора(
форма = "Заведение заявки в Jira",
переменная = "t6",
название = "Теги",
тип = "Множественный выбор",
описание = "Выберите теги, которыми пометить обращение",
варианты = "{tags}",
обязательное = true
) |
Список возможных значений параметра "тип":