Interactive conversation implementation in Bixby - bixby

I am new to Bixby, facing trouble in Interactive conversation implementation.
Something like below :
User: "Hi Bixby, book me a table at Flemings Steakhouse."
Okay, for what day?
User: "Tomorrow."
Okay, for what time?
User: "6:00pm."
Okay, for how many people?
User: "Four."
Okay, booking a table for 4 people at Flemings Steakhouse tomorrow at 6:00pm.
If any suggestion , please help.

This isn't too hard with Bixby. What you'll want to do is create an action that will collect all the input from the user. It could look similar to this
Your action
action (BookReservaton) {
type(Search)
description (Book a reservation)
collect {
// Ask for the user's reservation date
input (reservationDate) {
type (time.DateTimeExpression)
min (Required) max (One)
}
// Prompt for number of guests, but also allow them to confirm 2
input (numberOfGuests) {
type (NumberOfGuests)
min (Required) max (One)
default-init {
intent {
goal: NumberOfGuests
value: NumberOfGuest(2)
}
}
prompt-behavior (AlwaysSelection)
}
}
output (Reservation)
}
In your case, you're going to need to collect input from the user when they don't provide your required input from their utterance. This is a good example of collecting dates, etc. You can also support someone saying 'Book a table for 4 this Tuesday at 7PM' without needing to prompt them for input. Bixby will only prompt the user when it doesn't have a required input.

Related

Need to store parameter values that I get from previous conversation into a variable and merge it dialogflow

The flow :
User: Hi.
Bot: Spell the characters.
User: joh.
Bot: continue.
User: ny.
Bot: continue.
User: thats it.
Bot: Thank you ,johny(joh+ny)
Here, how can I store all the uservalues into a variable and merge them and display to user?I tried using context. I created a globalparameter context that has the values displayed.
For this,I have created 2 intents
First intent: firstnameletters
Second intent: Thank you
In Firstintent,
const first_name_letters = async (df,globalParameter) =>{
let name=df._request.queryResult.parameters.alphabets;//slot values like joh
df.setResponseText(("name").replace("name",name).split('').join(' ')+"\n\n"+"continue");
}
The code below when I print globalparameter:
const first_name_letters = async (df,globalParameter) =>{
console.log("globalparametr ",globalParameter);
let name=df._request.queryResult.parameters.alphabets;
console.log("alphabets",globalParameter.alphabets);
}
//output of global parameter when I pass "suchi" in the DF console.
globalparametr {
alphabets: 'suchi',
reqIntent: 'first_name_letters',
languageCode: 'en',
'alphabets.original': 'suchi'
}
alphabets suchi
//output of globalparameter during next time when I pass "itra"
globalparametr before {
alphabets: 'itra',
reqIntent: 'first_name_letters',
languageCode: 'en',
'alphabets.original': 'itra'
}
alphabets itra
Dialogflow:
Now,I want to combine "suchitra" and want the bot to display "Thank you suchitra" in the thank you intent.
As confirmed by #lakshmi, to be able to combine the user inputs in an ongoing conversation you can:
Store values of name in a list every time the user provides an input.
Concatenate the values in the list when user is done providing inputs.
Use the concatenated value as response to the user.

Is there a way to trigger different query while filling the required slots in dialogflow

I have an intent orderPizza and entities as #pizzaOptions #pizzaSize #qty
happy path (working fine)
user: order 2 pizza
bot: which pizza you want?
user: pepperoni
bot: and pizza size?
user: large
bot: okay! your order for 2 large pepperoni pizza has been placed.
CASE_2
user: order 2 pizza
bot: which pizza you want?
user: which pizza options do you have?
bot: which pizza you want?
so in case 2 when user ask for the pizza Options then bot re-prompt the same question
I want bot to answer the user query or bot can present the options (different re-prompt) instead of same re-prompt
is there a way to handle this use case
The best setup for this would be to have 2 intents.
Order pizza intent ("Order x Pizza")
Get Pizza option intent ("What pizza options do you have?")
The reason for this is, because the user is trying to get two completely different results from you bot. When the user asks for Pizza type, they aren't always ordering a pizza, they could just be interested in your available types.
The Get Pizza option intent you just return an response which gives
the user an example of the available pizza types.
If you make sure both these intents don't require any input context,
you should be able to implement the usecase that you are trying to go
for.
If you use this setup and make sure that the parameters aren't set as required, you should be able to switch between these two intents during the slot filling. In the example you gave you can see that you bot in Case2 keeps asking the user about the pizza type, this is because it expects a pizza type entity as input.
Some example conversations would be:
User: I want to order a pizza.
Bot: Sure, which Pizza do you want? // Order Pizza Intent
User: I don't know, which pizzas do you have?
Bot: We currently sell Pepperoni Pizza and Vegan Pizza, what else can I Help you with? // Get Pizza Option Intent
User: I'd like to order 2 large Pepperoni Pizzas
Bot: Okay! your order for 2 large pepperoni pizza has been placed. // Order Pizza Intent
User: Hey, what types of pizza do you have? // Order Pizza Intent
Bot: We currently sell Pepperoni Pizza and Vegan Pizza, what else can I help you with? // Get Pizza Option Intent
User: Hhm, I'm looking for something else, I'll go look somewhere else.
Bot: Sorry to hear that, I hope you have a nice day.
Slot filling in the webhook
Because we chose to not make the parameters required, we now have save and check all the paramters ourself. Each time the user mentions an order, we should check if it is complete.
function orderIntent(conv) {
const pizzaOption = conv.paramters.pizzaOption;
const pizzaSize = conv.parameters.pizzaSize;
const quantity = conv.parameters.qty;
if (!pizzaOption) {
return conv.ask("Which pizza do you want?");
}
if (!pizzaSize) {
return conv.ask("Which size pizza do you want?");
}
if (!quantity) {
return conv.ask("How many pizzas do you want?");
};
This will now allow us to prompt the user until they provide all the information to complete the order, if you would use this code, the bot would keep looping until the user mentions a single phrase that includes a pizzaType, pizzaSize and quantity entity.
Because it is unlikely that the user will ever do this, we need to expand the code to allow the order to be split up in multiple steps and understand which step we are in. We will do this by adding context and follow-up intents.
Remembering the users order
Firstly, lets add the follow-up intent. Because we want to be able to split up the reservation, we should add a follow-up intent for each step. My dialogflow agent that I used to test this looks like this:
Each follow-up intent takes one of the entities as a example phrase:
Missing PizzaTypes, #PizzaOption entity as trained phrase
Missing PizzaSize, #PizzaSize entity as trained phrase
Missing Quantity, #system.integer as trained phrase
After setting these up, you need to enable fulfillment for these follow-ups and add them to the same handler as with the order intent. Now that the intents are setup, we need to add the reservation context and save any valid data.
// All the order follow-ups and the order intent use the same handler.
app.intent(
["Order Intent", "Complete Order - Missing PizzaType", "Complete Order - Missing Pizza Amount", "Complete Order - Missing PizzaSize"],
(conv) => {
// Check if any reservation info is available.
const order = conv.contexts.get("reservation");
// If the user has already mentioned pizza info, use context, otherwise take it from the user input.
const pizzaType = order?.parameters.pizzaType ?? conv.parameters.pizzaType;
const pizzaSize = order?.parameters.pizzaSize ?? conv.parameters.pizzaSize;
const pizzaAmount = order?.parameters.pizzaAmount ?? conv.parameters.pizzaAmount;
// Allow the fallback intents to be triggered
conv.contexts.set("OrderIntent-followup", 2);
// Validate the input
if (!pizzaAmount) {
return conv.ask("How many pizza's would you like to order?");
}
// Save input if valid
conv.contexts.set("reservation", 5, { pizzaAmount });
if (!pizzaType) {
return conv.ask("Which pizza would you like?");
}
conv.contexts.set("reservation", 5, { pizzaAmount, pizzaType });
if (!pizzaSize) {
return conv.ask("What size should your pizza be?");
}
return conv.ask(`Alright, your order has been completed: ${pizzaAmount} ${pizzaSize} ${pizzaType}`);
},
);
The final result

How to build proposed order with what the user has selected?

I'm building an AOG (actions on google) project that will do basic transaction functionality. Since I'm still a bit new to AOG, I'm completely stuck on how to take what the user selects (whether it be a carousel, a basic card etc.) and pass that argument value/key that they selected into the proposed order or the order preview before they finish their transaction.
Here is basically what I have tried (This isn't the actual code because it's rather long, but it still gets the idea across)
app.intent('delivery_address_complete', (conv) => {
const arg = conv.arguments.get('DELIVERY_ADDRESS_VALUE');
if (arg.userDecision ==='ACCEPTED') {
conv.ask('Ok, what would you like to order?');
conv.ask(new Suggestions(intentSuggestions));
conv.ask(new Carousel({
items: {
// Add the first item to the carousel
SELECTION_KEY_COFFEE: {
synonyms: [
'Coffee'
],
title: 'Coffee',
description: 'Sweet cream and sugar coffee.',
image: new Image({
url: IMG_URL_COFFEE,
alt: 'Image alternate text',
}),
},
}));
}
});
const yesOrno = [
'Yes',
'No'
];
app.intent('actions.intent.OPTION', (conv ) => {
conv.ask('Okay, are you ready to proceed?');
conv.ask(new Suggestions(yesOrno));
});
app.intent('transaction_decision_action', (conv) => {
const order = {
id: UNIQUE_ORDER_ID,
cart: {
merchant: {
id: 'coffee',
name: 'Coffee Store',
},
lineItems: [
{
name: 'My Memoirs',
id: 'coffee_1',
price: {
amount: {
currencyCode: 'USD',
nanos: 990000000,
units: 3,
},
type: 'ACTUAL',
},
quantity: 1,
subLines: [
{
note: 'coffee',
},
],
type: 'REGULAR',
},
otherItems: [
{
name: 'Subtotal',
id: 'subtotal',
price: {
amount: {
currencyCode: 'USD',
nanos: 220000000,
units: 32,
},
type: 'ESTIMATE',
},
type: 'SUBTOTAL',
},
{
name: 'Tax',
id: 'tax',
price: {
amount: {
currencyCode: 'USD',
nanos: 780000000,
units: 2,
},
type: 'ESTIMATE',
},
type: 'TAX',
},
],
totalPrice: {
amount: {
currencyCode: 'USD',
nanos: 0,
units: 35,
},
type: 'ESTIMATE',
},
};
Please note: This is mostly dummy code, so if some things like over charging or prices not making sense is happening, it's not the problem I'm trying to fix.
How can I take what the user selected from whatever method, and get it so it will appear on the order preview or proposed order? I do not need help with anything regarding making carousels or basic cards ect. Just how to get this selected information to the order preview.
To be more specific:
I can create an order object that is required, and I know how to send it to Google (and then to the user) as part of a ProposedOrder object that becomes part of the TransactionDecision object. (The "transaction_decision_action" Intent handler in the code above.)
What I don't understand is how to build the order based on the user saying things or by selecting on carousel or list items that I've shown them. (What do I do in the "actions.intent.OPTION" Intent handler above, for example?)
edit: This also may clear up any confusion. This is a video representation of what I'm attempting to do (mentioned in comments below):
youtube.com/watch?v=LlgMcJBnNN8 from 1:02 to 1:29 I know how to do, I'm confused (In the video example) how they were able to get the 'turkey sandwich' and the 'Green smoothie' added to the order preview at 1:35 ish from the carousel selections
What you're looking to do is what Google refers to as building the order. As it notes at that link
Once you have the user information you need, you'll build a "cart
assembly" experience that guides the user to build an order. Every
Action will likely have a slightly different cart assembly flow as
appropriate for your product or service.
You could build a cart assembly experience that enables the user to
re-order their most recent purchase via a simple yes or no question.
You could also present the user a carousel or list card of the top
"featured" or "recommended" items. We recommend using rich responses
to present the user's options visually, but also design the
conversation such that the user can build their cart using only their
voice.
For more information on how to build a high-quality cart assembly
experience, see the Transactions Design Guidelines.
So there is no one way to do what you're asking about. However, there are a few tips of things you can and should be doing to build the proposed order.
Managing the order
The big thing you need to do is to keep track of all the things that the user is ordering as you go through the process. There are a number of ways you can store this information:
In a Dialogflow Context
In the user session store
In a database or data store for the session
In short, any of the current ways you have to store session information. All of the information below assumes you've picked some way to do this.
Since everything will become one of the lineItems, an easy solution is to build this array as you go along, and then you can just copy the array directly into the order object. Another approach is to just store a list of item IDs, and then populate the rest of the information later when we build the order.
For this example, we're going to go with this latter scheme (because its easier to show) and store it in the session storage object using the actions-on-google library.
So for starters, when we start the Action, or when we know we'll be taking the order, we need to initialize our list of items being ordered with something like
conv.user.data.items = [];
Now that we have our initial item list, we can explore different ways to add to this list.
Adding an item: "my regular"
For some types of orders, it may make sense for the user to be able to say "I'll have my usual". In cases like this, we want an Intent that handles this phrase (or handles a "yes" response to our prompting), and an Intent Handler that looks up the user's regular order and adds it to the items. Perhaps something like this:
app.intent('order.usual', conv => {
// Get their user profile from our database
// The "loadUser" function is up to you, and has little to do with AoG
return loadUser( conv )
.then( user => {
// Add each item in their usual order to the current items
let usualOrder = user.usualOrder;
usualOrder.forEach( item => conv.user.data.items.push( item ) );
// Send a message back to the user
conv.add( "You got it! Do you want anything else?" );
});
});
Adding an item from a list
If you've presented a carousel or a list to the user of possible items, your life is a little easier (although you may not think it at the moment). You do need to setup a Dialogflow Intent that handles the actions_intent_OPTION event (which I'll call order.option in this case).
In the handler for this, we'll assume that the key you used for the option also happens to be the item ID, so you can just add it to the list
app.intent('order.option', (conv, params, option) => {
// The item is the option sent
let item = option;
// Add the item to the list of items
conv.user.data.items.push( item );
// Send a message back to the user
conv.add( "I've put that in your cart. Anything else?" );
});
Adding an item by name
But remember, the user can take the conversation in any direction at any time. So they may ask for an item that you currently aren't showing in the carousel. The best way to handle this is by creating an Entity Type in Dialogflow (which I'll call item, as an example)
And then an Intent that captures some phrases that expresses the user asking to add them (which I'll call order.name and which has an itemName parameter that the user has to include).
[
In the handler, you need to get the name that they spoke, look up what the item is, and add this to the list of items they've ordered.
app.intent('order.name', (conv, params) => {
// Get the name
let itemName = params['itemName'];
// Look it up to find out what they ordered
// You need to implement the itemFromName function
return itemFromName( itemName )
.then( item => {
// Add the item
conv.user.data.items.push( item );
// And reply
conv.add( "You got it! Anything else?" );
});
});
Finish building the order
Once you've finished collecting everything they want, your Intent Handler should put the order together, assembling the full list of lineItems from the conv.user.data.items array that we've been putting together, calculating tax, totals, and all the other parts of the order.
We then need to propose the order by sending a TransactionDecision object that contains our order in the proposedOrder parameter. Clever, no? Possibly something like this:
app.intent('review', conv => {
// Get the items the user has saved
let items = conv.user.data.items;
// Turn these into more complete lineItems
// You will need to provide the "itemToLineItem" function
let lineItems = items.map( itemToLineItem );
// Get some other objects we need
// You'll need to define these functions, too
let orderId = generateOrderId();
let subtotal = computeSubtotal( lineItems );
let tax = computeTax( lineItems );
let total = computerTotal( subtotal, tax );
// Build the order object
let order = buildOrder( lineItems, subtotal, tax, total );
conv.ask(new TransactionDecision({
orderOptions: {
requestDeliveryAddress: false,
},
paymentOptions: {
googleProvidedOptions: {
prepaidCardDisallowed: false,
supportedCardNetworks: ['VISA', 'AMEX'],
// These will be provided by payment processor,
// like Stripe, Braintree, or Vantiv.
tokenizationParameters: {
tokenizationType: 'PAYMENT_GATEWAY',
parameters: {
'gateway': 'stripe',
'stripe:publishableKey': (conv.sandbox ? 'pk_test_key' : 'pk_live_key'),
'stripe:version': '2017-04-06'
},
},
},
},
proposedOrder: order,
}));
});
I broke most of the stuff out as a function since there is nothing specific about them, except the format of the order (which you illustrate in your example). You can really build it any way you want.
Conclusion
Much of what you need to do really boils down to
Collecting the information of what the user wants to order, mostly storing the IDs of these items
Turning this list of items into the complete order object
Sending this order for the user to review

Extracting entity in the middle of conversation

I have an intent in LUIS called ChangeFlight. I can extract the date entity when user input some kind of date format initially. When the user forgets to input some date, it will ask the user to input a date.
However, I don't want to just get the results of the response, instead, I want it to extract the date entity such as the initial step. I have bot.dialog('askForDate') which asks for date from user but I am not sure how to extract the builtin date entity in the middle of the conversation.
How should I handle this?
Thanks.
You can use the Prompt dedicated for time resolution, it will allow a user to input a time or date/time. doc is here.
For example:
function (session, results, next) {
if (results.response) {
session.dialogData.name = results.response;
builder.Prompts.time(session, "What time would you like to set an alarm for?");
} else {
next();
}
},
function (session, results) {
if (results.response) {
session.dialogData.time = builder.EntityRecognizer.resolveTime([results.response]);
}
// TO DO : add here what you want to do with the value
}

After the entity and intent recognition in LUIS, what can be the bot's logic in order to provide the response to the user?

for example, If a user asks the bot "whats the weather", and the luis will recognize the entity and the bot will ask for location. After that, the bot has to pick an answer from a point and has to reply back to the user with an answer. I am not able to do the 'reply back with the answer' to the user.
Thanks in advance.
Are you using a standard waterfall methodology in your dialog? For example, the following code is pulled from a demo I built (written in TypeScript):
bot.dialog("location", [
(sess, args, next) => {
builder.Prompts.choice(sess, "We are showing multiple results. Please choose one:", getEntities(builder, args));
},
(sess, results) => {
sess.send(new builder.Message(sess).addAttachment(dialogs.createHeroCard(sess, parser.findExact("title", results.response.entity))));
}
]).triggerAction({
matches: "location"
});
In this example, the intent in LUIS is labeled "location", so the triggerAction matches against that. The dialog has two functions. The first is called when LUIS returns, and it displays a choice dialog with multiple options. When the user chooses one of those options, the result ends up in the second function. So this encompasses two questions. First, the user asks where a particular speaking engagement is being held, and the bot returns a few items that match the intent (maybe there are three presentations on "bots" at a conference). It displays a choice dialog with the elements, and the user's choice pings back to the dialog (but in the second function), and sends a hero card of the presentation chosen.
In the first instance, the bot uses builder.Prompts.choice() to ask for the choice information, and the second response uses session.send() to display the result.
In your example, you could use builder.Prompts.text() to ask for the user's location, and upon receiving the response (available in the second function of the waterfall as results.response, if your function parameters are session and results), you'd parse that data, and then use session.send() to display the results.
So if this were translated to your example, you could probably do something like:
bot.dialog("weather", [
(sess, args, next) => {
builder.Prompts.text(sess, "What location do you want weather for?");
},
(sess, results) => {
//Do something with the results
sess.send("Here's the weather!");
}
]).triggerAction({
matches: "weather"
});

Resources