Quickstart: Change model using C#

In this quickstart, add example utterances to a Travel Agent app and train the app. Example utterances are conversational user text mapped to an intent. By providing example utterances for intents, you teach LUIS what kinds of user-supplied text belongs to which intent.

For more information, see the technical documentation for the add example utterance to intent, train, and training status APIs.

For this article, you need a free LUIS account.

Prerequisites

  • Your LUIS authoring key.
  • Import the TravelAgent app from the cognitive-services-language-understanding GitHub repository.
  • The LUIS application ID for the imported TravelAgent app. The application ID is shown in the application dashboard.
  • The utterances.json file containing the example utterances to import.
  • The version ID within the application that receives the utterances. The default ID is "0.1".

Note

The complete solution including an example utterances.json file are available from the cognitive-services-language-understanding GitHub repository.

Example utterances JSON file

The example utterances file, utterances.json, follows a specific format.

The text field contains the text of the example utterance. The intentName field must correspond to the name of an existing intent in the LUIS app. The entityLabels field is required. If you don't want to label any entities, provide an empty array.

If the entityLabels array is not empty, the startCharIndex and endCharIndex need to mark the entity referred to in the entityName field. The index is zero-based, meaning 6 in the top example refers to the "S" of Seattle and not the space before the capital S. If you begin or end the label at a space in the text, the API call to add the utterances fails.

[
  {
    "text": "go to Seattle today",
    "intentName": "BookFlight",
    "entityLabels": [
      {
        "entityName": "Location::LocationTo",
        "startCharIndex": 6,
        "endCharIndex": 12
      }
    ]
  },
  {
    "text": "purple dogs are difficult to work with",
    "intentName": "BookFlight",
    "entityLabels": []
  }
]

Create quickstart code

In Visual Studio, create a new Windows Classic Desktop Console app using the .NET Framework. Name the project ConsoleApp1.

Visual Studio project type

Add the System.Web dependency

The Visual Studio project needs System.Web. In the Solution Explorer, right-click on References and select Add Reference from the Assemblies section.

Add System.web reference

Add other dependencies

The Visual Studio project needs JsonFormatterPlus and CommandLineParser. In the Solution Explorer, right-click on References and select Manage NuGet Packages.... Browse for and add each of the two packages.

Add 3rd party dependencies

Write the C# code

The Program.cs file should be:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Update the dependencies so that are:

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

// 3rd party NuGet packages
using JsonFormatterPlus;
using CommandLine;

Add the LUIS IDs and strings to the Program class.

// NOTE: Replace this example LUIS application ID with the ID of your LUIS application.
static string appID = "YOUR-APP-ID";

// NOTE: Replace this example LUIS application version number with the version number of your LUIS application.
static string appVersion = "0.1";

// NOTE: Replace this example LUIS authoring key with a valid key.
static string authoringKey = "YOUR-AUTHORING-KEY";

// Uses westus region
static string host = "https://westus.api.cognitive.microsoft.com";
static string path = "/luis/api/v2.0/apps/" + appID + "/versions/" + appVersion + "/";

Add class to manage command-line parameters to the Program class.

// parse command line options 
public class Options
{
    [Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
    public bool Verbose { get; set; }

    [Option('t', "train", Required = false, HelpText = "Train model.")]
    public bool Train { get; set; }

    [Option('s', "status", Required = false, HelpText = "Get training status.")]
    public bool Status { get; set; }

    [Option('a', "add", Required = false, HelpText = "Add example utterances to model.")]
    public IEnumerable<string> Add{ get; set; }
}

Add the GET request method to the Program class.

async static Task<HttpResponseMessage> SendGet(string uri)
{
    using (var client = new HttpClient())
    using (var request = new HttpRequestMessage())
    {
        request.Method = HttpMethod.Get;
        request.RequestUri = new Uri(uri);
        request.Headers.Add("Ocp-Apim-Subscription-Key", authoringKey);
        return await client.SendAsync(request);
    }
}

Add the POST request method to the Program class.

async static Task<HttpResponseMessage> SendPost(string uri, string requestBody)
{
    using (var client = new HttpClient())
    using (var request = new HttpRequestMessage())
    {
        request.Method = HttpMethod.Post;
        request.RequestUri = new Uri(uri);

        if (!String.IsNullOrEmpty(requestBody))
        {
            request.Content = new StringContent(requestBody, Encoding.UTF8, "text/json");
        }

        request.Headers.Add("Ocp-Apim-Subscription-Key", authoringKey);
        return await client.SendAsync(request);
    }
}

Add example utterances from file method to the Program class.

async static Task AddUtterances(string input_file)
{
    string uri = host + path + "examples";
    string requestBody = File.ReadAllText(input_file);

    var response = await SendPost(uri, requestBody);
    var result = await response.Content.ReadAsStringAsync();
    Console.WriteLine("Added utterances.");
    Console.WriteLine(JsonFormatter.Format(result));
}

After the changes are applied to the model, train the model. Add method to the Program class.

async static Task Train()
{
    string uri = host + path + "train";

    var response = await SendPost(uri, null);
    var result = await response.Content.ReadAsStringAsync();
    Console.WriteLine("Sent training request.");
    Console.WriteLine(JsonFormatter.Format(result));

}

Training may not complete immediately, check status to verify training is complete. Add method to the Program class.

async static Task Status()
{
    var response = await SendGet(host + path + "train");
    var result = await response.Content.ReadAsStringAsync();
    Console.WriteLine("Requested training status.");
    Console.WriteLine(JsonFormatter.Format(result));
}

To manage command-line arguments, add the main code. Add method to the Program class.

        static void Main(string[] args)
        {

            // Parse commandline options
            // For example: 
            // ConsoleApp1.exe --add utterances.json --train --status
            Parser.Default.ParseArguments<Options>(args)
                               .WithParsed<Options>(o =>
                               {
                                   
                                   // add example utterances
                                   if (o.Add != null && o.Add.GetEnumerator().MoveNext())
                                   {
                                       AddUtterances(o.Add.FirstOrDefault()).Wait();
                                   }

                                   // request training
                                   if (o.Train)
                                   {
                                       Train().Wait();

                                   }

                                   // get training status
                                   if (o.Status)
                                   {
                                       Status().Wait();

                                   }
                               });

        }
    }
}

Copy utterances.json to output directory

In the Solution Explorer, add the utterances.json by right-clicking in the Solution Explorer's project name, then selecting Add, then selecting Existing item. Select the utterances.json file. This adds the file to the project. Then it needs to be added to the output direction. Right-click the utterances.json and select Properties. In the properties windows, mark the Build Action of Content, and the Copy to Output Directory of Copy Always.

Mark the JSON file as content

Build code

Build the code in Visual Studio.

Run code

In the project's /bin/Debug directory, run the application from a command line.

ConsoleApp1.exe --add utterances.json --train --status

This command-line displays the results of calling the add utterances API.

The response array for adding the example utterances indicates success or failure for each example utterance with the hasError property. The following JSON response shows both utterances were added successfully.

    "response": [
        {
            "value": {
                "UtteranceText": "go to seattle today",
                "ExampleId": -5123383
            },
            "hasError": false
        },
        {
            "value": {
                "UtteranceText": "book a flight",
                "ExampleId": -169157
            },
            "hasError": false
        }
    ]

The following JSON shows the result of a successful request to train:

{
    "request": null,
    "response": {
        "statusId": 9,
        "status": "Queued"
    }
}

The following JSON shows the result of a successful request for training status. Each modelID is an intent. Each intent has to be trained on all the utterances to correctly identify utterances to do belong to the intent as well as utterances that do not belong to the intent.

[
    {
        "modelId": "0c694cf9-8c32-44b8-9ea0-3d30a7d901ca",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "10e53836-ade4-494e-9531-3bd6a944c510",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "21e48732-a512-4c33-b5ed-8ea629465269",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "edee15b1-9999-45c2-bbab-591d3a643033",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "aa78e06e-df81-4bb2-b2d9-a2fbb2f81c54",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "e39bb7bd-b417-41a9-a24f-caf4c47fc62c",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "3782eac7-db84-4d66-ba00-0598dffb48ee",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "a941d926-cb0f-47a8-ab7e-deba4378b96f",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "8137f40e-ce6d-40a5-881f-dfd46a05f7e0",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "dc08f95a-58b4-4064-a210-03fe34f75a3c",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    },
    {
        "modelId": "4fabdbed-5697-4562-8c7d-36e174efff2e",
        "details": {
            "statusId": 3,
            "status": "InProgress",
            "exampleCount": 48
        }
    }
]

Clean up resources

When you are done with the quickstart, remove all the files created in this quickstart.

Next steps