Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

Dialogflow

Entity for number of ingredients and number of recipe steps

While implementing the previous capability we only implemented three features that can be used to filter recipes on. To make our addFilter intent more useful and allow a user to make requests about more recipe features, we need to add more training phrases that can capture what a user wants in Dialogflow. For each type of recipe feature that we want to add, however, we need to also add all of the values of such a feature as entity entries. There is, however, one relatively cheap way to add a new feature that makes use of the system entities of Dialogflow. We can use, for example, the @sys.number entity for implementing feature requests related to the number of ingredients. For example, you can add phrases like “A recipe with less than 10 ingredients” to cater to users looking for simpler recipes. Remember to annotate the number of ingredients in each phrase with the @sys.number system entity so Dialogflow can correctly identify and extract this parameter. And, just as important, you should specify a parameter name such as nrOfIngredients for the parameter Dialogflow should extract. Your new entry in the table in the Actions and parameters section should look as follows:

In a similar vein, you should add phrases about the number of recipe instruction steps such as “I’m looking for a recipe with less than 8 steps”, and the number of servings of a recipe. Use as parameter names nrOfSteps and servings. This will make sure the MARBEL agent will receive filters of the form nrOfSteps=8 and servings=4 and store that in its conversational memory. Finally, also annotate for recipe duration for a parameter called duration but instead of @sys.number use the @sys.duration system entity of Dialogflow.

Extracting multipe features from a single user expression

Another way to improve your Dialogflow agent is to enable a user to include multiple requests in a single user expression. You can achieve this simply by including many more phrases such as “I’d like a Chinese recipe with less than 8 ingredients”. This will ensure that your conversational agent can recognize multiple filter requests.

Prolog and Patterns

Retrieving the (number of) ingredients and recipe steps

As before, we will need to do some work to extract information from the database to implement new filters for requests related to the number of ingredients and recipe steps. We will start by implementing Prolog rules to extract the list of ingredients and the list of recipe instruction steps for a particular recipe from the recipe database. We will define a rule for extracting ingredients including their quantities, which will be useful also later again when we revisit and extend the recipe confirmation page; see Visuals section below. Using those rules it will then be easy to compute their number. As the rules for extracting the ingredients and recipe instructions from the database are very similar, we will only guide you through the one for ingredients and leave the other up to you. You should add both rules in the recipe_selection.pl file at the designated locations in that file.

  • Add a Prolog rule for ingredients(RecipeID, IngredientList) that returns the list of ingredients with their quantities for the recipe with identifier RecipeID in the output argument IngredientList:

    1. Find a built-in Prolog predicate that you can use for returning a set of ingredients that match a specific goal (i.e., they are associated with the given recipe RecipeID). Be sure to read the Prolog documentation (check here: SWI-Prolog) to make sure you understand what kind of arguments the predicate expects.

    2. In the recipe_database.pl file, find the predicate that is used to store ingredient information including the quantities needed. You should use this predicate as the “goal” that the built-in predicate expects as its second argument. Note that we only want to retrieve the ingredients for the recipe with identifier RecipeID. As we are only interested in the IngredientAndQuantity argument, you should abstract away the other argument. You can do this by using the caret ^ operator in Prolog and put the “goal” of the operator inside the template RecipeID^(...).

    3. Those ingredients with their quantities that match the “goal” should be returned as a list in the output argument IngredientList.

  • Add a Prolog rule for steps(RecipeID, StepList) that returns the list of instruction steps for the recipe with identifier RecipeID in the output argument StepList.

Using the rules for ingredients/2 and steps/2, you should now be able to define rules for nrOfIngredients(RecipeID, N) and nrOfSteps(RecipeID, N) that return the number of ingredients and instruction steps, respectively, by computing the length of the list of ingredients and steps.

Applying filters: Number of ingredients and recipe steps

As we did before for ingredient (types) and cuisine, to enable filtering the recipe database for recipes with fewer than a specified number of ingredients, we want to define a rule for (the head) in the recipe_selection.pl file:

applyFilter('nrOfIngredients', Value, RecipeIDsIn, RecipeIDsOut)

Here Value is the number specified by the user for the maximal number of ingredients that a recipe should have. To make sure that Value is an integer value, we first apply the convert_to_int/2 predefined predicate in utils.pl. In the body of the rule, use the query convert_to_int(Value, MaxInt) first and than add a findall/3 query similar to the ones that we used before but now for evaluating the condition that the number of ingredients for a recipe are less than MaxInt.

It is very important to make sure that values are of the right type. The values that Dialogflow returns are often atoms or strings. Comparing strings to numbers using the < operator, for example, will result in a Type error in SWI Prolog that will terminate the MARBEL agent.

To avoid such issues, we therefore always need to make sure that values that must be numbers (because they match with @sys.number entity type in Dialogflow) are converted to numbers again in Prolog. There are predicates defined for this purpose in the utils.pl file.

  • Now add a similar rule that applies a filter for the nrOfSteps feature; your Training phrases should dictate how to read the constraint. I.e., if your phrase says “less than N recipe steps” than you should write code that implements the filter to mean exactly that.

  • Add a similar rule that applies a filter for the servings feature. You probably want to make sure that a recipe has exactly the right number of servings that the user asked for.

  • Finally, add a rule that applies a filter for the duration feature. This feature is a bit more tricky and you should take the warning above about data types to heart. However, most of the work has already been done for you in the dialog_update.mod2g file in a step called Pre-process parameters of intent. In this step, the duration values received from Dialogflow are transformed to minutes (numbers) using the duration_to_min predicate defined in the utils.pl file. This means that to define the rule for filtering, you simply need to look up the time it takes to cook a recipe in the database (specified in minutes), and compare that value with the maximum duration that the user specified.

Visuals

Extend the recipe confirmation page

The initial version of the recipe confirmation page that we created for Capability 2: Request a Recommendation should be extended now and also show the recipe instruction and ingredient details. Use the Prolog rules you created for recipeSteps(RecipeID, StepsList) and ingredients(RecipeID, IngredientList) to retrieve these from the recipe database. Then add these to two new cards that you add to the page for showing these recipe details.

  1. Retrieve the following information by putting the appropriate predicates in the places indicated in the rule by comments and by using the variable names indicated below.

    1. We need to retrieve the chosen recipe from memory. Find the necessary predicate and name that variable ‘Recipe’.

    2. The previous step retrieves the Recipe ID, but we also need the recipe name. Use a variable called ‘Name’ for this.

    3. Retrieve the time needed to complete the recipe in a variable named ‘Minutes’.

    4. Retrieve the number of servings in a variable called ‘Persons’.

  2. To retrieve a list of the recipe steps and a list of ingredients, you will need two additional predicates in recipe_selection.pl.

    1. The first of the two predicates is a rule that returns a list of ingredients ingredients(RecipeID, IngredientList) :-

  3. Implement a rule in recipe_selection.pl called recipeSteps(RecipeID, StepsList) :- to retrieve a list of the recipe steps without changing their order. There is no repetition, so this predicate does not need to remove duplicates. Your rule for retrieving the steps needs to use the accompanying rule given below getStepString in your goal of the built-in Prolog predicate, so your goal should look as follows: RecipeID^getStepString(RecipeID, Step).

    1. getStepString(RecipeID, String) :-
      	step(RecipeID, NrStep, StepSentence), 
      	to_upper_case(StepSentence, StepSentenceUpper),
      	atomic_list_concat(['Step ', NrStep, ': ', StepSentenceUpper], String). %, '.'
  4. Go back to html.pl and to a50recipeConfirm

    1. Save the recipe steps as ‘Steps’

    2. Save the list of ingredients as ‘Ingredients’

Ask for recipes with 5 ingredients and see if you receive the following answer.

Test it Out

Check if the recipe on the a50recipeConfirm page fulfills the criteria you chose for the number of steps, number of servings, and duration. Make sure to test that all filters introduced for this capability work.

  • No labels