Статьи

Робот Навыки и API обмена сообщениями

Службы обмена сообщениями создают основу для взаимодействия людей с программируемыми роботами, используя те же устройства, которые мы уже используем для общения друг с другом. Такое взаимодействие немного похоже на магию, но это магия, которую может создать любой, кто кодирует. Чтобы показать вам, что я имею в виду, нам нужно взглянуть на навык Misty’s Photo Booth, который Misty продемонстрировал на Twilio SIGNAL 2019 .

Когда этот навык срабатывает, вы можете отправить SMS, чтобы попросить вашего робота Misty сфотографировать вас. Когда Мисти получает ваш текст, она останавливает то, что она делает, поворачивается, чтобы посмотреть на вас, и щелкает ваш портрет с камерой в козырьке. Затем она отправляет эту картинку обратно на телефон через MMS.

Для того, чтобы показать , как все это работает, эта статья ломается , что происходит за-козырьком Photo Booth мастерства Мисти, с вашего пальца трогательной отправить на свой портрет посадки обратно в устройство. Он исследует связи между каждым сервисом, который объединяет навык, и объясняет несколько важных блоков кода JavaScript, который контролирует ответ Мисти.

Давайте начнем с того, что посмотрим на Twilio Autopilot, сервис, который посещает ваш текст в первую очередь.

SMS -> Twilio Автопилот

Чтобы привлечь внимание Мисти, пользователь набирает номер телефона, подключенного к услуге Автопилот Twilio . Если вы новичок в Autopilot, вот как Twilio описывает это:

Autopilot — это диалоговая AI-платформа для создания многоканальных ботов и виртуальных помощников с пониманием естественного языка и полной программируемостью с помощью Autopilot Actions.

-Twilio

Когда вы набираете этот специальный номер, Twilio направляет ваше сообщение в канал Programmable Messaging, связанный с уникальным «ботом» автопилота. Каждый созданный вами автопилотский бот может выполнять одну или несколько «задач» (то есть действий, которые запускаются, когда ваш бот получает сообщения определенного типа). Вы настраиваете задачи в консоли Twilio для программирования того, что они должны делать при запуске.

Для навыка фотобудки, основная функция нашего бота Autopilot живет в задаче, которую мы называем take_picture. Мы «обучаем» нашего бота запускать take_pictureзадачу, когда он получает одну из следующих фраз:

Снимок экрана в личку

Следующим шагом является программирование действий бота при take_pictureзапуске задачи. Возможные действия включают отправку сообщения обратно пользователю, прослушивание ответов или сбор и хранение информации. Или, если встроенных действий недостаточно, вы можете запрограммировать задачи на перенаправление на другие службы. Это то, что мы делаем в навыке Photo Booth. Когда take_pictureзадача запускается, она вызывает перенаправление для запуска функции Twilio.

Автопилот -> Функция Twilio

Функции Twilio — это бесполезные функции для обработки входящих сообщений Twilio. Эти функции представляют собой быстрый способ представить сообщения, которые вы обрабатываете в Twilio, остальным сетям (среда общения, в которой такие роботы, как Мисти, исключительно хорошо разбираются).

Функция Twilio, которую мы используем в навыке Photo Booth, делает несколько вещей. Во-первых, он назначает номер телефона пользователя переменной. Затем он использует API Twilio , чтобы ответить пользователю с SMS: [••] Time to Pose. Наконец, он отправляет телефонный номер пользователя (и характер запрашиваемого им действия) на канал PubNub, который Мисти прослушивает на предмет новых сообщений. (Подробнее об этом в следующем разделе).

Снимок экрана в AM

Код функции Twilio для навыка Photo Booth выглядит примерно так:

exports.handler = function(context, event, callback) {
    // Saves phone number to contact variable
    var contact = event.UserIdentifier || "19294421336";  

    // Sends SMS to user
    const replySms = {"actions": [{"say": "[••] Time to Pose"}]};
    const replyErrorSms = {"actions": [{"say": "[••] Oops an error occured, Could you please try again.."}]};

    const axios = require('axios')
    // The PubNub URL includes publish/subscribe keys, a 
    // channel name (similar to the name of a chatroom),
    // and a client name (a unique name identifying this
    // device in the PubNub channel).
    axios.post('https://ps.pndsn.com/publish/<publish-key>/<subscribe-key>/0/<channel-name>/0?store=0&uuid=<client-name>', {
      'phNumber': contact, 'type': 'photo' 
    })
    .then((res) => {
        console.log(res);
        callback(null, replySms);
    })
    .catch((error) => {
        console.log(error);
      callback(null, replyErrorSms);
    });
};

С настройкой Twilio Function и Autopilot Bot мы готовы взглянуть на PubNub, сервис, который уведомляет Misty о необходимости сфотографировать.

Функция Twilio -> PubNub

Взломать робота, чтобы он отреагировал на смс, это круто. Еще круче? Когда этот робот реагирует практически без задержки. Вот где приходит PubNub.

PubNub предоставляет API для обмена сообщениями в реальном времени, который разработчики могут использовать с помощью протоколов обмена данными HTTP, что обеспечивает быструю связь между всеми видами компьютеров. Когда вы используете API обмена сообщениями PubNub, вы создаете канал данных — что-то вроде чата для устройств — на который несколько устройств (например, серверы и роботы Twilio) могут подписываться и публиковать сообщения.

В то время как PubNub предоставляет SDK для нескольких разных языков, мы отлично ладим с навыком Photo Booth с базовыми HTTP-запросами. Когда вы создаете новое «приложение» в PubNub, вы получаете уникальные ключи API для публикации и подписки на это приложение. Чтобы опубликовать данные (как мы делали в функции Twilio выше), мы отправляем запрос POST по адресу:

https://ps.pndsn.com/publish/ <ключ публиковать> / <подписаться ключ> / <имя-канала> / 0/0? магазин = 0 UUID = <имя клиента> &

Вы заметите, что URL-адрес PubNub включает ключи публикации / подписки, имя канала (вроде имени чата) и имя клиента (уникальное имя, которое идентифицирует это устройство в канале PubNub). Когда мы отправляем этот запрос, мы передаем тело JSON с сообщением, которое мы хотим опубликовать. В нашем случае это сообщение напоминает:

{
  'phNumber': contact,
  'type': 'photo'
}

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

photoBothMisty

PubNub -> Мисти

Прежде чем мы рассмотрим код навыка робота, полезно понять, что мы подразумеваем под навыком . В Misty robo-verse умение — это ваш код JavaScript, работающий локально на роботе. Для каждого навыка требуется файл кода JavaScript, при этом Misty JavaScript выполняется при запуске навыка, и метафайл JSON с другой информацией о навыке.

Встроенный в Misty JavaScript API предоставляет методы для подписки на данные от датчиков и других событий, и вы определяете обратные вызовы для обработки этих данных в своем коде навыков. Этот API также включает методы для таких команд, как перемещение робота, использование его датчиков, воспроизведение звуков и отправка веб-запросов. Последний момент — то, как Мисти получает данные из PubNub в навыке Photo Booth.

Для быстрого ответа робот, работающий с навыком Photo Booth, должен быть включен и запускать код, прежде чем кто-нибудь отправит ей текст. Пока мастерство работает, Misty прослушивает новые SMS-уведомления, регулярно отправляя запросы на наш канал PubNub. Мы делаем это в нашем коде с помощью misty.SendExternalRequest()метода из Misty JavaScript API.

Каждый запрос, который отправляет Misty, истекает, если он не получает ответа через двадцать секунд, и нет никакой гарантии, что кто-то отправит Misty сообщение в течение этого периода времени. Мы работаем над этим в своем умении, соединяя наш запрос на подписку с запросом на публикацию пустого сообщения на канал PubNub, который работает по циклу, чтобы сохранить открытые линии связи. Когда наш бот Twilio перенаправляет сообщение в PubNub, Misty возвращает его нашему навыку и передает его в _pubNubSubscribe()функцию обратного вызова.

В файле JavaScript для нашего навыка Photo Booth этот код выглядит примерно так (вы также можете найти пример только извлеченной функциональности PubNub на GitHub ):

// Calls the keepActive() function every 15 seconds
misty.RegisterTimerEvent("keepActive", 15000, true);


// Sends a publish request to work around timeouts 
function _keepActive() {
    misty.SendExternalRequest("POST", "https://ps.pndsn.com/publish/<publish-key>/<subscribe-key/0/<channel-name>/myCallback", null, null, "{}", false, false, "", "application/json");
}

// Gets the message Twilio sends to PubNub and passes
// the response into the _pubNubSubscribe callback function
misty.SendExternalRequest("GET", "https://ps.pndsn.com/subscribe/<subscribe-key>/<channel-name>/0/0?uuid=<client-id>", null, null, "{}", false, false, "", "application/json","_pubNubSubscribe");

// Extracts the phone number and runs the function that
// has Misty take a picture
function _pubNubSubscribe(data) {
    outputExt(data.Result.ResponseObject.Data);
}

outputExt()Функции ( как показано выше) извлекает телефонный номер и значение параметра типа из сообщения функции Twilio посылает. Misty сохраняет номер телефона и проверяет, что значение типа равно фотографии. Если это так, она запускает блок кода, который заставляет ее повернуть голову (и камеру) лицом к пользователю, изменить свое отображаемое изображение и воспроизводить звуки, чтобы пользователь знал, что происходит. Вот пример того, как это может выглядеть:

if (data != [] && data.type == 'photo')
    {
        // Saves the user's contact info
        misty.Set("contact", (data.phNumber).toString(), false);
        // Changes display image, sets head position, and plays
        // sounds to show she's taking a picture
        misty.DisplayImage("DefaultEyes_SystemCamera.jpg");
        misty.Pause(100);
        misty.PlayAudio("DefaultSounds_Awe3.wav", 100);
        misty.Set("pictureMode", true, false);
        misty.MoveHeadPosition(0, 0, 0, 45);
        misty.Pause(3000);
        misty.DisplayImage("DefaultEyes_SystemFlash.jpg");
        misty.ChangeLED(255, 255, 255);
        misty.PlayAudio("DefaultSounds_SystemCameraShutter.wav", 100);

        // Snaps a portrait! By default, this method passes 
        // a base64-encoded string with the image data for the
        // picture into the _TakePicture() callback function.
        misty.TakePicture("Photobooth", 375, 812, false, true);
        misty.Pause(200);
        misty.DisplayImage("DefaultEyes_SystemCamera.jpg");
        misty.ChangeLED(140, 0, 255);
        misty.Pause(500);
        misty.DisplayImage("DefaultEyes_Joy2.jpg");
    }

Мисти -> Имгур

Когда вы кодируете Misty для съемки, вы можете передавать закодированные в base64 строки данных изображения в функции обратного вызова для дополнительной обработки. По умолчанию эти функции обратного вызова используют то же имя, что и misty.TakePicture()метод, с префиксом подчеркивания: _TakePicture().в нашем навыке мы используем эту _TakePicture()функцию обратного вызова для передачи строки в кодировке base64 с нашими данными изображения в uploadImage()функцию. Этот обратный вызов напоминает следующее:

function _TakePicture(data) {
var base64String = data.Result.Base64;
uploadImage(base64String);
}

Когда мы вызываем uploadImage()функцию, Мисти публикует изображение в личном альбоме Imgur. Есть несколько сервисов обмена изображениями, которые мы могли бы использовать для размещения этих изображений, но API Imgur делает две вещи, которые делают его идеальным для навыка Photo Booth Skill. Thing One: он принимает строки в кодировке base64, а Thing Two: возвращает URL для загруженного изображения в теле ответа. Передав этот возвращенный URL-адрес обратно в MMS API Twilio, Misty может отправить изображение непосредственно тому, кто его попросил.

Код для управления этим в навыке Photo Booth выглядит примерно так:

function uploadImage(imageData) {
    // Sets up the JSON body for uploading the picture
    var jsonBody = {
        'image': imageData,
        'type' : 'base64',
        'album': '<album-name>
    };
    // Uploads the picture to a private album; then, passes Imgur
    // response data into the _imageUploadResponse() callback
    misty.SendExternalRequest("POST", "https://api.imgur.com/3/image", "Bearer", "<bearer-token>", JSON.stringify(jsonBody), false, false, "", "application/json", "_imageUploadResponse");
}
function _imageUploadResponse(responseData) {
    // Saves the URL
    misty.Set("imageLink", JSON.parse(responseData.Result.ResponseObject.Data).data.link, false);
    // Runs the code to send the picture
    sendPicture();
}

Мисти -> MMS

С изображением в нашем альбоме Imgur остается только один шаг: получить это изображение в телефон, который его хочет. Это также происходит с помощью API Twilio. В нашем коде навыков JavaScript мы используем SendPicture()функцию для отправки запроса, который включает в себя контактную информацию человека, отправившего исходный текст, а также URL-адрес, который ссылается на загруженное изображение.

Когда мы вызываем sendPicture()функцию, Misty отправляет запрос в API Twilio, который перетаскивает изображение по указанному URL в папку входящих сообщений нашего пользователя. Это выглядит примерно так:

function sendPicture() { 
    misty.Debug("Sending Image to User");
    // Sets up thee JSON body for the Twilio SMS API.
    // Includes the phone number of the recipient and
    // the URL for their photograph on Imgur
    var jsonBody = {
        'Body': '[••] Greetings from Misty!',
        'From': '<number-to-send-from>',
        'To': misty.Get("contact"),
        'MediaUrl': misty.Get("imageLink")
    };


    // Sends a request to the Twilio API with our account
    // credentials to send the picture to the person who asked for it
    var credentials = "<base64-encoded-Twilio-credentials>"
    misty.SendExternalRequest("POST", "https://api.twilio.com/2010-04-01/Accounts/<account-id>/Messages.json", "Basic", credentials, JSON.stringify(jsonBody), false, false, "", "application/x-www-form-urlencoded");
}

Резюмировать

В этом посте мы обсудили, как связать API-интерфейсы обмена сообщениями Twilio и PubNub, сервисы обмена фотографиями Imgur и код JavaScript на основе роботов, чтобы создать навык Photo Booth для Misty. Когда мы используем этот навык:

  1. Кто-то отправляет сообщение на наш номер телефона Twilio
  2. Twilio передает сообщение нашему боту Twilio Autopilot
  3. Наш бот Autopilot читает сообщение, идентифицирует задачу и перенаправляет на нашу функцию Twilio
  4. Функция Twilio отправляет номер телефона пользователя на наш канал PubNub
  5. Мисти, которая все время использует навык Photo Booth, записывает сообщение от PubNub
  6. Мисти перемещает свою камеру и делает снимок
  7. Мисти загружает изображение в личный альбом Imgur и обращается к Twilio API, чтобы отправить его в виде MMS нашему пользователю

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