Эмоционально-интеллектуальные чат-боты - Часть 1. Получение эмоций от лица пользователя

Это первая статья из серии о создании эмоционально-интеллектуальных чат-ботов. В этой серии статей мы сосредоточимся на разработке чат-бота, который понимает эмоции своих пользователей. Мы узнаем, как использовать различные сервисы, такие как Microsoft Emotion API для обнаружения эмоций по выражениям лица, WebEmpath API для определения эмоций по речевым (аудио) вводам пользователя и многое другое.

TL;DR;

  1. Мы возьмем видеопоток с веб-камеры пользователя и покажем его в элементе видео.
  2. Мы будем отслеживать лицо пользователя в видеопотоке, чтобы определять присутствие лица.
  3. Мы сделаем снимок лица пользователя из прямой видеотрансляции.
  4. Мы отправим этот снимок в Emotion API и проведем анализ эмоций пользователя.

Все началось, когда Джагдип Сони и я впервые подумали о Джойе: инструктор по осознанности и психическому благополучию, которую мы создали. Наша идея была очень простой: получить некоторую информацию о пользователе, а затем, исходя из настроения, которое мы определяем путем анализа собираемых данных, предложить им контент с Youtube и Spotify. Но пока я работал только над тем, чтобы сделать чат-ботов умными. Но затем я познакомился с совершенно новым взглядом на чат-ботов, более личным и интимным подходом к чат-ботам с эмоциональным интеллектом. И это заставило меня изменить мою цель. И это то, на чем я хочу, чтобы вы, ребята, сосредоточились. Так какова же наша цель здесь?

Наша цель - не просто создавать интеллектуальных чат-ботов. Он предназначен для создания эмоционально-интеллектуальных чат-ботов.

И мы начинаем делать это, собирая данные об эмоциях пользователя по его лицу. И здесь на сцену выходит Microsoft Emotion API. Так что же это за API Emotion?

Что ж, Emotion API позволяет распознавать эмоции в изображениях. Он принимает выражение лица на изображении в качестве входных данных и возвращает уверенность в наборе эмоций для каждого лица на изображении, а также ограничивающую рамку для лица, используя Face API. Он может обнаруживать различные эмоции, такие как гнев, презрение, отвращение, страх, счастье, нейтральность, печаль и удивление. Считается, что эти эмоции универсально и межкультурно передаются с помощью определенных выражений лица. Подробнее об этом можно прочитать ниже.



Хорошо, теперь, когда мы знаем, что такое Emotion API, именно его мы будем использовать для преобразования Face to Emotion. Но нам также понадобится способ, чтобы изображение было снято автоматически. Что с этим можно сделать? Что ж, на помощь приходит TrackingJS. Он анализирует видеопоток и, основываясь на заданной нами конфигурации, отслеживает такие вещи, как объекты, цвета и т. Д. И куда именно мы с этим собираемся?

Милая, правда? Это идеальное решение для нас. Это легко и быстро. Итак, теперь мы выяснили, что мы будем использовать для выполнения работы. А теперь начнем с самой работы.

Предпосылки:

  1. Следующий курс действий предполагает, что вы хорошо разбираетесь в Angular и ранее создавали SPA с помощью AngularCLI.
  2. Убедитесь, что у вас установлены все зависимости для создания проекта Angular с AngularCLI.
  3. Создайте проект, используя ng new project-name
  4. Для использования Microsoft Emotion API вам понадобится ключ подписки. Вы можете получить его здесь.
  5. Сохраните ключ подписки в environment.prod.ts следующим образом:

После того, как вы выполнили все вышеупомянутые шаги, можно начинать. А теперь следуйте.

Шаг 1. Представьте фид видео пользователя и покажите его в элементе видео.

Это довольно просто. Вот шаги:

  1. Откройте app.component.html и поместите в него элемент video. Дайте ему переменную шаблона, чтобы мы могли получить к ней доступ в нашем app.component.ts. Примерно так:
    <video #userVideoStream id="userVideoStream" autoplay></video>
  2. Затем откройте app.component.ts и
    import { Component, OnInit, ViewChild } from ‘@angular/core’;
  3. Определите некоторые свойства класса компонента:
    videoNativeElement;
    @ViewChild(‘userVideoStream’) userVideoStream;
  4. Теперь в ngOnInit инициализируйте videoNativeElement с nativeElement из userVideoStream следующим образом:
    this.videoNativeElement = <HTMLVideoElement>this.userVideoStream.nativeElement;
  5. Здесь мы приводим nativeElement к HTMLVideoElement, чтобы получить IntelliSense.
  6. Теперь последний шаг - вызвать getUserMedia на navigator.mediaDevices и передать ему конфигурацию video: true. Он возвращает promise, который можно обработать. Обратный вызов функции then этого promise возвращает stream с веб-камеры / передней камеры пользователя (в случае мобильного устройства), который мы можем установить как srcObject для videoNativeElement. В коде это будет выглядеть примерно так:
    navigator.mediaDevices.getUserMedia({ video: true }).then(
    stream => {
    this.videoNativeElement.srcObject = stream;
    });
  7. Попробуйте это, выполнив ng serve. Он запросит ваши разрешения на доступ к веб-камере. Как только вы разрешите, он будет транслировать входной поток с вашей веб-камеры на видеоэлемент.

Итак, после прохождения до этого момента ваши app.component.ts и app.component.html должны выглядеть так:

ВНИМАНИЕ: этот метод не поддерживается в Internet Explorer и более ранних версиях некоторых других популярных браузеров. Не забудьте проверить совместимость браузера, чтобы узнать больше.

Шаг 2 - Определите присутствие человеческого лица на видео и сделайте снимок, если оно есть.

Здесь мы будем использовать библиотеку TrackingJS. Вот что вам следует делать:

  1. npm install tracking --save
  2. Поместите элемент canvas на app.component.html, который в конечном итоге будет отображать изображение, которое мы захватим с video. Дайте ему переменную шаблона, чтобы мы могли получить к нему доступ из app.component.ts.
    <canvas #canvasToRenderUserImage></canvas>
  3. Определите свойства в файле класса компонента:
    canvasNativeElement; context;
  4. @ViewChild(‘canvasToRenderUserImage’) canvasToRenderUserImage;
  5. Теперь в ngOnInit инициализируйте canvasNativeElement и context следующим образом:
    this.canvasNativeElement = <HTMLCanvasElement>this.canvasToRenderUserImage.nativeElement;
    this.context = this.canvasNativeElement.getContext(‘2d’);
  6. Теперь у нас есть canvas, на котором можно рисовать изображение пользователя из видеопотока. Теперь нам нужно отслеживать лицо пользователя. Для этого сначала импортируем следующее:
    import ‘tracking/build/tracking’;
    import ‘tracking/build/data/face’;
  7. Объявите переменную с именем tracking прямо под этими импортированными, чтобы предотвратить любые ошибки при инициализации объекта tracking. Примерно так:
    declare var tracking: any;
  8. Это даст нам доступ к объекту tracking, для которого мы можем вызвать метод с именем ObjectTracker. Передаем то, что хотим отслеживать. Лицо в этом случае. Для этого:
    const tracker = new tracking.ObjectTracker(‘face’);
  9. Теперь мы настроим некоторые параметры для только что инициализированного трекера. После этого запустим трекер. В коде это будет выглядеть так:
    tracker.setInitialScale(4);
    tracker.setStepSize(2);
    tracker.setEdgesDensity(0.1);
    tracking.track(‘#userVideoStream’, tracker);
  10. Трекер начнет отслеживать видеопоток на предмет любых человеческих лиц. Он продолжит вызывать событие с именем track, которое мы можем слушать. Мы передаем функцию обратного вызова в качестве обработчика события track, которое принимает объект event в качестве первого параметра. Этот объект события имеет массив data. Длина этого массива составляет > 1, если трекер идентифицировал какие-либо человеческие лица на видео, и = 0 в противном случае. Теперь мы хотим нарисовать изображение пользователя на canvas в точном соответствии с кадром, на котором был пользователь. Итак, делаем это:
    tracker.on(‘track’, event => {
    if (event.data.length > 0) // capture user image;
    });
  11. А теперь, чтобы захватить изображение пользователя, мы просто вызываем метод drawImage на context и передаем ему необходимые аргументы.
    this.context.drawImage(this.videoNativeElement, 0, 0, this.canvasNativeElement.width, this.canvasNativeElement.height);
  12. Давайте также остановим видеодорожки, чтобы остановить прямую трансляцию видео. Это можно сделать, вызвав метод getVideoTracks на srcObject videoNativeElement. Как только мы получим видеодорожки, мы можем вручную остановить их, вызвав метод stop для каждой из этих дорожек. Примерно так:
    this.videoNativeElement.srcObject.getVideoTracks().forEach(track => track.stop());
  13. Наконец, мы можем извлечь из этого canvas jpeg, выполнив следующие действия:
    let userImage = this.canvasNativeElement.toDataURL(‘image/jpeg’, 1);

После всего этого ваши app.component.ts и app.component.html должны выглядеть так:

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

Шаг 3. Вызовите Emotion API с изображением пользователя и получите для него данные Emotion.

Поначалу это может показаться довольно простым. Но возникнет проблема, если вы никогда не отправляли визуальные данные как octet stream в POST запросе. Emotion API принимает большой двоичный объект в потоке октетов. Но у нас есть изображение как JPEG. И это не тот формат, который принимает Emotion API. Поэтому нам нужно применить к изображению некоторые преобразования, чтобы преобразовать JPEG в приемлемый формат. Для этого мы создадим службу и делегируем задачу преобразования изображения методу этой службы. Хорошо, хватит разговоров. Давайте код:

  1. Создайте службу с именем emotion. Мне нравится помещать все свои службы в папку с именем services в моей папке app. Итак, для этого:
    ng g s services/emotion/emotion
  2. Теперь внутри этой службы эмоций мы создадим общедоступный метод, который будем вызывать из нашего app.component.ts. И мы передадим ему изображение, которое мы создали из canvas. Этот метод будет отвечать за AJAX-вызов EmotionAPI. Этот метод вызывает внутренний частный метод, который преобразует jpeg в octet stream. Этот метод вернет Observable, который был возвращен в результате вызова метода HttpClient post. Это выглядело бы примерно так:

3. Мы подпишемся на эту наблюдаемую внутри app.component.ts, и тогда мы сможем получить ответ и использовать его для анализа настроения. Это будет выглядеть так:
this._emotionService.getUserEmotion(this.userImage).subscribe(emotionData => { console.log(emotionData); });

После этого в вашем app.component.html не будет никаких изменений. Но ваш app.component.ts будет выглядеть так:

Я просто распечатал ответ от EmotionAPI на консоль. Но возможности такого рода данных - предел возможностей.

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

На всякий случай, если у вас возникла ошибка, я что-то упустил в этой статье, у вас не работает или у вас возникли проблемы с дальнейшим продвижением, вы можете найти здесь весь образец проекта:



ОБНОВИТЬ:

Я также добавил вторую статью в эту серию. Я добавляю ссылку на то же самое ниже:



ПОСЛЕДНЯЯ ВЕЩЬ:

Если вы хотите изучить Angular 5 с самых основ, у меня есть курс по Udemy. Курс включает около 14,5 часов содержания, в которых мы рассматриваем каждую тему, которую вам необходимо понять, чтобы создать полноценное одностраничное приложение. Ознакомьтесь с курсом здесь:



Хлопайте по этой статье, если она вам понравилась, аплодируйте, если вы узнали из нее что-то новое. Поделитесь им с друзьями, если вы нашли это полезным. До скорого.