如何为 no.input 事件的每个意图提供自定义重新提示?
How can I provide a custom re-prompt for each intent on the event of no.input?
我正在为智能音箱创建一个问卷机器人,它会向用户询问几个问题。答案存储在 firebase 中。我正在使用 node.js、actions-on-google.
对话是这样的:
- Bot:用户好,你准备好回答问题了吗? [欢迎意图,Yes/No 跟进意图]{输出上下文 = q1}
- 用户:是
- Bot:你对 Q1 的回答是什么? [意图 q1]{输入上下文 = q1,输出上下文 = q2}
- 用户:这是我的答案。
- Bot:你对 Q2 的回答是什么? [意图 q2]{输入上下文 = q2,输出上下文 = q2}
- ...
- ...
- 用户:这是我的答案。
- 机器人:谢谢你的回答。再见
在这次对话中,如果用户没有回应(no.input),我想在fulfillment中处理。
对于 no.input,我使用的代码来自:https://developers.google.com/assistant/conversational/reprompts#dialogflow_2。我有 'No Input Prompt' 和 'action and parameters' no.input 的意图。此意图没有后续意图或任何上下文。
我的问题是:如何为 no.input 事件的每个意图提供自定义重新提示?
我正在做这样的事情:
const { dialogflow, SignIn, Confirmation } = require('actions-on-google');
const functions = require('firebase-functions');
const app = dialogflow({
debug: true
});
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'DATABASE URL',
});
const db = admin.firestore();
const db_ref = db.collection('users');
let current_context = '';
app.intent('q1', (conv, {response}) =>{
const payload = conv.user.profile.payload
db_ref.doc(`${payload.email}`).collection(today).doc('q1').set({
answer: response,
timestamp: time
});
current_context='q1';
conv.ask(question('Whats your answer for q1?'));
})
app.intent('No Input Prompt', (conv) => {
const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
if(current_context === 'q1'){
if (repromptCount === 0) {
conv.ask("What is your answer for Q1?");
} else if (repromptCount === 1) {
conv.ask("What is your answer for Q1? You can say option 1,2,3 or 4");
} else if (conv.arguments.get('IS_FINAL_REPROMPT')) {
conv.close("Lets talk some other time.");
}
}
})
使用此代码,当我模拟无输入时,出现此错误:
Failed to parse Dialogflow response into AppResponse because of
invalid platform response: Could not find a RichResponse or
SystemIntent in the platform response for agentId:
12ae4038-8f17-4005-9bfa-1691ffcde5e5 and intentId:
218605f2-e718-47e0-97f6-e1925755fa7c
您发布的代码存在三个主要问题
- 在 JavaScript 中,变量名中不能有破折号。所以
current-context
不是一个有效的变量名。
- 您将
current-context
声明为常量。顾名思义,这意味着它无法更改。然后您尝试更改它。
- 您没有指明执行环境是什么,但是如果您使用的是 Firebase Cloud Functions 之类的东西,则无法保证 "q1" Intent Handler 时您将使用同一台服务器运行s 并且当 "No Input Prompt" Intent Handler 运行s.
要绕过 (3),您需要在对任何 Intent Handler 的调用之间传递信息。在大多数情况下,您会使用 actions-on-google conv.data
storage 或 Dialogflow Context.
来执行此操作
但是,由于您要检测的 是 上下文,您可以做得更好,只需查看当前处于活动状态的上下文即可。您可以通过调用 conv.contexts.get('name')
获取上下文来查看上下文是否处于活动状态。如果它是活动的,你会得到一个结果。如果它不是活动的,它将是未定义的。
因此您的代码可能类似于
app.intent('No Input Prompt', (conv) => {
const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
if(conv.contexts.get('q1')){
if (repromptCount === 0) {
conv.ask("What is your answer for Q1?");
} else if (repromptCount === 1) {
conv.ask("What is your answer for Q1? You can say option 1,2,3 or 4");
} else if (conv.arguments.get('IS_FINAL_REPROMPT')) {
conv.close("Lets talk some other time.");
}
}
})
根据您评论中的问题更新:
Cloud Functions for Firebase 使用 "serverless" 技术,因此没有任何一台服务器始终加载您的代码并准备好执行。相反,当您向 URL 发出应该 运行 函数的请求时,Firebase 会确定它是否需要将代码的新副本启动到 运行 然后 运行是请求。如果当前 运行ning 没有副本(它可能出于某种原因将它们全部关闭)或者请求多于当前实例当前可以处理的请求,它可能会启动一个新副本。即使有副本 运行ning,您的两个单独请求也可能会发送到不同的服务器,并且它们不会共享变量实例。
每个被触发的 Intent 都会导致对 Firebase 函数的另一次调用,因此无法保证您会获得同一台服务器,即使同一台服务器一次 运行ning到下一个。
当您开始获得多个用户时,不使用全局变量也很重要。如果您使用的是全局变量,那么两个用户同时说话可能会相互重叠,因此您为一个用户保存的内容可能会被另一个用户使用。
这就是为什么除了使用变量之外,还必须以某种方式保存在 Intent Handler 调用之间您想记住的任何内容。
我正在为智能音箱创建一个问卷机器人,它会向用户询问几个问题。答案存储在 firebase 中。我正在使用 node.js、actions-on-google.
对话是这样的:
- Bot:用户好,你准备好回答问题了吗? [欢迎意图,Yes/No 跟进意图]{输出上下文 = q1}
- 用户:是
- Bot:你对 Q1 的回答是什么? [意图 q1]{输入上下文 = q1,输出上下文 = q2}
- 用户:这是我的答案。
- Bot:你对 Q2 的回答是什么? [意图 q2]{输入上下文 = q2,输出上下文 = q2}
- ...
- ...
- 用户:这是我的答案。
- 机器人:谢谢你的回答。再见
在这次对话中,如果用户没有回应(no.input),我想在fulfillment中处理。
对于 no.input,我使用的代码来自:https://developers.google.com/assistant/conversational/reprompts#dialogflow_2。我有 'No Input Prompt' 和 'action and parameters' no.input 的意图。此意图没有后续意图或任何上下文。
我的问题是:如何为 no.input 事件的每个意图提供自定义重新提示?
我正在做这样的事情:
const { dialogflow, SignIn, Confirmation } = require('actions-on-google');
const functions = require('firebase-functions');
const app = dialogflow({
debug: true
});
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'DATABASE URL',
});
const db = admin.firestore();
const db_ref = db.collection('users');
let current_context = '';
app.intent('q1', (conv, {response}) =>{
const payload = conv.user.profile.payload
db_ref.doc(`${payload.email}`).collection(today).doc('q1').set({
answer: response,
timestamp: time
});
current_context='q1';
conv.ask(question('Whats your answer for q1?'));
})
app.intent('No Input Prompt', (conv) => {
const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
if(current_context === 'q1'){
if (repromptCount === 0) {
conv.ask("What is your answer for Q1?");
} else if (repromptCount === 1) {
conv.ask("What is your answer for Q1? You can say option 1,2,3 or 4");
} else if (conv.arguments.get('IS_FINAL_REPROMPT')) {
conv.close("Lets talk some other time.");
}
}
})
使用此代码,当我模拟无输入时,出现此错误:
Failed to parse Dialogflow response into AppResponse because of invalid platform response: Could not find a RichResponse or SystemIntent in the platform response for agentId: 12ae4038-8f17-4005-9bfa-1691ffcde5e5 and intentId: 218605f2-e718-47e0-97f6-e1925755fa7c
您发布的代码存在三个主要问题
- 在 JavaScript 中,变量名中不能有破折号。所以
current-context
不是一个有效的变量名。 - 您将
current-context
声明为常量。顾名思义,这意味着它无法更改。然后您尝试更改它。 - 您没有指明执行环境是什么,但是如果您使用的是 Firebase Cloud Functions 之类的东西,则无法保证 "q1" Intent Handler 时您将使用同一台服务器运行s 并且当 "No Input Prompt" Intent Handler 运行s.
要绕过 (3),您需要在对任何 Intent Handler 的调用之间传递信息。在大多数情况下,您会使用 actions-on-google conv.data
storage 或 Dialogflow Context.
但是,由于您要检测的 是 上下文,您可以做得更好,只需查看当前处于活动状态的上下文即可。您可以通过调用 conv.contexts.get('name')
获取上下文来查看上下文是否处于活动状态。如果它是活动的,你会得到一个结果。如果它不是活动的,它将是未定义的。
因此您的代码可能类似于
app.intent('No Input Prompt', (conv) => {
const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
if(conv.contexts.get('q1')){
if (repromptCount === 0) {
conv.ask("What is your answer for Q1?");
} else if (repromptCount === 1) {
conv.ask("What is your answer for Q1? You can say option 1,2,3 or 4");
} else if (conv.arguments.get('IS_FINAL_REPROMPT')) {
conv.close("Lets talk some other time.");
}
}
})
根据您评论中的问题更新:
Cloud Functions for Firebase 使用 "serverless" 技术,因此没有任何一台服务器始终加载您的代码并准备好执行。相反,当您向 URL 发出应该 运行 函数的请求时,Firebase 会确定它是否需要将代码的新副本启动到 运行 然后 运行是请求。如果当前 运行ning 没有副本(它可能出于某种原因将它们全部关闭)或者请求多于当前实例当前可以处理的请求,它可能会启动一个新副本。即使有副本 运行ning,您的两个单独请求也可能会发送到不同的服务器,并且它们不会共享变量实例。
每个被触发的 Intent 都会导致对 Firebase 函数的另一次调用,因此无法保证您会获得同一台服务器,即使同一台服务器一次 运行ning到下一个。
当您开始获得多个用户时,不使用全局变量也很重要。如果您使用的是全局变量,那么两个用户同时说话可能会相互重叠,因此您为一个用户保存的内容可能会被另一个用户使用。
这就是为什么除了使用变量之外,还必须以某种方式保存在 Intent Handler 调用之间您想记住的任何内容。