Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Tom Hudson
Published © MIT

Bueller, Bueller, Bueller...

Do you miss the days of John Hughes movies? Looking for a quick 80s fix? Look no further than Bueller, an 80s films audio clip generator.

IntermediateFull instructions providedOver 1 day607
Bueller, Bueller, Bueller...

Things used in this project

Hardware components

Amazon Echo
Amazon Alexa Amazon Echo
×1

Software apps and online services

AWS Lambda
Amazon Web Services AWS Lambda
AWS S3
Amazon Web Services AWS S3
ffmpeg

Story

Read more

Schematics

Bueller VUI Diagram

Here is a diagram that shows how everything works together to get you that awesome quote from the 80s.

Code

index.js

JavaScript
This is the main file that handles grabbing the request, then grabbing an audio file to play.
/**
    Copyright 2016 thirteen23. 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.
*/

/**
 * This skill is for remembering those silly quotes from movies gone by. The 1980s
 * to be specific. It was time of innocence. A time when John Hughes ruled the teen
 * movie space (see all his movies below). And a time when the internet didn't exist
 * as we know it today. The skill is called Bueller, as in Ferris Bueller. And 
 * Bueller can call up lots of movie quotes from the following movies: Back to the Future, 
 * Breakfast Club, Better Off Dead, Big Trouble in Little China, Caddyshack, Christmas 
 * Vacation, Coming to America, Die Hard, E.T., Fast Times at Ridgemont High, 
 * Ferris Bueller's Day Off, Ghostbusters, Raiders of the Lost Ark, The Lost Boys, 
 * Planes, Trains and Automobiles, Poltergeist, Pretty In Pink, Rambo, Real
 * Genius, Revenge of the Nerds, Say Anything, Scarface, Sixteen Candles, Spaceballs,
 * The Terminator, The Karate Kid, The Princess Bride, The Shining, Top Gun,
 * Vacation, and Weird Science. See below on how to hear a clip and have fun!
 *
 * Examples:
 * One-shot model:
 *  User: "Alexa, ask Bueller for a quote."
 *  Alexa: <random movie clip>

 * Specific movie model:
 *  User: "Alexa, ask Bueller for a quote from <insert movie name>"
 *  Alexa: <random movie clip from spoken movie name>
 */

/**
 * App ID for the skill
 */
var APP_ID = "amzn1.echo-sdk-ams.app.4547d96d-cdd1-4fbd-b6d3-5d43c95b1694"; 

/**
 * Prefix for the S3 server that holds the audio files.
 */
var serverPrefix = "https://s3.amazonaws.com/t23-play/audio/";

/**
 * Arrays of all movies and their corresponding audio files.
 */
var BACKTOTHEFUTURE_QUOTES = [
    "blindspot.mp3",
    "calvinklein.mp3",
    "gimmeatab.mp3",
    "gotthehots.mp3",
    "greatscott.mp3",
    "jumpship.mp3",
    "lightning.mp3",
    "meltmybrain.mp3",
    "myreports.mp3",
    "nuclear.mp3",
    "planetvulcan.mp3",
    "plutonium2.mp3",
    "ronaldreagan.mp3",
    "savetheclock.mp3",
    "seriousBLEEP.mp3",
    "soheavy.mp3",
    "television.mp3",
    "thelybians.mp3",
    "timemachine.mp3",
    "toodarnloud.mp3",
    "tothefuture.mp3",
    "weekin1955.mp3",
    "youraslacker.mp3",
    "yourmymo.mp3"
];

var BREAKFASTCLUB_QUOTES = [
    "breakfast_club.mp3",
    "couldntignoreme.mp3",
    "getthehorns.mp3",
    "illadvised.mp3",
    "itssushi.mp3",
    "raidwardrobe.mp3",
    "ruckus.mp3",
    "skulls.mp3"
];

var BETTEROFFDEAD_QUOTES = [
    "2dollars.mp3",
    "2dollars2.mp3",
    "2dollars4weeks.mp3",
    "7years.mp3",
    "adime.mp3",
    "barneybeth.mp3",
    "bethdumps.mp3",
    "blewup.mp3",
    "buckup.mp3",
    "christmas.mp3",
    "crydate.mp3",
    "dates_team.mp3",
    "drugs.mp3",
    "entrance.mp3",
    "friend.mp3",
    "frzbrain.mp3",
    "gothtway.mp3",
    "hisnose.mp3",
    "kickass.mp3",
    "mailman_beth.mp3",
    "memorize.mp3",
    "meyer.mp3",
    "mother_says.mp3",
    "northern_ca.mp3",
    "nose_flat.mp3",
    "puresnow.mp3",
    "race_lose_die.mp3",
    "race01.mp3",
    "raisins.mp3",
    "relish.mp3",
    "smut.mp3",
    "spk_french.mp3",
    "sunburn.mp3",
    "thats_nice.mp3",
    "virginity.mp3",
    "whiteboy.mp3",
    "worried.mp3",
    "wtr_ballet.mp3"
];

var BIGTROUBLEINLITTLECHINA_QUOTES = [
    "btlc-blackblood.mp3",
    "btlc-comeon.mp3",
    "btlc-see.mp3",
    "CallThePrez.mp3",
    "ComeOn.mp3",
    "PissOff.mp3",
    "ShutUp.mp3"
];

var CADDYSHACK_QUOTES = [
    "1000buks.mp3",
    "badhat.mp3",
    "barkdog.mp3",
    "bighit.mp3",
    "cannonbl.mp3",
    "cinderla.mp3",
    "forkeeps.mp3",
    "getlaid.mp3",
    "gungagag.mp3",
    "hegotall.mp3",
    "inthehol.mp3",
    "lean.mp3",
    "letsgo.mp3",
    "opencrtn.mp3",
    "poontang.mp3",
    "russia.mp3",
    "shewrote.mp3",
    "slouch.mp3",
    "stepduck.mp3",
    "tiemeup.mp3"
];

var CHRISTMASVACATION_QUOTES = [
    "breakwind.mp3",
    "eddie.mp3",
    "grace.mp3",
    "jellyfothemonth.mp3",
    "lipfungus.mp3",
    "merrychristmas.mp3",
    "misery.mp3",
    "mississippi.mp3",
    "myboss.mp3",
    "overdoingit.mp3",
    "playball.mp3",
    "snots.mp3",
    "surprised.mp3",
    "tenyards.mp3",
    "thatsound.mp3",
    "treelots.mp3",
    "treethatbig.mp3",
    "yulelog.mp3"
];

var COMINGTOAMERICA_QUOTES = [
    "fineline.mp3",
    "next.mp3",
    "reallife.mp3"
];

var DIEHARD_QUOTES = [
    "diehrd01.mp3",
    "diehrd03.mp3",
    "diehrd06.mp3",
    "diehrd07.mp3",
    "diehrd10.mp3",
    "diehrd11.mp3",
    "diehrd12.mp3"
];

var ET_QUOTES = [
    "Mjg5MTIyNzcyODkxNzE_6IK1qQqT0r8.mp3",
    "MTk3MjIyNzcxOTcyMzE_qU_2bNSlZoays.mp3",
    "MzQwNTIyNzczNDA1OTI__2beTl9CbUM9Y.mp3",
    "NjkzMjIyNzc2OTMzMDI_gk7z8j7DDaI.mp3",
    "NzEzODIyNzc3MTM5MDM_RXnSAp2CJyE.mp3",
    "Nzk3OTIyNzc3OTgwNjU_2RVEj279rSA.mp3",
    "ODA0NjIyNzc4MDQ3MDE_ZLIRkji_2frGA.mp3",
    "ODU5MDIyNzc4NTkwOTk_VlWQR7NlTBY.mp3"
];

var FASTTIMES_QUOTES = [
    "class.mp3",
    "fags.mp3",
    "getajob.mp3",
    "gnarly.mp3",
    "halucin8.mp3",
    "hey_bud.mp3",
    "i-have.mp3",
    "imwasted.mp3",
    "moron.mp3",
    "mr_hand.mp3",
    "no-shirt.mp3",
    "on-dope.mp3",
    "playboy.mp3",
    "prick.mp3",
    "problem.mp3",
    "tappin.mp3",
    "thatdude.mp3",
    "totally.mp3",
    "ushistry.mp3",
    "wasted.mp3",
    "wus.mp3",
    "yeah.mp3",
    "you-dick.mp3"
];

var FERRISBUELLER_QUOTES = [
    "batter.mp3",
    "bezerk.mp3",
    "BLEEPhole.mp3",
    "dankeshn.mp3",
    "diamond.mp3",
    "dude.mp3",
    "ferrari.mp3",
    "holyBLEEP.mp3",
    "ill_go.mp3",
    "life.mp3",
    "likenass.mp3",
    "mortuary.mp3",
    "playsick.mp3",
    "psandqs.mp3",
    "school.mp3",
    "testicle.mp3",
    "understd.mp3"
];

var GHOSTBUSTERS_QUOTES = [
    "backoff.mp3",
    "bad.mp3",
    "bedroom.mp3",
    "bitch.mp3",
    "busthds.mp3",
    "chore.mp3",
    "dick.mp3",
    "disaster.mp3",
    "dog.mp3",
    "goodeve.mp3",
    "kicked.mp3",
    "ok.mp3",
    "results.mp3",
    "rule.mp3",
    "split_up.mp3",
    "toast.mp3",
    "toys.mp3"
];

var INDIANAJONES_QUOTES = [
    "asps.mp3",
    "backbone.mp3",
    "how.mp3",
    "snakes.mp3",
    "thirsty.mp3"
];

var LOSTBOYS_QUOTES = [
    "lbinvit.mp3",
    "lbnite2.mp3",
    "lbrules.mp3",
    "lbstop.mp3",
    "lbvamp.mp3"
];

var KARATEKID_QUOTES = [
    "MjQ0OTU5ODU4MjQ0OTQx_p0dR42DQ9KY.mp3",
    "MTI5MTU5ODU4MTI5MTMz_y1W63RpjwPY.mp3",
    "MzM2MjU5ODU4MzM2MjQ5_w4VG6L1PioY.mp3",
    "NjAwNDU5ODU4NjAwNTE4_PlzgwkNG5EA.mp3",
    "NTc2NDU5ODU4NTc2NTM1_BMwScC8wKgo.mp3",
    "NzE3MDU5ODU4NzE3MTM3_ITxsVPHUEn0.mp3",
    "NzExMzU5ODU4NzExNDYw_D8b8OEWtcYo.mp3",
    "NzYwMDU5ODU4NzYwMDgz_UUSAhd3Xo5I.mp3",
    "OTA3MTU5ODU4OTA3Mjcx_Yqm9SemF44E.mp3",
    "OTEyNjU5ODU4OTEyNzAz_K3phodHOfS0.mp3",
    "OTMzMTU5ODU4OTMzMjI0_8mdQtimi_2b_2bE.mp3"
];

var PLANESTRAINSAUTOS_QUOTES = [
    "pta001.mp3",
    "pta002.mp3",
    "pta003.mp3",
    "pta004.mp3",
    "pta005.mp3",
    "pta007.mp3",
    "pta009.mp3",
    "pta010.mp3",
    "pta012.mp3",
    "pta015.mp3",
    "pta016.mp3",
    "pta018.mp3",
    "pta019.mp3",
    "pta020.mp3",
    "pta024.mp3",
    "pta025.mp3",
    "pta026.mp3"
];

var POLTERGEIST_QUOTES = [
    "cross_over.mp3",
    "dream_state.mp3",
    "get_it_away.mp3",
    "life_force.mp3",
    "mommy.mp3",
    "never_sensed.mp3",
    "pg2back.mp3",
    "pg2tv.mp3",
    "pgcann.mp3"
];

var PRETTYINPINK_QUOTES = [
    "pip-admire.mp3",
    "pip-bed.mp3",
    "pip-believe.mp3",
    "pip-believe2.mp3",
    "pip-blaine.mp3",
    "pip-breakme.mp3",
    "pip-dontknow.mp3",
    "pip-herelong.mp3",
    "pip-ifyouleave.mp3",
    "pip-kissed.mp3",
    "pip-marvelous.mp3",
    "pip-mother.mp3",
    "pip-nexttime.mp3",
    "pip-offend.mp3",
    "pip-pretty.mp3",
    "pip-ridebike.mp3",
    "pip-ruining.mp3",
    "pip-taste.mp3",
    "pip-thatsit.mp3",
    "pip-thetruth.mp3",
    "pip-whatsthis.mp3",
    "pip-woman.mp3"
];

var RAMBO_QUOTES = [
    "fbbusy.mp3",
    "fblife.mp3",
    "fbmiss.mp3",
    "fbres.mp3",
    "fbwar.mp3"
];


var REALGENIUS_QUOTES = [
    "NjE3NDY3ODM5NjE3NTIx_xWGxyMTA4VQ.mp3",
    "NjUxODY3ODM5NjUxODcz_QDY_2fXpzeIXI.mp3",
    "NTY3MzY3ODM5NTY3NDQ1_OdSy0OUoB14.mp3"
];

var REVENGEOFTHENERDS_QUOTES = [
    "NDk3OTI5MDE0OTgwMzk_6CGMt_2faTERM.mp3",
    "NTIxMjI5MDE1MjEzMDM_Xsn2Tx7sb34.mp3",
    "NTk0NTI5MDE1OTQ1NzM_1FAciaMq6TM.mp3",
    "NTM5NjI5MDE1Mzk2Njg_Vq2Y1ZVxBDc.mp3",
    "ODA0NjI5MDE4MDQ3Mzc_WvUC7YgGII4.mp3",
    "ODM5NjI5MDE4Mzk3NTg_gaj_2fGsBs_2bow.mp3"
];

var SAYANYTHING_QUOTES = [
    "clip1.mp3",
    "clip2.mp3",
    "clip3.mp3",
    "clip4.mp3",
    "clip5.mp3",
    "clip6.mp3"
];

var SCARFACE_QUOTES = [
    "scarface_bad_guy.mp3",
    "scarface_money.mp3",
    "scarface_say_hello.mp3"
];

var SIXTEENCANDLES_QUOTES = [
    "geek.mp3",
    "hotstuff.mp3",
    "nomore.mp3"
];

var SPACEBALLS_QUOTES = [
    "chicken.mp3",
    "dolls3.mp3",
    "goodumb.mp3",
    "half-man-half-dog.mp3",
    "self-destruct-button.mp3",
    "swartz.mp3"
];

var TERMINATOR_QUOTES = [
    "t1_be_back.mp3",
    "t1_clothes_x.mp3",
    "t2_learning_computer_x.mp3"
];

var THEPRINCESSBRIDE_QUOTES = [
    "boo.mp3",
    "breasts.mp3",
    "brutesquad.mp3",
    "bye.mp3",
    "coward.mp3",
    "dead.mp3",
    "decent.mp3",
    "despair.mp3",
    "killed.mp3",
    "marraige.mp3",
    "pry.mp3",
    "rous.mp3",
    "truelove.mp3",
    "witch.mp3",
    "worst.mp3"
];

var THESHINING_QUOTES = [
    "allofredrum.mp3",
    "heresjohnny.mp3",
    "inmymouth.mp3",
    "littlepigs.mp3",
    "myconcentration.mp3",
    "playwithus.mp3",
    "room237.mp3",
    "setemup.mp3",
    "stayhere.mp3",
    "wendyimhome.mp3",
    "youlikelamb.mp3"
];

var TOPGUN_QUOTES = [
    "aircraft.mp3",
    "dangerous.mp3",
    "defense2.mp3",
    "flyby.mp3",
    "hitbrake.mp3",
    "lovinf.mp3",
    "migdata.mp3",
    "migstory.mp3",
    "speed.mp3",
    "stud.mp3"
];

var VACATION_QUOTES = [
    "bro.mp3",
    "helper.mp3",
    "kiss.mp3",
    "sorry.mp3"
];

var WEIRDSCIENCE_QUOTES = [
    "brasonhead.mp3",
    "chess.mp3",
    "dickweed.mp3",
    "dofirst.mp3",
    "dontruinthefantasy.mp3",
    "morgue.mp3",
    "partyanimal.mp3",
    "pukes.mp3",
    "sandwich.mp3",
    "seriousbitch.mp3",
    "shutup.mp3",
    "sprain.mp3",
    "toaster.mp3",
    "wanker.mp3",
    "yourestewed.mp3"
];


/**
 * This Array puts it all together: the movie title as lower case and no spaces, array of audio clips, 
 * and the audio folder name on the S3 server. 
 */
var MOVIES = [
    {title:"backtothefuture",ary:BACKTOTHEFUTURE_QUOTES,audioFolder:"backtothefuture"},
    {title:"breakfastclub",ary:BREAKFASTCLUB_QUOTES,audioFolder:"bc"},
    {title:"betteroffdead",ary:BETTEROFFDEAD_QUOTES,audioFolder:"bod"},
    {title:"bigtroubleinlittlechina",ary:BIGTROUBLEINLITTLECHINA_QUOTES,audioFolder:"bigtroubleinlittlechina"},
    {title:"caddyshack",ary:CADDYSHACK_QUOTES,audioFolder:"cs"},
    {title:"christmasvacation",ary:CHRISTMASVACATION_QUOTES,audioFolder:"christmasvacation"},
    {title:"comingtoamerica",ary:COMINGTOAMERICA_QUOTES,audioFolder:"comingtoamerica"},
    {title:"diehard",ary:DIEHARD_QUOTES,audioFolder:"diehard"},
    {title:"et",ary:ET_QUOTES,audioFolder:"et"},
    {title:"fasttimesatridgemonthigh",ary:FASTTIMES_QUOTES,audioFolder:"fasttimes"},
    {title:"ferrisbuellersdayoff",ary:FERRISBUELLER_QUOTES,audioFolder:"ferrisbueller"},
    {title:"ghostbusters",ary:GHOSTBUSTERS_QUOTES,audioFolder:"ghostbusters"},
    {title:"indianajones",ary:INDIANAJONES_QUOTES,audioFolder:"indianajones"},
    {title:"raidersofthelostark",ary:INDIANAJONES_QUOTES,audioFolder:"indianajones"},
    {title:"lostboys",ary:LOSTBOYS_QUOTES,audioFolder:"lostboys"},
    {title:"thelostboys",ary:LOSTBOYS_QUOTES,audioFolder:"lostboys"},
    {title:"karatekid",ary:KARATEKID_QUOTES,audioFolder:"karatekid"},
    {title:"thekaratekid",ary:KARATEKID_QUOTES,audioFolder:"karatekid"},
    {title:"planestrainsandautomobiles",ary:PLANESTRAINSAUTOS_QUOTES,audioFolder:"planestrainsandautos"},
    {title:"poltergeist",ary:POLTERGEIST_QUOTES,audioFolder:"poltergeist"},
    {title:"prettyinpink",ary:PRETTYINPINK_QUOTES,audioFolder:"pip"},
    {title:"rambo",ary:RAMBO_QUOTES,audioFolder:"rambo"},
    {title:"realgenius",ary:REALGENIUS_QUOTES,audioFolder:"realgenius"},
    {title:"revengeofthenerds",ary:REVENGEOFTHENERDS_QUOTES,audioFolder:"revengeofthenerds"},
    {title:"sayanything",ary:SAYANYTHING_QUOTES,audioFolder:"sayanything"},
    {title:"scarface",ary:SCARFACE_QUOTES,audioFolder:"scarface"},
    {title:"sixteencandles",ary:SIXTEENCANDLES_QUOTES,audioFolder:"sc"},
    {title:"spaceballs",ary:SPACEBALLS_QUOTES,audioFolder:"spaceballs"},
    {title:"terminator",ary:TERMINATOR_QUOTES,audioFolder:"terminator"},
    {title:"theterminator",ary:TERMINATOR_QUOTES,audioFolder:"terminator"},
    {title:"theprincessbride",ary:THEPRINCESSBRIDE_QUOTES,audioFolder:"princessbride"},
    {title:"princessbride",ary:THEPRINCESSBRIDE_QUOTES,audioFolder:"princessbride"},
    {title:"theshining",ary:THESHINING_QUOTES,audioFolder:"theshining"},
    {title:"shining",ary:THESHINING_QUOTES,audioFolder:"theshining"},
    {title:"16candles",ary:SIXTEENCANDLES_QUOTES,audioFolder:"sc"},
    {title:"topgun",ary:TOPGUN_QUOTES,audioFolder:"topgun"},
    {title:"vacation",ary:VACATION_QUOTES,audioFolder:"vacation"},
    {title:"weirdscience",ary:WEIRDSCIENCE_QUOTES,audioFolder:"weirdscience"}
];

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

/**
 * Bueller 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 Bueller = function () {
    AlexaSkill.call(this, APP_ID);
};

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

/**
 * Function to invoke anything when starting up. (nothing at this time)
 */
Bueller.prototype.eventHandlers.onSessionStarted = function (sessionStartedRequest, session) {
    console.log("Bueller onSessionStarted requestId: " + sessionStartedRequest.requestId
        + ", sessionId: " + session.sessionId);
};

/**
 * Once launched we go ahead and handle the request from the Echo. 
 */
Bueller.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
    console.log("Bueller onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);

    //Call for a movie quote with no movie title
    handleNewFactRequest(response, null);
};

/**
 * Overridden to show that a subclass can override this function to teardown session state.
 */
Bueller.prototype.eventHandlers.onSessionEnded = function (sessionEndedRequest, session) {
    console.log("Bueller onSessionEnded requestId: " + sessionEndedRequest.requestId
        + ", sessionId: " + session.sessionId);
    // any cleanup logic goes here
};

Bueller.prototype.intentHandlers = {
    "GetRandomQuoteIntent": function (intent, session, response) {

        //Grab the movie title, whether it exists or not
        var movieSlot = intent.slots.Movie;

        //Call for a movie quote with possible movie title
        handleNewFactRequest(response, movieSlot);
    },

    "AMAZON.HelpIntent": function (intent, session, response) {
        response.ask("You can get a random movie clip by saying open bueller. You can also say Alexa, ask bueller for a quote. If you want a specific movie, you can say, for example, Alexa, ask bueller for a quote from die hard.", "What can I help you with?");
    },

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

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

/**
 * Gets a random movie clip to play or a clip specific to the movie passed in. 
 */
function handleNewFactRequest(response, movieSlot) {

    var index = 0;
    if (movieSlot && movieSlot.value) {
        // First we need to see if the movie spoken exists in our set of movie titles.
        var movieKey = movieSlot.value.toLowerCase();
        movieKey = movieKey.replace(/\s/g, '');
        console.log("movie name: " + movieKey);

        for (var j = 0; j < MOVIES.length; j++) {
            var tempObj = MOVIES[j];
            //console.log("lengths: " + tempObj.title.length + "::" + movieKey.length);
            if ((tempObj.title.indexOf(movieKey) >= 0) && (tempObj.title.length == movieKey.length)) {
                index = j;
                break;
            }
        }

    } else {
        // If it doesn't, we grab a random movie. 
        index = Math.floor(Math.random() * MOVIES.length);
    }

    // Get the folder where the audio file exists to help build the URL. 
    var audioFolder = MOVIES[index].audioFolder;
    // Get the array of audio files for that movie. 
    var moviesList = MOVIES[index].ary;

    // Get a random index for grabbing a random clip from the list. 
    index = Math.floor(Math.random() * moviesList.length); 
    // Build the URL for the movie quote. 
    var quote = serverPrefix + audioFolder + "/" + moviesList[index];

    // Create speech output
    var speechOutput = "<speak><audio src='" + quote + "' /> </speak>";
    console.log("output: " + speechOutput);
    response.tellWithCard(speechOutput, "Bueller", speechOutput);
}

// Create the handler that responds to the Alexa Request.
exports.handler = function (event, context) {
    // Create an instance of the Bueller skill.
    var bueller_new = new Bueller();
    bueller_new.execute(event, context);
};

AlexaSkill.js

JavaScript
Standard Alexa code from their sample code.
/**
    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',
            //HACK
            type: optionsParam.type || 'SSML',
            //text: optionsParam.speech || optionsParam
            ssml: 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

Tom Hudson

Tom Hudson

1 project • 0 followers
Thanks to thirteen23.

Comments