John Michael Stewart
Created December 11, 2016

Pokedex

Pokedex allows you to ask Alexa for various information about pokemon. This app is powered by the Poke API https://pokeapi.co/.

44
Pokedex

Things used in this project

Story

Read more

Code

index.js

JavaScript
This is the code that powers the Alexa skill. It is a nodeJS app that is hosted within AWS Lambda. Once you configure the Alexa skill to point to this Lambda function, it passes in the voice commands to the appropriate methods in this file to fetch the data from the PokeAPI
'use strict';
var Alexa = require('alexa-sdk');
var aws = require('aws-sdk');

var Pokedex  = require('pokedex-promise-v2');
var options = {
	timeout: 5 * 1000
};
var P = new Pokedex(options);

var _this = null;

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

function getPokemonByName(pokemon, query) {
	console.log("Pokemon Name: " + pokemon);
	
	pokemon = replaceAll(pokemon, "", "u");
	
	console.log("fixed: " + pokemon);
	
	var q = ddb.query({
		TableName: "Pokemon",
		IndexName: "Name-index",
		Limit: 1,
		KeyConditionExpression: "#N = :pokemon",
		ExpressionAttributeNames: {
			"#N": "Name"
		},
		ExpressionAttributeValues: {
			":pokemon": {"S": pokemon.toLowerCase() }
		}
	}, function(err, data) {
		if(err) {
			console.log("Error: " + err);
			_this.emit(":tell", "Unable to locate the pokemon you requested");
			return err;
		} else {
			console.log("server response: " + JSON.stringify(data));
			
			var pokemon = data.Items;
			
			if(pokemon.length >= 1)
				pokemon = pokemon[0];
			else {
				_this.emit(":ask", "The pokemon you requested could not be found, repeat your request?");
				return;
			}
			
			var speech = "";
			if(query == "evolution") {
				if(pokemon.Evolution.M.Type.S.toLowerCase() == "level") {
					speech = pokemon.PhoneticName.S + " evolves at " + pokemon.Evolution.M.Action.S + " into " + pokemon.Evolution.M.EvolvesTo.S;
				} else if(pokemon.Evolution.M.Type.S.toLowerCase() == "item") {
					speech = pokemon.PhoneticName.S + " evolves into " + pokemon.Evolution.M.EvolvesTo.S + " when you use a " + pokemon.Evolution.M.Action.S; 
				} else if(pokemon.Evolution.M.Type.S.toLowerCase() == "friendship") {
					speech = pokemon.PhoneticName.S + " evolves into " + pokemon.Evolution.M.EvolvesTo.S + " when it levels up with high friendship"; 
				} else if(pokemon.Evolution.M.Type.S.toLowerCase() == "location") {
					speech = pokemon.PhoneticName.S + " evolves into " + pokemon.Evolution.M.EvolvesTo.S + " when it levels up in " + pokemon.Evolution.M.Action.S; 
				} else {
					speech = pokemon.PhoneticName.S + " does not evolve.";
				}
			} else if(query == "type") {
				var type = "";
				for(var i = 0; i < pokemon.Types.L.length; ++i) {
					if(i !== 0) { 
						type += ", "; 
					}
					
					type += pokemon.Types.L[i].S;
				}
				speech += pokemon.PhoneticName.S + " is a " + type + " pokemon.";
			}

			_this.emit(':tellWithCard', speech, "Pokedex", speech);
		}
	});
}

function generateSpeech(data, version) {
	var entry = data.Item; 
	
	var speechOutput = entry.DisplayName.S + ", the " + entry.KnownAs.S + ".  ";
	
	if(entry.Types.L.length > 0) {
		speechOutput += "It is a  ";
		for(var i = 0; i < entry.Types.L.length; ++i) {
			if(i !== 0) speechOutput += ", ";
			speechOutput += entry.Types.L[i].S;
		}
		speechOutput += " type pokemon.  ";
	}
	
	if(entry.Abilities.L.length > 0) {
		speechOutput += "Abilities: ";
		for(var i = 0; i < entry.Abilities.L.length; ++i) {
			if(i !== 0) speechOutput += ", ";
			if(entry.Abilities.L[i].M.IsHidden.BOOL)
				speechOutput += "Hidden ability: ";
			speechOutput += entry.Abilities.L[i].M.Name.S;
		}
		speechOutput += ".  ";
	}
	
	for(var i = 0; i < entry.Descriptions.L.length; ++i) {
		if(entry.Descriptions.L[i].M.Game.S.toLowerCase() === version.toLowerCase())
			speechOutput += entry.Descriptions.L[i].M.Description.S;
	}
	
	_this.emit(':tellWithCard', replaceAll(speechOutput, entry.DisplayName.S, entry.PhoneticName.S), "Pokedex", speechOutput);
}

function getItemName(item) {
	var queryItemName = replaceAll(item, " ", "-");

	console.log(queryItemName);

    P.getItemByName(queryItemName.toLowerCase())
        .then(function(response) {
            console.log(JSON.stringify(response));

            var speech = item + ": ";

            if(response.effect_entries.length > 0) {
            	speech += response.effect_entries[0].short_effect;
			}

            var imageObj = {
                smallImageUrl: response.sprites.default,
                largeImageUrl: response.sprites.default
            };

			_this.emit(':tellWithCard', speech, "Pokedex", speech, imageObj);
        })
        .catch(function(error) {
            console.log('There was an ERROR: ', error);
            _this.emit(":ask", "There was a problem locating the item you requested.  Repeat the item name?");
            return error;
        });
}

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'LaunchRequest': function () {
        this.emit(':ask', "Which entry would you like to hear?");
    },
	'GetEvolutionIntent': function() {
		_this = this;
		var pokemonName = this.event.request.intent.slots.pokemonName;
		if(pokemonName && pokemonName.value)
			pokemonName = pokemonName.value;

        pokemonName = replaceAll(pokemonName, "", "u");
        console.log("Pokemon Name: " + pokemonName);
        var pokemonId, speech;
        P.getPokemonSpeciesByName(pokemonName.toLowerCase()).then(function(response) {
            console.log(response);
            pokemonId = response.id;
            var evolutionId = response.evolution_chain.url.split('/')[6];

            return P.getEvolutionChainById(evolutionId);
        }).then(function(evolutionResponse) {
            var evolvesTo;
			console.log("response from evolution chain call: " + evolutionResponse);
			/*
			 Once you have the evolution chain, you must determine which pokemon was requested.  For example,
			 if we were asked about Pikachu, the evolution chain starts at Pichu.  This helps us determine how deep
			 we need to go into the evolution
			 */

            var evolutions = [];
            function getEvolutions(input) {
                for(var i = 0; i < input.length; ++i) {
                    evolutions.push(input[i]);
                    if(input[i].evolves_to)
                        getEvolutions(input[i].evolves_to);
                }
            }

            getEvolutions(evolutionResponse.chain.evolves_to);

            for(var i = 0; i < evolutions.length; ++i) {
                if(evolutions[i].species.url.indexOf(pokemonId.toString()) < 0 ) {
                    evolvesTo = evolutions[i];
                    break;
                }
            }

            if(evolvesTo == null) {
                _this.emit(":tell", pokemonName + " does not evolves");
            }

            var newPokemon = evolvesTo.species.name;
            var trigger = evolvesTo.evolution_details[0].trigger.name;
            var hasItem = trigger == "use-item";
            var item = hasItem ? evolvesTo.evolution_details[0].item.name : null;

            speech = "";
            if(hasItem)
                speech += pokemonName + " evolves into " + newPokemon + " when you use a " + item;
            else if(trigger == "level-up")
                speech += pokemonName + " evolves into " + newPokemon + " at level " + evolvesTo.evolution_details[0].min_level;

            return P.getPokemonByName(newPokemon);
        }).then(function(pResp) {
        	console.log("getPokemonByName for evolution");
            var imageObj = {
                smallImageUrl: pResp.sprites.front_default,
                largeImageUrl: pResp.sprites.front_default
            };

            _this.emit(':tellWithCard', speech, "Pokedex", speech, imageObj);
		}).catch(function (error) {
            console.log('There was an error: ', error);
            _this.emit(":tell", "There was an error checking the evolution for the pokemon you requested.");
            return;
        }).catch(function (error) {
            console.log('There was an error: ', error);
            _this.emit(":tell", "There was an error checking the evolution for the pokemon you requested.");
            return;
        }).catch(function(error) {
            console.log('There was an ERROR: ', error);
            _this.emit(":tell", "There was an error checking the evolution for the pokemon you requested.");
            return;
        });
	},
	'GetTypeIntent': function() {
		_this = this;
		var pokemonName = this.event.request.intent.slots.pokemonName;
		if(pokemonName && pokemonName.value)
			pokemonName = pokemonName.value;
		
		console.log("Get Evolution for " + pokemonName);

		getPokemonByName(pokemonName, "type");
	},
	'GetItemIntent': function() {
        _this = this;
        var itemName = this.event.request.intent.slots.itemName;
        if(itemName && itemName.value)
            itemName = itemName.value;

        console.log("Get Info for item " + itemName);

        getItemName(itemName);
	},
    'AMAZON.HelpIntent': function () {
        var speechOutput = this.t("HELP_MESSAGE");
        var reprompt = this.t("HELP_MESSAGE");
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', this.t("STOP_MESSAGE"));
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', this.t("STOP_MESSAGE"));
    }
};

Credits

John Michael Stewart

John Michael Stewart

1 project • 0 followers

Comments