[英]Handling Adaptive cards in Microsoft Bot Framework v4 - Nodejs
return new Promise((resolve, reject) => {
x = context.sendActivity({
text: 'hi',
attachments: [CardFactory.adaptiveCard(menuJson)]
})
I am trying to send an adaptive card, which contains a Input.text field in it...Now my question is how to get the input data from the user in my program using a context object ?我正在尝试发送一个自适应卡,其中包含一个 Input.text 字段......现在我的问题是如何使用上下文对象从我的程序中的用户获取输入数据?
ie How to Handle adaptive cards in bot framework v4 using node js ?即如何使用 node js 在 bot framework v4 中处理自适应卡?
Adaptive Cards send their Submit results a little different than regular user text.自适应卡片发送的提交结果与常规用户文本略有不同。 When a user types in the chat and sends a normal message, it ends up in
context.activity.text
.当用户输入聊天内容并发送一条普通消息时,它最终会出现在
context.activity.text
。 When a user fills out an input on an Adaptive Card, it ends up in context.activity.value
, which is an object where the key names are the id
in your menuJson
and the values are the field values in the adaptive card.当用户在自适应卡片上填写输入时,它最终会出现在
context.activity.value
,这是一个对象,其中键名是menuJson
中的id
,值是自适应卡片中的字段值。
For example, the json:例如,json:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Test Adaptive Card"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "Text:"
}
],
"width": 20
},
{
"type": "Column",
"items": [
{
"type": "Input.Text",
"id": "userText",
"placeholder": "Enter Some Text"
}
],
"width": 80
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
.. creates a card that looks like: .. 创建一张如下所示的卡片:
If a user enters "Testing Testing 123" in the text box and hits Submit, context.activity
will look something like:如果用户在文本框中输入“Testing Testing 123”并点击提交,
context.activity
将类似于:
{ type: 'message',
value: { userText: 'Testing Testing 123' },
from: { id: 'xxxxxxxx-05d4-478a-9daa-9b18c79bb66b', name: 'User' },
locale: '',
channelData: { postback: true },
channelId: 'emulator',
conversation: { id: 'xxxxxxxx-182b-11e9-be61-091ac0e3a4ac|livechat' },
id: 'xxxxxxxx-182b-11e9-ad8e-63b45e3ebfa7',
localTimestamp: 2019-01-14T18:39:21.000Z,
recipient: { id: '1', name: 'Bot', role: 'bot' },
timestamp: 2019-01-14T18:39:21.773Z,
serviceUrl: 'http://localhost:58453' }
The user submission can be seen in context.activity.value.userText
.用户提交可以在
context.activity.value.userText
看到。
Note that adaptive card submissions are sent as a postBack, which means that the submission data doesn't appear in the chat window as part of the conversation--it stays on the Adaptive Card.请注意,自适应卡片提交作为回发发送,这意味着提交数据不会作为对话的一部分出现在聊天窗口中——它保留在自适应卡片上。
Using Adaptive Cards with Waterfall Dialogs在瀑布对话框中使用自适应卡片
Your question doesn't quite relate to this, but since you may end up attempting this, I thought it might be important to include in my answer.您的问题与此不太相关,但由于您最终可能会尝试这样做,因此我认为将其包含在我的答案中可能很重要。
Natively, Adaptive Cards don't work like prompts.自适应卡片本身不像提示那样工作。 With a prompt, the prompt will display and wait for user input before continuing.
使用提示,提示将显示并等待用户输入,然后再继续。 But with Adaptive Cards (even if it contains an input box and a submit button), there is no code in an Adaptive Card that will cause a Waterfall Dialog to wait for user input before continuing the dialog.
但是对于自适应卡片(即使它包含一个输入框和一个提交按钮),自适应卡片中没有代码会导致瀑布对话框在继续对话框之前等待用户输入。
So, if you're using an Adaptive Card that takes user input, you generally want to handle whatever the user submits outside of the context of a Waterfall Dialog.因此,如果您使用的是接受用户输入的自适应卡片,您通常希望处理用户在瀑布对话框上下文之外提交的任何内容。
That being said, if you want to use an Adaptive Card as part of a Waterfall Dialog, there is a workaround.话虽如此,如果您想将自适应卡片用作瀑布对话框的一部分,则有一种解决方法。 Basically, you:
基本上,您:
In your Waterfall Dialog file (steps 1 and 2):在您的瀑布对话框文件中(步骤 1 和 2):
async displayCard(step) {
// Display the Adaptive Card
await step.context.sendActivity({
text: 'Adaptive Card',
attachments: [yourAdaptiveCard],
});
// Display a Text Prompt
return await step.prompt('textPrompt', 'waiting for user input...');
}
async handleResponse(step) {
// Do something with step.result
// Adaptive Card submissions are objects, so you likely need to JSON.parse(step.result)
...
return await step.next();
In your bot.ts
file (step 3):在您的
bot.ts
文件中(第 3 步):
const activity = dc.context.activity;
if (!activity.text && activity.value) {
activity.text = JSON.stringify(activity.value);
}
I'm using Adaptive Card in a ComponentDialog with WaterfallDialog, I want to handle Input.submit action.我在带有 WaterfallDialog 的 ComponentDialog 中使用 Adaptive Card,我想处理 Input.submit 操作。
My problem is: How to handle the response, get the input value, and go to next dialog step correctly?我的问题是:如何处理响应、获取输入值并正确转到下一个对话步骤?
I try 2 ways to resolve my problem.我尝试了 2 种方法来解决我的问题。
My adaptive card's json like:我的自适应卡的 json 像:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Create Schedule",
"size": "large",
"weight": "bolder"
},
{
"type": "TextBlock",
"text": "Name",
"size": "small"
},
{
"type": "Input.Text",
"id": "name"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Save",
"data": {
"result": "save"
}
},
{
"type": "Action.Submit",
"title": "Cancel",
"data": {
"result": "cancel"
}
}
]
}
1. Using prompt and prompt validate 1.使用提示和提示验证
This way uses prompt validate function to handle Input.submit postback action.这种方式使用提示验证功能来处理 Input.submit 回发操作。
Because postback action doesn't send a text message (not show in channel), that makes TextPrompt's default validate can't pass (send retryPrompt), so I write a prompt validate function and validate response is postback action.因为postback action不发送短信(不显示在channel中),这使得TextPrompt的默认validate无法通过(发送retryPrompt),所以我写了一个提示validate函数,validate响应是postback action。
class MyDialog extends ComponentDialog{
constructor(dialogId) {
// ...
this.addDialog(new TextPrompt('textPropmt', this.promptValidator);
this.addDialog(new WaterfallDailog(dialogId, [
// dialog steps
async function(step){
await step.context.sendActivity({
attachments: [CardFactory.adaptiveCard(FormCard)]
})
await step.prompt('TextPrompt', 'waiting for your submit.')
},
async function(step){
await step.context.sendActivity('get response.');
// get adaptive card input value
const resultValue = step.context.activity.value;
return await step.endDialog();
}
]));
}
// prompt validate function
async promptValidator(promptContext){
const activity = promptContext.context.activity;
return activity.type === 'message' && activity.channelData.postback;
}
// ..
}
2. Using Dialog.EndOfTurn 2. 使用 Dialog.EndOfTurn
This way uses Dialog.EndOfTurn to end turn.这种方式使用 Dialog.EndOfTurn 来结束转弯。 If user sends any response, the bot will go to next dialog step.
如果用户发送任何响应,机器人将进入下一个对话步骤。
Please remember to check if the response is adaptive card submit action (postback), if not, do something to reject it or retry.请记住检查响应是否为自适应卡片提交操作(回发),如果不是,请执行某些操作以拒绝它或重试。
class MyDialog extends ComponentDialog{
constructor(dialogId) {
// ...
this.addDialog(new WaterfallDialog(dialogId, [
// dialog steps
async function(step) {
await step.context.sendActivity({
attachments: [CardFactory.adaptiveCard(FormCard)]
});
return Dialog.EndOfTurn;
},
async function(step) {
await step.context.sendActivity('get response.');
const activity = step.context.activity;
if (activity.channelData.postback) {
// get adaptive card input value
const resultValue = activity.value;
} else {
await step.context.sendActivity("Sorry, I don't understand.");
}
return await step.endDialog();
}
]));
}
// ...
}
In the end, I would choose the second way (Dialog.EndOfTurn) to solve the problem, because I think it is easier to control the dialog step and handle user interrupt, for example, when user wants to cancel this action and return to main dialog.最后,我会选择第二种方式(Dialog.EndOfTurn)来解决这个问题,因为我认为控制对话步骤和处理用户中断更容易,例如当用户想要取消这个动作并返回到main时对话。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.