Quickstart: Add utterances to app using Python

In this quickstart, write a program to add an utterance to an intent using the Authoring APIs in Python.

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

For this article, you need a free LUIS account in order to author your LUIS application.

Prerequisites

  • Python 3.6 or later.
  • [Recommended] Visual Studio Code for IntelliSense and debugging.
  • Your LUIS authoring key. You can find this key under Account Settings in the LUIS website.
  • Your existing LUIS application ID. The application ID is shown in the application dashboard. The LUIS application with the intents and entities used in the utterances.json file must exist prior to running the code in add-utterances.js. The code in this article does not create the intents and entities. It only adds the utterances for existing intents and entities.
  • The version ID within the application that receives the utterances. The default ID is "0.1"
  • Create a new file named add-utterances-3-6.py project in VSCode.

Note

The complete add-utterances-3-6.py file is available from the LUIS-Samples Github repository.

Write the Python code

  1. Copy the following code snippets:

    ########### Python 3.6 #############
    # -*- coding: utf-8 -*-
    
    import http.client, sys, os.path, json
    
    # Authoring key, available in luis.ai under Account Settings
    LUIS_authoringKey  = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    # ID of your LUIS app to which you want to add an utterance
    LUIS_APP_ID      = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    
    # The version number of your LUIS app
    LUIS_APP_VERSION = "0.1"
    
    # Update the host if your LUIS subscription is not in the West US region
    LUIS_HOST       = "westus.api.cognitive.microsoft.com"
    
    # uploadFile is the file containing JSON for utterance(s) to add to the LUIS app.
    # The contents of the file must be in this format described at: https://aka.ms/add-utterance-json-format
    UTTERANCE_FILE   = "./utterances.json"
    RESULTS_FILE     = "./utterances.results.json"
    
    # LUIS client class for adding and training utterances
    class LUISClient:
        
        # endpoint method names
        TRAIN    = "train"
        EXAMPLES = "examples"
    
        # HTTP verbs
        GET  = "GET"
        POST = "POST"
    
        # Encoding
        UTF8 = "UTF8"
    
        # path template for LUIS endpoint URIs
        PATH     = "/luis/api/v2.0/apps/{app_id}/versions/{app_version}/"
    
        # default HTTP status information for when we haven't yet done a request
        http_status = 200
        reason = ""
        result = ""
    
        def __init__(self, host, app_id, app_version, key):
            if len(key) != 32:
                raise ValueError("LUIS subscription key not specified in " +
                                 os.path.basename(__file__))
            if len(app_id) != 36:
                raise ValueError("LUIS application ID not specified in " +
                                 os.path.basename(__file__))
            self.key = key
            self.host = host
            self.path = self.PATH.format(app_id=app_id, app_version=app_version)
    
        def call(self, luis_endpoint, method, data=""):
            path = self.path + luis_endpoint
            headers = {'Ocp-Apim-Subscription-Key': self.key}
            conn = http.client.HTTPSConnection(self.host)
            conn.request(method, path, data.encode(self.UTF8) or None, headers)
            response = conn.getresponse()
            self.result = json.dumps(json.loads(response.read().decode(self.UTF8)),
                                     indent=2)
            self.http_status = response.status
            self.reason = response.reason
            return self
    
        def add_utterances(self, filename=UTTERANCE_FILE):
            with open(filename, encoding=self.UTF8) as utterance:
                data = utterance.read()
            return self.call(self.EXAMPLES, self.POST, data)
            
        def train(self):
            return self.call(self.TRAIN, self.POST)
    
        def status(self):
            return self.call(self.TRAIN, self.GET)
    
        def write(self, filename=RESULTS_FILE):
            if self.result:
                with open(filename, "w", encoding=self.UTF8) as outfile:
                    outfile.write(self.result)
            return self
    
        def print(self):
            if self.result:
                print(self.result)
            return self
    
        def raise_for_status(self):
            if 200 <= self.http_status < 300:
                return self
            raise http.client.HTTPException("{} {}".format(
                self.http_status, self.reason))
    
    if __name__ == "__main__":
    
        # uncomment a line below to simulate command line options
        # sys.argv.append("-train")
        # sys.argv.append("-status")
    
        luis = LUISClient(LUIS_HOST, LUIS_APP_ID, LUIS_APP_VERSION,
                          LUIS_authoringKey)
    
        try:
            if len(sys.argv) > 1:
                option = sys.argv[1].lower().lstrip("-")
                if option == "train":
                    print("Adding utterance(s).")
                    luis.add_utterances()   .write().raise_for_status()
                    print("Added utterance(s). Requesting training.")
                    luis.train()            .write().raise_for_status()
                    print("Requested training. Requesting training status.")
                    luis.status()           .write().raise_for_status()
                elif option == "status":
                    print("Requesting training status.")
                    luis.status().write().raise_for_status()
            else:
                print("Adding utterance(s).")
                luis.add_utterances().write().raise_for_status()
        except Exception as ex:
            luis.print()    # JSON response may have more details
            print("{0.__name__}: {1}".format(type(ex), ex))
        else:
            print("Success: results in", RESULTS_FILE)
            
    

Specify utterances to add

Create and edit the file utterances.json to specify the array of utterances you want to add to the LUIS app. The intent and entities must already be in the LUIS app.

Note

The LUIS application with the intents and entities used in the utterances.json file must exist prior to running the code in add-utterances.js. The code in this article does not create the intents and entities. It only adds the utterances for existing intents and entities.

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

If the entityLabels list is not empty, the startCharIndex and endCharIndex need to mark the entity referred to in the entityName field. Both indexes are zero-based counts meaning 6 in the top example refers to the "S" of Seattle and not the space before the capital S.

[
    {
        "text": "go to Seattle",
        "intentName": "BookFlight",
        "entityLabels": [
            {
                "entityName": "Location::LocationTo",
                "startCharIndex": 6,
                "endCharIndex": 12
            }
        ]
    },
    {
        "text": "book a flight",
        "intentName": "BookFlight",
        "entityLabels": []
    }
]

Add an utterance from the command-line

Run the application from a command-line with Python 3.6.

Calling add-utterance with no arguments adds an utterance to the app, without training it.

> python add-utterances-3-6.py

This sample creates a file with the results.json that contains the results from calling the add utterances API. The response field is in this format for utterances that was added. The hasError is false, indicating the utterance was added.

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

Add an utterance and train from the command-line

Call add-utterance with the -train argument to send a request to train, and subsequently request training status. The status is queued immediately after training begins. Status details are written to a file.

> python add-utterances-3-6.py -train

Note

Duplicate utterances aren't added again, but don't cause an error. The response contains the ID of the original utterance.

When you call the sample with the -train argument, it creates a training-results.json file indicating the request to train the LUIS app was successfully queued.

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

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

After the request to train is queued, it can take a moment to complete training.

Get training status from the command line

Call the sample with the -status argument to check the training status and write status details to a file.

> python add-utterances-3-6.py -status

Clean up resources

When you are done with the tutorial, remove Visual Studio and the console application if you don't need them anymore.

Next steps