65.9K
CodeProject 正在变化。 阅读更多。
Home

将您的 FAQ 页面变成有趣的聊天机器人(使用 QnA Maker)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2017 年 5 月 10 日

CPOL

2分钟阅读

viewsIcon

19183

Microsoft QnA Maker 帮助您将 FAQ 页面转换为有趣的聊天机器人。它配置和集成都非常简单。

引言

我们创建的每个网站,无论是外部营销网站还是内部后台应用程序,都始终会包含一个包含常见问题解答 (FAQ) 的页面。这些 FAQ 通常设计在一个页面上,包含问题和答案列表以及内部链接和搜索框。如何让它更有趣?

让我们开始

Microsoft 推出了 QnA Maker 产品,可以将任何 FAQ 转换为聊天机器人。将 FAQ 转换为聊天机器人非常简单。只需按照这些简单的步骤操作即可。

登录到 QnA Maker

如果您没有帐户,请创建一个帐户并按照常规注册流程进行操作。

登录后,用户将进入此页面

单击“创建新服务”按钮。为服务提供名称,如果您有基于互联网的网站,可以提供 FAQ 页面的 URL,QnAMaker 将从中提取问题和答案。

您也可以在 Word 文档中提供问题和答案,格式如下

或者,您可以在下一步中手动提供问题和答案。

单击“创建服务”继续。服务已创建。知识库屏幕将列出从上一步中提取的所有问题和答案。如果它没有提取一些,您可以单击右上角的“添加新的问答对”手动添加它们。

完成添加所有问题和答案后,您可以单击右侧的“测试”菜单来测试您的机器人

在聊天文本框中输入,您可以看到机器人如何回答您的问题。如果机器人识别到问题的多个替代方案,您可以从左侧选项中选择合适的选项。单击“保存并重新训练”以训练您的机器人。

训练完成后,单击“发布”完成该过程。

显示了示例 HTTP 请求,要发送的请求采用 JSON 格式。

{“question”:””}

我们可以通过创建一个 ASP.NET MVC 应用程序来创建一个消费者应用程序。在 HomeController.cs 文件中,创建一个名为“Chat”的方法

        [ValidateInput(false)]
        public string Chat(string query)
        {
            string responseString = string.Empty;
            var knowledgebaseId = ""; // Use knowledge base id created.
            var qnamakerSubscriptionKey = ""; //Use subscription key assigned to you.
            //Build the 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");

            //Add the question as part of the body
            var postBody = "{\"question\": \"" + query + "\"}";

            //Send the POST request
            using (WebClient client = new WebClient())
            {
                //Set the encoding to UTF8
                client.Encoding = System.Text.Encoding.UTF8;

                //Add the subscription key header
                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 "Sorry, I don't have an answer. Please mail 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(/\&#160;/g, ''));
                            data = data.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>');

                            self.people.push({ Name: "Smarty - ", Query: data });
                        },
                        error: function () { alert('Error'); }
                    });
                }
                
            }

        }

        ko.applyBindings(new AppViewModel());

HTML 视图可以表示为

<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="Type your message here..." 
                           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>

如果知识库中包含 a 标签和 HTML 文本,则创建一个自定义绑定

 ko.bindingHandlers.bindHTML = {
            init: function () {
                // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
                return { 'controlsDescendantBindings': true };
            },
            update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
                // setHtml will unwrap the value if needed
                ko.utils.setHtml(element, valueAccessor());
                var elementsToAdd = element.children;
                for (var i = 0; i < elementsToAdd.length; i++) {
                    ko.cleanNode(elementsToAdd[i]); //Clean node from Knockout bindings
                    ko.applyBindings(bindingContext, elementsToAdd[i]);
                }
            }
        };
© . All rights reserved.