Вы хотите, чтобы помощник проверил наличие непрочитанных SMS-сообщений, прочитал их вслух и позволил вам ответить отправителю без необходимости использования телефона или касания одной кнопки на устройстве? Если да, продолжайте читать эту статью, так как мы обсудим разработку приложения для выполнения такой задачи.
В этом уроке мы пройдем все необходимые шаги, чтобы развить навык Alexa, который связывается с вашей учетной записью RingCentral, и выполнить следующие задачи.
-
Попросите пользователя войти в свою учетную запись RingCentral.
-
Получите имя пользователя и номер телефона.
-
Получить непрочитанные смс сообщения.
-
Прочитайте вслух каждое SMS-сообщение, и пусть пользователь решит: а) Ответить отправителю с помощью текстового сообщения. б) Прослушайте следующее сообщение.
-
Отметить непрочитанное сообщение как прочитанное после прочтения сообщения.
Предпосылки
- У вас должна быть учетная запись разработчика RingCentral. Если у вас его нет, нажмите здесь, чтобы создать бесплатный аккаунт разработчика.
- У вас должна быть учетная запись разработчика AWS. Если у вас его нет, нажмите здесь, чтобы создать бесплатный аккаунт.
Предварительные требования
Вы должны иметь базовые знания о том, как создать набор навыков Алекса и функцию AWS Lambda . Если вы новичок в разработке Alexa Skill, нажмите здесь, чтобы начать, прежде чем читать эту статью.
Обратите внимание, что фрагменты кода, показанные в этой статье, предназначены только для иллюстрации и могут не работать напрямую с копированием и вставкой. Мы рекомендуем вам скачать весь проект отсюда .
Вам также может понравиться: Учебное пособие по умному дому: ESP8266, Alexa и Amazon Echo
Создать приложение RingCentral
Войдите в свою учетную запись разработчика RingCentral и нажмите кнопку « Создать приложение» , чтобы создать новое приложение.
Введите название приложения и описание.
Укажите тип приложения и выберите тип платформы, как показано ниже:
Добавьте необходимые разрешения и укажите URI перенаправления OAuth. Сейчас мы можем оставить поле URI перенаправления OAuth пустым. URI перенаправления будет получен в разделе « Связывание аккаунтов » ниже.
Наконец, нажмите кнопку « Создать» , чтобы завершить процесс создания приложения. На панели инструментов приложения скопируйте учетные данные App Key и App Secret и храните их в надежном месте, чтобы мы могли использовать их позже.
Если вы хотите узнать больше о создании приложения RingCentral. Пожалуйста, обратитесь к этому началу документа для деталей.
Создание лямбда-функции AWS для Alexa Skill
Мы предполагали, что вы уже знаете, как создать лямбда-функцию для навыка Alexa, поэтому мы не будем подробно обсуждать, как ее создать в этом уроке. Если вы не знаете, с чего начать, обратитесь к этому документу для получения подробных инструкций.
При создании лямбда-функции предоставьте всю обязательную информацию и выберите Node JS 6.10 для параметра времени выполнения .
Вам также необходимо добавить следующие параметры ключ / значение в переменные окружения функции .
- RC_APP_SERVER_URL: https://platform.devtest.ringcentral.com .
- AppID: значение будет получено при создании пользовательского навыка Alexa в следующем разделе.
- RC_APP_SECRET: секрет приложения RingCentral, полученный из предыдущего раздела.
- RC_APP_KEY: ключ приложения RingCentral, полученный из предыдущего раздела.
В разделе кода функции Lambda выберите «Загрузить файл Zip» в раскрывающемся списке Тип ввода кода . Мы внедрим код и загрузим файлы позже.
Создать новый пользовательский навык Alexa
Войдите в свою учетную запись Amazon Developer и откройте свой список навыков. Нажмите кнопку « Добавить новый навык» в правом верхнем углу страницы. На странице « Создать новый навык» установите переключатель « Тип навыка» на «Модель пользовательского взаимодействия». Установите для имени «RingCentral Messaging Skill», а для имени вызова «my assistant».
Сохраните приложение и нажмите « Далее», чтобы перейти к форме « Модель взаимодействия» , затем скопируйте следующий блок кода и вставьте его в поле « Схема намерений» .
Джава
x
1
{ "intents": [ { "intent": "GetUnreadTextMessageIntent" }, { "intent":
2
"ReadTextMessageIntent" }, { "intent": "ReplyTextMessageIntent" }, { "slots": [
3
{ "name": "MessageBody", "type": "AMAZON.LITERAL" } ], "intent":
4
"TextMessageIntent" }, { "intent": "DoneIntent" }, { "intent":
5
"AMAZON.HelpIntent" }, { "intent": "AMAZON.YesIntent" }, { "intent":
6
"AMAZON.NoIntent" } ] }
Затем определите набор образцов высказываний. Просто скопируйте следующий блок кода и вставьте его в поле Sample Utterances .
Джава
xxxxxxxxxx
1
GetUnreadTextMessageIntent get unread message GetUnreadTextMessageIntent get
2
text message ReadTextMessageIntent next ReadTextMessageIntent next message
3
ReplyTextMessageIntent reply ReplyTextMessageIntent reply message DoneIntent I'm
4
"done DoneIntent I am done TextMessageIntent message body {short
5
"message|MessageBody} TextMessageIntent message body {this is for a long text
6
"message|MessageBody}
7
Свяжите свою учетную запись RingCentral
Лучший способ разрешить каждому пользователю входить в RingCentral со своими учетными данными - включить привязку учетной записи. Чтобы включить эту функцию, мы продолжаем с шага, описанного выше, выбрав параметр « Конфигурация» на информационной панели навыков Alexa, а в разделе « Связывание аккаунта » выберите переключатель « Да » и предоставьте необходимую информацию, как показано и объяснено ниже:
- URL авторизации : используйте конечную точку авторизации RingCentral https://platform.devtest.ringcentral.com/restapi/oauth/authorize .
- Идентификатор клиента : используйте AppKey приложения RingCentral для этого поля.
Чтобы завершить настройку привязки аккаунта, выполните следующие действия:
- Скопируйте URL-адрес перенаправления и вставьте его в URL-адрес перенаправления OAuth приложения RingCentral, как описано в последнем шаге раздела « Создание приложения RingCentral ». Предполагается, что пользовательское устройство зарегистрировано в США, будет использоваться https://pitangui.amazon.com/api/skill/link/XXX URL.
- Установите переключатель Auth Code Grant для Типа авторизации
- Скопируйте этот URI и вставьте его в поле URI токена доступа : https://platform.devtest.ringcentral.com/restapi/oauth/token .
- Скопируйте AppSecret приложения RingCentral и вставьте его в поле Client Secret .
Завершите процесс создания Alexa Skill, предоставив публикуемую информацию и бета-тестирование навыков, чтобы другие пользователи могли проверить свои навыки.
Кроме того, не забудьте скопировать идентификатор приложения навыка Alexa (найденный в форме «Информация о навыке») и вставить его в переменные среды функции Lambda, как обсуждалось ранее в разделе « Создание функции лямбда AWS для навыка Alexa ».
Реализуйте код для лямбда-функции
С локальной машины создайте новый проект с именем RC-Alexa-skill.
Примечание . Полный исходный код этого навыка доступен для загрузки здесь .
xxxxxxxxxx
1
$ mkdir rc-alexa-skill
2
$ cd rc-alexa-skill
Затем установите Alexa и JS SDK для RingCentral Node . Мы сохраняем SDK локально, чтобы можно было их сжать и позже загрузить файлы SDK на сервер AWS Lambda.
Джава
xxxxxxxxxx
1
$ npm install alexa-sdk — save
2
$ npm install ringcentral –save
Для простоты мы создаем один файл с именем index.js, а затем выполняем пошаговый код, как описано в следующем разделе.
Джава
xxxxxxxxxx
1
‘use strict’; const Alexa = require(‘alexa-sdk’); const RC =
2
require(‘ringcentral’); var rcsdk = new RC({ server:
3
process.env.RC_APP_SERVER_URL, appKey: process.env.RC_APP_KEY, appSecret:
4
process.env.RC_APP_SECRET }); var platform = rcsdk.platform(); var
5
speech_output = "" var reprompt_text = "" exports.handler = function(event,
6
context){ var alexa = Alexa.handler(event, context); alexa.appId =
7
process.env.AppID; alexa.registerHandlers(handlers); alexa.execute(); };
Из приведенного выше кода мы импортируем SDK и создаем экземпляр rcsdk для RingCentral SDK. Мы будем использовать AppKey и AppSecret приложения RingCentral, указанные в переменных среды лямбда-функции.
Важное замечание : Когда вы публикуете свое приложение RingCentral, не забудьте изменить переменные среды функции Lambda с помощью рабочего сервера (https://platform.ringcentral.com) и учетные данные приложения для производства!
Мы также получаем экземпляр платформы из SDK, поэтому мы можем использовать его для вызова API RingCentral позже.
Затем мы создаем и экспортируем обработчик функции Lambda. Следующим шагом является определение объекта обработчика и реализация функций для обработки запросов Alexa.
Джава
xxxxxxxxxx
1
var handlers = { 'LaunchRequest': function () { }, 'GetUnreadTextMessageIntent':
2
function () { }, 'ReadNextTextMessageIntent': function () { },
3
'ReplyTextMessageIntent': function () { }, 'TextMessageIntent':
4
function () { }, 'AMAZON.YesIntent': function () { },
5
'AMAZON.NoIntent': function () { }, 'DoneIntent': function () {
6
}, 'AMAZON.HelpIntent': function () { }, 'Unhandled': function
7
() { } };
Давайте теперь реализуем каждую функцию намерения и объясним основные коды. Помните, что фрагменты кода в этом разделе могут быть неполными. Для реализации используйте вместо этого код проекта, доступный в GitHub .
Джава
xxxxxxxxxx
1
'LaunchRequest': function () { if (this.event.session.user.accessToken ==
2
undefined) {
3
this.emit(':tellWithLinkAccountCard','to start using my assistant skill,
4
"please use the companion app to authenticate on RingCentral');
5
}else{ var data = platform.auth().data(); data.token_type = "bearer"
6
data.expires_in = 86400 data.refresh_token_expires_in = 86400
7
data.access_token = this.event.session.user.accessToken
8
platform.auth().setData(data) ... } }
Когда пользователь вызывает умение (говоря «Алекса, открой моего помощника»), вызывается функция LaunchRequest . Сначала мы проверяем, авторизовал ли пользователь Amazon запросить токен доступа OAuth для нашего приложения RingCentral.
Если токен доступа не существует, мы возвращаем карту «LinkAccount», отображаемую в приложении Alexa. Карта будет содержать ссылку, позволяющую пользователю проходить аутентификацию при входе в систему с помощью RingCentral.
Если токен доступа существует, мы установим токен доступа с помощью метода платформы .auth (). SetData (data), чтобы мы могли использовать экземпляр платформы для вызова API-интерфейсов RingCentral.
Мы продолжаем реализовывать функцию LaunchIntent для получения имени пользователя, прямого номера телефона, и мы будем хранить их в атрибутах сеанса для дальнейшего использования. Вы можете сохранить информацию, например, в AWS DynamoDB, если хотите избежать вызова этих кодов каждый раз, когда пользователь вызывает навык.
Джава
xxxxxxxxxx
1
var thisHandler = this // Retrieve the user's name and extension number from RC
2
//account platform.get('/account/~/extension/~/') .then(function(response) {
3
//var obj = response.json(); thisHandler.attributes['extNumber'] =
4
//obj.extensionNumber thisHandler.attributes['userName'] = obj.name //
5
//Retrieve the user's phone number platform.get('/account/~/extension/' +
6
//obj.id + '/phone-number') .then(function(response) { var obj =
7
//response.json(); var count = obj.records.length for (var record of
8
//obj.records){ // check if the user has a direct number if (record.usageType
9
//== "DirectNumber"){ thisHandler.attributes['ownPhoneNumber'] =
10
//record.phoneNumber.replace("+", "") break; } } // if there is no direct
11
//number if (!thisHandler.attributes['ownPhoneNumber']) { speech_output = "Hi
12
//" speech_output += thisHandler.attributes['userName'] speech_output +=
13
//"Unfortunately, your account does not support SMS message."
14
//thisHandler.emit(':tell', speech_output) }else{ speech_output = "Hi "
15
//speech_output += thisHandler.attributes['userName'] speech_output += ". How
16
//can I help you?" reprompt_text = "How can I help you?"
17
//thisHandler.emit(':ask', speech_output, reprompt_text) } })
18
//.catch(function(e) { thisHandler.emit(':tell', "Fail to read your account.
19
//Please try again.") }); }) .catch(function(e) { thisHandler.emit(':tell',
20
//"Fail to read your account. Please try again.") }); }
21
Функция GetUnreadTextMessageIntent вызывается, когда пользователь говорит, например, «получить непрочитанное сообщение». Внутри функции мы реализуем код для извлечения непрочитанных сообщений из учетной записи RingCentral пользователя. Мы определяем переменную params и указываем параметры messageType , readStatus и direction для выбора только входящих и непрочитанных SMS-сообщений.
xxxxxxxxxx
1
'GetUnreadTextMessageIntent': function () { this.attributes['index'] = -1
2
this.attributes['textMsgs'] = [] var params = {} params['messageType'] =
3
"SMS" params['readStatus'] = "Unread" params['direction'] = "Inbound" var
4
thisHandler = this // Call to fetch SMS messages
5
//platform.get('/account/~/extension/~/sms', params) .then(function
6
//(response) { var obj =response.json(); var count = obj.records.length if
7
//(count > 0){ // iterate the records array to read each message details. //
8
//last message first for (var i=count-1; i>=0; i--) { var record =
9
//jsonObj.records[i] var message = {} message['id'] = record.id // check if
10
//sender name exists in the message if ("name" in record.from){
11
//message['from'] = record.from.name }else{ // sender's name is not defined.
12
//Convert the sender's // number to a string with space between each number
13
// so Alexa can read the digit instead of the number message['from'] =
14
//getNumberAsString(record.from.phoneNumber) } // keep the number so we can
15
//reply to the sender if needed message['fromNumber'] =
16
//record.from.phoneNumber // store the message body message['subject'] =
17
//record.subject // add the message object to the 'textMsgs' array
18
//thisHandler.attributes['textMsgs'].push(message) } // emit the
19
//ReadTextMessageIntent to read the first message
20
//thisHandler.emit('ReadTextMessageIntent') }else{ thisHandler.emit(':tell',
21
//"You have no unread message."); } }); }
Функция ReadTextMessageIntent вызывается, когда пользователь говорит «следующее» или «следующее сообщение». Внутри функции мы реализуем код для чтения непрочитанного сообщения из массива «textMsgs». Мы также устанавливаем статус сообщения для чтения при прочтении непрочитанного сообщения.
xxxxxxxxxx
1
'ReadTextMessageIntent': function () {
2
// check if there is any message in the array if (!this.attributes['textMsgs']
3
|| this.attributes['textMsgs'].length == 0) { return this.emit(':ask', "Please say get unread message to check for new messages.", "How can I help you?"); } var count = this.attributes['textMsgs'].length var index = this.attributes['index'] if (index >= count-1){
4
// no more message return this.emit(':ask', "There is no more unread
5
//message. You can say reply, or say get unread message to check for new
6
//messages.", "How can I help you?"); }
7
// increase the index and retrieve a message object from the array
8
//this.attributes['index']++ var msg = this.attributes['textMsgs']
9
//[this.attributes['index']] var prefix = "" if (this.attributes['index']
10
//== 0){ if (count == 1) prefix = "You have 1 unread message " else prefix
11
//= "You have "+count+" unread messages. First message " }else{ if
12
//(this.attributes['index'] == count - 1) prefix = "Last message " else {
13
//prefix = convertNumtoOrder(this.attributes['index']) prefix += " unread
14
//message " } } speech_output = prefix speech_output += "from " +
15
//msg['from'] speech_output += ". Message. " + msg['subject'] + ". " if
16
//(this.attributes['index'] < count) { speech_output += "You can say reply
17
//or next message. " reprompt_text = "You can say reply or next message."
18
//}else { speech_output += "You can say reply or I am done." reprompt_text
19
//= "How can I help you?" } // call to set this message's status in the
20
//server to "read" platform.put('/account/~/extension/~/message-
21
//store/'+msg['id'], { readStatus: "Read" }) .then(function (response) { //
22
//ask Alexa to read the message this.emit(':ask', speech_output,
23
//reprompt_text); }) .catch(function(e) { console.log("Failed to set
24
//readStatus") console.error(e); }); }
Функция ReplyTextMessageIntent вызывается, когда пользователь говорит «ответ» или «ответное сообщение». Внутри функции мы реализуем код для подтверждения номера телефона получателя и готовимся принять текстовое сообщение от пользователя.
Джава
xxxxxxxxxx
1
'ReplyTextMessageIntent': function () {
2
// check if there is any message in the message array if
3
//(!this.attributes['textMsgs'] || this.attributes['textMsgs'].length == 0) {
4
//return this.emit(':ask', "Please say get unread message to check for new
5
//messages, then say reply.", "How can I help you?"); } // retrieve the
6
//message object from the array var msg = this.attributes['textMsgs']
7
//[this.attributes['index']] speech_output = "Reply to " + msg['from']
8
//speech_output += ". Now you can say message body, followed by the message
9
//you want to send." this.attributes['message'] = ""
10
//this.attributes['toNumber'] = msg['fromNumber']; this.emit(':ask',
11
//speech_output, speech_output); }
Функция TextMessageIntent вызывается, когда пользователь произносит «тело сообщения» и произносит слова для отправки. Внутри функции мы просим Alexa повторить текстовое сообщение пользователя, чтобы подтвердить, правильно ли Alexa услышала все слова. Затем мы ждем, пока пользователь скажет «да», чтобы отправить сообщение, или «нет», чтобы отменить действие.
Джава
xxxxxxxxxx
1
'TextMessageIntent': function () { var intent = this.event.request.intent; var
2
message = intent.slots.MessageBody.value this.attributes['message'] = message
3
speech_output = "I repeat your message. " speech_output += message + ". Do you
4
want to send it now?" reprompt_text = "Say yes to send the message or say no
5
to cancel." this.emit(':ask', speech_output, reprompt_text); }
6
Функция AMAZON.YesIntent вызывается, когда пользователь говорит «да». Внутри функции мы проверяем значения номера телефона получателя и текстового сообщения перед отправкой сообщения.
x
1
AMAZON.YesIntent': function () { // check if we have the phone number to reply
2
a message // check also if we've captured the text message if
3
(this.attributes['toNumber']){ if (this.attributes['message']) { var
4
thisHandler = this platform.post('/account/~/extension/~/sms', { from: {
5
'phoneNumber': this.attributes['ownPhoneNumber']}, to: [{'phoneNumber':
6
this.attributes['toNumber']}], text: this.attributes['message'] })
7
.then(function (response) { speech_output = "Message is sent. " var count =
8
thisHandler.attributes['textMsgs'].length if (
9
thisHandler.attributes['index'] < count - 1) { speech_output += "You can
10
say next to listen to the next message" reprompt_text = "You can say next
11
to listen to the next message" }else{ speech_output += "No more unread
12
message. You can say get message to check for new unread messages."
13
reprompt_text = "How can I help you?" } thisHandler.emit(':ask',
14
speech_output,
15
reprompt_text); }) .catch(function(e) { console.error(e);
16
thisHandler.emit(':ask', "Failed to send message. Please try again", "Say
17
message body, followed by the text message you want to
18
send."); }); }else{ // no message is missing, prompt the
19
user to say the message speech_output = "Say message
20
body, followed by the text message you want to send."
21
this.emit(':ask', speech_output, speech_output); }
22
}else{ speech_output = 'Sorry, I don\'t understand what
23
you want me to do. Please say help to hear what you
24
can say.';
25
this.response.speak(speech_output).listen(speech_output);
26
this.emit(':responseReady'); } }
27
Функция AMAZON.NoIntent вызывается, когда пользователь говорит «нет». Внутри функции мы проверяем, отменяет ли пользователь действие, потому что ответное сообщение было принято неправильно. Если это так, мы просим пользователя предоставить тело сообщения снова.
xxxxxxxxxx
1
AMAZON.NoIntent': function () { if (this.attributes['message'] &&
2
this.attributes['message'].length > 0){ speech_output = "If the message is
3
incorrect, you can say message body, followed by the text message you want to
4
send." }else{ speech_output = 'How can I help you?' } this.emit(':ask',
5
speech_output, 'How can I help you?') }
Функция DoneIntent вызывается, когда пользователь говорит «Я закончил». Внутри функции мы прощаемся с пользователем и завершаем сеанс. Мы также реализуем функцию AMAZON.HelpIntent, чтобы сообщить пользователю, как использовать умение помощника. Наконец, мы реализуем необработанную функцию для обработки неожиданных команд.
Джава
xxxxxxxxxx
1
'DoneIntent': function () { this.emit(':tell', 'Good bye'); },
2
'AMAZON.HelpIntent': function () { speech_output = 'Say get unread message to
3
fetch new unread text messages.' reprompt_text = 'How can I help you?'
4
this.emit(':ask', speech_output, reprompt_text); }, 'Unhandled': function () {
5
speech_output = 'Sorry, I don\'t understand what you want me to do. Please say
6
help to hear what you can say.';
7
this.response.speak(speech_output).listen(speech_output);
8
this.emit(':responseReady'); }
9
Когда вы закончите с кодом, выберите index.js файл и node_modules папку для сжатия файла .zip затем загрузить сжатый файл в проект AWS лямбда , как описано в Создание функции AWS Lambda для Alexa Skill секции.
Поздравляем! Вы только что завершили реализацию простого навыка Alexa для RingCentral. Есть много других функций, которые вы можете добавить к навыку, чтобы повысить удобство использования и функциональность.
Например, реализуйте состояния обработчика и используя диалоговый интерфейс, и добавьте новые намерения для проверки голосовой почты, воспроизведения голосовой почты или совершения звонка с вызовом и так далее. Я оставлю это вашим инновациям и воображению, чтобы сделать вашего помощника по обмену сообщениями более полезным.
Дальнейшее чтение
Разработка ориентированных на местоположение навыков Alexa