はじめに
前回LUISを使用して自然言語処理を試してみました。
しかしそのままではあまり意味がありません。
ですので今回は作成したLUIS Appをプログラムから利用していきます。
BotFramework編
LUIS AppはMicrosoftのBotFrameworkから簡単に利用することが出来ます。
LUISを利用したBotの作成
Bot Frameworkと雑談対話APIを使用したチャットBotを参照して、テンプレートを利用したBotApplicationのプロジェクトの作成、NuGetパッケージの復元まで実施します。
[Serializable]
public class RootDialog : LuisDialog<object>
{
~
}
RootDialog.csの基底クラスをIDialog<object>からLuisDialog<object>に変更します。
基底クラスを変更した段階でテンプレートにより作成されている、StartAsyncメソッドとMessageReceivedAsyncメソッドは使用しないので削除します。
[LuisModel("{Application ID}", "{Programmatic Key}")]
[Serializable]
public class RootDialog : LuisDialog<object>
{
}
RootDailogクラスのAttributeとしてLuisModel
を追加します。
Attributeのパラメータには
LUIS AppのSETTINGメニュー内のApplication ID
User settings内のProgrammatic Key
を設定する。
[LuisIntent("")]
[LuisIntent("None")]
public async Task None(IDialogContext context, LuisResult result)
{
await context.PostAsync($"インテント引っかからず");
context.Done<object>(null);
}
[LuisIntent("ScheduleSearch")]
public async Task ScheduleSearch(IDialogContext context, LuisResult result)
{
await context.PostAsync($"インテントScheduleSearchに引っかかる");
await context.PostAsync($"スコアは{result.Intents[0].Score}です。");
foreach (var entity in result.Entities)
{
await context.PostAsync($"エンティティ{entity.Type}");
await context.PostAsync($"値は{entity.Entity}です。");
}
context.Done<object>(null);
}
クラス内にNoneメソッドとScheduleSearchメソッドを追加する。
各メソッドのAttributeとしてLuisIntent
が設定し、パラメータとしてはLUIS AppのIntentの名前を設定する。
LuisIntent
Attributeを設定することにより、Botに対して入力された文章をLUIS Appが判断し、判断したIntentがAttirbuteに設定されているメソッドに対して処理が投げられる。
デバッグ実行し、BotFramework Emulatorで実行した結果です。
「山田さんの予定は」という文章を入力すると、ScheduleSearchインテントと判断し、Bot側のインテントとエンティティを返す処理が動作しています。
「こんにちは」という文章を入力すると、Noneインテントと判断し、Bot側でインテントに引っかからなかったことを返す処理が動作しています。
このようにBotFrameworkと連携する場合は、LUIS Appを使用していることを感じさせずにプログラムを作成することができます。
REST API編
LUIS AppはREST APIの口も用意されているので色々なプラットフォームからも利用することが出来ます。
URLは
https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/{ApplicationID}
となっています。
※リージョンがwestusの場合。無償アカウントの場合はこれになるはず。
パラメータは
パラメータ | 値 | 備考 |
---|---|---|
subscription-key | {Programmatic Key} | |
verbose | true | falseにしたらどうなるか不明… |
timezoneOffset | 540 | タイムゾーンによる時差を分で設定 |
q | LUIS Appに判断させる文章 |
のように設定します。
{
"query": "山田さんの予定は",
"topScoringIntent": {
"intent": "ScheduleSearch",
"score": 0.973934
},
"intents": [
{
"intent": "ScheduleSearch",
"score": 0.973934
},
{
"intent": "None",
"score": 0.153738111
}
],
"entities": [
{
"entity": "山田",
"type": "LastName",
"startIndex": 0,
"endIndex": 1,
"score": 0.8487269
}
]
}
実行するとレスポンスとしてJSONが返ってきます。
REST APIを利用してハングアウトBotに自然言語処理を組み込む
ハングアウトBotを作ってみる
G Suite 組織内ユーザーの予定を名前から取得してみる
で作成したG Suite組織内ユーザーの予定を取得するハングアウトBotに自然言語処理を組み込んで行きます。
と言ってもハングアウトBotのコマンドの/bot コマンド パラメータ
という構成は変えようが無いので、入力した文字列をLUIS Appで処理した後、その内容次第でコマンドを生成する形にします。
@asyncio.coroutine
def handle_command(self, event):
…
# ensure bot alias is always a list
if not isinstance(self.bot_command, list):
self.bot_command = [self.bot_command]
# ↓ 追加処理 始まり
# 自然言語処理で予定問い合わせか判断
response = requests.get(
'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/{ApplicationID}',
params={'subscription-key': '{Programmatic Key}',
'verbose': 'true',
'timezoneOffset': '540',
'q': event.text})
luisJson = response.json()
if luisJson['topScoringIntent']['intent'] == 'ScheduleSearch':
createCommand = '/bot calendar '
lastName = ''
firstName = ''
for entity in luisJson['entities']:
if entity['type'] == 'LastName':
lastName = entity['entity']
if len(lastName) > 0:
createCommand = createCommand + lastName
else:
createCommand = ''
if len(createCommand) > 0:
event.text = createCommand
# ↑ 追加処理 終わり
処理を追加するのはhandlers.pyのhandle_commandメソッドです。
handle_commandメソッドでは入力された文字列がハングアウトBotのコマンド構成と一致しているかを判断している箇所です。
そこで判断をする前にLUIS Appで入力された文字列を判断させ、「予定を聞く」文脈だった場合、/bot Calendar 名字
のコマンドを生成し入力した文字列と置き換えるようにしています。
実際に実行してみるとハングアウトBotのコマンド構成で入力した場合と、「予定を聞く」文脈の文章を入力した場合の結果は同じになります。