如何将自适应卡中的用户输入检索到 C# 代码以及如何在提交按钮单击时调用下一个意图
How to retrieve user entered input in adaptive card to the c# code and how to call next intent on submit button click
我有一个日期选择器自适应卡,我在意向调用期间调用它。
我不知道如何获取用户输入的值并将其传递给我的 bot luis,在那里我将有一个意图将被这些值触发
我已尝试解析自适应卡 json,但我想要更新后的 json,其中包含用户在单击提交按钮时输入的值。
private Attachment CreateAdaptiveCardAttachment()
{
// combine path for cross platform support
string[] paths = { ".", "Cards", "AddingLeaveDetails.json" };
string fullPath = Path.Combine(paths);
var adaptiveCard = File.ReadAllText(fullPath);
return new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCard),
};
}
private Activity CreateResponse(IActivity activity, Attachment attachment)
{
var response = ((Activity)activity).CreateReply();
response.Attachments = new List<Attachment>() { attachmen`enter code here`t };
return response;
}
@NikhilBansal,您可以跳过此答案的 "Waterfall Dialog" 部分(更多内容是为了后代),然后转到 "Capture User Input" 部分。阅读 "Additional Context" 和 "Additional Resources" 链接也可能会有所帮助。
将自适应卡片与 Waterfall Dialogs
一起使用
自适应卡片本身不像提示那样工作。有了提示,提示将显示并等待用户输入,然后再继续。但是对于自适应卡片(即使它包含一个输入框和一个提交按钮),自适应卡片中没有代码会导致瀑布对话框在继续对话框之前等待用户输入。
因此,如果您使用的是接受用户输入的自适应卡片,您通常希望处理用户在 Waterfall Dialog 上下文之外提交的任何内容。
也就是说,如果您想将自适应卡片用作瀑布对话框的一部分,则有一个解决方法。基本上,你:
- 显示自适应卡片
- 显示文本提示
- 将用户的自适应卡片输入转换为文本提示的输入
在瀑布对话框中 class(步骤 1 和 2):
private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Display the Adaptive Card
var cardPath = Path.Combine(".", "AdaptiveCard.json");
var cardJson = File.ReadAllText(cardPath);
var cardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(cardJson),
};
var message = MessageFactory.Text("");
message.Attachments = new List<Attachment>() { cardAttachment };
await stepContext.Context.SendActivityAsync(message, cancellationToken);
// Create the text prompt
var opts = new PromptOptions
{
Prompt = new Activity
{
Type = ActivityTypes.Message,
Text = "waiting for user input...", // You can comment this out if you don't want to display any text. Still works.
}
};
// Display a Text Prompt and wait for input
return await stepContext.PromptAsync(nameof(TextPrompt), opts);
}
private async Task<DialogTurnResult> HandleResponseAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Do something with step.result
// Adaptive Card submissions are objects, so you likely need to JObject.Parse(step.result)
await stepContext.Context.SendActivityAsync($"INPUT: {stepContext.Result}");
return await stepContext.NextAsync();
}
捕获用户输入
在您的主机器人 class (<your-bot>.cs
) 中,在 OnTurnAsync()
下,靠近方法开始处,在调用 await dialogContext.ContinueDialogAsync(cancellationToken)
之前的某处(第 3 步):
var activity = turnContext.Activity;
if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
activity.Text = JsonConvert.SerializeObject(activity.Value);
}
更新:对于您的代码,具体而言,您需要在将其发送到您的识别器之前直接修改 turnContext
。由于 RecognizeAsync
不适用于对象,我们需要确保发送适当的值。类似于:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
// Capture input from adaptive card
if (string.IsNullOrEmpty(turnContext.Activity.Text) && turnContext.Activity.Value != null)
{
// Conditionally convert based off of input ID of Adaptive Card
if ((turnContext.Activity.Value as JObject)["<adaptiveCardInputId>"] != null)
{
turnContext.Activity.Text = (turnContext.Activity.Value as JObject)["<adaptiveCardInputId>"].ToString();
}
}
// First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);
// Top intent tell us which cognitive service to use.
var topIntent = recognizerResult.GetTopScoringIntent();
// Next, we call the dispatcher with the top intent.
await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
}
上面两块代码不起作用的原因只是因为它没有为您的代码设置。 RecognizeAsync
查看 turnContext.Activity.Text
,这对于自适应卡来说是空的(因为自适应卡输入 Activity.Value
。因此,这个新代码将 turnContext.Activity.Text
设置为 turnContext.Activity.Value
. 然而,要将它发送到识别器,你需要它是一个字符串而不是一个对象,所以一定要将 <adaptiveCardInputId>
更改为你的自适应卡上的任何 ID。
其他上下文
自适应卡片发送的提交结果与常规用户文本略有不同。当用户输入聊天内容并发送一条普通消息时,它会以 Context.Activity.Text
结尾。当用户在自适应卡片上填写输入时,它以 Context.Activity.Value
结束,这是一个对象,其中键名称是卡片中的 id
,值是自适应卡片中的字段值卡片。
例如,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"
}
.. 创建一张如下所示的卡片:
如果用户在文本框中输入 "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' }
用户提交可见Context.Activity.Value.userText
。
请注意,自适应卡片提交是作为回发发送的,这意味着提交数据不会作为对话的一部分出现在聊天 window 中——它保留在自适应卡片上。
其他资源
- Blog Post on Using Adaptive Cards
AdaptiveCardPrompt
- 这可能会在某天添加到 SDK 中。同时也可以作为开发参考
我有一个日期选择器自适应卡,我在意向调用期间调用它。 我不知道如何获取用户输入的值并将其传递给我的 bot luis,在那里我将有一个意图将被这些值触发
我已尝试解析自适应卡 json,但我想要更新后的 json,其中包含用户在单击提交按钮时输入的值。
private Attachment CreateAdaptiveCardAttachment()
{
// combine path for cross platform support
string[] paths = { ".", "Cards", "AddingLeaveDetails.json" };
string fullPath = Path.Combine(paths);
var adaptiveCard = File.ReadAllText(fullPath);
return new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCard),
};
}
private Activity CreateResponse(IActivity activity, Attachment attachment)
{
var response = ((Activity)activity).CreateReply();
response.Attachments = new List<Attachment>() { attachmen`enter code here`t };
return response;
}
@NikhilBansal,您可以跳过此答案的 "Waterfall Dialog" 部分(更多内容是为了后代),然后转到 "Capture User Input" 部分。阅读 "Additional Context" 和 "Additional Resources" 链接也可能会有所帮助。
将自适应卡片与 Waterfall Dialogs
一起使用自适应卡片本身不像提示那样工作。有了提示,提示将显示并等待用户输入,然后再继续。但是对于自适应卡片(即使它包含一个输入框和一个提交按钮),自适应卡片中没有代码会导致瀑布对话框在继续对话框之前等待用户输入。
因此,如果您使用的是接受用户输入的自适应卡片,您通常希望处理用户在 Waterfall Dialog 上下文之外提交的任何内容。
也就是说,如果您想将自适应卡片用作瀑布对话框的一部分,则有一个解决方法。基本上,你:
- 显示自适应卡片
- 显示文本提示
- 将用户的自适应卡片输入转换为文本提示的输入
在瀑布对话框中 class(步骤 1 和 2):
private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Display the Adaptive Card
var cardPath = Path.Combine(".", "AdaptiveCard.json");
var cardJson = File.ReadAllText(cardPath);
var cardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(cardJson),
};
var message = MessageFactory.Text("");
message.Attachments = new List<Attachment>() { cardAttachment };
await stepContext.Context.SendActivityAsync(message, cancellationToken);
// Create the text prompt
var opts = new PromptOptions
{
Prompt = new Activity
{
Type = ActivityTypes.Message,
Text = "waiting for user input...", // You can comment this out if you don't want to display any text. Still works.
}
};
// Display a Text Prompt and wait for input
return await stepContext.PromptAsync(nameof(TextPrompt), opts);
}
private async Task<DialogTurnResult> HandleResponseAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Do something with step.result
// Adaptive Card submissions are objects, so you likely need to JObject.Parse(step.result)
await stepContext.Context.SendActivityAsync($"INPUT: {stepContext.Result}");
return await stepContext.NextAsync();
}
捕获用户输入
在您的主机器人 class (<your-bot>.cs
) 中,在 OnTurnAsync()
下,靠近方法开始处,在调用 await dialogContext.ContinueDialogAsync(cancellationToken)
之前的某处(第 3 步):
var activity = turnContext.Activity;
if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
activity.Text = JsonConvert.SerializeObject(activity.Value);
}
更新:对于您的代码,具体而言,您需要在将其发送到您的识别器之前直接修改 turnContext
。由于 RecognizeAsync
不适用于对象,我们需要确保发送适当的值。类似于:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
// Capture input from adaptive card
if (string.IsNullOrEmpty(turnContext.Activity.Text) && turnContext.Activity.Value != null)
{
// Conditionally convert based off of input ID of Adaptive Card
if ((turnContext.Activity.Value as JObject)["<adaptiveCardInputId>"] != null)
{
turnContext.Activity.Text = (turnContext.Activity.Value as JObject)["<adaptiveCardInputId>"].ToString();
}
}
// First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);
// Top intent tell us which cognitive service to use.
var topIntent = recognizerResult.GetTopScoringIntent();
// Next, we call the dispatcher with the top intent.
await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
}
上面两块代码不起作用的原因只是因为它没有为您的代码设置。 RecognizeAsync
查看 turnContext.Activity.Text
,这对于自适应卡来说是空的(因为自适应卡输入 Activity.Value
。因此,这个新代码将 turnContext.Activity.Text
设置为 turnContext.Activity.Value
. 然而,要将它发送到识别器,你需要它是一个字符串而不是一个对象,所以一定要将 <adaptiveCardInputId>
更改为你的自适应卡上的任何 ID。
其他上下文
自适应卡片发送的提交结果与常规用户文本略有不同。当用户输入聊天内容并发送一条普通消息时,它会以 Context.Activity.Text
结尾。当用户在自适应卡片上填写输入时,它以 Context.Activity.Value
结束,这是一个对象,其中键名称是卡片中的 id
,值是自适应卡片中的字段值卡片。
例如,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"
}
.. 创建一张如下所示的卡片:
如果用户在文本框中输入 "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' }
用户提交可见Context.Activity.Value.userText
。
请注意,自适应卡片提交是作为回发发送的,这意味着提交数据不会作为对话的一部分出现在聊天 window 中——它保留在自适应卡片上。
其他资源
- Blog Post on Using Adaptive Cards
AdaptiveCardPrompt
- 这可能会在某天添加到 SDK 中。同时也可以作为开发参考