Use custom functions in language generation

APPLIES TO: SDK v4

Developers can use both prebuilt functions supported by adaptive expressions and custom functions in language generation (LG) templates. This article shows you how to add a custom function in your bot to adaptive expressions and use the function in an LG template.

Prerequisites

About the sample

This LG custom functions sample is an example of how to add a simple custom function to adaptive expressions and then use that expression in an LG template. The bot asks the user for a number, and if the input is valid returns the square root. The function that computes the square root, contoso.sqrt, is defined in the bot logic, and is used in the LG template that generates bot responses.

This article uses a bottom up approach to adding and using custom functions in LG templates. You will learn about how to:

Packages

To use adaptive expressions and LG, install the Microsoft.Bot.Builder.LanguageGeneration and AdaptiveExpressions packages. The sample already has the packaged installed. Then add the following snippet to your main bot file.

Bots/CustomFunctionBot.cs

using Microsoft.Bot.Builder.LanguageGeneration;
using AdaptiveExpressions;

Add a custom function to adaptive expressions

To use custom functions in your bot, you need to add them to adaptive expressions. This section shows how to add a custom function named contoso.sqrt to adaptive expressions.

Start by adding a string constant with the name of your custom function to your bot constructor. The name of your function should be short but recognizable. In this sample, the custom function is named contoso.sqrt:

Bots/CustomFunctionBot.cs

const string mySqrtFnName = "contoso.sqrt";

Important

Prefix your functions to avoid namespace collisions.

In the function name contoso is the prefix and sqrt is short hand for square root, which the function returns.

Now you can define the logic for your function in your bot constructor and add it to adaptive expressions using the Expression.Functions.Add() function. Adding your custom function to adaptive expression makes it possible to use your function across LG templates, just as you can with any of the prebuilt functions.

The snippet below shows how to add a function, defined as mySqrtFnName, to adaptive expressions. This function returns the square root of a single argument, args, if valid, and null if not not:

// Add custom sqrt function
Expression.Functions.Add(mySqrtFnName, (args) =>
{
    object retValue = null;
    if (args[0] != null)
    {
        double dblValue;
        if (double.TryParse(args[0], out dblValue))
        {
            retValue = Math.Sqrt(dblValue);
        }
    }
    return retValue;
});

Use your custom function in an LG template

After adding your custom function to adaptive expressions you can use it in LG templates. This section describes how to set up the bot's response depending on whether the user input was valid.

There are two template definitions in main.lg: the simple response template sqrtReadBack and the conditional response template sqrtTemplate:

Resources/main.lg

# sqrtReadBack
- You said '${text}'. ${sqrtTemplate()}.

This template generates a response that contains the user input, ${text} and the result of the second conditional if-else template sqrtTemplate:

# sqrtTemplate
- IF : ${contoso.sqrt(text) != null}
    - It's square root is ${coalesce(contoso.sqrt(text), 'NaN')}
- ELSE : 
    - Sqrt not possible.

In this template, the result of contoso.sqrt(text) is used to determine the response:

  • If the result is not null, the line under the IF block is used in sqrtReadBack. Note that this line uses an inline expression, ${coalesce(contoso.sqrt(text), 'NaN)}. The prebuilt function coalesce returns the result of contoso.sqrt(text) if it is not null and NaN if it is null.
  • If the result is null, the line under the ELSE block is used in sqrtReadBack.

Load and use your LG template in your bot

Now that you've created your bot's response template sqrtReadBack in main.lg, you can use the template in your bot's logic.

To start, create a private Templates object called _templates.

Bots/CustomFunctionBot.cs

protected Templates _templates;

The _templates object is used to reference templates in your .lg files.

Then combine the path for cross-platform support. Make sure to include main.lg by adding the following:

var lgFilePath = Path.Join(Directory.GetCurrentDirectory(), "Resources", "main.lg");

Now you can parse the files in lgFilePath and load your LG templates, as shown below. By default this uses Expression.Function, which includes your custom function.

_templates = Templates.ParseFile(lgFilePath);

Your templates are now loaded and you can reference them by name in your bot. In this sample, the result of evaluating sqrtReadBack is used as the replyText sent to the user.

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var replyText = _templates.Evaluate("sqrtReadBack", turnContext.Activity);
    await turnContext.SendActivityAsync(ActivityFactory.FromObject(replyText), cancellationToken);
}

You're now ready to test your bot.

Test the bot

Download and install the latest version of the Bot Framework Emulator.

  1. Run the sample locally on your machine. If you need instructions, refer to the README file for the C# or JavaScript sample.
  2. In the Emulator, type anything. You will notice that the Emulator will return the square root of numbers entered and NaN for all other input.

test the bot

Additional Information