Чат-бот для внутренней информационной службы. Пример реализации доступными средствами на RX

36 0

Данная статья является логическим продолжением статьи "Работают роботы, счастлив человек. Или как получить задачу в DirectumRX из социальной сети ВКонтакте". Статья за короткий интервал времени набрала большое число «лайков», что говорит об актуальности темы. В данной статье будет рассмотрена задача создания простого чат-бота для автоматизации внутренней справочной службы организации.

Цели и задачи внутренней справочной службы

В любой компании сотрудники нуждаются в быстрой и квалифицированной поддержке, в случае возникновения вопросов и прочих нештатных ситуациях (выход из строя оборудования, необходимость отгула и пр.). Зачастую сотрудники обращаются к другим сотрудникам и руководителю, «вынимая» их из рабочего процесса. Другой отрицательной чертой является то, что данные о запросе часто не фиксируются, что затрудняет создание внутренних ЧаВо для сотрудников, теряется информация о нештатных ситуациях, что уменьшает вероятность их последующей обработки.

Выделим три основные процесса, которые постараемся передать в работу чат-боту:

· регистрация отгулов

· регистрация запросов в техническую службу поддержки

· регистрация общих вопросов

Общие доработки на стороне DirectumRX

Для обработки входящих запросов из социальной сети необходимо перекрыть справочник Сотрудник (Employee) и создать дополнительное свойство для каждого сотрудника – ИД из социальной сети:

В случае, если у сотрудника отсутствует ИД социальной сети, запрос будет квалифицирован как общий и отправлен на выделенную роль (Дежурный по общим вопросам) для обработки входящего запроса.

Вспомним схему взаимодействия чат-бота с пользователем ВК:

Чат-бот задает вопрос, пользователь отвечает на предоставленный вопрос и этот ответ в дальнейшем обрабатывается и передается в RX.

Обработку запросов будем производить на стороне DirectumRX. Тип запроса будем определять из темы ответа пользователя.

Для регистрации отгула чат-бот будет ожидать ответ вида:

<причина отгула>, с <дата начала в формате ДД.ММ.ГГГГ> по <дата завершения в формате ДД.ММ.ГГГГ >

Для регистрации заявки в техническую поддержку чат-бот будет ожидать ответ вида:

ситуация: <описание ситуации>, критичность: <плановая/средняя/высокая>

Для регистрации общих вопросов: прием строки любого формата.

Справочник отгулов

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

Создадим справочник «Отсутствие сотрудника» - для хранения информации об отгуле и больничном:

Добавленные в справочник свойства:

  • Name – наименование записи
  • Employee – ссылка на конкретного сотрудника
  • StartDate – дата начала отгула
  • EndDate – дата завершения отгула
  • Text – содержимое ответа сотрудника

Справочник заявок в техподдержку

В данной статье мы не будем рассматривать полноценную систему работы с заявками (к слову, такая задача глубоко рассматривается на курсе разработчика DirectumRX), предположим, что данная система уже разработана, и мы будем работать с готовым справочником Tickets:

  • Employee – сотрудник, от которого получено сообщение
  • Criticality – критичность заявки  
  • Text – поле для фиксации общения с сотрудником

Создание необходимых ролей и выдача прав на справочники

Создадим две новые роли:

  • дежурный по общим вопросам – обрабатывает все поступающие общие вопросы и запросы, которые не удалось обработать
  • дежурный техподдержки – обрабатывает вопросы по технической поддержке пользователей
    /// <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;
    }

Описание функций Absence.CreateItem и Tickets.CreateItem

Чтобы обработать сообщения от пользователей, будем использовать регулярные выражения.

Для работы с регулярными выражениями необходимо подключить модуль 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 

36
Авторизуйтесь, чтобы оценить материал.
7
Пока комментариев нет.

Авторизуйтесь, чтобы написать комментарий