在许多在线服务中,常见问题解答(FAQ)页面是必不可少的。这些页面通常包含一系列问题和答案,以及内部链接和搜索框。但如何让这些FAQ页面更加有趣和互动呢?一个解决方案是将FAQ转化为聊天机器人。
微软推出了一个名为QnA Maker的产品,它可以将任何FAQ转化为聊天机器人。将FAQ转化为聊天机器人非常简单,只需遵循以下简单步骤。
首先,如果没有账户,请创建一个账户,并按照常规注册流程进行。登录后,用户将被带到主页面。
点击“创建新服务”按钮。为服务提供名称,如果有一个基于互联网的网站,可以提供FAQ页面的URL,QnAMaker将从中提取问题和答案。
也可以在Word文档中提供问题和答案,格式如下:
问题1:如何操作?
答案1:请按照以下步骤操作。
问题2:如何获取帮助?
答案2:请联系客户服务。
或者,可以在下一步中手动提供问题和答案。
点击“创建服务”继续。服务创建后,知识库屏幕将列出从上一步提取的所有问题和答案。如果没有提取到某些内容,可以通过点击右上角的“添加新的QnA对”手动添加。
添加完所有问题和答案后,可以通过点击右侧的“测试”菜单来测试聊天机器人。在聊天文本框中输入,可以看到聊天机器人如何回答问题。如果聊天机器人识别出多个问题的答案,可以从左侧选项中选择适当的答案。点击“保存并重新训练”来训练聊天机器人。
训练完成后,点击发布以完成整个过程。示例HTTP请求如下,请求以JSON格式发送。
{
"question": ""
}
可以通过创建ASP.NET MVC应用程序来创建一个消费者应用程序。在HomeController.cs文件中,创建一个名为“Chat”的方法。
[ValidateInput(false)]
public string Chat(string query)
{
string responseString = string.Empty;
var knowledgebaseId = "";
// 使用创建的知识库ID。
var qnamakerSubscriptionKey = "";
// 使用分配给订阅密钥。
// 构建URI
Uri qnamakerUriBase = new Uri("https://westus.api.cognitive.microsoft.com/qnamaker/v1.0");
var builder = new UriBuilder("https://westus.api.cognitive.microsoft.com/qnamaker/v1.0/knowledgebases/" + knowledgebaseId + "/generateAnswer");
// 将问题作为正文的一部分
var postBody = "{\"question\": \"" + query + "\"}";
// 发送POST请求
using (WebClient client = new WebClient())
{
// 设置编码为UTF8
client.Encoding = System.Text.Encoding.UTF8;
// 添加订阅密钥头
client.Headers.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);
client.Headers.Add("Content-Type", "application/json");
responseString = client.UploadString(builder.Uri, postBody);
var response = JsonConvert.DeserializeObject<QnAMakerResult>(responseString);
if (response.Score > 10.0)
{
return response.Answer;
}
else
{
return "对不起,没有答案。请发送邮件至admin@application.com";
}
}
}
在客户端,可以使用knockout.js脚本来调用控制器端点,并将结果绑定到HTML上。
function AppViewModel() {
var self = this;
self.people = ko.observableArray([]);
self.searchKeyUp = function(d, e) {
if (e.keyCode == 13) {
addPerson();
}
};
self.addPerson = function() {
addPerson();
};
function addPerson() {
var q = $("#btn-input").val();
if (q != "") {
$("#btn-input").val("");
self.people.push({ Name: "You - ", Query: q });
$.ajax({
type: "GET",
url: '@Url.Action("Chat", "Home")',
contentType: "application/json; charset=utf-8",
data: { query: q },
dataType: "json",
success: function(data) {
console.log(data.replace(/\ /g, ' '));
data = data.replace(/\</g, '<').replace(/\>/g, '>');
self.people.push({ Name: "Smarty - ", Query: data });
},
error: function() { alert('Error'); }
});
}
}
}
ko.applyBindings(new AppViewModel());
<div class="row">
<div class="col-md-offset-7 col-md-5">
<div class="panel panel-default">
<div class="panel-heading" id="accordion">
<div class="input-group">
<input id="btn-input" type="text" data-bind="event: { keyup: searchKeyUp }" class="form-control input-sm" placeholder="在这里输入消息..." vk_18c1e="subscribed" style="direction: ltr;" />
<span class="input-group-btn">
<button class="btn btn-default btn-sm" id="btn-chat" data-bind="click: addPerson">
<i class="fa fa-paper-plane" aria-hidden="true"></i>
</button>
</span>
</div>
</div>
<div class="panel-collapse collapse in" id="collapseOne">
<div class="panel-body">
<ul class="chat" style="font-size:11px">
<li class="left clearfix" data-bind="foreach:people">
<div class="chat-body clearfix" style="padding:10px">
<div class="header">
<strong class="pull-left primary-font" style="margin-right:8px" data-bind="text:Name"></strong>
</div>
<div style="padding-left:2px" data-bind="bindHTML:Query"></div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
ko.bindingHandlers.bindHTML = {
init: function() {
// 防止在动态注入的HTML上进行绑定(因为开发者不太可能期望这样做,而且有安全风险)
return {
'controlsDescendantBindings': true
};
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// setHtml将需要时解包值
ko.utils.setHtml(element, valueAccessor());
var elementsToAdd = element.children;
for (var i = 0; i < elementsToAdd.length; i++) {
ko.cleanNode(elementsToAdd[i]);
// 清理节点上的Knockout绑定
ko.applyBindings(bindingContext, elementsToAdd[i]);
}
}
};