问题
I've created a simple Google Assistant interface using DialogFlow with several Carousels that I want to be able to chain together. Whenever I touch a carousel option though, it always goes to the first Intent that has the actions_intent_OPTION event specified. I can get to all of my screens using voice commands, but I'm not sure how to process the touch commands to send the user to right Intent.
Current code in webhook:
const party = 'party';
const cocktail = 'cocktail';
const SELECTED_ITEM_RESPONSES = {
[party]: 'You selected party',
[cocktail]: 'You selected cocktail',
};
function carousel(agent) {
//agent.add(`Item selected`);
app.intent('actions.intent.OPTION', (conv, params, option) => {
let response = 'You did not select any item from the list or carousel';
if (option && SELECTED_ITEM_RESPONSES.hasOwnProperty(option)) {
response = SELECTED_ITEM_RESPONSES[option];
} else {
response = 'You selected an unknown item from the list or carousel';
}
conv.ask(response);
});
}
If I leave the agent.add() line in, then I get "Item selected"... but if I try to use the app.intent code, it says I'm just getting an empty speech response.
I was trying to create 1 intent called CarouselHandler to process all the menu selections. I used the sample code to call the carousel() function when that intent gets hit by the event.
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('CarouselHandler', carousel);
agent.handleRequest(intentMap);
回答1:
You have several questions in here about using options. Let's try to clear a few things up.
Can I get a different Intent triggered for each option?
No. The way options are reported to Dialogflow is that all options will trigger the same Intent. You're responsible for looking at the option string sent and calling another function if you wish.
As you've noted, you need to create an Intent with the Event actions_intent_OPTION
.
Your code to handle this might look something like this, although there are other ways to handle it:
app.intent('list.reply.click', (conv, params, option) => {
// Get the user's selection
// Compare the user's selections to each of the item's keys
if (!option) {
conv.ask('You did not select any item from the list or carousel');
} else if (option === 'OPTION_1') {
handleOption1( conv );
} else if (option === 'OPTION_2') {
handleOption2Or3( conv );
} else if (option === 'OPTION_3') {
handleOption2Or3( conv );
} else {
conv.ask('You selected an unknown item from the list, or carousel');
}
});
Can I get a different Intent triggered for each carousel?
Yes. To do this, when you send the carousel you will set an OutgoingContext and delete any other OutgoingContexts you created for a carousel (set their lifespan to 0). Then you will create an Intent that has this Context as an IncomingContext.
The code to send a carousel might look something like this if you're using the actions-on-google library
conv.ask("Here is menu 2");
conv.ask(new List({
title: "Menu 2",
items: {
"OPTION_1": {
title: "Option 1",
description: "Description 1"
},
"OPTION_2": {
title: "Option 2",
description: "Description 2"
},
"OPTION_3": {
title: "Option 3",
description: "Description 3"
},
}
});
conv.contexts.set("menu_2",99);
conv.contexts.delete("menu_1");
conv.contexts.delete("menu_3");
// Don't forget to add suggestions, too
If you're using the dialogflow-fulfillment library, it would be similar, although there are a few differences:
let conv = agent.conv();
conv.ask("Here is menu 2");
conv.ask(new List({
title: "Menu 2",
items: {
"OPTION_1": {
title: "Option 1",
description: "Description 1"
},
"OPTION_2": {
title: "Option 2",
description: "Description 2"
},
"OPTION_3": {
title: "Option 3",
description: "Description 3"
},
}
});
agent.add(conv);
agent.setContext({name:"menu_1", lifespan:0});
agent.setContext({name:"menu_2", lifespan:99});
agent.setContext({name:"menu_3", lifespan:0});
If you were using multivocal, the response configuration might look something like this:
{
Template: {
Text: "Here is menu 2",
Option: {
Type: "carousel",
Title: "Menu 2",
Items: [
{
Title: "Option 1",
Body: "Description 1"
},
{
Title: "Option 2",
Body: "Description 2"
},
{
Title: "Option 3",
Body: "Description 3"
}
]
}
},
Context: [
{
name: "menu_1",
lifetime: 0
},
{
name: "menu_2",
lifetime: 99
},
{
name: "menu_3",
lifetime: 0
}
]
}
The Intent that would capture this option suggestion might look something like this:
Your code to handle this would be similar as above, except using the different Intent name.
If there are overlapping options between the handlers, they could call the same function that actually does the work (again, as illustrated above).
How can I handle voice and option responses the same way?
AoG, in some cases, will use the voice response to trigger the option. This is what the aliases are for. But even beyond this, if you have Intents that catch phrases from the user and an Intent that works with the Options, all you need to do is have the fulfillment code call the same function.
Why doesn't the code work?
The line
app.intent('actions.intent.OPTION', (conv, params, option) => {
Probably doesn't do what you think it does. Unless this is the name for the Intent in Dialogflow, the string actions.intent.OPTION
won't be seen in your handler. It is also how you register an Intent handler with the actions-on-google library.
It also looks like you're mixing the dialogflow-fulfillment library way of registering Intent handlers with the actions-on-google library way of registering Intent handlers through your carousel()
function. Don't do this. (This may also be part of the cause about why replies aren't getting back correctly.)
来源:https://stackoverflow.com/questions/53486518/actions-on-google-handling-carousel-responses-from-dialogflow