Programmatically Updating A QnA Maker Service Using the QnA Maker API

Apr 5

Written by:
4/5/2017 4:24 AM  RssIcon

image

The QnA Maker website, allows you to quickly create a Chat Bot or Service based on your existing Frequently Asked Questions (and answers) known as a FAQ, and then query that database using natural language queries.

You can also programmatically update and train a QnA Maker service using the QnA Maker API.

image

We will start with the application created in the article: Using QnA Maker To Easily Create and Consume A Chat Bot.

image

In that article, we created a FAQ database.

image

We then have the ability to View/Edit and Deploy the FAQ database using the online web application at QnaMaker.ai.

This creates a QnA Maker Service.

image

Finally we created a ASP.NET Core web application to consume the database.

image

In this article (you can download the complete code on the downloads page of this site), we demonstrate how you can programmatically retrieve the FAQ database as a .csv file.

image

You can programmatically add to the FAQ database by entering a question and an answer and clicking the Add Entry button.

image

However, after doing so, while the item will show up when you log into the interface on the QnAMaker.ai website…

image

… it will not show up when you look at the export after clicking the Get FAQ button.

image

The reason is that you must first click the Train And Publish button to retrain the Model and Publish any changes to the FAQ database.

image

This is the equivalent to clicking the Save and retrain and Publish buttons in the web interface on the QnAMaker.ai website.

image

After clicking the Train And Publish button the additions show up in the FAQ database.

image

The same process is used to remove items from the FAQ database.

The exact question and answer to be removed are entered, and the Delete Entry button is clicked.

However, until you then click the Train And Publish button, the FAQ database will not be updated.

Programmatically Get The FAQ Database

To programmatically retrieve the FAQ database, we add a button to our View:

 

   <input name="GetFAQ" type="submit" id="GetFAQ" value="Get FAQ" />

 

We then add code to the Controller to respond to the click, to call the GetFAQ method, and to return the resulting .csv file:

 

    if (Request.Form["GetFAQ"].Count() > 0)
    {
        // The GetFAQ button was pressed
        // Call the QnA Service and get the FAQ
        var strFAQ = await GetFAQ();
        // Return the contents as a .csv file
        return File(
            new System.Text.UTF8Encoding().GetBytes(strFAQ),
            "text/csv",
            "KnowledgeBase.csv");
    }

 

This is the code for the GetFAQ method that retrieves the FAQ database:

 

       private static async Task<string> GetFAQ()
        {
            string strFAQUrl = "";
            string strLine;
            StringBuilder sb = new StringBuilder();
            // Get the URL to the FAQ (in .tsv form)
            using (System.Net.Http.HttpClient client =
                new System.Net.Http.HttpClient())
            {
                string RequestURI = String.Format("{0}{1}{2}{3}{4}",
                    @"https://westus.api.cognitive.microsoft.com/",
                    @"qnamaker/v2.0/",
                    @"knowledgebases/",
                    _KnowledgeBase,
                    @"? ");
                client.DefaultRequestHeaders.Add(
                    "Ocp-Apim-Subscription-Key", _OcpApimSubscriptionKey);
                System.Net.Http.HttpResponseMessage msg =
                    await client.GetAsync(RequestURI);
                if (msg.IsSuccessStatusCode)
                {
                    var JsonDataResponse =
                        await msg.Content.ReadAsStringAsync();
                    strFAQUrl =
                        JsonConvert.DeserializeObject<string>(JsonDataResponse);
                }
            }
            // Make a web call to get the contents of the
            // .tsv file that contains the database
            var req = WebRequest.Create(strFAQUrl);
            var r = await req.GetResponseAsync().ConfigureAwait(false);
            // Read the response
            using (var responseReader = new StreamReader(r.GetResponseStream()))
            {
                // Read through each line of the response
                while ((strLine = responseReader.ReadLine()) != null)
                {
                    // Write the contents to the StringBuilder object
                    string[] strCurrentLine = strLine.Split('\t');
                    sb.Append((String.Format("{0},{1},{2}\n",
                        CleanContent(strCurrentLine[0]),
                        CleanContent(strCurrentLine[1]),
                        CleanContent(strCurrentLine[2])
                        )));
                }
            }
            // Return the contents of the StringBuilder object
            return sb.ToString();
        }

 

Note that this method does two things.

First it makes a web call to retrieve the web URL that indicates where the FAQ database is, then it makes another web call to actually get the database as a .tsv (tab delimited) file.

Finally it converts the tab delimited file into the comma delimited (.csv) format.

 

Programmatically Add and Delete FAQ Items

In the View we add Add Entry and Delete Entry buttons:

 

    <input name="AddEntry" type="submit" id="AddEntry" value="Add Entry" />
    <input name="DeleteEntry" type="submit" id="DeleteEntry" value="Delete Entry" />

 

The following code, in the Controller, determines what Mode (Add or Delete) and calls the UpdateQueryQnABot method:

 

    else if (Request.Form["AddEntry"].Count() > 0)
    {
        // The AddEntry button was pressed
        if ((NewQuestion != null) && (NewAnswer != null))
        {
            // Call the QnA KnowledgeBase Service
            objQnAResult.Message =
                await UpdateQueryQnABot(NewQuestion, NewAnswer, Mode.Add);
        }
    }
    else if (Request.Form["DeleteEntry"].Count() > 0)
    {
        // The DeleteEntry button was pressed
        if ((NewQuestion != null) && (NewAnswer != null))
        {
            // Call the QnA KnowledgeBase Service
            objQnAResult.Message =
                await UpdateQueryQnABot(NewQuestion, NewAnswer, Mode.Delete);
        }
    }

 

The UpdateQueryQnABot method is as follows:

 

        private static async Task<string> UpdateQueryQnABot(
            string newQuestion, string newAnswer, Mode paramMode)
        {
            string strResponse = "";
            // Create the QnAKnowledgeBase that contains the new entry
            QnAKnowledgeBase objQnAKnowledgeBase = new QnAKnowledgeBase();
            QnaPair objQnaPair = new QnaPair();
            objQnaPair.question = newQuestion;
            objQnaPair.answer = newAnswer;
            if (paramMode == Mode.Add)
            {
                Add objAdd = new Add();
                objAdd.qnaPairs = new List<QnaPair>();
                objAdd.urls = new List<string>();
                objAdd.urls.Add(@"http://localhost");
                objAdd.qnaPairs.Add(objQnaPair);
                objQnAKnowledgeBase.add = objAdd;
            }
            if (paramMode == Mode.Delete)
            {
                Delete objDelete = new Delete();
                objDelete.qnaPairs = new List<QnaPair>();
                objDelete.urls = new List<string>();
                objDelete.urls.Add(@"http://localhost");
                objDelete.qnaPairs.Add(objQnaPair);
                objQnAKnowledgeBase.delete = objDelete;
            }
            using (System.Net.Http.HttpClient client =
                new System.Net.Http.HttpClient())
            {
                string RequestURI = String.Format("{0}{1}{2}{3}? ",
                    @"https://westus.api.cognitive.microsoft.com/",
                    @"qnamaker/v2.0/",
                    @"knowledgebases/",
                    _KnowledgeBase);
                using (HttpRequestMessage request =
                    new HttpRequestMessage(new HttpMethod("PATCH"), RequestURI))
                {
                    request.Content = new StringContent(
                        JsonConvert.SerializeObject(objQnAKnowledgeBase),
                        System.Text.Encoding.UTF8, "application/json");
                    request.Content.Headers.Add(
                        "Ocp-Apim-Subscription-Key",
                        _OcpApimSubscriptionKey);
                    HttpResponseMessage response = await client.SendAsync(request);
                    if (response.IsSuccessStatusCode)
                    {
                        strResponse = $"Operation {paramMode} completed.";
                    }
                    else
                    {
                        string responseContent =
                            await response.Content.ReadAsStringAsync();
                        strResponse = responseContent;
                    }
                }
            }
            return strResponse;
        }

 

Train and Publish

The Train and Publish button calls the following method:

 

        private static async Task<string> TrainAndPublish()
        {
            string strResponse = "";
            using (System.Net.Http.HttpClient client =
                new System.Net.Http.HttpClient())
            {
                string RequestURI = String.Format("{0}{1}{2}{3}",
                    @"https://westus.api.cognitive.microsoft.com/",
                    @"qnamaker/v2.0/",
                    @"knowledgebases/",
                    _KnowledgeBase);
                var httpContent =
                    new StringContent("",
                    Encoding.UTF8, "application/json");
                httpContent.Headers.Add(
                    "Ocp-Apim-Subscription-Key", _OcpApimSubscriptionKey);
                System.Net.Http.HttpResponseMessage response =
                    await client.PutAsync(RequestURI, httpContent);
                if (response.IsSuccessStatusCode)
                {
                    strResponse = $"Operation Train and Publish completed.";
                }
                else
                {
                    string responseContent =
                        await response.Content.ReadAsStringAsync();
                    strResponse = responseContent;
                }
            }
            return strResponse;
        }

 

 

Ai Help Website Links

Using QnA Maker To Easily Create and Consume A Chat Bot

Links

QnA Maker Application Website

QnA Maker API V2.0 Reference

Create your first QnA bot using botframework’s QnA Maker

QnA Maker Dialog for Bot Framework – Gary Pretty

Adding rich attachments to your QnAMaker bot responses – Gary Pretty

Download

You can download the code from the Download page