Table of Contents | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
Dialogflow
As a first step towards recipe recommendation, we want a user to be able to ask for a random recipe recommendation. The idea is that the agent would randomly select one of the recipes from its database and recommend that to its user. This may not seem particularly useful at this stage, when you only have implemented Capability 1: Greet, and Self-Identify. A , as a user cannot yet have made any requests for specific features of a recipe. However, at a later stage, when a user can also already have made such specific feature requests, adding using this capability makes more sense. In these cases, a user simply may not want to add any other feature requests and ask the agent to recommend an arbitrary recipe from those that satisfy the requests they have made thus far. We want to prepare the agent for doing just that already now. The first thing to do to enable this is to create another intent in your Dialogflow agent for requesting a (random) recipe recommendation. To create such an intent, you should follow the same steps as before:
...
Under Action and parameters make sure the box above the table is filled in with the name of your intent. You do not need to define any parameters since a recipe recommendation does not require the specification of anything any specific parameters. Keep the warning above in mind, however!
...
Warning |
---|
Test that your intent is correctly recognizing user requests by using the microphone button in the Dialogflow test console. Try various phrases and check whether what you say is classified as your recipe recommendation intent. |
Prolog and Patterns
This section is about implementing the dialog management capabilities of the conversational agent but also about implementing the domain logic that the agent needs to be able to perform its task. As our conversational agent is a task-based agent for recipe recommendation, the conversational competence of our agent focuses on patterns and responses for recipe recommendation. The logic that we need to implement concerns the capabilities our agent needs to reason about user requests about recipes that are available in the agent’s database. We will first focus on adding some conversational capabilities for our agent to respond to a user request to provide a (random) recipe. As before, the approach to dialog management that we use here will require the definition of a pattern and the specification of a (textual) response to the user request. When we have completed that part, we will continue with the part focusing on implementing the reasoning capabilities for extracting such a recipe from the database in Prolog. This will require the definition of several rules for extracting a suitable recipe from the agent’s recipe database.
...
Conversational patterns represent natural patterns of interaction in a conversation (cf. Moore and Arar, 2019). A conversation essentially consists of a sequence of dialog moves that accomplish certain conversational and domain-specific aims of the conversational partners or actors. A pattern is a part of a conversation that is repeated and more often seen also in and is generalizable to other conversations. The parts that are repeated are often short. Patterns therefore are typically also short sequences of dialog moves that can be reused in various dialog contexts. The part of a dialog between the user and agent that we focus on for this capability provides an example:
...
Identify fragments of a conversation as a type of pattern and classify it using the taxonomy of Moore and Arar; we will suggest which pattern types to implement for each capability, identify the taxonomy code, and suggest slightly more concrete pattern IDs for instantiating a pattern for our recipe recommendation agent.
Identify the actors of each consecutive move in a pattern and specify an intent label for each move; when these intents are performed by the user, a Dialogflow intent needs to be defined; otherwise, if the agent is the actor, a new label needs to be provided to refer to the agent’s move (whereas as we saw for the greeting pattern we can also choose to reuse the same label greeting twice, for both user and agent).
Specify the agent’s textual responses for each agent intent label that is introduced; this step concerns specifying what the agent will say when it performs its move.
...
Note that the third and last move in our example move can be viewed as raising expectations again about the user letting the agent know that it appreciates they appreciate the recommendation made. Because there is always the possibility that a user does not like the recommendation, we would like the user to confirm that they like the recipe that was recommended by the agent. We do not want to include this confirmation as part of our current a50recipeSelect
pattern but introduce another pattern ID a50recipeConfirm
for a confirmation pattern. The idea is that the agent should follow up the any recommendation with this pattern and ask the user whether they like the recommendation. As we do not want to add these moves to the current pattern but do want to put this as a follow-up in the agenda of the agent after completing the a50recipeSelect
pattern, we add a special action insert(a50recipeConfirm)
that inserts the pattern a50recipeConfirm
in the agenda at the end of the a50recipeSelect
pattern. This will tell the agent how to follow up and continue the conversation after completing the pattern where a user asks for a random recipe recommendation.
...
Start creating a pattern fact:
Begin by typing
pattern([
for adding a new pattern fact; note that the[
is the start of a list!
Add the pattern ID:
Add as the first item on the list the pattern ID:
a50recipeSelect
.
Add the list of actor-intent pairs:
For each move in the pattern, add an actor-intent pair in the order they are supposed to occur.
Ensure these pairs are written between square brackets and separated by commas.
For example, type
[agent, specifyGoal],
to represent the first move by the agent.Add all the remaining actor-intent pairs.
Add the special agenda insert action at the end of the list:
Add
[agent, insert(a50recipeConfirm)]
to the list of actor-intent pairs.
Close the pattern fact:
End the list and close the pattern fact with a closing bracket
])
.Conclude the statement with a period
.
as it signifies the end of a Prolog statement.
...
The second intent label that we need to specify a response for is the recommend
intent. The example phrase above “What about ___?”, however, is incomplete. The idea is that the agent could insert a random recipe name here from the agent’s database. That, of course, would require the agent to extract one of the recipes from its database. We will look at that next. For now, to add at least something, let’s add the fact text(recommend, "What about a pasta this dish?").
to the responses.pl
file. After implementing the logic for extracting recipes from the database below, you should change this into something that uses the implemented logic and is more specific.
Warning |
---|
To test the pattern you just added, as before, you still need to do one more thing: In the You can now Run your Conversational Agent again to hear your agent ask you for your recipe preferences. Note that your team must have also added the recipe recommendation page (but not the recipe confirmation page; see Visuals section below) to enable you to respond to the agent’s inquiry. This page is needed to display a microphone icon that you will need to respond to the agent. |
...
Before we add Prolog code for retrieving recipes from the database, we will first add an action rule to the MARBEL agent for updating its conversational memory. The agent uses a memory(KeyValuePairList)
fact for recording user parameter input (the predicate is declared in the dialog.pl
file). It is used to store a list of entity key-value pairs that are updated during the conversation. We have already seen one example of such a key-value pair before the button='start'
. We now want to add another key-value pair to keep track of the recipe that has been selected of the form recipe= RecipeName
. Here, the idea is to add such a key-value pair whenever a user requests a recommendation for a recipe (when they do not want to provide more features that can be used to select a recipe, for example). When a user asks for just a recommendation, we want the agent to randomly select a recipe from all the recipes that remain after filtering all recipes using the features that have been provided already (in our case, for now, that is no feature).
...
The first rule you will be working on is a rule for defining currentRecipe(RecipeID)
. This rule will first retrieve a recipe name from the agent’s conversational memory. The idea is to look up the the recipe name in the memory (assuming it is there, otherwise the rule will simply fail) using the predefined memoryKeyValue("recipe", RecipeName)
predicate (it is defined in the dialog.pl
file, check it out). We then use recipeName(RecipeID, RecipeName)
to retrieve the RecipeID
matching the recipe’s name from the database. This matching or mapping is essential as it translates a user's choice, i.e. a selected recipe stored with its recipe name in conversational memory, into an identifier of a recipe that can subsequently be used to retrieve other recipe features from the recipe database too (these features have been indexed using recipe identifiers, not the recipe’s name!).
...
The head of the rule: use
recipesFiltered(RecipeIDs)
as the head of the rule.The body of the rule:
First query: Retrieve all recipe IDs: Use the
recipeIDs(RecipeIDsAll)
query that we just defined above to get a list of all recipe identifiers from the recipe database.Second query: Fetch all filters from conversational memory: For fetching the set of filters that have been stored in the agent’s conversational memory, we use the predefined predicate
filters_from_memory(Filters)
(you can find the definition of this predicate in thedialogflow.pl
file). At this stage of the project, there is nothing to do for this predicate yet, and an empty list (of filters) will be returned, i.e.Filters=[]
. It will be useful, however, to already add it to complete the implementation of the rule that we are defining.Third query: Filter the recipes: Assuming that a (right now still empty) list of filters has been retrieved, in hand, the idea is to apply the filters to the list of recipes to retrieve only those recipes that meet the criteria specified by each filter. We assume that we have a predicate
recipesFiltered(RecipeIDsAll, Filters, RecipeIDsFiltered)
that does exactly that. You should use this as the third query of the rule to produce a list of recipesRecipeIDsFiltered
that only consists of identifiers of recipes that match all filters.Fourth query: Remove duplicates: We still need to add a final query for eliminating any duplicate entries in our filtered list of recipes. As we will be making use of the builtin
findall
predicate later to define the filtering process and the use of that predicate may result in duplicates in our list, you should add thelist_to_set(RecipeIDsFiltered, RecipeIDs)
query to convert the list of filtered recipe identifiers into a set, effectively removing any duplicates, to complete the definition.
In the definition of our last rule, we assumed that recipesFiltered(RecipeIDsAll, Filters, RecipeIDsFiltered)
is defined. We, therefore, need to make sure that this query will succeed to make our code do something. As discussed above, the list of filters will still be empty. For now, it will thus be sufficient to simply add a fact to our Prolog code that covers the base case (the empty list) of a definition that filters all recipes by recursively going through the list of filters.
...
This clause specifies that if there are no filters to apply (i.e., the filter list is empty), the output of this filtering of a list of RecipeIDs
thus remains unchanged and is that same list of recipe identifiers RecipeIDs
.
Visuals
Recipe recommendation page
...
At this stage, for this capability, we will only provide code for a very basic skeleton page that provides the minimal functionality needed to implement the main requirement for this page: enable a user to talk to the agent using a microphone button. The design is kept minimal below and in the step-by-step walkthrough below we will only use a single and simple alert element to style the page. As the recipe recommendation page will be the first interaction point for users who are actually interested in finding a recipe, we leave it up to you to try and make this page more inviting and add clear and useful content that the agent will show. Note that we will also ask you to extend this page at a later stage when you are implementing Capability 5: Filter Recipes by Ingredients and Cuisine.
Step 1: Adding the head of a Prolog rule for a recipe recommendation page.
...
The next page that we want you to add is a recipe confirmation page. At the end of the pattern enabling a user to request a (random) recipe, the agent inserts the a50recipeConfirm
pattern ID in the agenda. No pattern has been added for this pattern ID yet, but because it will appear at the top level in the agent’s agenda, we can already create a confirmation page for the recipe that is selected. The idea is that this page allows the user to preview the recipe and indicate whether they are satisfied with the recipe (confirm) or not (disconfirm). To enable a user to make this decision, the main requirement for this page is that it shows the recipe’s name, and what the result of cooking the recipe will look like (a picture of the recipe). A second requirement is that the page shows a microphone button to enable the user to inform the agent about whether it wants they want to (dis)confirm the recipe. Note that at a later stage, we will ask you to extend the recipe confirmation page when you implement Capability 6: Filter by Number of Ingredients & Recipe Steps.
For the design, a https://www.w3schools.com/bootstrap4/bootstrap_cards.asp element seems a suitable element for styling the page. We will use it below to create a first (but still simple) recipe confirmation page with a basic recipe card. We will want to generate the following HTML code for this card:
...
We have kept things again simple here and just created one HTML element for our recipe confirmation page. We, therefore, have nothing to do here either.
...
We have introduced the bare essentials for these pages but you should feel free to modify it in any way you like to make it look more appealing. However, please note that the a50recipeConfirm
page is extended later to include recipe information. More information about these extensions can be found here: https://socialrobotics.atlassian.net/wiki/spaces/PM2/pages/2229600267/Capability+6+Filter+by+Number+of+Ingredients#Visuals2229600267#Visuals.
It is important that you make sure that the requirements marked in bold in the text are met.
...
After the Start page, when you click the Start button,
You should see the welcoming page.
The agent starts by greeting you by self-identifying it (moves
greeting
,selfIdentification
).You should be able to greet the agent (
greeting
).You should see the recipe recommendation page.
The agent asks you what kind of recipe you would like (
specifyGoal
).You should be able to say that you just want some a random recipe (
requestRecommendation
).The agent then suggests a random recipe (
recommend
).You should see the recipe confirmation page.
...