Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / Azure

Turn your FAQ pages into an interesting Chat Bot using QnA Maker

5.00/5 (5 votes)
10 May 2017CPOL2 min read 18.7K  
Microsoft QnA Maker helps turn your FAQ pages into interesting Chat Bot. It is very simple to configure and integrate with.

Introduction

Every website that we create be it an external marketing website or an internal back office application always will have a page which will contain the Frequently Asked Questions(FAQ). These FAQs are usually designed in a single page with the list of questions and answers with internal links and a search box. How to make this interesting?

Let us Begin

Microsoft came up with a product QnA Maker which can turn any FAQs into a chat bot. Converting FAQs into chat bot is very simple. Just follow these simple instructions.

Login to QnA Maker

Create an account, if you don’t have one and follow the usual registration process

Once you log in, the user is taken to this page

Image 1

Click on the “Create New Service” button. Provide the name for the service, if you have an internet based website, you can provide the URL of the FAQ page, the QnAMaker will extract the Questions and Answers out of it.

You can also provide the Questions and Answers in a word document, in the following format

Else, you can provide the Questions and Answers manually in the next step.

Image 2

Click “Create Service” to continue. The service is created. The Knowledge Base screen will list all the questions and answers extracted out of the previous step. If it hasn’t extracted some, you can manually add those by clicking on the “Add new QnA Pair” on the top right hand corner.

Image 3

Once you are done adding all the Questions and Answers you can test your bot by clicking on the “Test” Menu on the right hand side

Image 4

Type in the chat text box and you could see how the bot answers to your questions. If the bot identifies more than one alternatives to the question. You can select the appropriate ones from the left hand side options. Click “Save and Retrain” to train you bot.

Once the training is done, Click on Publish to complete the process.

Image 5

The sample HTTP request is shown, the request to be sent is in a JSON format.

{“question”:””}

We can create a consumer application by creating an ASP.NET MVC application. In the HomeController.cs file, Create a method “Chat

C#
[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";
        }

    }
}

In the client side, we can create a simple knockout.js script to invoke the controller endpoint and tie it to a HTML. 

JavaScript
   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());

The HTML view can be expressed 

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>

In case if the knowledge has some a tag and HTML text then create a custom binding 

JavaScript
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]);
               }
           }
       };

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)