company_banner

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

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



    Недавно у нас проходил хакатон для студентов-партнеров 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 = "Неверно. Но я могу подсказать. \n\n\u200C" + tasks.Tasks[tasks.Number].Explanation + "\n\n\u200CВ следующий раз будь внимательнее";
    
                    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 могут изменить мир к лучшему.
    Microsoft 381,54
    Microsoft — мировой лидер в области ПО и ИТ-услуг
    Поделиться публикацией
    Похожие публикации
    Комментарии 14
    • –4
      Я считаю что такое отношение у реально жившему и умершему человеку совершенно неприемлемо. И даже не собираюсь пояснять почему. И даже на хеллоуин.
      • +3
        Глупость какая-то. Анекдоты с участием исторических лиц вы тоже считаете неприемлимыми?
        • 0
          Только если те в ответ не спамят ссылками.
      • –2

        Действительно как-то не по себе. Из хорошего человека делать игрушку.

        • +1
          вообще это ключ к бессмертию. Бот был воссоздан по ее настоящим цитатам и соответственным образом обучен.
          • 0
            А в чем тут бессмертие? Что я вижу конкретно в этом так это желание попиариться одной отдельно взятой компании на имени уже мертвого человека. Особенно учитывая заявление из предыдущей статьи что не стоит ожидать что бот пройдет хотя бы тест Тьюринга («хотя бы» потому что этот тест еще не гарантирует интеллекта) Ну т.е. никаких объективных достижений он не демонстрирует, но привлекает внимание. И да я понимаю что это блог компании и пиар тут допустим. Но согласен с людьми которым такой вид рекламы не нравится — это вполне правильно. И оно никак не приближает нас к бессмертию от слова совсем.
            • +2
              Так это не биологическое бессмертие, которое пытаются добиться учёные, а «нерукотворный памятник»
              Не вижу ничего плохого в том, что айти-контора использует имя великого айтишника из прошлого — никто вроде не возмущается, когда певцы проводят концерты в память своих ушедших коллег (тоже ведь можно расценить как пиар)
              • 0
                Расценить можно что и как угодно. Конечно это мое субъективное мнение. Так что вопросы этики можно и в стороне оставить. Однако мне видится что в этой статье рекламы больше, чем чего то полезного. Статья по сути раздувает хайп вокруг того что уже давно существует. А неплохо бы показать что то действительно новое. До певцов честно сказать дела нет — они на хабре рекламных статей пока не пишут.
        • 0
          Код, похоже, прошел через html escape: "Task&-lt;string&-gt" и теперь не код.
        • +1

          Спасибо. Попробовал. Пока эффекта осмысленного диалога не достигнуто. Хотя опыта тоже у меня маловато. Алиса не впечатлила аналогично. Хотелось бы встретить умную, интерактивную, динамичную ботессу для общения и обучения.
          Разработчикам удачи и мои наилучшие.

          • 0

            Мне она выдаёт всего одну задачу:


            задача

            Утром, после завтрака я очень люблю засиживаться в отцовском кабинете и читать исследования отца. В очередной раз, читая его дневник, я обнаружила потертые записи какого-то математическиого вычисления. В этом математическом вычислении было число, которое инкрементировалось(+) или декрементировалось(-) определенным другим числом. Данное вычисление завершалось только тогда, когда сумма достигала определенного значения, которое мы задавали сами. Такое повторение я решила назвать "Цикл".

            ‌ Для практического подтверждение правильности определения своего термина, я решила провести простое математическое вычисление.

            ‌ Через сколько действий цикл прекратится, при условии: стартовое число равно 5, значение инкремента равно 3, пороговое число для прекращения цикла равно 35.

            ‌ Подсказка: количество повторений цикла отправьте числом.


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

            • 0
              POST to halloween_bot failed: POST to the bot's endpoint failed with HTTP status 500

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое