4/5/2017 Webmaster

Programmatically Updating A QnA Maker Service Using the QnA Maker API


** Note this is outdated – See new information here: https://docs.microsoft.com/en-us/azure/cognitive-services/QnAMaker/quickstarts/csharp

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.


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


In that article, we created a FAQ database.


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.


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


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.


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


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


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


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.


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


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


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.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.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


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


You can download the code from the Download page

An error has occurred. This application may no longer respond until reloaded. Reload 🗙