Bot Frameworkは自然言語解析エンジンは提供してくれていません。 ただし、LUISとの連携機能は提供しています。
ということでBot Frameworkで自然言語解析をしたければLUISを使うのが一番自然な流れになります。
LUIS
LUISはLanguage Understanding Intelligent Serviceの略で、以下のページからアカウントが作成できます。
LUIS: Language Understanding Intelligent Service (beta)
アプリケーションを作りましょう、気を付けるのはJapaneseを選ぶところくらいですかね。
アプリケーションを作成したら、そこにIntentとEntityを作っていきます。
- Intent: 認識結果の種類みたいなの。
- Entity: 文章から抜き出すパラメータみたいなもの。
ということで、基本的にIntentにはEntityが含まれてます。
今回は、「こんにちは〇〇」というというとhelloというIntentになって〇〇の部分をnameというEntityとして抜き出すようにしてみたいと思います。
まずnameというEntityを追加します。
次に、helloというIntentを追加します。例題となるサンプル文章を打ち込んで作ります。
New utterancesに画面が遷移して文章が文節ごとに区切られた感じに表示されます。
ここにEntityを指定していきます。今回は世界の部分をnameとしたいので世界を選択してnameを割り当てます。
「こんにちは〇〇」以外にも「こんばんは〇〇」とか「おはようございます〇〇」もついでに同じ要領で覚えさせてみましょう。
こういう風に延々と満足いくまで学習させていきます。
publishをするとWebAPIになります。
URLにidとsubscription-keyが含まれてます。こいつがアクセスするのに必要になります。テキストボックスに何か文字列を入れてEnterを押すと結果のJSONが取得できます。
{"query": "こんにちは世界", "intents": [{"intent": "hello", "score": 0.9999995 }, {"intent": "None", "score": 0.0215021987 }], "entities": [{"entity": "世界", "type": "name", "startIndex": 5, "endIndex": 6, "score": 0.9617552 }]}
intentがhelloでentityのnameが世界になってることが確認できます。
Bot Frameworkとの連携
LUISで言語解析するAPIができたのでBot Frameworkと連携してみたいと思います。 「こんにちは世界」という感じで話しかけると、「世界さん!!ようこそ!!」と返答するようにしたいと思います。 わからないケースの場合は、「すいません。わかりません」と回答したいと思います。
LuisDialog<T>
というクラスが提供されているので、これを継承することでLUISと連携ができます。LuisDialog
の型引数には、このダイアログが返す値の型になります。
今回は、LuisDialog
で延々と処理を回したいと思うのでobject
を指定しています。
ダイアログにはLuisModel
属性を指定して、先ほどのLUISのURLに埋め込まれてるidとsbscription-keyの値を設定します。
Intentに応答したかったらLuisIntent
属性にIntent名を指定することで、そのメソッドがIntentに応答するようにできます。
コードは以下のようになります。
using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Luis; using Microsoft.Bot.Builder.Luis.Models; using System; using System.Threading.Tasks; namespace HelloBot.Dialogs { [LuisModel("idの値", "subscription-keyの値")] [Serializable] publicclass HelloLuisDialog : LuisDialog<object> { // noneの場合 [LuisIntent("")] public Task None(IDialogContext context ,LuisResult result) { } // helloの場合 [LuisIntent("hello")] public Task Hello(IDialogContext context, LuisResult result) { } } }
LuisIntent
に空文字を渡すとnoneの場合になります。
簡単なNoneメソッドから作っていきましょう。
// noneの場合 [LuisIntent("")] public async Task None(IDialogContext context ,LuisResult result) { await context.PostAsync("すいません。わかりません"); context.Wait(this.MessageReceived); }
メッセージを返した後に、MessageReceivedメソッドの処理を待つことで再度LUISとの連携待ちに入ります。
次に、Helloメソッドです。こいつは、nameというEntityを抜き出す必要があります。
抜き出すにはLuisResult
のTryFindEntity
メソッドで抜き取れます。
// helloの場合 [LuisIntent("hello")] public async Task Hello(IDialogContext context, LuisResult result) { EntityRecommendation nameEntity; if (result.TryFindEntity("name", out nameEntity)) { await context.PostAsync($"こんにちは!!{nameEntity.Entity}さん!!"); } else { await context.PostAsync("すいません。わかりません"); } context.Wait(this.MessageReceived); }
EntityRecommendation
を使って抜き出したEntityを操作できます。Entity
プロパティでテキストにアクセスできます。
なので、基本的に文字列を組み立ててユーザーにフィードバックをしています。
名前がとれなかった場合は、すいません。わかりませんと言っています。
そして、context.Wait(this.MessageReceived);
でLUISとの連携を待ってます。
最後にMessagesController
で作成したDialogを使うように変更します。
public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { await Conversation.SendAsync(activity, () => new HelloLuisDialog()); } else { HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; }
動作確認
実行してエミュレータでつないでみましょう。
ちゃんと動いてますね!ということでLUISを使って自然言語で最初のトリガーを識別して、そのあとFormFlowを使って必要な情報を集めてアクションをするといった流れとかができますね。