Tommy Einarsson
Tommy Einarsson

Reputation: 63

Use Bing Spell Check before Microsoft Translate which is called before call to LUIS

So... I'm trying to use the Bot Framwork with LUIS in Swedish. Using the samples I implemented translation of the input from Swedish to English and then called the LUIS functionality. It worked perfect until we got some very strange intent hits from LUIS. What we found out was that a very small spelling error (in Swedish) caused the translation to create a message that triggered wrong intent. We can solve the problem by checking the score of the received intent, but the message back to the user "I didn't understand that" isn't especially helpful. Running the same message through Bing Spell Check and replace the faulty text with the correct one will produce a correct behaviour (mostly).

What I would like to do is to use the result from the Spell Check to ask the user if the text he/she should be replace with the result from Bing.

Now the problem: I can't find a proper way to implement the dialog to the user. (If possible, I would like to avoid using the PromptDialog.Confirm since it is tricky to localize)

What I have now (that doesn't work) is roughly:

if (activity.Type == ActivityTypes.Message)
{
    correctedText = await sc.BingSpellCheck(activity.Text, spellValues);

    if (spellValues.Count > 0)
    {
      // Ask the client if the correction is ok
      await Conversation.SendAsync(activity, () => new CorrectSpellingDialog());
    }
    Translate.Current.ToEnglish(activity.Text, "en");
    await Conversation.SendAsync(activity, () => new MeBotLuisDialog());
}

What I would like here is to create a CorrectSpellingDialog() that just returns true or false, nad if it is true I will call the ...MeBotLuisDialog().

Sorry for all the text but it's a long problem :-)

Any takers on this?

(The other solution I had was to create an Intent "SpellCheckError" that is trigged from the Bing Spell Check and the in the intent send a message with the corrected message back to the bot (even though I don't know I that is doable in a proper way)) // Tommy

Upvotes: 2

Views: 635

Answers (1)

Grace Feng
Grace Feng

Reputation: 16652

To enable Bing Spell Check API in your bot, you will first get the key from Bing service, then in the Web.config file add the BingSpellCheckApiKey and together enable IsSpellCorrectionEnabled for example:

<appSettings>
  <!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
  <add key="BotId" value="YourBotId" />
  <add key="MicrosoftAppId" value="" />
  <add key="MicrosoftAppPassword" value="" />
  <add key="BingSpellCheckApiKey" value="YourBingSpellApiKey" />
  <add key="IsSpellCorrectionEnabled" value="true" />
</appSettings>

Then you can create a component for your bot to use Bing Spell Api, for more information, you can refer to Quickstart for Bing Spell Check API with C#. Here you can a service in your app for example like this Service.

Then in MessagesController, check the spell first before sending message to dialog. and since your want to show a confirm dialog to user if the text should be replace with the result from Bing, you can send a FormFlow first to let user to have a choice. For example:

Code of MessagesController:

private static readonly bool IsSpellCorrectionEnabled = bool.Parse(WebConfigurationManager.AppSettings["IsSpellCorrectionEnabled"]);
private BingSpellCheckService spellService = new BingSpellCheckService();

/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
   if (activity.Type == ActivityTypes.Message)
    {
        if (IsSpellCorrectionEnabled)
        {
            try
            {
                var text = await this.spellService.GetCorrectedTextAsync(activity.Text);
                if(text != activity.Text)
                {
                    //if spelling is wrong, go to rootdialog
                    await Conversation.SendAsync(activity, () => new Dialogs.RootDialog(activity.Text, text));
                }
                else
                {
                    //if right, direct go to luisdialog

                    await Conversation.SendAsync(activity, () => new Dialogs.MyLuisDialog());

                }
            }
            catch(Exception ex)
            {
                Trace.TraceError(ex.ToString());
            }
        }
        else
        {                    
            await Conversation.SendAsync(activity, () => new Dialogs.MyLuisDialog());
        }

    }
    else
    {
        HandleSystemMessage(activity);
    }
    var response = Request.CreateResponse(HttpStatusCode.OK);
    return response;
}

Code of my RootDialog:

[Serializable]
public class RootDialog : IDialog<object>
{
    private string otext;
    private string ntext;
    public RootDialog(string oldtext, string newtext)
    {
        otext = oldtext;
        ntext = newtext;
    }

    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);
    }

    public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var message = await result;
        var form = new FormDialog<Confirmation>(new Confirmation(otext, ntext),
                Confirmation.BuildForm, FormOptions.PromptInStart, null);
        context.Call(form, this.GetResultAsync);
    }

    private async Task GetResultAsync(IDialogContext context, IAwaitable<Confirmation> result)
    {
        var state = await result;
        await context.Forward(new MyLuisDialog(), null, context.Activity, System.Threading.CancellationToken.None);
    }

}

[Serializable]
public class Confirmation
{

    public string Text { get; set; }
    private static string otext;
    private static string ntext;
    public Confirmation(string oldtext, string newtext)
    {
        otext = oldtext;
        ntext = newtext;
    }
    public static IForm<Confirmation> BuildForm()
    {
        return new FormBuilder<Confirmation>()
            .Field(new FieldReflector<Confirmation>(nameof(Text))
            .SetType(null)
            .SetDefine(async(state, field) =>
            {
                field
                .AddDescription(otext, otext)
                .AddTerms(otext, otext)
                .AddDescription(ntext,ntext)
                .AddTerms(ntext, ntext);

                return true;
            }))
            .Build();
    }
}

Upvotes: 2

Related Questions