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!
Drew
Published © CC BY-NC

Gaming Against Violence: The Echo Edition

Educators can ask Alexa to teach their students about teen dating violence and Alexa will ask five randomly selected questions about TDV.

BeginnerShowcase (no instructions)4 hours730

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

Story

Read more

Schematics

VUI for Teen Dating Violence Quiz

Code

Teen Dating Violence quiz

JavaScript
This quiz uses the quiz template from Amazon for their Echo device.

Place this in the AWS Lambda function and customize as needed. Line #s 273, 570, 571, 619, 620, 636, and 637 need additional info as described.
/**
 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.
 */

/**
 * This sample shows how to create a simple Trivia skill with a multiple choice format. The skill
 * supports 1 player at a time, and does not support games across sessions.
 */

'use strict';

/**
 * When editing your questions pay attention to your punctuation. Make sure you use question marks or periods.
 */
var questions = [
	{
        "How many teens in an abusive relationship ever tell anybody about it?": [
            "one third of them",
            "most of them",
            "all of them",
            "half of them"
        ]
    },
    {
        "How many parents either believe that teen dating violence is not an issue or just don't know?": [
            "81%",
            "10%",
            "15%",
            "35%"
        ]
    },
    {
        "What percent of parents cannot identify all the warning signs of an abusive relationship?": [
            "58%",
            "10%",
            "20%",
            "30%"
        ]
    },
    {
        "What percent of pregnant teen girls are in abusive relationships?": [
            "85%",
            "15%",
            "20%",
            "25%"
        ]
    },
    {
        "If a teen girl is in an abusive relationship, how much more likely is she to get an S T I?": [
            "twice as likely",
            "10% more likely",
            "20% more likely",
            "no more likely"
        ]
    },
    {
        "By the time that they graduate from college, what percent of students have been in an abusive relationship?": [
            "44%",
            "Almost one third",
            "10%",
            "20%"
        ]
    },
    {
        "How many high school students experience Physical abuse every year in the U.S.?": [
            "One point five million",
            "ten thousand",
            "fifty thousand",
            "one hundred and twenty five thousand"
        ]
    },
    {
        "How many high school students are physically hit or hurt by their dating partner?": [
            "one in ten",
            "one in a hundred",
            "one in a thousand",
            "one in fifty"
        ]
    },
    {
        "What impact can teen dating violence have??": [
            "all of these",
            "serious drug and alcohol abuse",
            "dropping out of school",
            "suicidal ideation and self-harm"
        ]
    },
    {
        "What percent of teens have discussed dating violence with their parents?": [
            "less than one quarter",
            "about half",
            "three-quarters",
            "almost all"
        ]
    },
    {
        "How many Seventh grade students in the U.S. report being a victim of dating violence?": [
            "1 in 3",
            "1 in 100",
            "1 in 50",
            "1 in 10"
        ]
    },
    {
        "How many college students in the U.S. are currently in an abusive relationship?": [
            "1 in 5",
            "1 in 10",
            "1 in 20",
            "1 in 25"
        ]
    },
    {
        "Which of these are a warning sign of an abusive relationship?": [
            "all of these are warning signs",
            "puts you down",
            "tells you what to wear",
            "threatens to hurt you or themselves"
        ]
    },
    {
        "Which of these is a warning sign of an abusive relationship?": [
            "all of these are warning signs",
            "blames you for their own anger",
            "does not respect your wishes about safe sex",
            "threatens to reveal private information or images"
        ]
    },
    {
        "What is an example of digital abuse?": [
            "all of these",
            "demanding your partner's social media password",
            "incessant and unwanted texts demanding to know where you are or what you are doing",
            "logging into your partner's account and pretending to be them"
        ]
    },
    {
        "Which of these is a warning sign of an abusive relationship?": [
            "all of these",
            "History of discipline problems",
            "Serious drug or alcohol abuse",
            "Prevents you from spending time with friends or family"
        ]
    },
    {
        "What percent of girls who have been physically abused continue to date the abuser?": [
            "Nearly 80%",
            "Less than 10%",
            "Almost half",
            "Around 25%"
        ]
    },
    {
        "What percent of college students say that it is difficult to identify dating abuse?": [
            "57%",
            "10%",
            "20%",
            "28%"
        ]
    },
    {
        "What percent of college students say that they do not know how to help somebody in an abusive relationship?": [
            "58%",
            "15%",
            "33%",
            "25%"
        ]
    },
    {
        "Which of these are a form of dating violence?": [
            "all of these",
            "physical abuse",
            "sexual abuse",
            "emotional abuse"
        ]
    },
    {
        "What is another name for teen dating violence?": [
            "all of these are other names for teen dating violence",
            "dating abuse",
            "relationship abuse",
            "intimate partner violence"
        ]
    },
    {
        "Are L G B T couples as likely to be in an abusive relationship?": [
            "they are just as likely",
            "they are much less likely",
            "they are much more likely",
            "they are somewhat less likely"
        ]
    },
    {
        "What percent of high school counselors feel prepared to address dating violence on campus?": [
            "less than 20%",
            "over 90%",
            "around 80%",
            "close to 75%"
        ]
    },
    {
        "What can you do if you know someone who might be in an abusive relationship?": [
            "all of these",
            "Ask how you can help",
            "Encourage your friend to seek help",
            "Educate yourself about dating violence and healthy relationships"
        ]
    },
    {
        "What percent of people age 14 to 24 have experienced digital abuse?": [
            "50%",
            "25%",
            "15%",
            "33%"
        ]
    },
    {
        "What is the financial impact of domestic violence in the U.S. every year?": [
            "Eight point three billion dollars",
            "Eighty-three million dollars",
            "Eight point three million dollars",
            "Eight hundred and thirty million dollars"
        ]
    },
    {
        "What is the most common location for teen dating abuse?": [
            "at home",
            "at school or school events",
            "at social events like parties",
            "at public places like malls"
        ]
    },
    {
        "What percent of teens in an abusive relationship have called an abuse helpline?": [
            "5%",
            "50%",
            "75%",
            "25%"
        ]
    },
    {
        "What percent of teens in an abusive relationship have talked to a school counselor?": [
            "15%",
            "50%",
            "75%",
            "25%"
        ]
    },
    {
        "What percent of teens between the age of 13 and 18 say that they've been in a dating relationship?": [
            "89%",
            "50%",
            "65%",
            "77%"
        ]
    }
];

// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
    try {
        console.log("event.session.application.applicationId=" + event.session.application.applicationId);

        /**
         * Uncomment this if statement and populate with your skill's application ID to
         * prevent someone else from configuring a skill that sends requests to this function.
         */
		 
       if (event.session.application.applicationId !== "PLACE APPLICATION ID HERE") {
           context.fail("Invalid Application ID");
        }

        if (event.session.new) {
            onSessionStarted({requestId: event.request.requestId}, event.session);
        }

        if (event.request.type === "LaunchRequest") {
            onLaunch(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "IntentRequest") {
            onIntent(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "SessionEndedRequest") {
            onSessionEnded(event.request, event.session);
            context.succeed();
        }
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // add any session init logic here

}

/**
 * Called when the user invokes the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log("onLaunch requestId=" + launchRequest.requestId
        + ", sessionId=" + session.sessionId);
    getWelcomeResponse(callback);
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId
        + ", sessionId=" + session.sessionId);

    var intent = intentRequest.intent,
        intentName = intentRequest.intent.name;

    // dispatch custom intents to handlers here
    if ("AnswerIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AnswerOnlyIntent" === intentName) {
        handleAnswerRequest(intent, session, callback);
    } else if ("AMAZON.StartOverIntent" === intentName) {
        getWelcomeResponse(callback);
    } else if ("AMAZON.RepeatIntent" === intentName) {
        handleRepeatRequest(intent, session, callback);
    } else if ("AMAZON.HelpIntent" === intentName) {
        handleGetHelpRequest(intent, session, callback);
    } else if ("AMAZON.StopIntent" === intentName) {
        handleFinishSessionRequest(intent, session, callback);
    } else if ("AMAZON.CancelIntent" === intentName) {
        handleFinishSessionRequest(intent, session, callback);
    } else {
        throw "Invalid intent";
    }
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // Add any cleanup logic here
}

// ------- Skill specific business logic -------

var ANSWER_COUNT = 4,
    GAME_LENGTH = 5;

function getWelcomeResponse(callback) {
    var sessionAttributes = {},
        cardTitle = "Teen Dating Violence Quiz",
        speechOutput = "Welcome to the Teen Dating Violence Quiz brought to you by the good people at Jennifer Ann's Group.\r\nI will ask you " + GAME_LENGTH.toString() 
            + " questions and you try to get as many right as you can. Just say the number of the answer and I'll keep score of how you're doing.\r\n ",
        shouldEndSession = false,

        gameQuestions = populateGameQuestions(),
        correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT)), // Generate a random index for the correct answer, from 0 to 3
        roundAnswers = populateRoundAnswers(gameQuestions, 0, correctAnswerIndex),

        currentQuestionIndex = 0,
        spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0],
        repromptText = "Question 1. " + spokenQuestion + "\n ",

        i, j;


    for (i = 0; i < ANSWER_COUNT; i++) {
        repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
    }
    speechOutput += repromptText;
    sessionAttributes = {
        "speechOutput": repromptText,
        "repromptText": repromptText,
        "currentQuestionIndex": currentQuestionIndex,
        "correctAnswerIndex": correctAnswerIndex + 1,
        "questions": gameQuestions,
        "score": 0,
        "correctAnswerText":
            questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
    };
    callback(sessionAttributes,
        buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}



function populateGameQuestions() {
    var gameQuestions = [],
        randomNum;

    // Pick 5 random questions from the list to ask the user, make sure there are no repeats
    while (gameQuestions.length != GAME_LENGTH) {
        randomNum = Math.floor(Math.random() * (questions.length - 1));
        if (gameQuestions.indexOf(randomNum) == -1) {
            gameQuestions.push(randomNum);
        }
    }
    return gameQuestions;
}

function populateRoundAnswers(gameQuestions, index, correctAnswer) {
    // Get the answers for a given question, and place the correct answer at the spot marked by the
    // correctAnswer variable
    var answers = [],
        answersCopy = questions[gameQuestions[index]][Object.keys(questions[gameQuestions[index]])[0]],
        temp, i;
    for (i = 0; i < ANSWER_COUNT; i++) {
        answers[i] = answersCopy[i];
    }
    temp = answers[0];
    answers[0] = answers[correctAnswer];
    answers[correctAnswer] = temp;
    return answers;
}

function handleAnswerRequest(intent, session, callback) {
    var cardTitle = "Teen Dating Violence Quiz",
        speechOutput = "";

    var answerSlot = intent.slots.Answer;
    // If the user provided answer isn't a number > 0 and < 5,
    // return an error message to the user
    if (!answerSlot || !answerSlot.value || isNaN(parseInt(answerSlot.value))
        || !(parseInt(answerSlot.value) < ANSWER_COUNT+1 && parseInt(answerSlot.value) > 0)) {
        speechOutput = "Your answer must be a number between 1 and 4.\n"
        callback(session.attributes,
            buildSpeechletResponse(cardTitle, speechOutput, speechOutput, false));
    }
    else {
        // If the user responded with an answer but there is no game in progress, ask the user
        // if they want to start a new game
        if (!session.attributes || !session.attributes.questions) {
            speechOutput = "There is no game in progress. To start a new game, say, " +
                "start game.\n";
            callback(session.attributes,
                buildSpeechletResponse(cardTitle, speechOutput, speechOutput, false));
        }
        else {
            var gameQuestions = session.attributes.questions,
                correctAnswerIndex = parseInt(session.attributes.correctAnswerIndex),
                currentScore = parseInt(session.attributes.score),
                currentQuestionIndex = parseInt(session.attributes.currentQuestionIndex),
                correctAnswerText = session.attributes.correctAnswerText;

            var speechOutputAnalysis = "";
            if (parseInt(answerSlot.value) == correctAnswerIndex) {
                currentScore++;
                speechOutputAnalysis = "correct.\n ";
            } else {
                speechOutputAnalysis = "wrong. The correct answer is " + correctAnswerText + ".\n ";
            }
            // if currentQuestionIndex is 4, we've reached 5 questions (zero-indexed) and can exit the game session
            // if perfect score then say something different
            if (currentQuestionIndex == GAME_LENGTH - 1) {
                if (currentScore.toString() == 5) {
                speechOutput = "That answer is " + speechOutputAnalysis + "You got " +
                    currentScore.toString() + " out of " + GAME_LENGTH.toString() + " questions correct!\n Wow, perfect score. You rock!\n Jennifer Ann's Group thanks you for your interest in teen dating violence!";
                callback(session.attributes,
                    buildSpeechletResponse(cardTitle, speechOutput, "", true));
                 }
                    else {
                        speechOutput = "That answer is " + speechOutputAnalysis + "You got " +
                            currentScore.toString() + " out of " + GAME_LENGTH.toString() + " questions correct.\n You can do better!\n Jennifer Ann's Group thanks you for your interest in teen dating violence!";
                        callback(session.attributes,
                            buildSpeechletResponse(cardTitle, speechOutput, "", true));
                    }
                }    
            else {
                currentQuestionIndex += 1;
                var spokenQuestion = Object.keys(questions[gameQuestions[currentQuestionIndex]])[0];
                // Generate a random index for the correct answer, from 0 to 3
                correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT));
                var roundAnswers = populateRoundAnswers(gameQuestions, currentQuestionIndex, correctAnswerIndex),

                    questionIndexForSpeech = currentQuestionIndex + 1,
                    repromptText = "Question " + questionIndexForSpeech.toString() + ".\n " + spokenQuestion + " ";
                for (var i = 0; i < ANSWER_COUNT; i++) {
                    repromptText += (i+1).toString() + ". " + roundAnswers[i] + ". "
                }
                speechOutput += "That answer is " + speechOutputAnalysis + "Your score is " + currentScore.toString() + ".\n " + repromptText;

                var sessionAttributes = {
                    "speechOutput": repromptText,
                    "repromptText": repromptText,
                    "currentQuestionIndex": currentQuestionIndex,
                    "correctAnswerIndex": correctAnswerIndex + 1,
                    "questions": gameQuestions,
                    "score": currentScore,
                    "correctAnswerText":
                        questions[gameQuestions[currentQuestionIndex]][Object.keys(questions[gameQuestions[currentQuestionIndex]])[0]][0]
                };
                callback(sessionAttributes,
                    buildSpeechletResponse(cardTitle, speechOutput, repromptText, false));
            }
        }
    }
}

function handleRepeatRequest(intent, session, callback) {
    // Repeat the previous speechOutput and repromptText from the session attributes if available
    // else start a new game session
    if (!session.attributes || !session.attributes.speechOutput) {
        getWelcomeResponse(callback);
    } else {
        callback(session.attributes,
            buildSpeechletResponseWithoutCard(session.attributes.speechOutput, session.attributes.repromptText, false));
    }
}

function handleGetHelpRequest(intent, session, callback) {
    // Provide a help prompt for the user, explaining how the game is played. Then, continue the game
    // if there is one in progress, or provide the option to start another one.

    // Do not edit the help dialogue. This has been created by the Alexa team to demonstrate best practices.

    var speechOutput = "I will ask you " + GAME_LENGTH.toString() + " multiple choice questions, try to get as many right as you can! "
        + "To give an answer to a question, respond with the number of the answer by saying one, two, three, or four. "
        + "To start a new game at any time, say, start game. "
        + "To repeat the last question asked, say, repeat.",
        repromptText = "To give an answer to a question, respond with the number of the answer. "
        + "To start a new game, say, start game",
        shouldEndSession = false;
    callback(session.attributes,
        buildSpeechletResponseWithoutCard(speechOutput, repromptText, shouldEndSession));
}

function handleFinishSessionRequest(intent, session, callback) {
    // End the session with a "Good bye!" if the user wants to quit the game
    callback(session.attributes,
        buildSpeechletResponseWithoutCard("Jennifer Ann's Group thanks you for your interest in stopping teen dating violence!\n Good bye!", "", true));
}

// ------- Helper functions to build responses -------


function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
//        card: {
//            type: "Simple",
//            title: title,
//            content: output
//        },
        card: {
            type: "Standard",
            title: title,
            image: {
                    "smallImageUrl": "PLACE URL TO IMAGE HERE",
                    "largeImageUrl": "PLACE URL TO IMAGE HERE"
                    },
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildSpeechletResponseWithoutCard(output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: "1.0",
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}




//function buildResponse(sessionAttributes, speechletResponse) {
//    return {
//        version: "1.0",
//        sessionAttributes: sessionAttributes,
//        response: speechletResponse,
//        type: "Standard",
//        image: {
//                    "smallImageUrl": "PLACE URL TO IMAGE HERE",
//                    "largeImageUrl": "PLACE URL TO IMAGE HERE"
//        }
//    };
//}    



// function getWelcomeCard() {
//        "version": "1.0",
//       "response": {
//          "outputSpeech":"type":"PlainText","text":"Test content!"},
//            "card":{
//               "type": "Standard",
//              "title": "Test welcome card",
//                "text": "Test welcome text",
//                "image": {
//                    "smallImageUrl": "PLACE URL TO IMAGE HERE",
//                    "largeImageUrl": "PLACE URL TO IMAGE HERE"
//                }
//            }
//        }    
//    }

Credits

Drew

Drew

2 projects • 1 follower
Founder and Executive Director of Jennifer Ann's Group, a nonprofit organization using technology in innovative ways to prevent teen dating violence.
Thanks to Jean-Marc Cote.

Comments