Last active
January 18, 2017 23:08
-
-
Save ddragosd/3afd5d8678e5dbda48b943a1125aad0c to your computer and use it in GitHub Desktop.
openwhisk-alexa-demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Handler for Amazon Alexa. | |
* SAMPLE EVENT: | |
* | |
{ | |
"session": { | |
"sessionId": "SessionId.baae4592-3194-463d-a1bf-a4cea0622913", | |
"application": { | |
"applicationId": "amzn1.ask.skill.647acd60-f1e7-4f77-9d5e-90c4a4cdfd76" | |
}, | |
"attributes": {}, | |
"user": { | |
"userId": "amzn1.ask.account.AFP3ZWPOS2BGJR7OWJZ3DHPKMOMCKURC2K6A2PLLNCMHBXRN7PSIZJIGE5Y2WGEAVZLBLUK4ZLWURQ2ZOW6WPFLWKVH6XC24ADTVXQULVDJ25JA6T2KU2S6CCJKBMMBDJWB7B5PILJABBQCW6R4X5NRHBVTDGYSLXJWZ3ICZROKXBOPFJBFLUDGLPGBITLPFBXI4UYMSGV6IWYY" | |
}, | |
"new": true | |
}, | |
"request": { | |
"type": "IntentRequest", | |
"requestId": "EdwRequestId.55f5f621-00a1-46fe-a0bb-130a58ff94a7", | |
"locale": "en-US", | |
"timestamp": "2016-10-20T04:56:11Z", | |
"intent": { | |
"name": "AMAZON.HelpIntent", | |
"slots": {} | |
} | |
}, | |
"version": "1.0" | |
} | |
*/ | |
var bind = function (fn, me) { | |
return function () { | |
return fn.apply(me, arguments); | |
}; | |
}; | |
var Alexa; | |
var AlexaResponse; | |
/** | |
* Create Alexa Responses | |
*/ | |
AlexaResponse = (function () { | |
function AlexaResponse() { | |
} | |
function createSpeechObject(optionsParam) { | |
if (optionsParam && optionsParam.type === 'SSML') { | |
return { | |
type: optionsParam.type, | |
ssml: optionsParam['speech'] | |
}; | |
} else { | |
return { | |
type: optionsParam.type || 'PlainText', | |
text: optionsParam['speech'] || optionsParam | |
}; | |
} | |
} | |
function buildSpeechletResponse(options) { | |
var alexaResponse = { | |
outputSpeech: createSpeechObject(options.output), | |
shouldEndSession: options.shouldEndSession | |
}; | |
if (options.reprompt) { | |
alexaResponse.reprompt = { | |
outputSpeech: createSpeechObject(options.reprompt) | |
}; | |
} | |
var returnResult = { | |
version: '1.0', | |
response: alexaResponse | |
}; | |
if (options.sessionAttributes) { | |
returnResult.sessionAttributes = options.sessionAttributes; | |
} | |
return returnResult; | |
} | |
function getSSMLResponse(message) { | |
return { | |
type: 'SSML', | |
speech: `<speak> ${message} </speak>` | |
}; | |
} | |
AlexaResponse.prototype.ask = function (speechOutput, repromptSpeech) { | |
var response = buildSpeechletResponse({ | |
sessionAttributes: this.attributes, | |
output: getSSMLResponse(speechOutput), | |
reprompt: getSSMLResponse(repromptSpeech), | |
shouldEndSession: false | |
}); | |
return response; | |
}; | |
AlexaResponse.prototype.tell = function (speechOutput) { | |
var response = buildSpeechletResponse({ | |
sessionAttributes: this.attributes, | |
output: getSSMLResponse(speechOutput), | |
shouldEndSession: true | |
}); | |
return response; | |
}; | |
return AlexaResponse; | |
})(); | |
/** | |
* | |
*/ | |
Alexa = (function () { | |
function Alexa() { | |
this.handleEvent = bind(this.handleEvent, this); | |
this.handleIntentRequest = bind(this.handleIntentRequest, this); | |
this.handleLaunchRequest = bind(this.handleLaunchRequest, this); | |
} | |
Alexa.prototype.handleLaunchRequest = function (event) { | |
var alexaResponse = new AlexaResponse(); | |
return handleOnLaunch(event.request, event.session, alexaResponse); | |
}; | |
Alexa.prototype.handleIntentRequest = function (event) { | |
var intent, alexaResponse; | |
intent = event.request.intent.name; | |
alexaResponse = new AlexaResponse(); | |
if (this.intentHandlers[intent] === null || typeof(this.intentHandlers[intent]) === "undefined") { | |
intent = "AMAZON.HelpIntent"; | |
} | |
// default | |
return this.intentHandlers[intent](event.request.intent, event.session, alexaResponse); | |
} | |
Alexa.prototype.intentHandlers = { | |
"ThankYouIntent": function (intent, session, response) { | |
return handleThankYouRequest(intent, session, response); | |
}, | |
"AMAZON.HelpIntent": function (intent, session, response) { | |
return handleHelpRequest(response); | |
}, | |
"PartnerDayWebsiteIntent": function (intent, session, response) { | |
return handlePartnerDayWebsiteRequest(intent, session, response); | |
}, | |
"PartnerdayPageViewsIntent": function (intent, session, response) { | |
return handlePartnerDayPageViewsRequest(intent, session, response); | |
}, | |
"PartnerdayPageViews": function(intent,session,response) { | |
return handlePartnerDayPageViewsGeneric(intent,session,response); | |
} | |
}; | |
function handleOnLaunch(launchRequest, session, response) { | |
var whatInfoPrompt = "What information would you like to retrieve from Adobe Analytics?", | |
speechOutput = "Welcome to Adobe Analytics.. Which report suite would you like to use?... Adobe I/O Portal, Partnerday Website.", | |
repromptOutput = "Please say either Adobe I/O Portal or Partnerday Website."; | |
return response.ask(speechOutput, repromptOutput); | |
} | |
/** | |
* Handles the request to use the partnerday website report suite | |
*/ | |
function handlePartnerDayWebsiteRequest(intent, session, response) { | |
var repromptText = "Currently, I can tell you information about the following metrics: page views"; | |
var speechOutput = "Ok, using the partner day report suite. How can I help you?"; | |
return response.ask(speechOutput, repromptText); | |
} | |
/** | |
* Handles the request to use the partnerday website report suite | |
*/ | |
function handlePartnerDayPageViewsRequest(intent, session, response) { | |
// TODO: make the request to get real data from Adobe Analytics | |
var speechOutput = "The total number of page views this month is 3,871."; | |
return response.ask(speechOutput); | |
} | |
/** | |
* Handles the request using a custom Slot 'MetricName' | |
*/ | |
function handlePartnerDayPageViewsGeneric(intent, session, response) { | |
// TODO: make the request to get real data from Adobe Analytics | |
var metricName = intent.slots.MetricName; // | |
var metricNameVal = " default metric "; | |
if (intent.slots.MetricName && intent.slots.MetricName.value) { | |
metricNameVal = intent.slots.MetricName.value; | |
} | |
var speechOutput = "The total number of " + metricNameVal + " this month is 1,231."; | |
return response.ask(speechOutput); | |
} | |
function handleHelpRequest(response) { | |
var repromptText = "What information would you like to retrieve from Adobe Analytics?"; | |
var speechOutput = "I can tell you the latest page view this month" | |
+ repromptText; | |
return response.ask(speechOutput, repromptText); | |
} | |
function handleThankYouRequest(intent, session, response) { | |
// get city re-prompt | |
var repromptText = "Say either, email or upload to creative cloud: "; | |
var speechOutput = "Serverless is cool, isn't it ? Goodbye !"; | |
return response.tell(speechOutput); | |
} | |
Alexa.prototype.handleEvent = function (event) { | |
// differentiate request type: LaunchRequest vs IntentRequest | |
var req_type = event.request["type"] || "LaunchRequest"; | |
if (req_type == "LaunchRequest") { | |
return this.handleLaunchRequest(event); | |
} | |
return this.handleIntentRequest(event); | |
}; | |
return Alexa; | |
})(); | |
function main(event) { | |
console.log('ALEXA Event', event.request.type + '!'); | |
var alexa = new Alexa(); | |
return alexa.handleEvent(event); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"intents": [ | |
{ | |
"intent": "PartnerDayWebsiteIntent" | |
}, | |
{ | |
"intent": "PartnerdayPageViewsIntent" | |
}, | |
{ | |
"intent": "PartnerdayPageViews", | |
"slots": [ | |
{ | |
"name":"MetricName", | |
"type":"LIST_OF_METRICS" | |
} | |
] | |
}, | |
{ | |
"intent": "ThankYouIntent" | |
}, | |
{ | |
"intent": "AMAZON.HelpIntent" | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"session": { | |
"sessionId": "SessionId.baae4592-3194-463d-a1bf-a4cea0622913", | |
"application": { | |
"applicationId": "amzn1.ask.skill.647acd60-f1e7-4f77-9d5e-90c4a4cdfd76" | |
}, | |
"attributes": {}, | |
"user": { | |
"userId": "amzn1.ask.account.AFP3ZWPOS2BGJR7OWJZ3DHPKMOMCKURC2K6A2PLLNCMHBXRN7PSIZJIGE5Y2WGEAVZLBLUK4ZLWURQ2ZOW6WPFLWKVH6XC24ADTVXQULVDJ25JA6T2KU2S6CCJKBMMBDJWB7B5PILJABBQCW6R4X5NRHBVTDGYSLXJWZ3ICZROKXBOPFJBFLUDGLPGBITLPFBXI4UYMSGV6IWYY" | |
}, | |
"new": true | |
}, | |
"request": { | |
"type": "IntentRequest", | |
"requestId": "EdwRequestId.55f5f621-00a1-46fe-a0bb-130a58ff94a7", | |
"locale": "en-US", | |
"timestamp": "2016-10-20T04:56:11Z", | |
"intent": { | |
"name": "AMAZON.HelpIntent", | |
"slots": {} | |
} | |
}, | |
"version": "1.0" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PartnerDayWebsiteIntent partnerday website | |
PartnerDayWebsiteIntent partner day website | |
PartnerDayWebsiteIntent partner day | |
PartnerdayPageViewsIntent how many page views this week | |
PartnerdayPageViewsIntent what's the page views this week | |
PartnerdayPageViewsIntent how many page views this month | |
PartnerdayPageViewsIntent what's the page views this month | |
PartnerdayPageViews how many {MetricName} this month | |
ThankYouIntent thank you | |
AMAZON.HelpIntent What can I do now |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
server { | |
listen 80; | |
# define any other domain name used to expose the openwhisk controller | |
server_name *.cloudfront.net; | |
proxy_http_version 1.1; | |
proxy_set_header Connection ""; | |
client_max_body_size 3m; # allow bigger functions to be deployed | |
location /docs { | |
proxy_pass http://whisk_controller; | |
} | |
location /api-docs { | |
proxy_pass http://whisk_controller; | |
} | |
location /api/v1 { | |
proxy_pass http://whisk_controller; | |
proxy_read_timeout 70s; # 60+10 additional seconds to allow controller to terminate request | |
} | |
include /etc/api-gateway/conf.d/includes/default_validators.conf; | |
include /etc/api-gateway/conf.d/includes/resolvers.conf; | |
set $oauth_host 'ims-na1-stg1.adobelogin.com'; | |
location = /validate-token { | |
internal; | |
set_if_empty $oauth_host 'ims-na1-stg1.adobelogin.com'; | |
proxy_pass https://$oauth_host/ims/validate_token/v1?client_id=$oauth_client_id&token=$authtoken; | |
proxy_method GET; | |
proxy_pass_request_body off; | |
proxy_pass_request_headers off; | |
} | |
location /github/webhook { | |
proxy_pass http://whisk_controller/api/v1/namespaces/guest/actions/github-deployer?blocking=true&result=true; | |
proxy_set_header Authorization "Basic MjNiYzQ2YjEtNzFmNi00ZWQ1LThjNTQtODE2YWE0ZjhjNTAyOjEyM3pPM3haQ0xyTU42djJCS0sxZFhZRnBYbFBrY2NPRnFtMTJDZEFzTWdSVTRWck5aOWx5R1ZDR3VNREdJd1A="; | |
proxy_read_timeout 70s; # 60+10 additional seconds to allow controller to terminate request | |
} | |
# this location exposes GitHub actions | |
location ~ ^/github.com/(?<git_org>[^\/].*?)/(?<git_repo>[^\/].*?)/(?<git_branch>[^\/].*?)/(?<package>[^\/].*?)/(?<action>[^\/].*) { | |
access_log /var/log/api-gateway/openwhisk_github_access.log; | |
error_log /var/log/api-gateway/openwhisk_github_error.log warn; | |
# ------------------------------------------------- | |
# Specify what to validate for this location | |
# ------------------------------------------------- | |
set $authtoken $http_authorization; # read the Bearer Token from the Authorization header | |
set_if_empty $authtoken $arg_user_token; # redis the token form the query string if the header is missing | |
set_by_lua $authtoken 'return ngx.re.gsub(ngx.arg[1], "bearer ", "","ijo") ' $authtoken; | |
# only enable OAuth validator if a token is present | |
set_by_lua_block $oauth_token_validator_status { | |
if ngx.var.authtoken == nil or #ngx.var.authtoken == 0 then | |
return "off"; | |
end | |
return "on"; | |
} | |
set $validate_oauth_token "$oauth_token_validator_status; order=1;"; | |
lua_need_request_body on; | |
access_by_lua_block { | |
ngx.apiGateway.validation.validateRequest() | |
if (ngx.var.oauth_token_validator_status == "off") then | |
return | |
end | |
-- decorate request with info from the OAuth validation | |
local cjson = require "cjson" | |
--1. read request body as JSON | |
ngx.req.read_body() | |
local data = ngx.req.get_body_data() | |
local json_data = {} | |
if (data ~= nil and #data > 0 ) then | |
json_data = assert( cjson.decode(data), "Could not read body as JSON:" .. tostring(data)) | |
end | |
--2. insert context.identity | |
json_data.context = json_data.context or {} | |
json_data.context.identity = json_data.context.identity or {} | |
json_data.context.identity.user_id = ngx.var.oauth_token_user_id | |
json_data.context.identity.scope = ngx.var.oauth_token_scope | |
json_data.context.identity.client_id = ngx.var.oauth_token_client_id | |
--3. update the body data | |
local new_body = cjson.encode(json_data) | |
ngx.req.set_body_data(new_body) | |
ngx.req.set_header("Content-Type", "application/json") | |
} | |
set $backend "http://whisk_controller/api/v1/namespaces/guest/actions/${git_org}.${git_repo}.${git_branch}_${package}/${action}"; | |
proxy_set_header Authorization "Basic MjNiYzQ2YjEtNzFmNi00ZWQ1LThjNTQtODE2YWE0ZjhjNTAyOjEyM3pPM3haQ0xyTU42djJCS0sxZFhZRnBYbFBrY2NPRnFtMTJDZEFzTWdSVTRWck5aOWx5R1ZDR3VNREdJd1A="; | |
proxy_pass $backend?blocking=true&result=true; | |
proxy_read_timeout 70s; # 60+10 additional seconds to allow controller to terminate request | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It looks like on line 79 you decode the data to rewrite it and add the context. There is where instead I propose you do instead
json_data.event = data; json_data.context = ...
. Does that not work? It avoid modifying the event payload and just boxes it into a new object.