#概要
こんにちは!吉田です。今回は、マイクロソフトが12月13日にリリースした、質問に対して回答を返してくれる新しいCognitive Service「QnA Maker」と11月にリリースされたAzure BOT Serviceを組み合わせて、とある企業のFAQに対応するチャットボットを作ってみたいと思います。
#事前に準備するもの
- 時間:30分ほど
- Azure サブスクリプション
- 質問・回答が同じページに掲載されているFAQのサイト(例:https://www.microsoft.com/ja-jp/software-download/faq 等)
- Skype アカウント(Microsoft Account) ※もしSkypeで試したい場合のみ必要
#設定手順
##Azure Bot Serviceの作成
-
Azureポータルへアクセスし、新規(+)から、「Intelligence + analytics」をクリックし、「Bot Service」をクリックします。
-
開くと、Microsoft App IDの作成が求められます。「Create Microsoft App ID and Password」をクリックします。
-
アプリ名は(1)で設定したアプリ名、アプリIDは自動で生成されます。「アプリパスワードを生成して続行」をクリックします。
-
パスワードが表示されます。表示されたパスワードをメモ帳等のテキストエディタへ貼り付けて、「OK」をクリックします。パスワードは後程利用します。
-
前回の投稿にはなかった、「Question and Answer」が選択できるようになっています!これを選択し、「Create bot」をクリックします。
-
ウィザードが立ち上がります。QnA MakerはBot Serviceとは別のサービスなのですが、ここから作成すると、ウィザードが自動的にアカウントを作成してくれます。「Sign In」をクリックします。
-
「I agree...」のところにチェックを入れて、「OK」をクリックします。OKをクリックしてから次の画面に移るまで10秒ぐらいあり、「あれ?反応しない?」っと最初は焦りましたが、待っていれば大丈夫(のはず)です。
-
次に「run.csx」のプログラムを以下のコードで上書きしてしまいます。ナレッジベースIDとキーの取得は、事前にQnA Makerで「Publish」をした後に表示されたものを利用します。
※本来はコードを書き換えなくてもそのまま利用できるはずなのですが、試したところ、日本語だと返ってくるメッセージが文字化けしてしまったので、暫定的にこの方法にしています。(修正されたら、この記事にも反映します)
#r "Newtonsoft.Json"
#load "BasicQnAMakerDialog.csx"
using System;
using System.Net;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook was triggered!");
// Initialize the azure bot
using (BotService.Initialize())
{
// Deserialize the incoming activity
string jsonContent = await req.Content.ReadAsStringAsync();
var activity = JsonConvert.DeserializeObject<Activity>(jsonContent);
// authenticate incoming request and add activity.ServiceUrl to MicrosoftAppCredentials.TrustedHostNames
// if request is authenticated
if (!await BotService.Authenticator.TryAuthenticateAsync(req, new[] { activity }, CancellationToken.None))
{
return BotAuthenticator.GenerateUnauthorizedResponse(req);
}
if (activity != null)
{
// one of these will have an interface and process it
switch (activity.GetActivityType())
{
case ActivityTypes.Message:
//await Conversation.SendAsync(activity, () => new BasicQnAMakerDialog());
//ナレッジベースIDとキーの取得は、事前にQnA Makerで「Publish」をした後に表示されたものを利用します。
var knowledgebaseId = "ここにナレッジベースIDを入力してください"; //Utils.GetAppSetting("QnASubscriptionKey"); // Use knowledge base id created.
var qnamakerSubscriptionKey = "ここにサブスクリプションキーを入力してください"; //Utils.GetAppSetting("QnAKnowledgebaseId"); //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($"{qnamakerUriBase}/knowledgebases/{knowledgebaseId}/generateAnswer");
//Add the question as part of the body
var postBody = $"{{\"question\": \"{activity.Text}\"}}";
//QnAMakerResult qnaresponse = new QnAMakerResult();
String qnaresponse = null;
//Send the POST request
using (WebClient webclient = new WebClient())
{
//Set the encoding to UTF8
webclient.Encoding = System.Text.Encoding.UTF8;
//Add the subscription key header
webclient.Headers.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);
webclient.Headers.Add("Content-Type", "application/json");
log.Info($"Requesting QnA...");
var qnaresponseString = webclient.UploadString(builder.Uri, postBody);
//qnaresponse = JsonConvert.DeserializeObject< QnAMakerResult >(qnaresponseString);
qnaresponse = JObject.Parse(qnaresponseString)["answer"].ToString();
}
var qnaclient = new ConnectorClient(new Uri(activity.ServiceUrl));
var qnareply = activity.CreateReply();
//qnareply.Text = qnaresponse.Answer.ToString();
qnareply.Text = qnaresponse;
await qnaclient.Conversations.ReplyToActivityAsync(qnareply);
break;
case ActivityTypes.ConversationUpdate:
var client = new ConnectorClient(new Uri(activity.ServiceUrl));
IConversationUpdateActivity update = activity;
if (update.MembersAdded.Any())
{
var reply = activity.CreateReply();
var newMembers = update.MembersAdded?.Where(t => t.Id != activity.Recipient.Id);
foreach (var newMember in newMembers)
{
reply.Text = "Welcome";
if (!string.IsNullOrEmpty(newMember.Name))
{
reply.Text += $" {newMember.Name}";
}
reply.Text += "!";
await client.Conversations.ReplyToActivityAsync(reply);
}
}
break;
case ActivityTypes.ContactRelationUpdate:
case ActivityTypes.Typing:
case ActivityTypes.DeleteUserData:
case ActivityTypes.Ping:
default:
log.Error($"Unknown activity type ignored: {activity.GetActivityType()}");
break;
}
}
return req.CreateResponse(HttpStatusCode.Accepted);
}
}
##質問と回答を登録する
Bot Serviceは出来上がりましたが、このままでは質問と回答が登録されていません。このステップでは、事前に用意しておいた質問と回答を登録し、Botが答えられるようにします。
-
QnA Makerのサイト(https://qnamaker.ai) へアクセスし、「My services」を選択します。ログインされていない場合は、先ほどの13の手順で利用していたMicrosoft Accountでログインしてください。
-
質問・回答集が表示されます。既定では「hi」という質問に対し、「hello」と返答することだけが登録されているので、これから編集します。「Settings」をクリックします。
-
手動で登録する方法もありますが、QnA Makerには、URLを指定するだけで自動で質問回答集を作成してくれる、非常に便利な機能が用意されています。今回はStarbucks Coffee JapanさんのFAQ(http://www.starbucks.co.jp/faq/products/) を試してみたいと思います。(スタバさん、勝手に使ってすみません…)
このように、質問と回答が同じページでないと、QnA Makerは自動で認識できないので、要注意です。
-
この画面が表示されたらQnA Makerの設定は完了です。Azure Portalから作成したAzure Bot Serviceへ戻ります。
##Skype BOTを作成する
FAQの登録が完了したので、Skypeで試してみます。Skypeでのテストは、Azure Bot Serviceの画面からBOTの連絡先が追加できるようになっています。