Skip to content

Instantly share code, notes, and snippets.

@ddragosd
Last active January 18, 2017 23:08
Show Gist options
  • Save ddragosd/3afd5d8678e5dbda48b943a1125aad0c to your computer and use it in GitHub Desktop.
Save ddragosd/3afd5d8678e5dbda48b943a1125aad0c to your computer and use it in GitHub Desktop.
openwhisk-alexa-demo
/**
* 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);
}
{
"intents": [
{
"intent": "PartnerDayWebsiteIntent"
},
{
"intent": "PartnerdayPageViewsIntent"
},
{
"intent": "PartnerdayPageViews",
"slots": [
{
"name":"MetricName",
"type":"LIST_OF_METRICS"
}
]
},
{
"intent": "ThankYouIntent"
},
{
"intent": "AMAZON.HelpIntent"
}
]
}
{
"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"
}
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
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
}
}
@rabbah
Copy link

rabbah commented Jan 7, 2017

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment