Данная статья является логическим продолжением статьи "Работают роботы, счастлив человек. Или как получить задачу в DirectumRX из социальной сети ВКонтакте". Статья за короткий интервал времени набрала большое число «лайков», что говорит об актуальности темы. В данной статье будет рассмотрена задача создания простого чат-бота для автоматизации внутренней справочной службы организации.
В любой компании сотрудники нуждаются в быстрой и квалифицированной поддержке, в случае возникновения вопросов и прочих нештатных ситуациях (выход из строя оборудования, необходимость отгула и пр.). Зачастую сотрудники обращаются к другим сотрудникам и руководителю, «вынимая» их из рабочего процесса. Другой отрицательной чертой является то, что данные о запросе часто не фиксируются, что затрудняет создание внутренних ЧаВо для сотрудников, теряется информация о нештатных ситуациях, что уменьшает вероятность их последующей обработки.
Выделим три основные процесса, которые постараемся передать в работу чат-боту:
· регистрация отгулов
· регистрация запросов в техническую службу поддержки
· регистрация общих вопросов
Для обработки входящих запросов из социальной сети необходимо перекрыть справочник Сотрудник (Employee) и создать дополнительное свойство для каждого сотрудника – ИД из социальной сети:
В случае, если у сотрудника отсутствует ИД социальной сети, запрос будет квалифицирован как общий и отправлен на выделенную роль (Дежурный по общим вопросам) для обработки входящего запроса.
Вспомним схему взаимодействия чат-бота с пользователем ВК:
Чат-бот задает вопрос, пользователь отвечает на предоставленный вопрос и этот ответ в дальнейшем обрабатывается и передается в RX.
Обработку запросов будем производить на стороне DirectumRX. Тип запроса будем определять из темы ответа пользователя.
Для регистрации отгула чат-бот будет ожидать ответ вида:
<причина отгула>, с <дата начала в формате ДД.ММ.ГГГГ> по <дата завершения в формате ДД.ММ.ГГГГ >
Для регистрации заявки в техническую поддержку чат-бот будет ожидать ответ вида:
ситуация: <описание ситуации>, критичность: <плановая/средняя/высокая>
Для регистрации общих вопросов: прием строки любого формата.
Работа с отгулами и больничными зачастую требует от сотрудника связаться с руководителем тем или иным образом, подключиться удаленно к системе документооборота и отправки соответствующей задачи по определенному регламенту. В большинстве случаев данный способ не удобен, т.к. требует от сотрудника существенной концентрации, способности вести диалог и т.д., что не всегда возможно в случае болезни. Удобнее написать корпоративному чат-боту о ситуации, а чат-бот в свою очередь запустит все необходимые процессы.
Создадим справочник «Отсутствие сотрудника» - для хранения информации об отгуле и больничном:
Добавленные в справочник свойства:
В данной статье мы не будем рассматривать полноценную систему работы с заявками (к слову, такая задача глубоко рассматривается на курсе разработчика DirectumRX), предположим, что данная система уже разработана, и мы будем работать с готовым справочником Tickets:
Создадим две новые роли:
/// <summary>
/// Создать предопределенные роли.
/// </summary>
[Remote]
public static void CreateRoles()
{
Logger.Debug("Init: Create Default Roles");
Sungero.Docflow.PublicFunctions.Module.CreateRole("Дежурный по общим вопросам", "Дежурный по общим вопросам", Constants.Module.RoleGuid.ChatBotRole);
Sungero.Docflow.PublicFunctions.Module.CreateRole("Дежурный техподдержки", "Дежурный техподдержки", Constants.Module.RoleGuid.SupportRole);
}
Для того, чтобы справочники были доступны пользователям выдаем на них права (в данном случае выдаем права всем пользователям, в реальной ситуации необходимо выдать права определенным группам пользователей):
/// <summary>
/// Выдать права на созданные справочники.
/// </summary>
[Remote]
public static void GrantRightsToDatabooks()
{
Logger.Debug("Init: Grant Rights to Databooks");
// выдача прав на чтение всем пользователям на справочник отгулов.
ChatBot.Absences.AccessRights.Grant(Sungero.CoreEntities.Roles.GetAll(g => g.Sid == Sungero.Domain.Shared.SystemRoleSid.AllUsers).FirstOrDefault(), DefaultAccessRightsTypes.Read);
// выдача полных прав всем пользователям на справочник заявок (в реальной ситуации ограничить группой технической поддержки).
ChatBot.Ticketses.AccessRights.Grant(Sungero.CoreEntities.Roles.GetAll(g => g.Sid == Sungero.Domain.Shared.SystemRoleSid.AllUsers).FirstOrDefault(), DefaultAccessRightsTypes.FullAccess);
}
В клиентской функции инициализации необходимо вызвать созданные выше функции:
/// <summary>
/// Создает предопределенные данные модуля.
/// </summary>
public virtual void Initialize()
{
Logger.Debug("Init: Create roles.");
Functions.Module.Remote.CreateRoles();
Logger.Debug("Init: Grant rights to Databooks.");
Functions.Module.Remote.GrantRightsToDatabooks();
}
В серверных функциях модуля ChatBot модифицируем функцию обработки входящих запросов:
/// <summary>
/// Обрабатывает запрос поступивший от чат-бота.
/// </summary>
[Remote]
public static int GetProcessingData(string SocialNetwork, string UserID, string UserURI, string Request, string Theme)
{
var chatbotrole = Roles.GetAll().FirstOrDefault(r => r.Sid == Constants.Module.RoleGuid.ChatBotRole);
var Employee = ChatBotSolution.Employees.GetAll(e => e.VKIDARD==UserID).FirstOrDefault();
if (Employee != null)
{
if (Theme == "отгул")
{
// если поступила заявка на отгул – регистрируем отгул в справочнике отгулов и отправляем задание руководителю.
var absenceitem = Functions.Absence.CreateItem(Employee,Request);
var Boss = Employee.Department.Manager;
if (Employee != Boss) // если пользователь и есть руководитель, задачу стартовать не требуется.
{
SendSimpleTask("Отсутствие сотрудника: "+Employee.Name, "Рассмотрите запрос от сотрудника по поводу отгула.", Boss, absenceitem,1);
}
}
if (Theme == "техподдержка")
{
// если поступили заявка в техподдержку – регистрируем заявку в справочнике заявок и отправляем заявку в работу на дежурного техподдержки
var ticket = Functions.Tickets.CreateItem(Employee,Request);
var supportrole = Roles.GetAll().FirstOrDefault(r => r.Sid == Constants.Module.RoleGuid.SupportRole);
SendSimpleTask("Заявка: "+ticket.Text, "Рассмотрите заявку от сотрудника.", supportrole.RecipientLinks.FirstOrDefault().Member, ticket,1);
}
if (Theme == "общее")
{
// если поступил общий вопрос от Сотрудника, то отправляем полученное сообщение в рамках задания на дежурного по общим вопросов.
SendSimpleTask("Общий вопрос от сотрудника: "+Employee.Name, "Рассмотрите вопрос от сотрудника.\n" + Request, chatbotrole.RecipientLinks.FirstOrDefault().Member,Employee,1);
}
}
else
{
// если пользователь социальной сети не сопоставлен с Сотрудником, то поступивший запрос будет рассмотрен как общий без дополнительной обработки.
string Text = "";
Text = "Социальная сеть: " + SocialNetwork + "\n" +
"Идентификатор пользователя: " + UserID + "\n" +
"Ссылка на пользователя: " + UserURI + "\n" +
"Тема: " + Theme + "\n" +
"Сообщение: " + "\n" +
Request;
SendSimpleTask("Вопрос из социальной сети", Text, chatbotrole.RecipientLinks.FirstOrDefault().Member,null,1);
}
return 0;
}
Чтобы обработать сообщения от пользователей, будем использовать регулярные выражения.
Для работы с регулярными выражениями необходимо подключить модуль System.Text.RegularExpressions:
using System.Text.RegularExpressions;
Для работы с регулярными выражениями будем использовать методы:
- Match – для поиска подстроки, которая соответствует заданному шаблону (будем использовать для поиска необходимых параметров в строке)
- Replace – для удаления подстроки по заданному шаблону (будем использовать для очистки искомой строки от лишних элементов)
Код функции Absence.CreateItem
[Remote]
public static ChatBot.IAbsence CreateItem(string UserID, string Text)
{
var Employee = ChatBotSolution.Employees.GetAll(e => e.VKIDARD==UserID).FirstOrDefault(); // определяем сотрудника по ID социальной сети.
if Employee == null
{
return null; // если сотрудник не найден, возвращаем null, для дальнейшей обработки ошибки.
}
string pattern = @"с\s+\d\d.\d\d.\d\d\d\d"; // задаем шаблон поиска "c XX.XX.XXXX".
Regex regex = new Regex(pattern); // создаем фильтр
string StartDate_part = regex.Match(Text).Value; // получаем строку, которая соответствует заданному шаблону
regex = new Regex(@"с\s+");
string StartDate = regex.Replace(StartDate_part,""); // удаляем конструкцию "с ", учитывая, что пробелов может быть много.
//Для поиска конечной даты выполняем порядок работ идентичен:
// Получение из текста даты начала отгула.
pattern = @"по\s+\d\d.\d\d.\d\d\d\d"; // задаем шаблон поиска "по XX.XX.XXXX".
regex = new Regex(pattern);
string EndDate_part = regex.Match(Text).Value;
regex = new Regex(@"по\s+"); // удаляем конструкцию "по ", учитывая, что пробелов может быть много.
string EndDate = regex.Replace(EndDate_part,"");
//Создаем новую запись об отсутствии сотрудника:
var newitem = Absences.Create();
newitem.Name = "Отгул сотрудника: " + Employee.Name; // задаем понятное наименование записи
newitem.StartDate = DateTime.Parse(StartDate); // фиксируем дату начала отгула.
newitem.EndDate = DateTime.Parse(EndDate); // фиксируем дату завершения отгула.
newitem.Employee = Employee; // фиксируем работника в карточке.
newitem.Text = Text; // фиксируем текст, указанный пользователем VK во время переписки.
newitem.Save(); // сохраняем новую карточку.
return newitem; // возвращаем ссылку на объект.
}
Код функции Tickets.CreateItem
[Remote]
public static ChatBot.ITickets CreateItem(Sungero.Company.IEmployee Employee, string Text)
{
// Шаблон:
// Ситуация: <описание ситуации>, критичность: <критичность>
// Получение описания ситуации.
string pattern = @"ситуация:\s+[\w\s]*"; // ищем конструкцию "ситуация: <описание ситуации, несколько слов, разделенных пробелами>".
Regex regex = new Regex(pattern);
string Info_part = regex.Match(Text).Value;
regex = new Regex(@"ситуация:\s+"); // удаляем конструкцию "ситуация: ", учитывая, что пробелов может быть много.
string Info = regex.Replace(Info_part,""); // получаем описание
// Получение критичности.
pattern = @"критичность:\s+\w+"; // ищем конструкцию "критичность: XX.XX.XXXX".
regex = new Regex(pattern);
string Crit_part = regex.Match(Text).Value;
regex = new Regex(@"критичность:\s+"); // удаляем конструкцию "критичность: ", учитывая, что пробелов может быть много.
string Crit = regex.Replace(Crit_part,"");
// Создание новой записи об отсутствии сотрудника.
var newitem =Ticketses.Create();
newitem.Name = "Заявка: "+ Info;
if (Crit == "высокая") { newitem.Criticality = ChatBot.Tickets.Criticality.hight; }
if (Crit == "средняя") { newitem.Criticality = ChatBot.Tickets.Criticality.middle; }
if (Crit == "плановая") { newitem.Criticality = ChatBot.Tickets.Criticality.planned; }
if (newitem.Criticality == null) { newitem.Criticality = ChatBot.Tickets.Criticality.planned; }
newitem.Employee = Employee;
newitem.Text = Text;
newitem.Save();
return newitem;
}
В нашем случае мы именно настраиваем чат-бота, а не обучаем.
Напомним, что разработанный чат-бот общается с пользователем социальной сети с использованием строк, хранящихся в базе банных mind.db.
Заполняем таблицу с кодами реакции:
Заполняем таблицу с синонимами:
Задаем одной из учетных записей ID пользователя из социальной сети:
Настроим предопределенные роли:
Запустим сервис сервисы чат-бота и сервис интеграции с DirectumRX и проведем проверку работоспособности чат-бота.
После выполнения сервиса синхронизации с DirectumRX, на стороне СЭД формируется соответствующая запись в справочнике отгулов и формируется задача руководителю. Во вложении задачи помещается ссылка на соответствующую запись справочника.
Информация по датам отгула выбирается из текста сообщения и проставляется в карточку отгула.
После выполнения сервиса синхронизации с DirectumRX, на стороне СЭД формируется соответствующая запись в справочнике заявок в техническую поддержку и формируется задача дежурному техподдержки.
Описание ситуации выбирается из сообщения и подставляется в наименование карточки заявки. Критичность заявки также автоматически заполняется исходя из сообщения. В поле "Общение" указано полное сообщение. В случае не успешной обработки сообщения, дежурный сможет корректно заполнить поля исходя из общения.
Все общие вопросы поступают дежурному по общим вопросам (как и в предыдущей статье) для дальнейшей проработки.
Если у Сотрудника известен идентификатор социальной сети, то в задаче дежурному будет указана карточка соответствующего сотрудника:
В случае, если у Сотрудника не заполнено поле с идентификатором социальной сети, то в задаче будет указан идентификатор пользователя социальной сети и его вопрос:
В рамках первой статьи "Работают роботы, счастлив человек. Или как получить задачу в DirectumRX из социальной сети ВКонтакте" мы рассмотрели вариант разработки простого чат-бота, который способен вести простой диалог с пользователем и собирать ответы на поставленные вопросы для дальнейшей обработки. В данной статье мы углубились в разработку на стороне DirectumRX, чтобы продемонстрировать один из вариантов обработки входящих запросов на уровне DirectumRX. Как видим инструмент разработки DirectumRX довольно мощный и универсальный. Вы можете использовать в процессе разработки существующие классы C#, однако необходимо проверять возможность использования того или иного класса. Поддержка сторонних классов и различных библиотек возможна, но конечная работоспособность такого решения не гарантируется. Экспериментируйте!
Как всегда, исходные коды, представленные в данной статье и исправленный робот (в сервисе ВКонтакте немного изменилось API) доступны по ссылке: https://gitlab.com/ardashev/ChatBotRX.git
Авторизуйтесь, чтобы написать комментарий