Разговоры с призраками: Ада Лавлейс

в 14:31, , рубрики: ada lovelace, Bot Framework, cognitive services, halloween, LUIS, microsoft, Wit.ai, Блог компании Microsoft

Ужасами Хэллоуина могут стать не только приведения за окном и страшные костюмы, в которых пришли коллеги. Для истинного интроверта — это будет общение с толпами людей во время праздника, да и не только. В прошлом году я участвовала в создании бота Ады Лавлейс, первой в мире женщины-программиста. В течение года я периодически болтала с ней и мечтала сделать её более совершенной. Приглашаю под кат почитать о новых возможностях, которые мы добавили: цитаты самой Ады, математические задачи от неё и распознавание изображений.

Разговоры с призраками: Ада Лавлейс - 1

Недавно у нас проходил хакатон для студентов-партнеров Microsoft, на котором одна из команд взялась за идею улучшить предыдущую версию бота Ады Лавлейс. Давайте посмотрим, что получилось.

Как учила Ада

Бот Ады Лавлейс построен на Microsoft Bot Framework, что позволяет его деплоить не только в Telegram, но и в другие каналы, такие как Skype, Slack, Facebook Messenger, Web Chat, Cortana, SMS, etc. Ребята постарались воссоздать бота, взяв за основу реальные цитаты Ады Лавлейс. Довольно интересно, о чём думала в тот момент девушка – сильный математик и первый программист.

Из нового функционала: Ада будет предлагать порешать с ней математические задачки, и задачки на алгоритмы, поскольку все мы с вами знаем, что она очень любила математику, а также впервые ввела в употребление такие термины, как «цикл» и «рабочая ячейка». На этот раз, помимо фановой составляющей, Ада может подтянуть вас в математике, переводе из одной системы счисления в другую, а также в базовых понятиях «циклов» и «рабочих ячеек». Все задачи имеют страшную легенду, накаляя страсти.

Вот пример одной из задач, которые вас попросит решить Ада.

По вечерам я люблю засиживаться на веранде, пополняя свой дневник все новыми и новыми исследованиями в области математики. Но однажды, я заметила, мой сосед – Мистер Сандерс по вечерам постоянно ходит в соседний сад. Мне стало интересно. Дождавшись полуночи, когда белый туман, освещенный лунным светом, окутывает просторы сада, я решилась узнать его тайну. Обойдя фонтан со всех сторон в еле видном лунном свете, я заметила странный рисунок на дне фонтана. На нем были изображены четыре отдельно расположенные надписи: «1010», «1100», «10010», «1111». Наверное, это какие цифры в десятичной системе исчисления. Интересно, если мои предположения верны, какие числа там были закодированы? Какую тайну скрывал Мистер Сандерс? У тебя есть предположения? Введи ответ целостно ниже». Или к примеру: «Утром, после завтрака я очень люблю засиживаться в отцовском кабинете и читать исследования отца. В очередной раз, читая его дневник, я обнаружила потертые записи какого-то математического вычисления. В этом математическом вычислении было число, которое инкрементировалось (+) или декрементировалось (-) определенным другим числом. Данное вычисление завершалось только тогда, когда сумма достигала определенного значения, которое мы задавали сами. Такое повторение я решила назвать "Цикл". Для практического подтверждение правильности определения своего термина, я решила провести простое математическое вычисление. Через сколько действий цикл прекратится, при условии: стартовое число равно 5, значение инкремента равно 3, пороговое число для прекращения цикла равно 35.

Некоторые из задач снабжены подсказками, если человек не может решить с первого раза, он получит подсказку, а если ошибется 3 раза, ему скажут ответ. Как только собеседник заводит разговор про математику или программирование, Ада может предложить ему решить задачку.

Задачи собеседнику бот будет выдавать с помощью обертки диалогов IDialog. Рандом будет случайно выбирать момент, когда следует дать пользователю задачу. Далее будет создаваться диалог, в котором будет заданы задачки из json файла с Blob на Microsoft Azure.

Код здесь.

        public async System.Threading.Tasks.Task MessageRecieveAsync(IDialogContext context, IAwaitable<IActivity> result)

        {

            IActivity message = await result;

            string reply = "";

            if (tasks.Unreaded)

            {

                reply = "Я знаю несколько интересных задач и предлагаю вам решить парочку из них";

                await context.PostAsync(reply);

                reply = tasks.Tasks[tasks.Number].Condition;

                await context.PostAsync(reply);

                tasks.Unreaded = false;

                context.Wait(MessageRecieveAsync);

            }

            else if (Helpers.NumParser(message.AsMessageActivity().Text) == tasks.Tasks[tasks.Number].Answer)

            {

                reply = "Это верный ответ!";

                await context.PostAsync(reply);

                tasks.Tasking = false;

                context.Done(this);

                return;

            }

            else

            {

                reply = "Неверно. Но я могу подсказать. nnu200C" + tasks.Tasks[tasks.Number].Explanation + "nnu200CВ следующий раз будь внимательнее";

                await context.PostAsync(reply);

                context.Done(this);

                return;

            }

        }

Как видела Ада

Помимо того, что Ада научилась задавать собеседникам задачи, она еще научилась видеть. Если вы отправите ей какую-нибудь картинку, то Ада увидит её и сможет сказать, что на ней изображено. Зрение Ада получила благодаря Microsoft Cognitive Services. Для реализации зрения Ады мы использовали Vision API. Если на картинке будут присутствовать люди, она сможет оценить эмоциональное настроение людей на картинке.

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

Код здесь.

if (activity.Attachments?.Any() == true)

Если Attachments будут иметь прикрепленный файл, в частности изображение, то сперва создаем http-клиент, по которому у нас будет отправляться фотография. Затем открываем Stream для фото и создаем файл по ссылке. Само распознавание будет происходить по Description, полученному после распознавания картинки.

Код здесь.

private async System.Threading.Tasks.Task StartRecognize(MemoryStream photo)

        {

            try

            {

                _analysisResult = await _visionServiceClient.DescribeAsync(photo);

                _isVision = true;

            }

            catch

            {

            }

        }

        public async Task<string> MakeSomeSummary(MemoryStream photo)

        {

            string result = "nothing";

            await StartRecognize(photo);

            if (_isVision)

            {

                if (_analysisResult.Description.Captions.Length > 0)

                {

                    result = _analysisResult.Description.Captions[0].Text;

                }

            }

            return await Helpers.TranslateText(result, "ru", await Helpers.GetAuthenticationToken("SubKey"));

        }

Для того, чтобы Ада отвечала нам по-русски, Description мы переведем с помощью Translation API.

Код здесь.

public static async Task<string> TranslateText(string inputText, string language, string accessToken)

        {

            string result = "";

            string url = " [http://api.microsofttranslator.com/v2/Http.svc/Translate](http://api.microsofttranslator.com/v2/Http.svc/Translate)";

            string query = $"?text={System.Net.WebUtility.UrlEncode(inputText)}&to={language}&contentType=text/plain";

            using (var client = new HttpClient())

            {

                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                var response = await client.GetAsync(url + query);

                result = await response.Content.ReadAsStringAsync();

                if (!response.IsSuccessStatusCode)

                    return "Hata: " + result;

                var translatedText = XElement.Parse(result).Value;

                return translatedText;

            }

            return result;

        }

        public static async Task<string> GetAuthenticationToken(string key)

        {

            string endpoint = " [https://api.cognitive.microsoft.com/sts/v1.0/issueToken](https://api.cognitive.microsoft.com/sts/v1.0/issueToken)";

            using (var client = new HttpClient())

            {

                client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);

                var response = await client.PostAsync(endpoint, null);

                var token = await response.Content.ReadAsStringAsync();

                return token;

            }

        }

После распознавания мы создаём ответ и проверяем, распознаны ли у нас эмоции. Здесь гораздо интереснее. Ада будет распознавать среднюю эмоциональную активность на всей фотографии, распознавая все лица и определяя, какая эмоция преобладает на картинке. Мы же собираем все эмоции на каждое лицо и находим по среднему арифметическому от каждой эмоции "среднюю температуру по больнице";.

Код здесь.

public async Task<string> MakeAboveEmotion(MemoryStream photo)

        {

            string result = "nothing";

            await StartRecognize(photo);

            if (_isEmotion)

            {

                double[] aboveEmo = new double[8];

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[0] += x.Scores.Anger;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[1] += x.Scores.Contempt;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[2] += x.Scores.Disgust;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[3] += x.Scores.Fear;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[4] += x.Scores.Happiness;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[5] += x.Scores.Neutral;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[6] += x.Scores.Sadness;

                });

                Emotions.ToList().ForEach(x =>

                {

                    aboveEmo[7] += x.Scores.Surprise;

                });

                int mx = aboveEmo.ToList().IndexOf(aboveEmo.ToList().Max());

                switch (mx)

                {

                    case 0:

                        result = "anger emotions";

                        break;

                    case 1:

                        result = "contempt emotions";

                        break;

                    case 2:

                        result = "disgust emotions";

                        break;

                    case 3:

                        result = "fear emotions";

                        break;

                    case 4:

                        result = "happiness emotions";

                        break;

                    case 5:

                        result = "neutral emotions";

                        break;

                    case 6:

                        result = "sadness emotions";;

                        break;

                    case 7:

                        result = "surprise emotions";

                        break;

                    default:

                        result = "nothing";

                        break;

                }

            }

            return await Helpers.TranslateText(result, "ru", await Helpers.GetAuthenticationToken("SubKey"));

        }

Как говорила Ада

Не стоит забывать и об основном функционале бота. В новой версии ребята постарались расширить базу интентов. Теперь можно услышать цитаты Ады Лавлейс. Например, на один из вопросов вы можете получить ответ, который содержит в себе факты о жизни первого в мире программиста.

Например, вот такую цитату о математике.

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

Надеемся, что вам это поможет погрузиться в мысли великого математика. Разумеется, не обошлось и без расширения базы основных ответов.

Вы можете поговорить с Адой в Telegram: @adalovelacebot_bot

Если вы хотите поучаствовать в улучшении бота, pull requests are welcome.

Об авторах

  • Разработчик: Максим Еремин. Студент-партнер Microsoft (MSP). Студент 3 курса 8 факультета кафедры "Вычислительной математики и программирования". Практикует создание ботов на Microsoft Bot Framework, разработку приложений, использующих Microsoft Cognitive Services.
  • Автор интентов: Никулкин Андрей. Студент-партнер Microsoft (MSP). Студент 3 курса факультета сервисных технологий кафедры "Информационные системы" ФГБОУ ВО "РГУТИС". Из интересов, ключевой является создание приложений дополненной реальности AR, информационная безопасность в Windows 10, финансовая бизнес-аналитика Power BI.
  • Team Lead, автор задач: Александр Поповкин. Microsoft Student Partners Lead | Microsoft Russia. Считает, что технологии Microsoft могут изменить мир к лучшему.

Автор: Schvepsss

Источник

Поделиться

* - обязательные к заполнению поля