chef 3808 Posted November 18, 2019 Posted November 18, 2019 I was just messing around with Alexa's personalized responses. Yeah she can figure out who is speaking to her. More information here: https://developer.amazon.com/docs/custom-skills/add-personalized-greetings-or-prompts.html Here is my Alexa response for Emby custom Skill, notice the Person object: using System; using System.Collections.Generic; namespace AlexaController.Alexa { public class AlexaRequest { public Session session { get; set; } public Request request { get; set; } public Context context { get; set; } public string version { get; set; } } public class Application { public string applicationId { get; set; } } public class Attributes { public string key { get; set; } } public class Permissions { public string consentToken { get; set; } } public class User { public string userId { get; set; } public string accessToken { get; set; } public Permissions permissions { get; set; } } public class Session { public bool @[member="new"] { get; set; } public string sessionId { get; set; } public Application application { get; set; } public Attributes attributes { get; set; } public User user { get; set; } } public class AudioPlayer { } public class SupportedInterfaces { public AudioPlayer AudioPlayer { get; set; } } public class Device { public string deviceId { get; set; } public SupportedInterfaces supportedInterfaces { get; set; } } public class Application2 { public string applicationId { get; set; } } public class Permissions2 { public string consentToken { get; set; } } public class User2 { public string userId { get; set; } public string accessToken { get; set; } public Permissions2 permissions { get; set; } } public class Person //right here { public string personId { get; set; } public string accessToken { get; set; } } public class System { public Device device { get; set; } public Application2 application { get; set; } public User2 user { get; set; } public Person person { get; set; } public string apiEndpoint { get; set; } public string apiAccessToken { get; set; } } public class AudioPlayer2 { public string playerActivity { get; set; } public string token { get; set; } public int offsetInMilliseconds { get; set; } } public class Context { public System System { get; set; } public AudioPlayer2 AudioPlayer { get; set; } } public class Intent { public string name { get; set; } public string confirmationStatus { get; set; } public Slots slots { get; set; } } public class Request { public string type { get; set; } public string requestId { get; set; } public DateTime timestamp { get; set; } public string locale { get; set; } public Intent intent { get; set; } } public class Slots { //public slotData MediaName { get; set; } public slotData SeriesName { get; set; } public slotData Username { get; set; } public slotData MusicGroup { get; set; } public slotData MusicAlbum { get; set; } public slotData MovieNames { get; set; } public slotData PlayToDevice { get; set; } public slotData DeviceNames { get; set; } public slotData DeviceRooms { get; set; } } public class slotData { public string name { get; set; } public string value { get; set; } } public class Error { public string type { get; set; } public string message { get; set; } } } Now in the Emby endpoint: //Most important parts of this class is the 'person' object, and the Id // Then using conditions to return '<alexa:name type="first personId="{personId}" /> The first name of the recognized User. using System; using System.Collections.Generic; using System.Linq; using System.Threading; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Services; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Entities; using System.IO; using AlexaController.Alexa; using MediaBrowser.Model.Serialization; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; using System.Threading.Tasks; using System.Text; using System.Net; using System.Text.RegularExpressions; using Person = AlexaController.Alexa.Person; namespace AlexaController.API { [Route("/Alexa", "POST", Summary = "Alexa End Point")] public class AlexaRequest: IRequiresRequestStream { public Stream RequestStream { get; set; } } [Route("/Alexa", "GET", Summary = "Alexa End Point")] public class Test : IReturnVoid { public Stream test { get; set; } } public class AlexaApi : IService { private readonly ILogger logger; //private ITVSeriesManager TvSeriesManager { get; set; } private IUserManager UserManager { get; } //private IMediaSourceManager MediaSourceManager { get; set; } private ILibraryManager LibraryManager { get; } //private IHttpClient HttpClient { get; set; } private ISessionManager SessionManager { get; } private IJsonSerializer JsonSerializer { get; } private IUserDataManager UserDataManager { get; } // The media item we want to play private static BaseItem RequestedMediaItem; //Was a playback Request private static bool IsPlaybackRequest; private static bool ResumeMedia; // ReSharper disable once TooManyDependencies public AlexaApi(ILibraryManager libraryManager, ISessionManager sessionManager, ILogManager logManager, IUserManager userManager, IJsonSerializer json, IUserDataManager userData) { logger = logManager.GetLogger(GetType().Name); //TvSeriesManager = tvSeriesManager; //MediaSourceManager = mediaSourceManager; SessionManager = sessionManager; LibraryManager = libraryManager; UserManager = userManager; //HttpClient = httpClient; JsonSerializer = json; UserDataManager = userData; } // ReSharper disable once MethodNameNotMeaningful public string Get(Test test) { return "Hello World Yes you can all see this"; } public object Post(AlexaRequest request) { //parse json request var alexaRequest = JsonSerializer.DeserializeFromStream<Alexa.AlexaRequest>(request.RequestStream); // ReSharper disable once TooManyChainedReferences var person = alexaRequest.context.System.person ?? null; //<--I am a person object that might not return anything for privacy reasons logger.Debug("ALEXA HERE"); var r = alexaRequest.request; switch (r.type) { case "IntentRequest": PostDirectiveResponseAsync(alexaRequest); //<--I can post a directive response switch (r.intent.name) { case "AMAZON.NavigateHomeIntent": BrowseHome("family room"); return BuildAlexaResponse("OK. Here is the Home Screen"); case "ShowCollectionLibrary": { RequestedMediaItem = LibraryManager.GetItemById(GetLibraryId("Collections")); BrowseItemAsync("family room", LibraryManager.GetItemById(GetLibraryId("Collections"))); return BuildAlexaResponse("Here is the Collections Library."); } case "ShowTVLibrary": { RequestedMediaItem = LibraryManager.GetItemById(GetLibraryId("TV Shows")); BrowseItemAsync("family room", LibraryManager.GetItemById(GetLibraryId("TV Shows"))); return BuildAlexaResponse("Here is the TV Series Library."); } case "ShowMovieLibrary": { RequestedMediaItem = LibraryManager.GetItemById(GetLibraryId("Movies")); BrowseItemAsync("family room", LibraryManager.GetItemById(GetLibraryId("Movies"))); return BuildAlexaResponse("Here is the Movie Library."); } case "DeviceChoice": { var str = r.intent.slots.DeviceNames.value ?? r.intent.slots.DeviceRooms.value; if (r.intent.slots.DeviceNames == null) { return " Sorry no device by that name was found"; } //PlayMediaItemAsync(str, RequestedMediaItem.MediaType); return BuildAlexaResponse("OK"); } case "NewMovies": { return BuildAlexaResponse(GetNewMovies(), true.ToString(), person); } case "NewTV": { return BuildAlexaResponse(GetNewTvNames()); } case "AMAZON.PauseIntent": { return RemoteChangeState(PlaystateCommand.Pause, "family room"); } case "AMAZON.ResumeIntent": { return RemoteChangeState(PlaystateCommand.Unpause, "family room"); } case "remoteSkip": { return RemoteChangeState(PlaystateCommand.NextTrack, "family room"); } case "remotePrevious": { return RemoteChangeState(PlaystateCommand.PreviousTrack, "family room"); } case "remoteStop": { return RemoteChangeState(PlaystateCommand.Stop, "family room"); } case "AMAZON.NoIntent": { if (!IsPlaybackRequest) return BuildAlexaResponse("I'm not sure what you are saying \"no\" to. Sorry"); ResumeMedia = false; IsPlaybackRequest = false; PlayMediaItemAsync("family room", RequestedMediaItem); return BuildAlexaResponse(AlexaOptions.HumanizeAlexa() + " Now playing the " + RequestedMediaItem.ProductionYear + " film <break strength='weak' />" + RequestedMediaItem.Name.Replace(":", string.Empty) .Replace(",", string.Empty)); } case "AMAZON.YesIntent": { if (!IsPlaybackRequest) return BuildAlexaResponse("I'm not sure I understand what you are agreeing to. Sorry"); ResumeMedia = true; IsPlaybackRequest = false; PlayMediaItemAsync("family room", RequestedMediaItem); return BuildAlexaResponse(AlexaOptions.HumanizeAlexa() + " Now playing the " + RequestedMediaItem.ProductionYear + " " + RequestedMediaItem.MediaType + " <break strength='weak' />" + RequestedMediaItem.Name.Replace(":", string.Empty) .Replace(",", string.Empty)); } case "AMAZON.CancelIntent": case "AMAZON.StopIntent": return BuildAlexaResponse(AlexaOptions.HumanizeAlexa() + "Canceling."); case "PlayMovie": { try { RequestedMediaItem = NarrowResults(r.intent.slots.MovieNames.value, new[] { "Movie" }); IsPlaybackRequest = true; if (RequestedMediaItem.SupportsPositionTicksResume) { return BuildAlexaResponse(RequestedMediaItem.Name + " is bookmarked. " + AlexaOptions.AlexaInsertStrengthBreak(AlexaOptions.StrengthBreaks.weak) + "Would you like to play the Movie from where you left off?", "false", person); } else { return BuildAlexaResponse(" in what room would you like to watch " + RequestedMediaItem.Name.Replace(":", string.Empty), "false"); } } catch (Exception) { return BuildAlexaResponse("Sorry. I couldn't find " + r.intent.slots.MovieNames.value + " in the library"); } } case "BrowseCommand": { //The type of media we want to search for - We'll expect a Movie name to start var type = "Movie"; //Amazon will return a Movie slot if it is a movie name var searchName = r.intent.slots.MovieNames.value; //If no Movie Name it must be a series Name if(r.intent.slots.MovieNames.value == null) { searchName = r.intent.slots.SeriesName.value; type = "Series"; } try { var result = NarrowResults(searchName, new[] { type }); if (result != null) { RequestedMediaItem = result; IsPlaybackRequest = false; BrowseItemAsync("family room", result); string overview = ""; string rating = ""; float? criticRating; overview = RequestedMediaItem.Overview; rating = RequestedMediaItem.OfficialRating; criticRating = RequestedMediaItem.CriticRating; return BuildAlexaResponse(" Here is the details for " + RequestedMediaItem.Name.Replace(":", string.Empty) + ". " + AlexaOptions.AlexaInsertStrengthBreak(AlexaOptions.StrengthBreaks.weak) + "Rated " + rating + "." + AlexaOptions.AlexaInsertStrengthBreak(AlexaOptions.StrengthBreaks.strong) + CalculateCriticRatings(criticRating), true.ToString(), person); } } catch (Exception) { return BuildAlexaResponse("Sorry. I couldn't find " + searchName + " in the library"); } return BuildAlexaResponse("Sorry. I couldn't find " + searchName + " in the library"); } default: return BuildAlexaResponse("no intent found"); } case "SessionEndedRequest": //Session End Request //No response message is allowed return null; case "LaunchRequest": return BuildAlexaResponse("Welcome"); //Not an Intent default: return BuildAlexaResponse("Unknown"); } } private string GetLibraryId(string type) { var results = LibraryManager.GetVirtualFolders(); foreach(var item in results) { if(item.Name == type) { return item.ItemId; } } return string.Empty; } private string GetNewMovies() { const string user = "Admin"; var results = LibraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { "Movie" }, IsPlayed = false, User = UserManager.GetUserByName(user.AsSpan()) }); string alexaSpeechString = string.Empty; var listOfNewMovies = new List<BaseItem>(); results.ToList().ForEach(item => { var itemInfo = LibraryManager.GetItemById(item); if (itemInfo.DateCreated >= DateTime.Now.AddDays(-25)) { listOfNewMovies.Add(itemInfo); } }); //If the movie is the last name in the list, let Alexa say "and also". She sounds more human. int movieCount = 0; foreach (var movie in listOfNewMovies) { if (movieCount == listOfNewMovies.Count - 1) { alexaSpeechString += " and also <break strength='weak' /> "; } alexaSpeechString += movie.Name.Replace(":", string.Empty).Replace("&", "and") + "<break strength='weak' />. "; //She doesn't like '&' and ':' in strings movieCount += 1; } return "Here are <say-as interpret-as='cardinal'>" + movieCount + "</say-as> of the newest movies available in the library <break strength='weak' />" + alexaSpeechString; } private string GetNewTvNames() { var results = LibraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { "Episode" } }); string str1 = string.Empty; string complete; int tvCount = 0; var listOfNewTv = new List<string>(); results.ToList().ForEach(item => { var itemInfo = LibraryManager.GetItemById(item); if (itemInfo.DateCreated >= DateTime.Now.AddDays(-20)) { listOfNewTv.Add(itemInfo.Parent.Parent.Name); //That would be the Series Name } }); if (listOfNewTv.Count == 0) { complete = "There are no new unwatched episodes"; } else { var distinctTvSeries = listOfNewTv.Distinct().ToList(); foreach (var name in distinctTvSeries) { //If the tv is the last name in the list, let Alexa say "and also". She sounds more human. if (tvCount == distinctTvSeries.Count - 1) { str1 += " and also <break strength='weak' />"; } str1 += name.Replace(":", string.Empty).Replace("&", "and") + "<break strength='weak' />"; tvCount += 1; } complete = "There are <say-as interpret-as='cardinal'>" + listOfNewTv.Distinct().ToList().Count + "</say-as> new episodes available in the library <break strength='weak' />" + "including episodes from <break strength='weak' />" + str1; } return complete; } private string GetDeviceIdFromName(string deviceName) { if (deviceName.ToLower().Contains("family room") || deviceName.ToLower().Contains("front room")) { deviceName = "Family Room Fire TV Stick"; } else if (deviceName.ToLower().Contains("back room") || deviceName.ToLower().Contains("kids")) { deviceName = "Kids TV"; } else if (deviceName.ToLower().Contains("bedroom") || deviceName.ToLower().Contains("upstairs")) { deviceName = "Chromecast0862"; } else if (deviceName.ToLower().Contains("theater") || deviceName.ToLower().Contains("movie theater")) { deviceName = "CastP6"; } foreach (var session in SessionManager.Sessions) { //If it is a browse request then we'll have have to use an emby app with a UI display to show the details //example: Emby Theater if (session.Client.ToLower().Contains("androidtv") && deviceName == "Family Room Fire TV Stick") { return session.DeviceId; } if (session.DeviceName.ToLower().Contains(deviceName.ToLower())) { return session.DeviceId; } if (session.Client.ToLower().Contains(deviceName.ToLower())) { return session.DeviceId; } } return string.Empty; } private SessionInfo GetSession(string deviceId) { //logger.Info("Looking for sessions for device " + deviceId); var r = SessionManager.Sessions.Where(i => i.DeviceId == deviceId); // "db464421188f5622f73acab7252660facbd63078"); var sessionInfos = r.ToList(); logger.Info("Found {0} sessions for device {1}", sessionInfos.Count().ToString(), deviceId); return sessionInfos.FirstOrDefault(); } private void BrowseHome(string device) { var d = GetDeviceIdFromName(device); var user = "Admin"; var s = GetSession(d); //DO NOT AWAIT THIS! ALEXA HATES YOU FOR IT SessionManager.SendGeneralCommand(null, s.Id, new GeneralCommand() { Name = "GoHome", ControllingUserId = UserManager.GetUserByName(user.AsSpan()).Id.ToString(), }, CancellationToken.None); } private void BrowseItemAsync(string device, BaseItem request) { try { var d = GetDeviceIdFromName(device); var s = GetSession(d); ////DO NOT AWAIT THIS! ALEXA HATES YOU FOR IT //SessionManager.SendGeneralCommand(null, s.Id, new GeneralCommand() //{ // Name = "GoHome", // ControllingUserId = UserManager.GetUserByName("Admin").Id.ToString() //}, // CancellationToken.None); Task.Delay(1500).Wait(); SessionManager.SendBrowseCommand(null, s.Id, new BrowseRequest() { ItemId = request.Id.ToString(), ItemName = request.Name, ItemType = request.MediaType }, CancellationToken.None); } catch { BuildAlexaResponse("I'm sorry. I'm unable to show details for " + RequestedMediaItem.Name.Replace(":", string.Empty) + " in the family room because the theater is not currently running."); } } private async void PlayMediaItemAsync(string device, BaseItem request) { var s = GetSession(GetDeviceIdFromName(device)); if (s == null) return;// "I'm sorry the " + device + " device is currently unavailable."; long startTicks = 0; var user = "Admin"; if (ResumeMedia) { startTicks = UserDataManager.GetUserData(UserManager.GetUserByName(user.AsSpan()).Id.ToString(), RequestedMediaItem).PlaybackPositionTicks; } SessionManager.SendPlayCommand(null, s.Id, new PlayRequest { StartPositionTicks = startTicks, PlayCommand = PlayCommand.PlayNow, ItemIds = new[] { request.InternalId }, ControllingUserId = UserManager.GetUserByName(user.AsSpan()).Id.ToString() }, CancellationToken.None); } private async Task<string> RemoteChangeState(PlaystateCommand psCmd, string device) { var d = GetDeviceIdFromName(device); var s = GetSession(d); var user = "Admin"; if (s == null) { return "device is not setup or is unavailable"; } var command = new PlaystateRequest() { Command = psCmd, ControllingUserId = UserManager.GetUserByName(user.AsSpan()).Id.ToString() }; try { //DO NOT AWAIT THIS! ALEXA HATES YOU FOR IT SessionManager.SendPlaystateCommand(null, s.Id, command, new CancellationToken(false)); } catch { } return BuildAlexaResponse("ok"); } public string GetSeriesId(string seriesName) { var r = LibraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { "Series" }, Name = seriesName }); return r.Any() ? r.FirstOrDefault().ToString() : ""; } //Actual Response private string BuildAlexaResponse(string text, string sessionEnd = "true", Person person = null) { var jsonString = "{\"version\": \"1.0\",\"response\": {\"outputSpeech\": {\"type\": \"SSML\",\"ssml\": "; jsonString += "\"<speak>"; jsonString += AlexaOptions.HumanizeAlexa(); // ReSharper disable ComplexConditionExpression jsonString += person != null ? " <alexa:name type='first' personId='" + person.personId + "'/> " : " "; jsonString += AlexaOptions.AlexaInsertStrengthBreak(AlexaOptions.StrengthBreaks.strong); jsonString += " "; jsonString += text; jsonString += "</speak>\" }, \"shouldEndSession\": "; jsonString += sessionEnd + "},\"sessionAttributes\": { } }"; logger.Log(LogSeverity.Debug, jsonString); return jsonString; } private void PostDirectiveResponseAsync(Alexa.AlexaRequest alexaRequest) { //const string uri = "https://api.amazonalexa.com/v1/directives"; var res = new DirectiveResponse { header = new Header { requestId = alexaRequest.request.requestId }, directive = new Directive { type = "VoicePlayer.Speak", speech = "<speak>" + AlexaOptions.HumanizeAlexa() + "Accessing Media Server." + AlexaOptions.AlexaInsertStrengthBreak(AlexaOptions.StrengthBreaks.weak) + " One moment please." + "<audio src='https://s3.amazonaws.com/ask-soundlibrary/scifi/amzn_sfx_scifi_radar_high_ping_01.mp3'/></speak>" } }; string json = JsonSerializer.SerializeToString(res); //Encode the JSON string into a byte array byte[] data = Encoding.ASCII.GetBytes(json); //Where we will send the info and how: POST var request = (HttpWebRequest)WebRequest.Create("https://api.amazonalexa.com/v1/directives"); request.Method = "POST"; request.ContentType = "application/json"; request.Headers["Authorization"] = "Bearer " + alexaRequest.context.System.apiAccessToken; request.ContentLength = data.Length; //Write the data to amazon using (var stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); } } private static string CalculateCriticRatings(float? percent) { if (percent <= 25.0F) { return "This film didn't get great reviews."; } else if (percent <= 50.0F) { return "This film has got some fair reviews."; } else if (percent <= 75.0F) { return "This film has got some decent reviews."; } else if (percent <= 90.0F) { return "This film has got some good reviews."; } else if (percent <= 100.0F) { return "This film has got great reviews."; } return ""; } //Narrow multiple Search Results From Emby private BaseItem NarrowResults(string searchName, string[] type) { var result = LibraryManager.GetItemIds(new InternalItemsQuery { Name = searchName, IncludeItemTypes = type, }); if (!result.Any()) { var queryResult = LibraryManager.QueryItems(new InternalItemsQuery() { IncludeItemTypes = type, NameStartsWith = ReturnStartWithString(searchName) }); return queryResult.Items.FirstOrDefault(r => RemoveSpecialCharacters(r.Name).Contains(RemoveSpecialCharacters(searchName))); } if (!result.Any()) { var queryResult = LibraryManager.QueryItems(new InternalItemsQuery() { IncludeItemTypes = type, SearchTerm = ReturnStartWithString(searchName) }); return queryResult.Items.FirstOrDefault(r => RemoveSpecialCharacters(r.Name).Contains(RemoveSpecialCharacters(searchName))); } return LibraryManager.GetItemById(result.FirstOrDefault()); } private static string ReturnStartWithString(string name) { try { name = name[0].ToString(); } catch { } return name; } private static string RemoveSpecialCharacters(string sample) { var result = sample.Replace("-", string.Empty) .Replace("&", string.Empty) .Replace(":", string.Empty) .Replace(Regex.Match(sample, "/(([0-9][0-9][0-9][0-9])/)").Groups[0].ToString(), string.Empty) .Replace("1", "one"); return result.Replace(" ", string.Empty).ToLower(); } } } Now use the home brew Alexa Options class to give her random response from a dictionary: using System.Collections.Generic; namespace AlexaController.Alexa { class AlexaOptions { public static Dictionary<int, string> humanSpeechLibrarySpoiler = new Dictionary<int, string> { { 1, AlexaExpressiveInterjection("Spoiler Alert. ") }, { 2, AlexaOptions.AlexaExpressiveInterjection("Watch out.") + AlexaOptions.AlexaInsertStrengthBreak(StrengthBreaks.weak) + AlexaOptions.AlexaExpressiveInterjection("Spoilers!!") }, { 3, "Hope this doesn't spoil it for you. " + AlexaInsertStrengthBreak(StrengthBreaks.weak) }, { 4, "I don't want to spoil it for you. " + AlexaInsertStrengthBreak(StrengthBreaks.weak) }, { 5, AlexaSayWithEffect(Effect.whispered, "I don't want to spoil it for you.") + AlexaInsertStrengthBreak(StrengthBreaks.weak) + " But, here is the overview." + AlexaInsertStrengthBreak(StrengthBreaks.weak) } }; // ReSharper disable once ComplexConditionExpression public static Dictionary<int, string> humanSpeechLibraryAgree = new Dictionary<int, string> { { 1, AlexaEmphasis(" alright ", Emphasis.reduced) }, { 2, AlexaEmphasis(" Very well ", Emphasis.reduced) }, { 3, AlexaEmphasis(" sounds good ", Emphasis.reduced) }, { 4, AlexaExpressiveInterjection(" sure ") + AlexaInsertStrengthBreak(StrengthBreaks.weak) }, { 5, AlexaExpressiveInterjection(" yeah ") + AlexaInsertStrengthBreak(StrengthBreaks.weak) }, { 6, AlexaExpressiveInterjection(" OK ") + AlexaInsertStrengthBreak(StrengthBreaks.weak) }, { 7, AlexaExpressiveInterjection(" you bet ") + AlexaInsertStrengthBreak(StrengthBreaks.weak) } }; public static string HumanizeAlexaSpoiler() { int rInt = Plugin.r.Next(1, 5); return humanSpeechLibrarySpoiler[rInt]; } private static int tempHumanSpeechChoices = 1; public static string HumanizeAlexa() { int rInt = Plugin.r.Next(1, 7); while (tempHumanSpeechChoices == rInt) { rInt = Plugin.r.Next(1, 7); } tempHumanSpeechChoices = rInt; return humanSpeechLibraryAgree[rInt]; } public enum StrengthBreaks { weak = 0, medium = 1, strong = 2 } public enum Emphasis { /// <summary> /// Decrease the volume and speed up the speaking rate. The speech is softer and faster. /// </summary> reduced = 0, /// <summary> /// Increase the volume and slow down the speaking rate so the speech is louder and slower. /// </summary> strong = 1, /// <summary> /// Increase the volume and slow down the speaking rate, but not as much as when set to strong. This is used as a default if level is not provided. /// </summary> moderate = 2 } public enum Rate { slow = 0, medium = 1, fast = 2 } public enum Effect { whispered = 0 } public static string AlexaSayWithEffect(Effect effect, string text) { return "<amazon:effect name='" + effect + "'>" + text + "</amazon:effect>"; } public static string AlexaSayAsCardinal(string text) { return "<say-as interpret-as='cardinal'>" + text + "</say-as>"; } public static string AlexaSpellOut(string text) { return "<say-as interpret-as='spell-out'>" + text + "</say-as>."; } public static string AlexaInsertTimedBreak(string intDurationSeconds) { return "<break time='" + intDurationSeconds + "s'/>"; } public static string AlexaInsertStrengthBreak(StrengthBreaks strength) { return "<break strength='" + strength + "'/>"; } public static string AlexaEmphasis(string text, Emphasis emphasis) { return "<emphasis level='" + emphasis + "'>" + text + "</emphasis>"; } public static string AlexaSpeechRate(Rate rate, string text) { return ("<prosody rate='" + rate + "'>" + rate + "</prosody>"); } public static string AlexaExpressiveInterjection(string text) { return "<say-as interpret-as='interjection'>" + text + "</say-as>"; } } } Now she reply's in a very human and personal way. It's super cool guys! 2
BillOatman 575 Posted May 22, 2020 Posted May 22, 2020 But, not allowing your son to watch Deadpool is child abuse! Deadpool 2 not so much 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now