This tutorial will teach you how to create an application in LUIS and write a simple client in python to consume the application.
We will leverage prebuilt entities to extract data from user queries in LUIS, and an API from the MLB to retrieve statistics about the entities LUIS finds.
- Python 3.x
- Requests, a python library for making HTTP requests easily.
- A LUIS.ai account where to create the sample’s LUIS model.
If you would like to run the sample, simply clone the repository and run the following command inside the directory:
python client.py
- Sign in to the LUIS portal.
- Select Create new app.
- In the pop-up dialog, enter the name
Baseball
and keep the default culture, English. You may leave the description blank. - Select Done. Next, the app shows the Dashboard.
- Select Build from the top right menu. The Intent page is shown.
LUIS provides several prebuilt entities for common data extraction.
- Select Entities from the left navigation menu.
- Select Add prebuilt entity button.
- Select the
PersonName
entity from the list, then select Done.
This entity will help us extract name data from user queries.
LUIS uses intents to determine what the query is attempting to ask. We are going to add two custom intents,
FindHomeRuns
and FindBattingAverage
- Select Intents from the left navigation menu.
- Select Create new intent button.
- In the pop-up dialog enter the name ‘FindHomeRuns’.
- Select Done. Next, the app show the Intents page with our FindHomeRuns Intent added as well as the default None Intent.
- Repeat steps 2-4 for FindBattingAverage
By providing example utterances, you are training LUIS about what kinds of utterances should be predicted for this intent. In order to have functioning predictions, we want about 15 or so sample utterances of varying gramatical structure and accuracy.
To add sample utterances to an intent, do the following:
- Select Intents from the left navigation menu.
- Select the desired intent, in this case FindHomeRuns.
- Input a sample utterance into the text field and press Enter.
- You will see the name data from the sample utterance replaced with a
personName
entity.
Repeat these steps for FindBattingAverage using the following sample utterances.
Example utterances for FindHomeRuns:
- How many home runs does John Smith have?
- How many home runs has Mike Trout hit?
- How many homers does Hanley Ramirez have?
Example utterances for FindBattingAverage:
- What is John Smith hitting?
- What is Mike Trout’s batting average?
- What is Robinson Cano batting?
- What is Hanley Ramirez’s average?
Patterns allow us to improve intent and entity prediction while providing fewer example utterances.
We can create a pattern from sample utterances by doing the following:
- Select Intents from the left navigation menu.
- Select the desired intent, in this case FindHomeRuns.
- Select the Add as pattern button.
- In the pop-up dialog, select Done.
- Repeat with other desired sample utterances.
The client application needs to know if an utterance is not meaningful or appropriate for the application. The None intent is added to each application as part of the creation process to determine if an utterance can’t be answered by the client application.
If LUIS returns the None intent for an utterance, your client application can ask if the user wants to end the conversation or give more directions for continuing the conversation.
- Select Intents from the left panel.
- Select the None intent. Add three utterances that your user might enter but are not relevant to your Human Resources app:
Example utterances:
- Barking dogs are annoying
- Order a pizza for me
- Penguins in the ocean
Now that we have sample utterances and patterns, we can train our model.
-
In the top right side of the LUIS website, select the Train button.
-
Training is complete when you see the green status bar at the top of the website confirming success.
In order to receive a LUIS prediction in a chat bot or other client application, you need to publish the app to the endpoint.
- Select Publish in the top right navigation.
- Select the Production slot and the Publish button.
- Publishing is complete when you see the green status bar at the top of the website confirming success.
- Select the endpoints link in the green status bar to go to the Keys and endpoints page. The endpoint URLs are listed at the bottom.
- Save the endpoint URL. We will use it in our client.
Now that our LUIS application has a trained and published model, we can write an application to leverage it.
If you don’t have the requests
python module installed, use the following command:
pip install requests
Make sure to include the library in our client.
import requests
We also define two important global variable with the URLS we need. Note in the player_stats URL there are variables for game_type (R for regular season or P for postseason) and season (year of the desired season).
luis_url = # The URL endpoint for LUIS
stats_url = "http://lookup-service-prod.mlb.com/"
player_info = "json/named.search_player_all.bam?sport_code='mlb'&active_sw='Y'&name_part="
player_stats = "json/named.sport_hitting_tm.bam?league_list_id='mlb'&game_type='R'&season='2017'&player_id="
Both LUIS and the MLB Stats API return data in the form of JSON. We create the following function to handle this:
def get_json(url):
response = requests.get(url)
try:
json = response.json()
return json
except:
return {}
In order to access a player’s statistics via the MLB Stats API, we need a way of turning a player’s name into the corresponding player ID. Fortunately, there is a way we can do that using the MLB’s api.
def get_player_id(player_name):
url = stats_url + player_info + "\'" + player_name + "\'"
json = get_json(url)
try:
player_id = json['search_player_all']['queryResults']['row']['player_id']
except Exception as e:
player_id = '0'
finally:
return player_id
Now that we can get the player’s ID, we can find any statistics we desire as long as we know the code representing it.
For the case of Home Runs and Batting averages, the codes are hr and avg, respectively.
def get_statistic(player_id, statistic):
url = stats_url + player_stats + player_id
json = get_json(url)
try:
res = json['sport_hitting_tm']['queryResults']['row'][statistic]
except Exception as e:
res = '0'
finally:
return res
Our data extracting functions are in place. Now all we need to do is write some Input/Output loops.
Our main function begins as such:
def main():
while True:
query = input("\nPlease enter your query: \n\n")
print()
url = luis_url + query
json = get_json(url) # response from our LUIS application
At this point our LUIS application has processed the user’s query, determining intent and finding entities. We can capture these values like this:
intent = json['topScoringIntent']['intent']
player_name = json['entities'][0]['entity'] # The 0 here represents the first entity returned
player_id = get_player_id(player_name)
What happens if the MLB’s api can’t find the player’s ID and player_id is 0? We could create and raise a custom Exception, but it is simpler just to notify the user and continue the loop.
if (player_id == '0'):
print("Couldn't find that player. Please try again.")
continue
Next we write the logic for handling the proper statistical query based on the User’s intent.
if (intent == "FindBattingAverage"):
avg = get_statistic(player_id,'avg')
print("\t" + player_name + " is batting " + avg)
elif (intent == "FindHomeRuns"):
hr = get_statistic(player_id,'hr')
print("\t" + player_name + " has " + hr + " home runs")
else: # intent == None
print("\tCouldn't understand your query, to exit press CTRL+C.")
continue
Because errors are possible if we trying to parce responses that are not valid, we handle any Exceptions raised by those operations at the end, wrapping all the above logic in a try block. The final main function looks like this:
def main():
while True:
query = input("\nPlease enter your query: \n\n")
print()
url = luis_url + query
json = get_json(url)
try:
intent = json['topScoringIntent']['intent']
player_name = json['entities'][0]['entity']
player_id = get_player_id(player_name)
if (player_id == '0'):
print("Couldn't find that player. Please try again.")
continue
if (intent == "FindBattingAverage"): # FindBattingAverage
avg = get_statistic(player_id,'avg')
print("\t" + player_name + " is batting " + avg)
elif (intent == "FindHomeRuns"): # FindHomeRuns
hr = get_statistic(player_id,'hr')
print("\t" + player_name + " has " + hr + " home runs")
else: # None
print("\tCouldn't understand your query, to exit press CTRL+C.")
except Exception as error:
print(error)
if __name__ == "__main__":
main()
The last two lines at the end cause the main function to autorun when the python module is invoked.
To run the client, open a command prompt, navigate to the directory where client.py
is and run
python client.py
Now you can enter queries and watch as our client uses LUIS and the MLB API to return relevant statistics based on user intent!
Please enter your query:
how many home runs does hanley ramirez have this season?
hanley ramirez has 23 home runs
Please enter your query:
what is joey votto batting?
joey votto is batting .320
Extending the functionality is easy. Simply update the LUIS app’s intents and add logic for the selection of additional stats. For more information about LUIS, please visit https://docs.microsoft.com/en-us/azure/cognitive-services/luis/.