Things used in this project

Code

indexJavaScript
/**
 *
 * Examples:
 * One-shot model
 * User: Alexa, get today horoscope for Leo.
 * Alexa: You will attempt to reschedule your daily routine to be able to make the most of your day. While it is easy to make plans, implementing 
 * them and sticking to them depends on your own discipline and determination. You will become more aware about health issues and pay closer 
 * attention to your diet. You will spend an enjoyable time with your family, says Ganesha.
 *
 * Dialog model:
 * User: Alexa, ask Good Luck Guru.
 * Alexa: Welcome to the Good Luck Guru.  What is your horoscope?
 * User: Leo
 * Alexa: You will attempt to reschedule your daily routine to be able to make the most of your day. While it is easy to make plans, implementing 
 * them and sticking to them depends on your own discipline and determination. You will become more aware about health issues and pay closer 
 * attention to your diet. You will spend an enjoyable time with your family, says Ganesha.
 *
 */

'use strict';
/**
 * App ID for the skill
 */
var APP_ID = "your_app_id"; 

/**
 * The key to find the current index from the session attributes
 */
var KEY_CURRENT_INDEX = "current";


var HOROSCOPES = [
	"aries",
	"taurus",
	"geminiemini",
	"cancer",
	"leo",
	"virgo",
	"libra",
	"scorpio",
	"sagittarius",
	"capricorn",
	"aquarius",
	"pisces"
];

var http = require("http");

var optionsGet = {
	host : 'horoscope-api.herokuapp.com', 
    port : 80,
    path : '', 
    method : 'GET'
};

/**
 * The AlexaSkill prototype and helper functions
 */
var AlexaSkill = require('./AlexaSkill');


/**
 * GoodLuckGuru is a child of AlexaSkill.
 * To read more about inheritance in JavaScript, see the link below.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance
 */
var GoodLuckGuru = function () {
    AlexaSkill.call(this, APP_ID);
};

// Extend AlexaSkill
GoodLuckGuru.prototype = Object.create(AlexaSkill.prototype);
GoodLuckGuru.prototype.constructor = GoodLuckGuru;

GoodLuckGuru.prototype.eventHandlers.onSessionStarted = function (sessionStartedRequest, session) {
    console.log("GoodLuckGuru onSessionStarted requestId: " + sessionStartedRequest.requestId
        + ", sessionId: " + session.sessionId);

    // any session init logic would go here
};

GoodLuckGuru.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
    console.log("GoodLuckGuru onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);
    getWelcomeResponse(response);
};

GoodLuckGuru.prototype.eventHandlers.onSessionEnded = function (sessionEndedRequest, session) {
    console.log("GoodLuckGuru onSessionEnded requestId: " + sessionEndedRequest.requestId
        + ", sessionId: " + session.sessionId);

    // any session cleanup logic would go here
};

GoodLuckGuru.prototype.intentHandlers = {
    "DailyHoroscope": function (intent, session, response) {
        getHoroscope(intent, session, response);
    },

    "AMAZON.HelpIntent": function (intent, session, response) {
        helpTheUser(intent, session, response);
    },

    "AMAZON.StopIntent": function (intent, session, response) {
        var speechOutput = "Goodbye";
        response.tell(speechOutput);
    },

    "AMAZON.CancelIntent": function (intent, session, response) {
        var speechOutput = "Goodbye";
        response.tell(speechOutput);
    }
};

/**
 * Returns the welcome response for when a user invokes this skill.
 */
function getWelcomeResponse(response) {
    // If we wanted to initialize the session to have some attributes we could add those here.
    var speechText = "Welcome to the Good Luck Guru. What is your horoscope?";
    var repromptText = "<speak>Please choose a horoscope by saying, " +
        "leo <break time=\"0.2s\" /> " +
        "libra <break time=\"0.2s\" /> " +
        "scorpio <break time=\"0.2s\" /> " +
        "pisces</speak>";

    var speechOutput = {
        speech: speechText,
        type: AlexaSkill.speechOutputType.PLAIN_TEXT
    };
    var repromptOutput = {
        speech: repromptText,
        type: AlexaSkill.speechOutputType.SSML
    };
    response.ask(speechOutput, repromptOutput);
}

function getHoroscope(intent, session, response) {
    var speechText = "",
        repromptText = "",
        speechOutput,
        repromptOutput;

    var horoscopeSlot = intent.slots.Horoscope;

    if (isHoroscope(horoscopeSlot)) {
        // Remove the periods to fix things like d. v. d.s to dvds
        var horoscope = horoscopeSlot.value.replace(/\.\s*/g, '');

		optionsGet.path = "/horoscope/today/" + horoscope;
		
		// do the GET request
		var reqGet = http.request(optionsGet, function(res) {
			console.log("statusCode: ", res.statusCode);
			// uncomment it for header details
			// console.log("headers: ", res.headers);
		 
		 
			res.on('data', function(d) {
				console.info('GET result:\n');
				process.stdout.write(d);
				console.info('\n\nCall completed');

				var obj = JSON.parse(d);
				speechText = obj.horoscope;
				repromptText = "<speak>" + obj.horoscope + "</speak>";
				
				speechOutput = {
					speech: speechText,
					type: AlexaSkill.speechOutputType.PLAIN_TEXT
				};
				repromptOutput = {
					speech: repromptText,
					type: AlexaSkill.speechOutputType.SSML
				};
				response.ask(speechOutput, repromptOutput);
			});
		 
		});
		 
		reqGet.end();
		reqGet.on('error', function(e) {
			console.error(e);

			speechText = "speech text err";
			repromptText = "reprompt text err";
			
			speechOutput = {
				speech: speechText,
				type: AlexaSkill.speechOutputType.PLAIN_TEXT
			};
			repromptOutput = {
				speech: repromptText,
				type: AlexaSkill.speechOutputType.SSML
			};
			response.ask(speechOutput, repromptOutput);

		});
    } else {

        // The horoscope didn't match one of our predefined horoscopes. Reprompt the user.
        speechText = "I'm not sure what the horoscope is, please try again";
        repromptText = "<speak>I'm not sure what the horoscope is, you can say, " +
            "leo <break time=\"0.2s\" /> " +
            "libra <break time=\"0.2s\" /> " +
            "scorpio <break time=\"0.2s\" /> " +
            "pisces.</speak>";
        speechOutput = {
            speech: speechText,
            type: AlexaSkill.speechOutputType.PLAIN_TEXT
        };
        repromptOutput = {
            speech: repromptText,
            type: AlexaSkill.speechOutputType.SSML
        };
        response.ask(speechOutput, repromptOutput);
    }
}

/**
 * Check if horoscopeSlot has a valid input value.
 */
function isHoroscope(horoscopeSlot) {
	var isHoroscope = false;
	if (horoscopeSlot && horoscopeSlot.value) {
		// lower case and remove spaces
		var horoscope = horoscopeSlot.value.toLowerCase().replace(/ /g, '').replace(/\./g, '');
		
		HOROSCOPES.forEach( function(item) {
			if (item === horoscope) {
				isHoroscope = true;
				return;
			}
		});
	}
	
	return isHoroscope;
}

/**
 * Instructs the user on how to interact with this skill.
 */
function helpTheUser(intent, session, response) {
    var speechText = "You can ask for the daily horoscope. " +
        "For example, get daily horoscope for leo, or you can say exit. " +
        "Now, what can I help you with?";
    var repromptText = "<speak> I'm sorry I didn't understand that. You can say things like, " +
        "leo <break time=\"0.2s\" /> " +
        "libra <break time=\"0.2s\" /> " +
        "scorpio. Or you can say exit. " +
        "Now, what can I help you with? </speak>";

    var speechOutput = {
        speech: speechText,
        type: AlexaSkill.speechOutputType.PLAIN_TEXT
    };
    var repromptOutput = {
        speech: repromptText,
        type: AlexaSkill.speechOutputType.SSML
    };
    response.ask(speechOutput, repromptOutput);
}

// Create the handler that responds to the Alexa Request.
exports.handler = function (event, context) {
    var goodLuckGuru = new GoodLuckGuru();
    goodLuckGuru.execute(event, context);
};
Intent SchemaJSON
{
  "intents": [
    {
      "intent": "DailyHoroscope",
      "slots": [
        {
          "name": "Horoscope",
          "type": "LIST_OF_HOROSCOPES"
        }
      ]
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}
List of HoroscopesAsciiDoc
aries
taurus
geminiemini
cancer
leo
virgo
libra
scorpio
sagittarius
capricorn
aquarius
pisces
Sample UtterancesAsciiDoc
DailyHoroscope get daily horoscope for {Horoscope}
DailyHoroscope get today horoscope for {Horoscope}
DailyHoroscope get me {Horoscope}
DailyHoroscope daily {Horoscope}
DailyHoroscope daily horoscope in {Horoscope}
DailyHoroscope today horoscope in {Horoscope}
DailyHoroscope {Horoscope}
AlexaSkillJavaScript
/**
    Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.

    Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

        http://aws.amazon.com/apache2.0/

    or in the "license" file accompanying this file. This file 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.
*/

'use strict';

function AlexaSkill(appId) {
    this._appId = appId;
}

AlexaSkill.speechOutputType = {
    PLAIN_TEXT: 'PlainText',
    SSML: 'SSML'
}

AlexaSkill.prototype.requestHandlers = {
    LaunchRequest: function (event, context, response) {
        this.eventHandlers.onLaunch.call(this, event.request, event.session, response);
    },

    IntentRequest: function (event, context, response) {
        this.eventHandlers.onIntent.call(this, event.request, event.session, response);
    },

    SessionEndedRequest: function (event, context) {
        this.eventHandlers.onSessionEnded(event.request, event.session);
        context.succeed();
    }
};

/**
 * Override any of the eventHandlers as needed
 */
AlexaSkill.prototype.eventHandlers = {
    /**
     * Called when the session starts.
     * Subclasses could have overriden this function to open any necessary resources.
     */
    onSessionStarted: function (sessionStartedRequest, session) {
    },

    /**
     * Called when the user invokes the skill without specifying what they want.
     * The subclass must override this function and provide feedback to the user.
     */
    onLaunch: function (launchRequest, session, response) {
        throw "onLaunch should be overriden by subclass";
    },

    /**
     * Called when the user specifies an intent.
     */
    onIntent: function (intentRequest, session, response) {
        var intent = intentRequest.intent,
            intentName = intentRequest.intent.name,
            intentHandler = this.intentHandlers[intentName];
        if (intentHandler) {
            console.log('dispatch intent = ' + intentName);
            intentHandler.call(this, intent, session, response);
        } else {
            throw 'Unsupported intent = ' + intentName;
        }
    },

    /**
     * Called when the user ends the session.
     * Subclasses could have overriden this function to close any open resources.
     */
    onSessionEnded: function (sessionEndedRequest, session) {
    }
};

/**
 * Subclasses should override the intentHandlers with the functions to handle specific intents.
 */
AlexaSkill.prototype.intentHandlers = {};

AlexaSkill.prototype.execute = function (event, context) {
    try {
        console.log("session applicationId: " + event.session.application.applicationId);

        // Validate that this request originated from authorized source.
        if (this._appId && event.session.application.applicationId !== this._appId) {
            console.log("The applicationIds don't match : " + event.session.application.applicationId + " and "
                + this._appId);
            throw "Invalid applicationId";
        }

        if (!event.session.attributes) {
            event.session.attributes = {};
        }

        if (event.session.new) {
            this.eventHandlers.onSessionStarted(event.request, event.session);
        }

        // Route the request to the proper handler which may have been overriden.
        var requestHandler = this.requestHandlers[event.request.type];
        requestHandler.call(this, event, context, new Response(context, event.session));
    } catch (e) {
        console.log("Unexpected exception " + e);
        context.fail(e);
    }
};

var Response = function (context, session) {
    this._context = context;
    this._session = session;
};

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
        }
    }
}

Response.prototype = (function () {
    var buildSpeechletResponse = function (options) {
        var alexaResponse = {
            outputSpeech: createSpeechObject(options.output),
            shouldEndSession: options.shouldEndSession
        };
        if (options.reprompt) {
            alexaResponse.reprompt = {
                outputSpeech: createSpeechObject(options.reprompt)
            };
        }
        if (options.cardTitle && options.cardContent) {
            alexaResponse.card = {
                type: "Simple",
                title: options.cardTitle,
                content: options.cardContent
            };
        }
        var returnResult = {
                version: '1.0',
                response: alexaResponse
        };
        if (options.session && options.session.attributes) {
            returnResult.sessionAttributes = options.session.attributes;
        }
        return returnResult;
    };

    return {
        tell: function (speechOutput) {
            this._context.succeed(buildSpeechletResponse({
                session: this._session,
                output: speechOutput,
                shouldEndSession: true
            }));
        },
        tellWithCard: function (speechOutput, cardTitle, cardContent) {
            this._context.succeed(buildSpeechletResponse({
                session: this._session,
                output: speechOutput,
                cardTitle: cardTitle,
                cardContent: cardContent,
                shouldEndSession: true
            }));
        },
        ask: function (speechOutput, repromptSpeech) {
            this._context.succeed(buildSpeechletResponse({
                session: this._session,
                output: speechOutput,
                reprompt: repromptSpeech,
                shouldEndSession: false
            }));
        },
        askWithCard: function (speechOutput, repromptSpeech, cardTitle, cardContent) {
            this._context.succeed(buildSpeechletResponse({
                session: this._session,
                output: speechOutput,
                reprompt: repromptSpeech,
                cardTitle: cardTitle,
                cardContent: cardContent,
                shouldEndSession: false
            }));
        }
    };
})();

module.exports = AlexaSkill;

Credits

Vincent square photo rv2erewqms
vincent wong
39 projects • 95 followers
Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaBlog