Skip to content

Commit

Permalink
Add a simple markdown to plain text converter (#210)
Browse files Browse the repository at this point in the history
* Add Alexa Auth Handler.

* Fix crazyness in merge.

* again.

* Add Alexa Skill Id validation check.

* Tabs to spaces

* Add a couple tests.

* Separate skill id check.

* Set ExpectReplies and add more tests.

* Dont NRE when activities is null.

* Make methods virutal for mocking

* Add check for Request being null so we don't throw NRE on bad requests from Alexa.

* Add simple markdown formatter

Co-authored-by: Gary Pretty <gary@garypretty.co.uk>
  • Loading branch information
NickEricson and garypretty authored Mar 25, 2020
1 parent 3b15b94 commit dc83d1d
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Xml;
Expand All @@ -7,6 +8,7 @@
using Alexa.NET.Request.Type;
using Alexa.NET.Response;
using Bot.Builder.Community.Adapters.Alexa.Core.Attachments;
using Bot.Builder.Community.Adapters.Alexa.Core.Utility;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
Expand Down Expand Up @@ -91,18 +93,13 @@ public SkillResponse ActivityToResponse(Activity activity, SkillRequest alexaReq
return response;
}

if (!SecurityElement.IsValidText(activity.Text))
{
activity.Text = SecurityElement.Escape(activity.Text);
}

if (!string.IsNullOrEmpty(activity.Speak))
{
response.Response.OutputSpeech = new SsmlOutputSpeech(activity.Speak);
}
else
{
response.Response.OutputSpeech = new PlainTextOutputSpeech(activity.Text ?? string.Empty);
response.Response.OutputSpeech = new PlainTextOutputSpeech(NormalizeActivityText(activity.TextFormat, activity.Text));
}

ProcessActivityAttachments(activity, response);
Expand All @@ -116,7 +113,7 @@ public SkillResponse ActivityToResponse(Activity activity, SkillRequest alexaReq
break;
case InputHints.ExpectingInput:
response.Response.ShouldEndSession = false;
response.Response.Reprompt = new Reprompt(activity.Text);
response.Response.Reprompt = new Reprompt(NormalizeActivityText(activity.TextFormat, activity.Text));
break;
default:
response.Response.ShouldEndSession = _options.ShouldEndSessionByDefault;
Expand Down Expand Up @@ -278,6 +275,40 @@ private string StripSpeakTag(string speakText)
{
return speakText;
}
}

private string NormalizeActivityText(string textFormat, string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}

// Default to plain text if it isn't specified.
if (textFormat == null)
{
textFormat = TextFormatTypes.Plain;
}

string plainText;
if (textFormat.Equals(TextFormatTypes.Plain, StringComparison.Ordinal))
{
plainText = text;
}
else if (textFormat.Equals(TextFormatTypes.Markdown, StringComparison.Ordinal))
{
plainText = AlexaMarkdownToPlaintextRenderer.Render(text);
}
else // xml format or other unknown and unsupported format.
{
plainText = string.Empty;
}

if (!SecurityElement.IsValidText(plainText))
{
plainText = SecurityElement.Escape(plainText);
}
return plainText;
}

/// <summary>
Expand Down Expand Up @@ -373,4 +404,4 @@ private ICard CreateAlexaCardFromHeroCard(HeroCard heroCard)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ItemGroup>
<PackageReference Include="Alexa.NET" Version="1.13.0" />
<PackageReference Include="Alexa.NET.CustomerProfile" Version="2.1.1" />
<PackageReference Include="Microsoft.MarkedNet" Version="1.0.13" />
<PackageReference Include="Microsoft.Bot.Builder" Version="4.8.0" />
<PackageReference Include="Microsoft.Bot.Schema" Version="4.8.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using Microsoft.MarkedNet;

namespace Bot.Builder.Community.Adapters.Alexa.Core.Utility
{
/// <summary>
/// Simple Markdown renderer to turn markdown into plain text for Alexa.
/// </summary>
public static class AlexaMarkdownToPlaintextRenderer
{
private static readonly Marked _marked = new Marked(new Options { Renderer = new RemoveMarkupRenderer() });

public static string Render(string source) => _marked.Parse(source);

private class RemoveMarkupRenderer : MarkdownRenderer
{
private const string ListItemMarker = "$$ListItemMarker$$";

public override string Blockquote(string quote) => string.Concat(Environment.NewLine, quote, Environment.NewLine);
public override string Br() => Environment.NewLine;
public override string Code(string code, string lang, bool escaped) => code;
public override string Codespan(string text) => text;
public override string Del(string text) => text;
public override string Em(string text) => text;
public override string Heading(string text, int level, string raw) => string.Concat(Environment.NewLine, text, Environment.NewLine);
public override string Hr() => Environment.NewLine;
public override string Html(string html) => string.Empty;
public override string Image(string href, string title, string text) => title ?? text;
public override string Link(string href, string title, string text) => $"{title ?? text} {href}";
public override string List(string body, bool ordered, int start)
{
if (ordered)
{
for (int marker = start, markerIndex = body.IndexOf(ListItemMarker); markerIndex >= 0; markerIndex = body.IndexOf(ListItemMarker), ++marker)
{
body = body.Substring(0, markerIndex) + Environment.NewLine + marker + " " + body.Substring(markerIndex + ListItemMarker.Length);
}
}
else
{
body = body.Replace(ListItemMarker, Environment.NewLine);
}
return body;
}
public override string ListItem(string text) => $"{ListItemMarker}{text}";
public override string Paragraph(string text) => string.Concat(Environment.NewLine, text, Environment.NewLine);
public override string Strong(string text) => text;
public override string Table(string header, string body) => string.Empty;
public override string TableCell(string content, TableCellFlags flags) => string.Empty;
public override string TableRow(string content) => string.Empty;
}
}
}

0 comments on commit dc83d1d

Please sign in to comment.