From cf8e456b007cfdf394a6883174147869c5d662fe Mon Sep 17 00:00:00 2001 From: Gonzalo Toledano Date: Sat, 27 Jan 2018 13:55:35 +0100 Subject: [PATCH 01/10] Replaced Api.ai with Dialogflow --- README.md | 18 ++++++++++-------- package.json | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0a40ac3..0122f9b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# AlexaApiAiBridge -Bridge to connect Amazon Alexa to Api.ai using an AWS Lambda Function. +# AlexaDialogflowBridge +Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. ## Steps ### 1. Create a new Alexa Skill @@ -56,10 +56,12 @@ Bridge to connect Amazon Alexa to Api.ai using an AWS Lambda Function. * Select **AWS Lambda ARN (Amazon Resource Name)** as *Service Endpoint Type*. * Select *Region* depending on your Lambda region and paste your Lambda **ANR** into the *Endpoint* field when you have it. -### 2. Create a new Api.ai Agent +### 2. Create a new Dialogflow Agent #### Account -* Log in to the [Api.ai console](https://console.api.ai/api-client/). -* [Create a new agent](https://console.api.ai/api-client/#/newAgent) and fill all necessary information. Then click **Save** to continue. +* Log in to the [Dialogflow console](https://console.dialogflow.com/api-client/). +* [Create a new agent](https://console.dialogflow.com/api-client/#/newAgent) and fill all necessary information. +* Enable **Dialogflow V2 API**. +* Click **Save** to continue. #### Intents * Select **Default Welcome Intent**: @@ -101,7 +103,7 @@ Bridge to connect Amazon Alexa to Api.ai using an AWS Lambda Function. * Enter a **Name** and choose **Node.js 6.x** as the *Runtime*. ##### Lambda function code - * [**Download the `AlexaApiAiBridge.zip` file**](https://github.com/Gnzlt/AlexaApiAiBridge/releases/latest) from the latest release of this repo. + * [**Download the `AlexaDialogflowBridge.zip` file**](https://github.com/Gnzlt/AlexaDialogflowBridge/releases/latest) from the latest release of this repo. * Drop down the *Code entry type* menu and select **Upload a .ZIP file**. * Click on the **Function package** upload button and choose the file you just downloaded. @@ -119,11 +121,11 @@ Bridge to connect Amazon Alexa to Api.ai using an AWS Lambda Function. ### Final Configuration * Copy the Lambda **ARN** (upper-right corner) and use in the [Alexa Skill Configuration section](#skill-configuration). * Go to your Lambda **Code** tab. -* Replace `ALEXA_APP_ID` with your **Alexa App Id** and `APIAI_DEVELOPER_ACCESS_TOKEN` with your **Api.ai Developer Access Token**: +* Replace `ALEXA_APP_ID` with your **Alexa App Id** and `DIALOGFLOW_DEVELOPER_ACCESS_TOKEN` with your **Dialogflow Developer Access Token**: ``` const ALEXA_APP_ID = 'amzn1.ask.skill.app.your-skill-id'; - const APIAI_DEVELOPER_ACCESS_TOKEN = 'your-apiai-developer-access-token'; + const DIALOGFLOW_DEVELOPER_ACCESS_TOKEN = 'your-dialogflow-developer-access-token'; ``` * Go to [Alexa Manager](http://alexa.amazon.com/spa/index.html#settings) and change the language of your device to **English (United States)** inside the Settings menu. diff --git a/package.json b/package.json index 434f5b7..a6aa23d 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "alexa-apiai-bridge", - "version": "1.1.1", - "description": "Bridge to connect Amazon Alexa to Api.ai using an AWS Lambda Function", + "name": "alexa-dialogflow-bridge", + "version": "1.2", + "description": "Bridge to connect Amazon Alexa to Dialogflow (aka. Api.ai) using an AWS Lambda Function", "author": "Gnzlt", "main": "index.js", "repository": { "type": "git", - "url": "https://github.com/Gnzlt/AlexaApiAiBridge.git" + "url": "https://github.com/Gnzlt/AlexaDialogflowBridge.git" }, "dependencies": { - "alexa-sdk": "^1.0.11", + "alexa-sdk": "^1.0.25", "apiai": "^4.0.2" } } From 4ec9dced25a6de2108fcd89afebc125f74a20508 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 13:03:28 +0530 Subject: [PATCH 02/10] Added dialogflow git --- index.js | 298 +++++++++++++++++++++++++++++++++----------------- package.json | 3 +- structjson.js | 102 +++++++++++++++++ 3 files changed, 302 insertions(+), 101 deletions(-) create mode 100644 structjson.js diff --git a/index.js b/index.js index 49f49dd..6d42fd9 100755 --- a/index.js +++ b/index.js @@ -1,119 +1,217 @@ 'use strict'; const ALEXA_APP_ID = 'amzn1.ask.skill.app.your-skill-id'; -const APIAI_DEVELOPER_ACCESS_TOKEN = 'your-apiai-developer-access-token'; +const APIAI_PROJECT_ID = 'your-apiai-gcp-project-id'; -var AlexaSdk = require('alexa-sdk'); -var ApiAiSdk = require('apiai'); -var ApiAi = ApiAiSdk(APIAI_DEVELOPER_ACCESS_TOKEN); +const AlexaSdk = require('alexa-sdk'); +const DialogflowSdk = require('dialogflow'); +const sessionClient = DialogflowSdk.SessionsClient(); +const structjson = require('./structjson.js'); -var alexaSessionId; +let alexaSessionId; exports.handler = function (event, context) { - var alexa = AlexaSdk.handler(event, context); - alexa.appId = ALEXA_APP_ID; - alexa.registerHandlers(handlers); - alexa.execute(); + let alexa = AlexaSdk.handler(event, context); + alexa.appId = ALEXA_APP_ID; + alexa.registerHandlers(handlers); + alexa.execute(); }; -var handlers = { - 'LaunchRequest': function () { - var self = this; - setAlexaSessionId(self.event.session.sessionId); - ApiAi.eventRequest({name: 'WELCOME'}, {sessionId: alexaSessionId}) - .on('response', function (response) { - var speech = response.result.fulfillment.speech; - self.emit(':ask', speech, speech); - }) - .on('error', function (error) { - console.error(error.message); - self.emit(':tell', error); - }) - .end(); - }, - 'ApiIntent': function () { - var self = this; - var text = self.event.request.intent.slots.Text.value; - setAlexaSessionId(self.event.session.sessionId); - if (text) { - ApiAi.textRequest(text, {sessionId: alexaSessionId}) - .on('response', function (response) { - var speech = response.result.fulfillment.speech; - if (isResponseIncompleted(response)) { - self.emit(':ask', speech, speech); - } else { - self.emit(':tell', speech); - } - }) - .on('error', function (error) { - console.error(error.message); - self.emit(':tell', error.message); - }) - .end(); - } else { - self.emit('Unhandled'); - } - }, - 'AMAZON.CancelIntent': function () { - this.emit('AMAZON.StopIntent'); - }, - 'AMAZON.HelpIntent': function () { - var self = this; - ApiAi.eventRequest({name: 'HELP'}, {sessionId: alexaSessionId}) - .on('response', function (response) { - var speech = response.result.fulfillment.speech; - self.emit(':ask', speech, speech); - }) - .on('error', function (error) { - console.error(error.message); - self.emit(':tell', error.message); - }) - .end(); - }, - 'AMAZON.StopIntent': function () { - var self = this; - ApiAi.eventRequest({name: 'BYE'}, {sessionId: alexaSessionId}) - .on('response', function (response) { - self.emit(':tell', response.result.fulfillment.speech); - }) - .on('error', function (error) { - console.error(error.message); - self.emit(':tell', error.message); - }) - .end(); - }, - 'Unhandled': function () { - var self = this; - ApiAi.eventRequest({name: 'FALLBACK'}, {sessionId: alexaSessionId}) - .on('response', function (response) { - var speech = response.result.fulfillment.speech; - self.emit(':ask', speech, speech); - }) - .on('error', function (error) { - console.error(error.message); - self.emit(':tell', error.message); - }) - .end(); +let handlers = { + 'LaunchRequest': function () { + let self = this; + setAlexaSessionId(self.event.session.sessionId); + let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + + const request = { + session: sessionPath, + queryInput: { + event: { + name: 'WELCOME' + }, + }, + }; + + sessionClient + .detectIntent(request) + .then(responses => { + logQueryResult(sessionClient, responses[0].queryResult); + const speech = responses[0].queryResult.fulfillment.text; + self.emit(':ask', speech, speech); + }) + .catch(err => { + console.error('ERROR:', err); + self.emit(':tell', err); + }); + }, + 'ApiIntent': function () { + var self = this; + var text = self.event.request.intent.slots.Text.value; + setAlexaSessionId(self.event.session.sessionId); + if (text) { + let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + + const request = { + session: sessionPath, + queryInput: { + text: { + text: text, + languageCode: languageCode, + }, + }, + }; + + sessionClient + .detectIntent(request) + .then(responses => { + logQueryResult(sessionClient, responses[0].queryResult); + const speech = responses[0].queryResult.fulfillment.text; + if (isResponseIncompleted(responses[0])) { + self.emit(':ask', speech, speech); + } else { + self.emit(':tell', speech); + } + }) + .catch(err => { + console.error('ERROR:', err); + self.emit(':tell', err); + }); + } else { + self.emit('Unhandled'); } + }, + 'AMAZON.CancelIntent': function () { + this.emit('AMAZON.StopIntent'); + }, + 'AMAZON.HelpIntent': function () { + var self = this; + setAlexaSessionId(self.event.session.sessionId); + let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + + const request = { + session: sessionPath, + queryInput: { + event: { + name: 'HELP' + }, + }, + }; + + sessionClient + .detectIntent(request) + .then(responses => { + logQueryResult(sessionClient, responses[0].queryResult); + const speech = responses[0].queryResult.fulfillment.text; + self.emit(':ask', speech, speech); + }) + .catch(err => { + console.error('ERROR:', err); + self.emit(':tell', err); + }); + }, + 'AMAZON.StopIntent': function () { + var self = this; + setAlexaSessionId(self.event.session.sessionId); + let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + + const request = { + session: sessionPath, + queryInput: { + event: { + name: 'BYE' + }, + }, + }; + + sessionClient + .detectIntent(request) + .then(responses => { + logQueryResult(sessionClient, responses[0].queryResult); + const speech = responses[0].queryResult.fulfillment.text; + self.emit(':tell', speech, speech); + }) + .catch(err => { + console.error('ERROR:', err); + self.emit(':tell', err); + }); + }, + 'Unhandled': function () { + var self = this; + setAlexaSessionId(self.event.session.sessionId); + let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + + const request = { + session: sessionPath, + queryInput: { + event: { + name: 'FALLBACK' + }, + }, + }; + + sessionClient + .detectIntent(request) + .then(responses => { + logQueryResult(sessionClient, responses[0].queryResult); + const speech = responses[0].queryResult.fulfillment.text; + self.emit(':ask', speech, speech); + }) + .catch(err => { + console.error('ERROR:', err); + self.emit(':tell', err); + }); + } }; function isResponseIncompleted(response) { - if (response.result.actionIncomplete) { - return true; - } + if (response.queryResult.allRequiredParamsCollected) { + return true; + } - for (var i = 0; i < response.result.contexts.length; i++) { - if (response.result.contexts[i].lifespan > 1) { - return true; - } + for (var i = 0; i < response.queryResult.outputContexts.length; i++) { + if (response.queryResult.outputContexts[i].lifespanCount > 1) { + return true; } - return false; + } + return false; } function setAlexaSessionId(sessionId) { - if (sessionId.indexOf("amzn1.echo-api.session.") != -1) { - alexaSessionId = sessionId.split('amzn1.echo-api.session.').pop(); - } else { - alexaSessionId = sessionId.split('SessionId.').pop(); - } + if (sessionId.indexOf("amzn1.echo-api.session.") != -1) { + alexaSessionId = sessionId.split('amzn1.echo-api.session.').pop(); + } else { + alexaSessionId = sessionId.split('SessionId.').pop(); + } +} + +function logQueryResult(sessionClient, result) { + // Imports the Dialogflow library + const dialogflow = require('dialogflow'); + + // Instantiates a context client + const contextClient = new dialogflow.ContextsClient(); + + console.log(` Query: ${result.queryText}`); + console.log(` Response: ${result.fulfillmentText}`); + if (result.intent) { + console.log(` Intent: ${result.intent.displayName}`); + } else { + console.log(` No intent matched.`); + } + const parameters = JSON.stringify( + structjson.structProtoToJson(result.parameters) + ); + console.log(` Parameters: ${parameters}`); + if (result.outputContexts && result.outputContexts.length) { + console.log(` Output contexts:`); + result.outputContexts.forEach(context => { + const contextId = contextClient.matchContextFromContextName(context.name); + const contextParameters = JSON.stringify( + structjson.structProtoToJson(context.parameters) + ); + console.log(` ${contextId}`); + console.log(` lifespan: ${context.lifespanCount}`); + console.log(` parameters: ${contextParameters}`); + }); + } } diff --git a/package.json b/package.json index a6aa23d..3dc72e6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "alexa-sdk": "^1.0.25", - "apiai": "^4.0.2" + "apiai": "^4.0.2", + "dialogflow": "^0.3.0" } } diff --git a/structjson.js b/structjson.js new file mode 100644 index 0000000..77336d7 --- /dev/null +++ b/structjson.js @@ -0,0 +1,102 @@ +/** + * Copyright 2017, Google, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utilities for converting between JSON and goog.protobuf.Struct + * proto. + */ + +'use strict'; + +function jsonToStructProto(json) { + const fields = {}; + for (let k in json) { + fields[k] = jsonValueToProto(json[k]); + } + + return {fields}; +} + +const JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP = { + [typeof 0]: 'numberValue', + [typeof '']: 'stringValue', + [typeof false]: 'boolValue', +}; + +const JSON_SIMPLE_VALUE_KINDS = new Set([ + 'numberValue', + 'stringValue', + 'boolValue', +]); + +function jsonValueToProto(value) { + const valueProto = {}; + + if (value === null) { + valueProto.kind = 'nullValue'; + valueProto.nullValue = 'NULL_VALUE'; + } else if (value instanceof Array) { + valueProto.kind = 'listValue'; + valueProto.listValue = {values: value.map(jsonValueToProto)}; + } else if (typeof value === 'object') { + valueProto.kind = 'structValue'; + valueProto.structValue = jsonToStructProto(value); + } else if (typeof value in JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP) { + const kind = JSON_SIMPLE_TYPE_TO_PROTO_KIND_MAP[typeof value]; + valueProto.kind = kind; + valueProto[kind] = value; + } else { + console.warn('Unsupported value type ', typeof value); + } + return valueProto; +} + +function structProtoToJson(proto) { + if (!proto || !proto.fields) { + return {}; + } + const json = {}; + for (const k in proto.fields) { + json[k] = valueProtoToJson(proto.fields[k]); + } + return json; +} + +function valueProtoToJson(proto) { + if (!proto || !proto.kind) { + return null; + } + + if (JSON_SIMPLE_VALUE_KINDS.has(proto.kind)) { + return proto[proto.kind]; + } else if (proto.kind === 'nullValue') { + return null; + } else if (proto.kind === 'listValue') { + if (!proto.listValue || !proto.listValue.values) { + console.warn('Invalid JSON list value proto: ', JSON.stringify(proto)); + } + return proto.listValue.values.map(valueProtoToJson); + } else if (proto.kind === 'structValue') { + return structProtoToJson(proto.structValue); + } else { + console.warn('Unsupported JSON value proto kind: ', proto.kind); + return null; + } +} + +module.exports = { + jsonToStructProto, + structProtoToJson, +}; \ No newline at end of file From ad53c62e22a229344f6df0ae4a11ef5d394411a1 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 13:05:20 +0530 Subject: [PATCH 03/10] Updated version to 2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3dc72e6..d52651b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alexa-dialogflow-bridge", - "version": "1.2", + "version": "2.0", "description": "Bridge to connect Amazon Alexa to Dialogflow (aka. Api.ai) using an AWS Lambda Function", "author": "Gnzlt", "main": "index.js", From 23a6b1b424513f2aa4bc07ff8e7931b41899f4eb Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 13:09:31 +0530 Subject: [PATCH 04/10] Removed previous version of package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index d52651b..53f7af0 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "alexa-sdk": "^1.0.25", - "apiai": "^4.0.2", "dialogflow": "^0.3.0" } } From 44db361d278df59072a2ae33c8c34eecf5a1e957 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 14:04:29 +0530 Subject: [PATCH 05/10] Updated to read from environment variable --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 6d42fd9..c6fac72 100755 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ 'use strict'; -const ALEXA_APP_ID = 'amzn1.ask.skill.app.your-skill-id'; -const APIAI_PROJECT_ID = 'your-apiai-gcp-project-id'; +const ALEXA_APP_ID = process.env.ALEXA_APP_ID || 'amzn1.ask.skill.app.your-skill-id'; +const APIAI_PROJECT_ID = process.env.APIAP_PROJECT_ID || 'your-apiai-gcp-project-id'; const AlexaSdk = require('alexa-sdk'); const DialogflowSdk = require('dialogflow'); From 1f0af9405ee95dda225926f7a0a4dfad23988fe5 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 14:16:12 +0530 Subject: [PATCH 06/10] Updated to do new on session client --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index c6fac72..5e9c66f 100755 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const APIAI_PROJECT_ID = process.env.APIAP_PROJECT_ID || 'your-apiai-gcp-project const AlexaSdk = require('alexa-sdk'); const DialogflowSdk = require('dialogflow'); -const sessionClient = DialogflowSdk.SessionsClient(); +const sessionClient = new DialogflowSdk.SessionsClient(); const structjson = require('./structjson.js'); let alexaSessionId; From 0ee004df692df9f8cfc7b59623a35bc25eb571d1 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 21:09:40 +0530 Subject: [PATCH 07/10] Fixed issues with Alexa --- index.js | 58 +++++++++++++++++++++++++++++----------------------- package.json | 5 ++++- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/index.js b/index.js index 5e9c66f..791dc3e 100755 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ 'use strict'; const ALEXA_APP_ID = process.env.ALEXA_APP_ID || 'amzn1.ask.skill.app.your-skill-id'; -const APIAI_PROJECT_ID = process.env.APIAP_PROJECT_ID || 'your-apiai-gcp-project-id'; +const GOOGLE_PROJECT_ID = process.env.GOOGLE_PROJECT_ID || 'your-apiai-gcp-project-id'; const AlexaSdk = require('alexa-sdk'); const DialogflowSdk = require('dialogflow'); @@ -17,26 +17,29 @@ exports.handler = function (event, context) { alexa.execute(); }; +const languageCode = 'en-US'; + let handlers = { 'LaunchRequest': function () { let self = this; setAlexaSessionId(self.event.session.sessionId); - let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + let sessionPath = sessionClient.sessionPath(GOOGLE_PROJECT_ID, alexaSessionId); const request = { session: sessionPath, queryInput: { event: { - name: 'WELCOME' - }, - }, + name: 'WELCOME', + languageCode: languageCode + } + } }; sessionClient .detectIntent(request) .then(responses => { logQueryResult(sessionClient, responses[0].queryResult); - const speech = responses[0].queryResult.fulfillment.text; + const speech = responses[0].queryResult.fulfillmentText; self.emit(':ask', speech, speech); }) .catch(err => { @@ -49,23 +52,23 @@ let handlers = { var text = self.event.request.intent.slots.Text.value; setAlexaSessionId(self.event.session.sessionId); if (text) { - let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + let sessionPath = sessionClient.sessionPath(GOOGLE_PROJECT_ID, alexaSessionId); const request = { session: sessionPath, queryInput: { text: { text: text, - languageCode: languageCode, - }, - }, + languageCode: languageCode + } + } }; sessionClient .detectIntent(request) .then(responses => { logQueryResult(sessionClient, responses[0].queryResult); - const speech = responses[0].queryResult.fulfillment.text; + const speech = responses[0].queryResult.fulfillmentText; if (isResponseIncompleted(responses[0])) { self.emit(':ask', speech, speech); } else { @@ -86,22 +89,23 @@ let handlers = { 'AMAZON.HelpIntent': function () { var self = this; setAlexaSessionId(self.event.session.sessionId); - let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + let sessionPath = sessionClient.sessionPath(GOOGLE_PROJECT_ID, alexaSessionId); const request = { session: sessionPath, queryInput: { event: { - name: 'HELP' - }, - }, + name: 'HELP', + languageCode: languageCode + } + } }; sessionClient .detectIntent(request) .then(responses => { logQueryResult(sessionClient, responses[0].queryResult); - const speech = responses[0].queryResult.fulfillment.text; + const speech = responses[0].queryResult.fulfillmentText; self.emit(':ask', speech, speech); }) .catch(err => { @@ -112,22 +116,23 @@ let handlers = { 'AMAZON.StopIntent': function () { var self = this; setAlexaSessionId(self.event.session.sessionId); - let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + let sessionPath = sessionClient.sessionPath(GOOGLE_PROJECT_ID, alexaSessionId); const request = { session: sessionPath, queryInput: { event: { - name: 'BYE' - }, - }, + name: 'BYE', + languageCode: languageCode + } + } }; sessionClient .detectIntent(request) .then(responses => { logQueryResult(sessionClient, responses[0].queryResult); - const speech = responses[0].queryResult.fulfillment.text; + const speech = responses[0].queryResult.fulfillmentText; self.emit(':tell', speech, speech); }) .catch(err => { @@ -138,22 +143,23 @@ let handlers = { 'Unhandled': function () { var self = this; setAlexaSessionId(self.event.session.sessionId); - let sessionPath = sessionClient.sessionPath(APIAI_PROJECT_ID, alexaSessionId); + let sessionPath = sessionClient.sessionPath(GOOGLE_PROJECT_ID, alexaSessionId); const request = { session: sessionPath, queryInput: { event: { - name: 'FALLBACK' - }, - }, + name: 'FALLBACK', + languageCode: languageCode + } + } }; sessionClient .detectIntent(request) .then(responses => { logQueryResult(sessionClient, responses[0].queryResult); - const speech = responses[0].queryResult.fulfillment.text; + const speech = responses[0].queryResult.fulfillmentText; self.emit(':ask', speech, speech); }) .catch(err => { diff --git a/package.json b/package.json index 53f7af0..755aa6a 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "alexa-dialogflow-bridge", - "version": "2.0", + "version": "2.0.0", "description": "Bridge to connect Amazon Alexa to Dialogflow (aka. Api.ai) using an AWS Lambda Function", "author": "Gnzlt", "main": "index.js", + "scripts": { + "postinstall": "npm rebuild grpc --target=6.1.0 --target_arch=x64 --target_platform=linux --target_libc=glibc" + }, "repository": { "type": "git", "url": "https://github.com/Gnzlt/AlexaDialogflowBridge.git" From 43b1caee16fc0e0e729bb23dcbd6b6f55323f4bd Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 21:30:55 +0530 Subject: [PATCH 08/10] Updated README --- README.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0122f9b..1616abe 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AlexaDialogflowBridge -Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. +Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. This version uses v2 API of dialogflow ## Steps ### 1. Create a new Alexa Skill @@ -85,6 +85,26 @@ Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda * Select the gear icon (upper-left corner) and go to **Settings**. * Copy your **Developer access token** to use it later in the [Final Configuration section](#final-configuration). +#### Dialogflow and GCP settings +1. Select or create a Cloud Platform project. + + [Go to the projects page][projects] + +1. Enable billing for your project. + + [Enable billing][billing] + +1. Enable the Dialogflow API. + + [Enable the API][enable_api] + +1. [Set up authentication with a service account][auth] so you can access the + API from your local workstation and AWS. Download your authentication json file and save as `gcp-credentials.json`. This file is to be added to code before uploading to AWS Lambda. + +[projects]: https://console.cloud.google.com/project +[billing]: https://support.google.com/cloud/answer/6293499#enable-billing +[enable_api]: https://console.cloud.google.com/flows/enableapi?apiid=dialogflow.googleapis.com +[auth]: https://cloud.google.com/docs/authentication/getting-started ### 3. Create an AWS Lambda Function #### AWS Account @@ -104,6 +124,7 @@ Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda ##### Lambda function code * [**Download the `AlexaDialogflowBridge.zip` file**](https://github.com/Gnzlt/AlexaDialogflowBridge/releases/latest) from the latest release of this repo. + * Add the `gcp-credentials.json` file for authentication in the zip file. * Drop down the *Code entry type* menu and select **Upload a .ZIP file**. * Click on the **Function package** upload button and choose the file you just downloaded. @@ -120,13 +141,9 @@ Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda ### Final Configuration * Copy the Lambda **ARN** (upper-right corner) and use in the [Alexa Skill Configuration section](#skill-configuration). -* Go to your Lambda **Code** tab. -* Replace `ALEXA_APP_ID` with your **Alexa App Id** and `DIALOGFLOW_DEVELOPER_ACCESS_TOKEN` with your **Dialogflow Developer Access Token**: - - ``` - const ALEXA_APP_ID = 'amzn1.ask.skill.app.your-skill-id'; - const DIALOGFLOW_DEVELOPER_ACCESS_TOKEN = 'your-dialogflow-developer-access-token'; - ``` +* Go to your Lambda function tab. +* Add environment variable `ALEXA_APP_ID` with your **Alexa App Id** and `GOOGLE_PROJECT_ID` with your Project Id. You can find Google project id @ //https://dialogflow.com/docs/agents#settings +* Add environment variable as `GOOGLE_APPLICATION_CREDENTIALS` with value as `gcp-credentials.json` * Go to [Alexa Manager](http://alexa.amazon.com/spa/index.html#settings) and change the language of your device to **English (United States)** inside the Settings menu. From 72831f39f18d13b26efd55a1f845690136c1afff Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 21:38:19 +0530 Subject: [PATCH 09/10] Fixes #10 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1616abe..a2766bb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AlexaDialogflowBridge -Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. This version uses v2 API of dialogflow +Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. This version uses v2 API of dialogflow ## Steps ### 1. Create a new Alexa Skill From 0a04e02dc163f1ab078561dd5e7eb82bdb5f4042 Mon Sep 17 00:00:00 2001 From: Rahul Jain Date: Mon, 23 Apr 2018 21:41:38 +0530 Subject: [PATCH 10/10] PR #9 Fixes #10 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2766bb..1616abe 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AlexaDialogflowBridge -Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. This version uses v2 API of dialogflow +Bridge to connect Amazon Alexa to Dialogflow *(aka. Api.ai)* using an AWS Lambda Function. This version uses v2 API of dialogflow ## Steps ### 1. Create a new Alexa Skill