在机器人内部,我们有一个自适应卡,用户可以选择是或否。在选择是时,提示用户输入关键字。用户在自适应卡中的文本块中输入输入后,必须捕获输入并将其作为输入参数发送到Web api。但是,在给出输入后,由于可能存在输入文本的同义词,因此我们将不得不应用luis。在下面的代码中,关键字variable指的是用户给定的输入文本,必须对其应用LUIS。
private async Task CustomisePPT(IDialogContext context, IAwaitable<object> result)
{
try
{
var replyMessage = context.MakeMessage();
var newMessage = context.Activity.AsMessageActivity();
var userMessage = newMessage.Value;
var take=userMessage.ToString().Substring(userMessage.ToString().IndexOf("GetUserInputKeywords"));
var split = take.ToString().Substring("GetUserInputKeywords".Length+2);
string keywords = split.Trim();
keywords = keywords.Substring(1, keywords.Length - 5);
using (HttpClient client = new HttpClient())
{
// api takes the user message as a query paramater
string RequestURI = "https://xyz" + ***keywords***;
HttpResponseMessage responsemMsg = await client.GetAsync(RequestURI);
// TODO: handle fail case
if (responsemMsg.IsSuccessStatusCode)
{
var apiResponse = await responsemMsg.Content.ReadAsStringAsync();
}
}
}
catch (Exception ex)
{
}
//throw new NotImplementedException();
await Task.CompletedTask;
}
答案 0 :(得分:1)
这实际上只是一个api调用,应该对其进行配置。
首先,您应该将Luis配置添加到.bot
文件中。
{
"name": "LuisBot",
"description": "",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "166"
},
{
"type": "luis",
"name": "LuisBot",
"appId": "<luis appid>",
"version": "0.1",
"authoringKey": "<luis authoring key>",
"subscriptionKey": "<luis subscription key>",
"region": "<luis region>",
"id": "158"
}
],
"padlock": "",
"version": "2.0"
}
接下来,我们在BotService
中初始化BotServices.cs
类的新实例,该实例从您的.bot文件中获取上述信息。外部服务使用BotConfiguration
类进行配置。
public class BotServices
{
// Initializes a new instance of the BotServices class
public BotServices(BotConfiguration botConfiguration)
{
foreach (var service in botConfiguration.Services)
{
switch (service.Type)
{
case ServiceTypes.Luis:
{
var luis = (LuisService)service;
if (luis == null)
{
throw new InvalidOperationException("The LUIS service is not configured correctly in your '.bot' file.");
}
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, luis.GetEndpoint());
var recognizer = new LuisRecognizer(app);
this.LuisServices.Add(luis.Name, recognizer);
break;
}
}
}
}
// Gets the set of LUIS Services used. LuisServices is represented as a dictionary.
public Dictionary<string, LuisRecognizer> LuisServices { get; } = new Dictionary<string, LuisRecognizer>();
}
接下来,使用Startup.cs
方法中的以下代码在ConfigureServices
文件中将LUIS应用注册为单例。
// Initialize Bot Connected Services clients.
var connectedServices = new BotServices(botConfig);
services.AddSingleton(sp => connectedServices);
services.AddSingleton(sp => botConfig);
在.bot
类中插入Bot.cs
文件中配置的服务:
public class LuisBot : IBot
{
// Services configured from the ".bot" file.
private readonly BotServices _services;
// Initializes a new instance of the LuisBot class.
public LuisBot(BotServices services)
{
_services = services ?? throw new System.ArgumentNullException(nameof(services));
if (!_services.LuisServices.ContainsKey(LuisKey))
{
throw new System.ArgumentException($"Invalid configuration....");
}
}
}
adaptivecard
的输入可以作为adaptivecard
捕获在Action.Submit
的动作数组中,如下所示:
"type": "Action.Submit"
现在,您可以真正进行Luis api调用了。可以在班级中任何需要的地方进行此调用,这会注入Luis服务:
var recognizerResult = await _services.LuisServices[LuisKey].RecognizeAsync(turnContext, cancellationToken);
此代码段摘自MS Docs here
答案 1 :(得分:1)
@Taher的答案将帮助您集成LUIS。这将帮助您将其与自适应卡一起使用。
自适应卡发送的“提交”结果与常规用户文本略有不同。当用户键入聊天并发送普通消息时,它最终以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”,然后单击Submit,则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
中看到用户提交的内容。
请注意,自适应卡的提交是作为postBack发送的(在Context.Activity.ChannelData
中可见),这意味着提交数据不会在对话的一部分中显示在聊天窗口中,而是保留在自适应卡上
将自适应卡与Waterfall Dialogs 一起使用
您的问题并不完全与此相关,但是由于您可能最终尝试这样做,因此我认为将其包含在答案中可能很重要。
从本质上讲,自适应卡不能像提示一样工作。带有提示,提示将显示并等待用户输入,然后继续。但是对于自适应卡(即使其中包含一个输入框和一个提交按钮),自适应卡中也没有代码,该代码将导致瀑布对话框在继续对话框之前先等待用户输入。
因此,如果您使用的是接受用户输入的自适应卡,则通常要处理用户在“瀑布对话框”上下文之外提交的所有内容。
话虽如此,如果您想在瀑布对话框中使用自适应卡,则有一种解决方法。基本上,您:
在“瀑布对话框”类中(步骤1和2):
private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var adaptiveCardJson = File.ReadAllText(Path.Combine(".", "AdaptiveCard.json"));
var cardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
var cardReply = stepContext.Context.Activity.CreateReply();
cardReply.Attachments = new List<Attachment>() { cardAttachment };
// Display the Adaptive Card
await stepContext.Context.SendActivityAsync(cardReply);
var opts = new PromptOptions
{
Prompt = new Activity
{
Type = ActivityTypes.Message,
Text = "waiting for user input...",
}
};
// Display a Text Prompt and wait for input
return await stepContext.PromptAsync(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();
}
在您的主要机器人课程(<your-bot>.cs
)中(步骤3):
if (activity.Type == ActivityTypes.Message)
{
// Ensure that message is a postBack (like a submission from Adaptive Cards
var channelData = JObject.Parse(dc.Context.Activity.ChannelData.ToString());
if (channelData != null && channelData.ContainsKey("postback"))
{
var postbackActivity = dc.Context.Activity;
// Convert the user's Adaptive Card input into the input of a Text Prompt
// Must be sent as a string
postbackActivity.Text = postbackActivity.Value.ToString();
await dc.Context.SendActivityAsync(postbackActivity);
}
}
您可以在HandleResponseAsync()
中将其与LUIS集成(如果您不太在乎确切的用户输入是否以Step.Result
结尾,也可以在{{1 }}块(如果要在将用户输入发送到对话框的下一步之前更改用户输入。