Привет, Хабр! Совсем недавно мы проводили хакатон для разработчиков в Бухаресте и Клуже. Основной задачей группы в Клуже было создание эффективной программы-робота для чатов с поддержкой Endava и использованием Microsoft Graph и Q&A Maker. Сегодня мы расскажем об этом проекте, затронув управление аутентификацией для взаимодействия с программой-роботом посредством любого канала, интегрирование Q&A Maker и использование Microsoft Graph в сочетании с SharePoint. Подробнее под катом!



Введение


Этот проект был создан в ходе закрытого хакатона для разработчиков Endava и Microsoft. Этот хакатон проводился в городах Клуж и Бухарест (Румыния). Основной задачей участников было создание прототипов ИИ-компонентов, которые улучшили бы веб-приложение Endava, используемое для ИТ-поддержки (например, позволили бы пользователям обмениваться с программами-роботами для чатов сообщениями на естественных языках или оптимизировали управление обращениями с помощью технологий машинного обучения).

Хакатон проводился с 30 января по 2 февраля 2018 г. На этой GitHub-странице представлена часть работы, которая была выполнена в Клуже в течение трех дней. В состав группы разработчиков входили:

  • Корина Чоканя (Corina Ciocanea), разработчик (Endava)
  • Александру Марчис (Alexandru Marchis), разработчик (Endava)
  • Тудор Муресан (Tudor Muresan), разработчик (Endava)
  • Лорен Эллербах (Laurent Ellerbach), руководитель группы технических евангелистов (Microsoft)

Описание проекта


Основной задачей группы в Клуже было создание эффективной программы-робота для чатов с поддержкой нескольких функций:

  • Удобное (для пользователя) создание запроса непосредственно в системе управления обращениями Endava.
  • Создание экспериментальной версией программы-робота, которая будет запрашивать доступ к SharePoint посредством Microsoft Graph, отправляя электронное письмо непосредственно владельцу SharePoint или подготавливая запрос на создание заявки в специализированном приложении компании, которое называется Service Now.
  • Использование Q&A Maker для поиска ответов на пользовательские вопросы в страницах Endava с ответами на вопросы.
  • Все операции аутентификации должны осуществляться через интеграцию с Endava Active Directory.
  • Решение должно поддерживать обработку электронных писем, поскольку раньше подавляющая часть пользователей создавала обращения путем отправки электронных писем.

Информация, содержащаяся в этом документе:

  • Как управлять аутентификацией для взаимодействия с программой-роботом посредством любого канала, в том числе электронной почты.
  • Как интегрировать Q&A Maker с программой-роботом (создание программы-робота Q&A Maker здесь рассматриваться не будет).
  • Использование Microsoft Graph в сочетании с SharePoint и отправка электронной почты. Приведенный здесь код является частью более сложного решения, которое было разработано за три дня.

Архитектурная схема решения:



Используемые технологии


В коде этого решения используются следующие технологии:

  • Q&A Maker;
  • Microsoft Bot Framework;
  • Microsoft Graph;
  • Azure Active Directory;
  • LUIS.ai — когнитивная служба распознавания текстов с возможностью анализа предложений;
  • все службы размещались в Microsoft Azure, программа-робот была реализована в виде веб-приложения;
  • весь код был написан на языке C# в среде Visual Studio Enterprise; платформа VSTS использовалась в качестве репозитория кода.

Аутентификация


Наша идея заключалась в том, чтобы предоставить программе-роботу доступ к контексту с информацией о конкретном пользователе (например, к сайтам SharePoint) и возможность отправлять электронную почту. Поэтому программа-робот должна была быть безопасной и доступной только для сотрудников.

Для решения этих задач требовалось реализовать аутентификацию. Ее внедрение было сопряжено с рядом сложностей, например, программа-робот должна уметь обрабатывать электронную почту, а значит, быть способной аутентифицировать пользователя при отсутствии внутренней процедуры аутентификации. Endava Azure Active Directory представляет собой службу AAD версии 1. Поэтому в качестве платформы для основной программы-робота мы использовали AAD 1. При реализации аутентификации рекомендуется учитывать следующее:

  • Если вы будете пользоваться кодом из примера AuthBot, обязательно сохраните (скопируйте) этот механизм. Это важно из соображений безопасности. Программа-робот для чатов и ваш браузер находятся в различных контекстах, что блокирует некоторые векторы атак.
  • Настройте вашу службу AAD так, чтобы она выполняла авторизацию для конкретного приложения. Вы получите ИД клиента и секрет, которые нужно будет внести в нужную часть файла web.config.
  • Убедитесь, что в файле конфигурации приложения указан правильный URL-адрес возврата. Вы можете создать несколько таких адресов (например, для отладочной и для рабочей версии), все они должны в точности соответствовать URL-адресу перенаправления, поэтому необходимо указать полный путь, в том числе протокол (https/http).
  • Убедитесь, что в настройках AAD для приложения в отношении конкретных ролей (например, Sites.Read.All, Mail.ReadWrite, User.Read, People.Read, Directory.AccessAsUser.All) указаны правильные параметры авторизации.


Аутентификация, безопасность и авторизация в готовом проекте устроены так:



Как видите, основной контекст зависит от аутентификации в AAD. На базе AAD работают следующие компоненты:

  • Внутренняя служба Service Now, которую мы здесь рассматривать не будем.
  • Ядро программы-робота, частью которого является веб-приложение. Здесь используются классические ИД и ключ клиента.
  • Сама программа-робот и когнитивные службы LUIS. Здесь также используются классические ИД и ключ клиента.
  • Программа-робот и служба Q&A Maker. Здесь также используются классические ИД и ключ клиента.

Настройка ключей и ИД для доступа ко всем службам


Настройка AAD


Теперь, после настройки необходимого окружения, нужно внести в файл web.config правильные значения перечисленных ниже параметров.

  • Параметр Tenant соответствует вашему доменному имени для AAD. Это может быть домен второго уровня (yourdomain.com) или третьего (yourdomain.onmicrosoft.com), в зависимости от конфигурации.
  • Настройки ClientId (ИД клиента) и ClientSecret (секрет) вы получаете при настройке приложения.
  • RedirectURL (URL-адрес перенаправления) — URL-адрес, на котором будет развернута программа-робот. В нашем примере это локальный узел. Для рабочей версии системы URL-адрес будет другим. Напоминаем, что при настройке приложения можно задать несколько URL-адресов для всех возможных случаев.

    <!-- Настройки AAD Auth v1-->
    <add key="ActiveDirectory.Mode" value="v1" />
    <add key="ActiveDirectory.ResourceId" value="https://graph.microsoft.com/" />    
    <add key="ActiveDirectory.EndpointUrl" value="https://login.microsoftonline.com" />
    <add key="ActiveDirectory.Tenant" value="YOUR_DOMAIN.COM" />
    <add key="ActiveDirectory.ClientId" value="client_ID" />
    <add key="ActiveDirectory.ClientSecret" value="super_secret" />
    <add key="ActiveDirectory.RedirectUrl" value="http://localhost:3979/api/OAuthCallback" />

Эта настройка — не самая простая задача. В случае ошибки аутентификации система выдаст сообщение, которое поможет понять, где искать причину. Эти сообщения очень подробны и весьма полезны при устранении неполадок. В целом эта настройка может оказаться довольно сложной; возможно, вам потребуется обратиться к администратору домена, чтобы получить определенные права доступа. Настоятельно рекомендуется выделить достаточно времени на этот этап. Хорошая новость: как только этот компонент заработает, возвращаться к его настройке не потребуется.

Настройка программ-роботов


На этапе создания и регистрации программы-робота генерируется имя программы-робота, ИД и ключ клиента. Эти значения нужно добавить в следующие строки файла web.config:

    <add key="BotId" value="YourBotId" />
    <add key="MicrosoftAppId" value="" />
    <add key="MicrosoftAppPassword" value="" />

Настройка Q&A Maker


При создании Q&A Maker вы также получите ИД и ключ. Они потребуются для того, чтобы обращаться к службе и получать рекомендации. Внесите соответствующие ключи в следующие строки файла web.config:

    <!-- настройки QnaMaker -->
    <add key="QnaMaker.KbId" value="QAMaker_ID" />
    <add key="QnaMaker.KbKey" value="QAMaker_Key" />

Настройка LUIS


LUIS используется в SharePoint Dialog для извлечения URL-адреса или имени ресурса SharePoint, к которому требуется обратиться, а также типа доступа. При создании и настройке этой (как и почти любой другой) службы вы получите ИД и секрет. Вам нужно будет отметить класс основного диалога атрибутом LUIS:

    [LuisModel("Key-with-dash", "secret")]
    public class SpDialog : LuisDialog<object>

Управление аутентификацией в коде


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

Аутентификация в AAD


Этот механизм работает по следующей схеме:



Большая часть кода относится к компоненту AuthBot. Как мы уже обсуждали, код важно перенести без изменений, чтобы заблокировать определенные векторы атаки. Помните, что токен очень важен, потому что он содержит все учетные данные, необходимые для доступа к самой различной информации (в том числе, в нашем случае, для отправки электронной почты с адреса пользователя). Никогда не старайтесь сэкономить усилия при работе с системой безопасности. Защите необходимо уделить максимальное внимание.

Аутентификация через AAD также работает для электронной почты. Обратите внимание: проверить аутентификацию при взаимодействии через электронную почту можно только в том случае, если программа-робот выполняется в рабочей среде. Электронные письма принимаются из учетной записи Office 365 и обрабатываются примерно каждые ___ минут.

Для пользователя взаимодействие с системой посредством электронной почты почти не отличается от других каналов. Пользователь отправляет электронное письмо, программа-робот высылает приглашение на вход в систему, в ответ на которое пользователь должен отправить код. Базовый код AuthBot был изменен таким образом, чтобы сделать взаимодействие более удобным (в частности, уменьшить количество отправляемых писем и упростить извлечение кода).

В ответ на первое письмо программа-робот отправляет пользователю сообщение с просьбой перейти по ссылке, чтобы пройти аутентификацию. После этого пользователь должен отправить код:



После его получения программа-робот высылает сообщение об успешной аутентификации. Все другие сообщения, которые отправляет пользователь, будут обработаны служебными процессами программы-робота уже с учетом контекста для этого пользователя. Вне зависимости от канала связи (Teams или какой-либо другой) пользователь может выполнять одни и те же операции. Однако канал электронной почты немного отличается от других: в частности, стоит ограничить объем отправляемых пользователю писем и учесть ряд дополнительных предположений. Подробнее об этом ниже.



Дополнительная информация об AuthBot доступна на соответствующей странице GitHub.

Аутентификация для взаимодействия с программой-роботом


Для аутентификации при взаимодействии с программой-роботом используются компоненты из пакета SDK для разработки таких программ. Если основной контроллер отмечен атрибутом BotAuthentication, то для него будет использоваться механизм аутентификации посредством ключа и секрета, упомянутых в предыдущем разделе (в части про настройку). Он является полностью прозрачным, и если вы без ошибок скопируете эти два элемента в файл web.config, будет прекрасно работать. ИД и секрет потребуются вам даже в режиме отладки. Эмулятор поддерживает этот механизм и отлично подходит для того, чтобы проверить, работает ли ваша пара.

namespace BotToQuerySharepoint
{
    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// <summary>
        /// POST: api/Messages
        /// Получает сообщение от пользователя и возвращает ответ
        /// </summary>
        [BotAuthentication]
        public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
        {
            //код метода
        }
    }
}

Аутентификация в Q&A Maker


Ключи используются для обращений к REST API. Работа организована простым и очевидным образом. Вот фрагмент кода:

public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> item)
{
    var message = await item;
    {
        string kbId = ConfigurationManager.AppSettings["QnaMaker.KbId"];
        string kbKey = ConfigurationManager.AppSettings["QnaMaker.KbKey"];
        string qnaUrl =
            $"https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases/{kbId}/generateAnswer";
        HttpClient client = new HttpClient();        
        var json = new
        {
            question = strtosend,
            top = 3
        };
        var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
        content.Headers.Add("Ocp-Apim-Subscription-Key", kbKey);
        HttpResponseMessage response = await client.PostAsync(qnaUrl, content);
        if (response.StatusCode == HttpStatusCode.OK)
        {
            // выполнить операции, необходимые для того, чтобы выбрать ответ и предложить его
        }
    }
}

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

Аутентификация в службах LUIS


Как объясняется в предыдущем разделе, для включения аутентификации мы просто указали атрибут класса. Этот механизм полностью прозрачен.

Канал обмена данными по электронной почте


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

Отправляя сообщение по электронной почте, пользователь вряд ли будет удалять предыдущую переписку и прочую лишнюю информацию — он просто добавит новый текст. В результате письмо будет содержать подпись пользователя и прочие элементы. Поэтому при взаимодействии через этот канал потребуется провести дополнительную работу по их удалению. В качестве примера ниже приводится фрагмент кода AzureAuthDialog из AuthBot:

if (msg.Text == null)
{
    if (msg.ChannelId != "email")
    {
        await context.PostAsync($"Пожалуйста, вставьте полученный вами номер в окно аутентификации.");
    }
    context.Wait(this.MessageReceivedAsync);

}
else
{
    // Этот код добавлен потому, что при взаимодействии с пользователем по некоторым каналам (например, через электронную почту или при копировании и вставке в Teams) в сообщении появляются лишние элементы
    string cleanedText = msg.Text;
    Match firstmatchedValue = Regex.Match(msg.Text, @"\d+", RegexOptions.IgnorePatternWhitespace);
    if (firstmatchedValue.Length > 0)
        cleanedText = firstmatchedValue.Value;

    if (cleanedText.Length >= 6 && magicNumber.ToString() == cleanedText.Substring(0, 6))
    {
        context.UserData.SetValue<string>(ContextConstants.MagicNumberValidated, "true");
        context.Done($"Спасибо {authResult.UserName}. You are now logged in. ");
    }
    else
    {
        context.UserData.RemoveValue(ContextConstants.AuthResultKey);
        context.UserData.SetValue<string>(ContextConstants.MagicNumberValidated, "false");
        context.UserData.RemoveValue(ContextConstants.MagicNumberKey);
        await context.PostAsync($"К сожалению, не удалось проверить ваш номер. Пожалуйста, попробуйте выполнить процедуру аутентификации еще раз.");
        context.Wait(this.MessageReceivedAsync);
    }
}

Чтобы уменьшить количество электронных писем, отправляемых пользователю, мы не просто просим его выслать обратно полученный код аутентификации, а выводим его на веб-странице и просим пользователя ответить на письмо. Как видно из кода OAuthCallbackController, процедура аутентификации в AuthBot зависит от канала связи:

await Conversation.ResumeAsync(resumptionCookie, message);
if (message.ChannelId == "skypeforbusiness")
    resp.Content = new StringContent($"<html><body>Почти готово! Для завершения аутентификации, пожалуйста, скопируйте этот номер и вставьте его в ваш чат:<br/> {magicNumber} </body></html>", System.Text.Encoding.UTF8, @"text/html");
else if (message.ChannelId == "email")
    resp.Content = new StringContent($"<html><body>Почти готово! Для завершения аутентификации, пожалуйста, отправьте этот номер в ответ на полученное вами электронное письмо с просьбой об аутентификации:<br/> {magicNumber} </body></html>", System.Text.Encoding.UTF8, @"text/html");
else
    resp.Content = new StringContent($"<html><body>Почти готово! Для завершения аутентификации, пожалуйста, скопируйте этот номер и вставьте его в ваш чат:<br/> <h1>{magicNumber}</h1>.</body></html>", System.Text.Encoding.UTF8, @"text/html");

Каждому каналу соответствует уникальное имя. Это позволяет с легкостью адаптировать действия вашей программы-робота под тип канала.

Еще один пример содержится в коде Q&A Dialog (kbDialog) главной программы-робота:

string strtosend = message.Text;
if (message.ChannelId == "email")
{
    var str = strtosend.Split('\n');
    int maxidx = str.Length;
    if (maxidx > 3)
        maxidx = 4;
    for (int i = 0; i < maxidx; i++)
        strtosend += str[i] + " ";
}

Задача этого кода — извлечь только первую часть электронного письма и удалить подпись. Предполагается, что возможный вопрос содержится в первых трех строках. Ниже находятся предыдущие письма или подпись пользователя. Это лишь предположение, и оно не всегда выполняется, но в ходе нашего трехдневного хакатона оно работало идеально.

Еще одним примером является фрагмент кода Q&A Maker, который управляет возвратом ответа. Обычно решение предоставляет пользователю не более трех вариантов и спрашивает у него, какой лучше всего ему подходит. Но если пользователь отправляет вопрос по электронной почте, он рассчитывает получить ответ, а не встречный запрос. Мы решили сделать так: если вопрос был получен по электронной почте, то решение просто возвращает первый ответ. Рассматривался также вариант включить в электронное письмо подробное содержимое всех ответов. В следующем фрагменте кода показано, как выполняется эта обработка:

if (qnaResponse.answers.Count == 0)
{
    await context.PostAsync(
        "Не удалось найти информацию по этой теме. \nМогу ли я еще чем-то помочь вам по разделу QNA?");
    context.Done(true);
}
else if ((qnaResponse.answers.Count == 1) || (message.ChannelId == "email"))
{
    await context.PostAsync(qnaResponse.answers.First().answer);
    context.Done(true);
}
else
{
    // другой код
}

Microsoft Graph и SharePoint


Microsoft Graph — единый интерфейс REST API для чтения, изменения и создания пользовательских данных (примеры: пользовательский календарь, электронная почта, содержимое SharePoint и OneDrive). В рамках этого проекта нас интересовали компоненты Graph API для взаимодействия с SharePoint и электронной почтой.

Чтобы упростить себе задачу, мы воспользовались Nuget-пакетом Microsoft.Graph. Компоненты из Nuget-пакета обрабатывают все запросы и возвращают объекты. Но провести аутентификацию и получить токен вы должны самостоятельно. К счастью, механизм аутентификации мы уже подготовили (и обсудили выше).

В качестве примера ниже приводится код функции, которая возвращает имя владельца некоторого дочернего сайта SharePoint:

public async Task<UserInfo> GetOwnerNameForSite(string token, string siteId)
{
    var graphService = new GraphServiceClient(
        new DelegateAuthenticationProvider(
            (requestMessage) =>
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                return Task.FromResult(0);
            }));

    var s = await graphService.Sites[siteId]
        .Drives.Request()
        .GetAsync();

    var user = await graphService.Users[s.First().CreatedBy.User.Id].Request().GetAsync();
    return new UserInfo()
    {
        EmailAddress = user.Mail,
        Name = user.DisplayName
    };
}

При создании объекта GraphServiceClient вам достаточно будет передать токен, как показано в коде, и после этого можно будет вызывать нужные функции Graph.

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

Отправить письмо с помощью Microsoft Graph также очень просто:

public async Task SendEmail(string accessToken, string emailAddress, string body, string subject)
{
    var message = new Message();
    message.Body = new ItemBody() { Content = body, ContentType = BodyType.Text };
    message.ToRecipients = new List<Recipient>()
    {
        new Recipient() {EmailAddress = new EmailAddress() {Address = emailAddress}}
    };
    message.Subject = subject;

    var graphserviceClient = new GraphServiceClient(
        new DelegateAuthenticationProvider(
            (requestMessage) =>
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
                return Task.FromResult(0);
            }));

    await graphserviceClient.Me.SendMail(message, true).Request().PostAsync();
}   

В этом примере отправляется простое текстовое письмо, но HTML тоже поддерживается. Возможна также отправка писем нескольким получателям. У нас было всего три дня на то, чтобы выпустить готовое решение, поэтому мы решили создать рабочий, но максимально простой код.

Если пользователь аутентифицировался с указанием собственных учетных данных, то электронное письмо будет отправлено с его ящика и будет доступно в папке «Отправленные».

Поэкспериментировать со всеми функциями Microsoft Graph можно на этом сайте. Вы можете пройти аутентификацию, указав собственные учетные данные, поработать с любыми функциями, посмотреть, как скажется на результатах добавление или удаление области.

Советы по работе с Q&A Maker


Q&A Maker — отличный инструмент для очень быстрой подготовки пар «вопрос — ответ» и для запуска когнитивной службы, у которой можно получать ответы на вопросы. Этот инструмент очень просто интегрировать, и им очень легко пользоваться. Работа над этой службой пока активно ведется. Доступная версия является лишь ознакомительной. Вот как это выглядит:



Поддерживается несколько способов заполнения списка. Вы можете использовать API (документация доступна здесь), импортировать файл tsv или указать URL-адрес.

Для использования базы знаний Endava требовалось проходить аутентификацию, а для работы с Q&A Maker — нет. Поэтому нам нужно было экспортировать базу. Данные хранились в различных форматах, в том числе в HTML-коде, и этот код нам нужно было вычистить.

Мы очистили данные с помощью регулярных выражений: удалили HTML-теги, добавили символы табуляции и переноса строки. Вот фрагмент кода:

// удалить все стили (требуется предварительная подготовка — очистка атрибутов)
result = System.Text.RegularExpressions.Regex.Replace(result,
            @"<( )*style([^>])*>", "<style>",
            System.Text.RegularExpressions.RegexOptions.IgnoreCase);
result = System.Text.RegularExpressions.Regex.Replace(result,
            @"(<( )*(/)( )*style( )*>)", "</style>",
            System.Text.RegularExpressions.RegexOptions.IgnoreCase);
result = System.Text.RegularExpressions.Regex.Replace(result,
            "(<style>).*(</style>)", string.Empty,
            System.Text.RegularExpressions.RegexOptions.IgnoreCase);

// заменить все теги <td> символами табуляции
result = System.Text.RegularExpressions.Regex.Replace(result,
            @"<( )*td([^>])*>", "\\t", //\t
            System.Text.RegularExpressions.RegexOptions.IgnoreCase);

Вы можете спросить, почему символ табуляции записывается как \\t, а не \t. Ответ такой же, как и для символа \\n. Дело в том, что Q&A Maker хранит и возвращает ответы в виде необработанных текстовых данных. Используемый файл tsv не может содержать символы возврата каретки или дополнительные символы табуляции, иначе система может обработать его некорректно. Обработчики для всех каналов корректно отображают символы \t и \n, что позволяет лучше отформатировать ответ.

Важное замечание: в Q&A Maker можно хранить данные с разметкой Markdown, но следует помнить, что некоторые каналы могут ее не поддерживать! На снимке экрана показаны некоторые из переносов строк \n.

Еще мы добавили в каждый ответ ссылку на главную страницу базы знаний. Эти страницы выглядят лучше, чем простой текст, и могут содержать изображения, которые мы из нашего основного кода полностью убрали. Мы старались сделать так, чтобы пользователю было максимально удобно.

При выборе подходящего ответа Q&A Maker анализирует текст как вопроса, так и ответа. Поэтому ответы также должны быть как можно более развернутыми.

Советы по работе со службой LUIS


Настройка службы LUIS достаточно проста. В нашем примере используется только одно намерение и три сущности.

LUIS работает примерно так:

  • Запрос пользователя: Я бы хотел получить доступ [read] к [Development] сайту sharepoint.
  • LUIS понимает намерение — доступ (access) к SharePoint — и извлекает две сущности: [read] и [Development].

Чтобы обработать намерение и вызвать определенную функцию из вашего класса диалога LUIS, просто отметьте функцию атрибутом с именем вашего намерения, как показано ниже:

[LuisIntent("sp-access")]
public virtual async Task ProcessSpAccessRequest(IDialogContext context, LuisResult luisResult)
{
    var accessToken =
        await context.GetAccessToken(
            ConfigurationManager.AppSettings[
                "ActiveDirectory.ResourceId"]); //предполагается, что ресурс — Graph API
    SpFormHandler formHandler = new SpFormHandler();
    IFormDialog<SharepointModel> formDialog = formHandler.GetFormDialog(luisResult.Entities, accessToken);

    context.Call(formDialog, OnFormComplete);
}

Взаимодействие с программой-роботом SharePoint гораздо более линейно, поэтому мы замещаем диалог LUIS диалогом посредством формы, работа с которым в случае линейных вопросов намного проще. Большая часть кода обработки вопросов SharePoint относится к форме SpFormHandler. Это элегантный способ объединить несколько диалогов. Как видно из кода, в конструктор можно передать любой объект:

[Serializable]
public class SpFormHandler
{
    public IFormDialog<SharepointModel> GetFormDialog(IEnumerable<EntityRecommendation> entities, string token)
    {
        var spForm = new SharepointModel();
        spForm.Token = token;
        foreach (EntityRecommendation entity in entities)
        {
            if (entity.Type == "sp-sitename" || entity.Type == "builtin.url")
            {
                spForm.SitenameOrUrl = entity.Entity;
            }

            if (entity.Type == "sp-accessright")
            {
                Enum.TryParse(entity.Entity, true, out AccessRights rights);
                spForm.AccessRights = rights;
            }
        }

        return new FormDialog<SharepointModel>(spForm, BuildForm, FormOptions.PromptInStart);
    }

    private IForm<SharepointModel> BuildForm()
    {
        //код
    } 
}

Передаются как сущности из LUIS, так и токен. Сущности используются для получения URL-адреса или имени ресурса SharePoint, а также запрошенного вида доступа. LUIS содержит множество встроенных сущностей, например URL. Настоятельно рекомендуем их использовать: они отлично работают и помогают экономить время.

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

Заключение и дальнейшие действия


Код этого проекта является лишь частью кода, написанного за три дня, но он представляет собой хороший пример сочетания различных технологий: аутентификация посредством Azure Active Directory, взаимодействие с программой-роботом посредством различных каналов, в том числе электронной почты, использование когнитивных служб, таких как Q&A Maker и LUIS, через Microsoft Graph.

Опубликованный код и документация образуют полностью функциональное решение. Вы можете испытать на практике как частичное, так и полное решение. Для работы с компонентом Microsoft Graph вам потребуется пройти аутентификацию и получить токен. Как упоминалось в разделе «Аутентификация», для настройки Azure Active Directory необходимо выполнить довольно много операций, а поиск ошибок часто требует времени. В случае ошибки проанализируйте полученное сообщение и действуйте последовательно.

Мы собираемся подготовить и запустить еще одно решение, которое будет прогнозировать вид инцидента и автоматически составлять заявки в службу поддержки.

Комментарии (0)