/// <summary> /// Creates a SkillResponse based on an Activity and original SkillRequest. /// </summary> /// <param name="mergedActivityResult">The Merged Activity Result to use to create the SkillResponse</param> /// <param name="alexaRequest">Original SkillRequest received from Alexa Skills service. This is used /// to check if the original request was a SessionEndedRequest which should not return a response.</param> /// <returns>SkillResponse</returns> public SkillResponse ActivityToResponse(MergedActivityResult mergedActivityResult, SkillRequest alexaRequest) { var response = new SkillResponse() { Version = "1.0", Response = new ResponseBody() }; var activity = mergedActivityResult?.MergedActivity; if (activity == null || activity.Type != ActivityTypes.Message || alexaRequest.Request is SessionEndedRequest) { response.Response.ShouldEndSession = true; response.Response.OutputSpeech = new PlainTextOutputSpeech { Text = string.Empty }; return(response); } if (!string.IsNullOrEmpty(activity.Speak)) { response.Response.OutputSpeech = new SsmlOutputSpeech(activity.Speak); } else { response.Response.OutputSpeech = new PlainTextOutputSpeech(activity.Text); } ProcessActivityAttachments(activity, response); if (ShouldSetEndSession(response)) { // If end of conversation was flagged use that, othwerwise look at the InputHint. if (mergedActivityResult.EndOfConversationFlagged) { response.Response.ShouldEndSession = true; } else { switch (activity.InputHint) { case InputHints.IgnoringInput: response.Response.ShouldEndSession = true; break; case InputHints.ExpectingInput: response.Response.ShouldEndSession = false; response.Response.Reprompt = new Reprompt(activity.Text); break; default: response.Response.ShouldEndSession = _options.ShouldEndSessionByDefault; break; } } } return(response); }
/// <summary> /// Concatenates activities into a single activity. Uses the last activity in the list as the base activity. /// If any of the activities being process contain an outer SSML speak tag within the value of the Speak property, /// these are removed from the individual activities and a <speak> tag is wrapped around the resulting /// concatenated string. An SSML strong break tag is added between activity content. For more infomation /// about the supported SSML for Alexa see /// https://developer.amazon.com/en-US/docs/alexa/custom-skills/speech-synthesis-markup-language-ssml-reference.html#break /// </summary> /// <param name="activities">The list of one or more outgoing activities</param> /// <returns>MergedActivityResult</returns> public MergedActivityResult MergeActivities(IList <Activity> activities) { if (activities == null || activities.Count == 0) { return(null); } var mergedActivityResult = new MergedActivityResult(); bool hasSpeakField = false; var speakFields = new List <string>(); var textFields = new List <string>(); var attachments = new List <Attachment>(); var endWithPeriod = activities.LastOrDefault(a => !string.IsNullOrEmpty(a.Text))?.Text?.TrimEnd().EndsWith(".") ?? false; foreach (var activity in activities) { if (activity == null) { continue; } switch (activity.Type) { case ActivityTypes.Message: mergedActivityResult.MergedActivity = activity; if (!string.IsNullOrEmpty(activity.Speak)) { hasSpeakField = true; speakFields.Add(StripSpeakTag(activity.Speak)); } else if (!string.IsNullOrEmpty(activity.Text)) { speakFields.Add(NormalizeActivityText(activity.TextFormat, activity.Text, forSsml: true)); } if (!string.IsNullOrEmpty(activity.Text)) { var text = NormalizeActivityText(activity.TextFormat, activity.Text, forSsml: false); if (!string.IsNullOrEmpty(text)) { textFields.Add(text.Trim(new char[] { ' ' })); } } if (activity.Attachments != null && activity.Attachments.Count > 0) { attachments.AddRange(activity.Attachments); } break; case ActivityTypes.EndOfConversation: mergedActivityResult.EndOfConversationFlagged = true; break; } } if (mergedActivityResult.MergedActivity != null) { if (hasSpeakField) { mergedActivityResult.MergedActivity.Speak = $"<speak>{string.Join("<break strength=\"strong\"/>", speakFields)}</speak>"; } mergedActivityResult.MergedActivity.Text = string.Join(" ", textFields); mergedActivityResult.MergedActivity.Attachments = attachments; if (mergedActivityResult.MergedActivity.Text.EndsWith(".") && !endWithPeriod) { mergedActivityResult.MergedActivity.Text = mergedActivityResult.MergedActivity.Text.TrimEnd('.'); } } return(mergedActivityResult); }