Skip to main content

LUIS Action Binding for Console Apps

This article is part 3 for our series on Action Binding in LUIS. You can checkout either of the links below for a refresher, or skip ahead.

Part One – Action Binding for Bots

Part Two – Action Binding for Web Apps

We recently announced that action binding from the LUIS Service has been deprecated and must now be handled on the client side of an application, which allows you to have stricter control over conversational flow instead of relying on LUIS to do the work. In the first article, we discussed how to implement action binding for a bot using the Microsoft Bot Framework SDK. The second article went over the same concepts for Web App implementation for ASP.NET (C#) and NodeJS (using Express). This article reviews similar action binding implementation for console applications.

Using LUIS Action Bindings for a Console Application (C#)

Source Code – C# Action Binding Samples

From Program.cs, the key function is the RunQuery method which accepts one string argument – the user’s query. When the method is invoked, a new LuisService object is created using our App configuration settings. The response from the luis service is stored in a reference of luisResult. The user’s intent is parsed from the result, and and object of LuisActionResolver is created, with a type of assembly for the action GetTimeInPlaceAction, and finally invoking ResolveActionFromLuisIntent – which determines which action from the client to bind the intent.

private static async Task RunQuery(string query)
{
    // Process message
    var luisService = new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LUIS_ModelId"], ConfigurationManager.AppSettings["LUIS_SubscriptionKey"]));
    var luisResult = await luisService.QueryAsync(query, CancellationToken.None);

    // Try to resolve intent to action
    var intentName = default(string);
    var intentEntities = default(IList<EntityRecommendation>);
    var intentAction = new LuisActionResolver(typeof(GetTimeInPlaceAction).Assembly)
        .ResolveActionFromLuisIntent(luisResult, out intentName, out intentEntities);

    if (intentAction != null)
    {
        var executionContextChain = new List<ActionExecutionContext> { new ActionExecutionContext(intentName, intentAction) };
        while (LuisActionResolver.IsContextualAction(intentAction))
        {
            var luisActionDefinition = default(LuisActionBindingAttribute);
            if (!LuisActionResolver.CanStartWithNoContextAction(intentAction, out luisActionDefinition))
            {
                Console.WriteLine($"Cannot start contextual action '{luisActionDefinition.FriendlyName}' without a valid context.");

                return;
            }

            intentAction = LuisActionResolver.BuildContextForContextualAction(intentAction, out intentName);
            if (intentAction != null)
            {
                executionContextChain.Insert(0, new ActionExecutionContext(intentName, intentAction));
            }
        }

        await RunActions(luisService, executionContextChain);
    }
    else
    {
        Console.WriteLine("Could not understand the input.");
    }
}

The RunActions method is responsible for determining wether or not a user’s intent has changed or not. This is used to handle a concept called context switching, which we will discuss at a later time; for now the primary emphasis is that LuisActionResolver method from the Microsoft.Cognitive.LUIS.ActionBinding will provide most of the heavy lifting, and bind the intent to a client defined action.

Using LUIS Action Bindings in a Console Application (Node.js)

Source Code – NodeJS Action Binding Samples

NOTE: After all packages are installed, run the command node app.js to run the application from the samples/console directory

From our sample console application, in app.js we can see that the bulk of the work is performed by the evaluate method in the new framework referenced in LuisActions.

The application prompts the user for an input query which is passed to LuisAction.evaluate –> a Promise which resolves to an actionModel is returned. In our sample, we use a switch case to handle our application’s behavior based on a LuisAction.status, an object which the framework defines in index.js as the following:

var Status = {
    NoActionRecognized: 'NoActionRecognized',
    Fulfilled: 'Fulfilled',
    MissingParameters: 'MissingParameters',
    ContextSwitch: 'ContextSwitch'
};
  • Status.NoActionRecognizedNo intent was detected or no matching action was found. Proceed to display a ‘not understood message’ and wait for another user query.
  • Status.MissingParametersAn action was matched, but there are missing or invalid parameters. Proceed to display the first error in the parameterErrors array and wait for user’s input. Then call the evaluate method again with the current actionModel and the new input. Internally, it will read the currentParameter field to recognize wich is the context’s current parameter.
  • Status.FulfilledAn action was matched, its parameters were validated and the action was fulfilled. The actionModel contains a result field with the action’s result. Proceed to display the result into the console’s output.
  • Status.ContextSwitchThe user’s intent has changed – this field is used to determine context switching, a concept we will discuss at a later time.

The developer may choose to handle the application’s behavior in whichever way they require, our switch case in the sample is just a guideline.

Summary

The first article in this series covered the mechanisms of the Action Binding framework and how to implement Action Binding on the client in a bot. The second article reviewed similar concepts and implementation for an ASP.NET MVC Web app in C# and a NodeJS Web app using Express. This final article in the series talked about using Action Binding for a console application.

The Luis Action Binding framework performs most of the ‘heavy lifting’ for binding intents to actions. Your actions can now be custom defined on the client end, and are agnostic to Bot, Web, or Console applications. In the future, we will re-visit the sample code and discuss context switching.

Happy Making!

Pablo Constantini, Ezequiel Jadib, and Matthew Shim from the Bot Framework Team