Skip to content

Instantly share code, notes, and snippets.

@c0achmcguirk
Last active March 13, 2017 02:44
Show Gist options
  • Save c0achmcguirk/ec748f13dac70c86a52c32061b07dc6a to your computer and use it in GitHub Desktop.
Save c0achmcguirk/ec748f13dac70c86a52c32061b07dc6a to your computer and use it in GitHub Desktop.
Alexa developer portal settings for talk 2017-04-28
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Alexa.NET.Request;
using Alexa.NET.Request.Type;
using Alexa.NET.Response;
using Amazon.Lambda.Core;
using Newtonsoft.Json;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace AlexaCountryInfo
{
public class Function
{
private static HttpClient _httpClient;
public const string INVOCATION_NAME = "Country Info";
public Function()
{
_httpClient = new HttpClient();
}
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
return await HandleIntentRequest(input, context);
}
else if (requestType == typeof(LaunchRequest))
{
return HandleLaunchRequest(input, context);
}
else if (requestType == typeof(SessionEndedRequest))
{
return MakeSkillResponse($"Thanks for using {INVOCATION_NAME}. Goodbye.", true);
}
else
{
return MakeSkillResponse($"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Canada.", true);
}
}
/// <summary>
/// this request comes in when someone asks "Alexa, Open Country Info" or "Alexa, Start Country Info"
/// </summary>
/// <param name="input"></param>
/// <param name="context"></param>
/// <returns></returns>
private SkillResponse HandleLaunchRequest(SkillRequest input, ILambdaContext context)
{
var launchRequest = input.Request as IntentRequest;
context.Logger.LogLine($"Launch request:\n{JsonConvert.SerializeObject(input)}");
var outputSpeech = $"Welcome to {INVOCATION_NAME}. To ask information about a country, say, tell me about Canada. To exit, say, exit.";
return MakeSkillResponse(outputSpeech, false);
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession, string repromptText = "Just say, tell me about Canada to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech {Text = outputSpeech}
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() {OutputSpeech = new PlainTextOutputSpeech() {Text = repromptText}};
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
private async Task<SkillResponse> HandleIntentRequest(SkillRequest input, ILambdaContext context)
{
var intentRequest = input.Request as IntentRequest;
context.Logger.LogLine($"Intent request:\n{JsonConvert.SerializeObject(input)}");
if (intentRequest.Intent.Name == "CountryInfoIntent")
{
context.Logger.LogLine($"Determining country with :\n{JsonConvert.SerializeObject(intentRequest?.Intent?.Slots)}");
var country = intentRequest?.Intent?.Slots["Country"].Value;
if (country == null)
{
context.Logger.LogLine($"The country was not understood.");
return MakeSkillResponse("I'm sorry, but I didn't understand the country you were asking for. Please ask again.", false);
}
context.Logger.LogLine($"Guessed that country is:\n{country}");
var countryInfo = await GetCountryInfo(country, context);
context.Logger.LogLine($"Done awaiting, got this back from method: {JsonConvert.SerializeObject(countryInfo)}");
var outputSpeech = "I couldn't find any information for that country. Please try another.";
if (countryInfo != null)
{
outputSpeech = $"About {countryInfo.name}. The capitol is {countryInfo.capital} " +
$"and the population is {countryInfo.population}.";
}
return MakeSkillResponse(outputSpeech, false);
}
else if (intentRequest.Intent.Name == "AMAZON.StopIntent")
{
var outputSpeech = "Goodbye";
return MakeSkillResponse(outputSpeech, true);
}
else
{
var outputSpeech = "Just say, tell me about Canada or what's the capital of Mexico. To exit, say, exit.";
return MakeSkillResponse(outputSpeech, false);
}
}
private async Task<Country> GetCountryInfo(string countryName, ILambdaContext context)
{
countryName = countryName.ToLowerInvariant();
var countries = new List<Country>();
// search by "North Korea" or "Vatican City" gives us poor results
// instead search by both "North" and "Korea" to get better results
var countryPartNames = countryName.Split(' ');
if (countryPartNames.Length > 1)
{
foreach (var searchPart in countryPartNames)
{
// The United States of America results in too many search requests.
if (searchPart != "the" || searchPart != "of")
{
countries.AddRange(await GetResultsForCountrySearch(searchPart, context));
}
}
}
else
{
countries.AddRange(await GetResultsForCountrySearch(countryName, context));
}
// try to find a match on the name "korea" could return both north korea and south korea
var bestMatch = (from c in countries
where c.name.ToLowerInvariant() == countryName ||
c.demonym.ToLowerInvariant() == $"{countryName}n" // north korea hack (name is not North Korea, by demonym is North Korean)
orderby c.population descending
select c).FirstOrDefault();
var match = bestMatch ?? (from c in countries
where c.name.ToLowerInvariant().IndexOf(countryName) > 0
|| c.demonym.ToLowerInvariant().IndexOf(countryName) > 0
orderby c.population descending
select c).FirstOrDefault();
if (match == null && countries.Count > 0)
{
match = countries.FirstOrDefault();
}
return match;
}
private async Task<List<Country>> GetResultsForCountrySearch(string countryName, ILambdaContext context)
{
List<Country> countries = new List<Country>();
var uri = new Uri($"https://restcountries.eu/rest/v2/name/{countryName}");
context.Logger.LogLine($"Attempting to fetch data from {uri.AbsoluteUri}");
try
{
var response = await _httpClient.GetStringAsync(uri);
context.Logger.LogLine($"Response from URL:\n{response}");
// TODO: (PMO) Handle bad requests
countries = JsonConvert.DeserializeObject<List<Country>>(response);
}
catch (Exception ex)
{
context.Logger.LogLine($"\nException: {ex.Message}");
context.Logger.LogLine($"\nStack Trace: {ex.StackTrace}");
}
return countries;
}
}
public class Country
{
public string name { get; set; }
public string[] topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public string[] callingCodes { get; set; }
public string capital { get; set; }
public string[] altSpellings { get; set; }
public string region { get; set; }
public int population { get; set; }
public float[] latlng { get; set; }
public string demonym { get; set; }
public float area { get; set; }
public float? gini { get; set; }
public string[] timezones { get; set; }
public string[] borders { get; set; }
public string nativeName { get; set; }
public string numericCode { get; set; }
public Currency[] currencies { get; set; }
public Language[] languages { get; set; }
public Translations translations { get; set; }
}
public class Translations
{
public string de { get; set; }
public string es { get; set; }
public string fr { get; set; }
public string ja { get; set; }
public string it { get; set; }
public string br { get; set; }
public string pt { get; set; }
}
public class Currency
{
public string code { get; set; }
public string name { get; set; }
public string symbol { get; set; }
}
public class Language
{
public string iso639_1 { get; set; }
public string iso639_2 { get; set; }
public string name { get; set; }
public string nativeName { get; set; }
}
}
{
"intents": [
{
"intent": "CountryInfoIntent",
"slots": [
{
"name": "Country",
"type": "AMAZON.Country"
}
]
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.StopIntent"
}
]
}
{
"version": "1.0.0-*",
"buildOptions": {
},
"dependencies": {
"Microsoft.NETCore.App": { "version": "1.1.1", "type": "platform" },
"Amazon.Lambda.Core": "1.0.0*",
"Amazon.Lambda.Serialization.Json": "1.0.1",
"Amazon.Lambda.Tools": {
"type": "build",
"version": "1.3.0-preview1"
},
"Alexa.NET": "1.0.0-beta-3"},
"tools": {
"Amazon.Lambda.Tools" : "1.3.0-preview1"
},
"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50"
}
}
}
CountryInfoIntent the capitol of {Country}
CountryInfoIntent get the capitol of {Country}
CountryInfoIntent country info for {Country}
CountryInfoIntent what is the capitol of {Country}
CountryInfoIntent about {Country}
CountryInfoIntent {Country}
CountryInfoIntent tell me the capitol of {Country}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment