Help us understand the problem. What is going on with this article?

[Microsoft Bot Framework] LUISに日本語を解析させる

More than 3 years have passed since last update.

概要

MicrosoftのLUISは自然言語を解析してくれるサービスですが、現状 英語/フランス語/イタリア語/スペイン語/中国語 にしか対応していないという問題があります。

【参考記事】
『Build2016 : LUIS による自然言語入力解析』
https://blogs.msdn.microsoft.com/bluesky/2016/04/05/build2016-luis-natural-language-understanding/

しかし、Bot Connectorを通すことでその自動翻訳機能を利用することができ、結果的に「自然な日本語で受け答えができるボット」を開発することができます。

今回は「日付を入力したらその曜日を答える」ボットを作ってみます。

ボットを作成し、Bot Connectorに登録する

下記記事にMicrosoft Bot Frameworkを使って作成したボットをBot Connectorに登録するまでの流れが紹介されています。

『SlackとWeb上のチャットをつなぐ / MS謹製のbot作成フレームワーク「Bot Builder」で遊んでみた!』
http://qiita.com/o0h/items/c10491a48cf014195338

記事中に公式ドキュメントから引用された図が貼られていますが、"Bot Connector"の欄に"Automatic translation to 30+ languages"という記述があります。今回はこれのお世話になろうというわけです。

コードは「Bot Builderを利用して」に貼られている方をベースとします。以下、転載となります。

var restify = require('restify');
var builder = require('botbuilder');

var bot = new builder.BotConnectorBot({ appId: process.env.appId, appSecret: process.env.appSecret});
var dialog   = new builder.CommandDialog();

dialog.matches(['Hi', 'Hello', 'こんにちは'], function (session) {
  session.send('こんにちは');
});
bot.add('/', dialog);

var server = restify.createServer();
server.post('/v1/messages', bot.listen());
server.listen(process.env.port || 8080, function () {
    console.log('%s listening to %s', server.name, server.url);
});

これをAzure(App Service)あたりに上げます。
よろしければ、下記記事もご覧ください。

『Macで開発したボットをAzureで運用する』
http://qiita.com/fullkawa/items/5a661d55311d45279aaf

Bot Connectorに登録する際、エンドポイントとして用意したパス(上記コードで言うと server.post('/v1/messages', bot.listen()); の部分)を登録するのがポイントです。

スクリーンショット 2016-06-15 10.12.40.png

appId, appSecret は「アプリケーション設定 > アプリ設定」から渡します。

スクリーンショット 2016-06-15 10.25.08.png

OK! 無事、Bot Connectorを通して受け答えができるようになりました。

スクリーンショット 2016-06-15 10.37.35.png

LUISにIntent, Entityを登録する

Microsoft LUISに関する説明、簡単な使い方は下記記事が参考になります。

『Build2016 : LUIS による自然言語入力解析』
https://blogs.msdn.microsoft.com/bluesky/2016/04/05/build2016-luis-natural-language-understanding/

このあたりから少し詳しく説明していきます。
まず、新規アプリケーションを作成します。

スクリーンショット 2016-06-15 10.44.21.png

ご覧の通り、選択できる言語のリストに日本語はありません。
ここは"English"を選択しておきます。

今回は「日付を入力したらその曜日を答える」ボットを作るのが目的だったわけですが、ここで具体的な問答を考えてみましょう。

問:今日は何曜日ですか?
答:その日は水曜日です。

上記問の「今日」の部分はいろいろな日付表現を受け付けたいところです。これが今回の"Entity"となります。
LUISには組み込みのエンティティ(Pre-built Entities)に日付(datetime)があるので、それを利用しましょう。

左メニュー「Pre-built Entities」横の追加ボタンを押し、"datetime"を選択し、[OK]を押します。

スクリーンショット 2016-06-15 11.01.00.png

"datetime"が利用可能になりました。

スクリーンショット 2016-06-15 11.01.35.png

次にIntentを登録します。
例文を英語で入力する必要がありますが、Bot Connectorで自動翻訳された英文がLUISに渡されるのであれば、Bing翻訳の英訳で十分でしょう。これで英語に自信がない人でも大丈夫です。

スクリーンショット 2016-06-15 11.05.54.png

左メニュー「Intents」横の追加ボタンを押し、インテント名(任意)と先程翻訳した例文を登録し、[Save]を押します。

スクリーンショット 2016-06-15 11.08.02.png

Entity候補として自動的に"today"の部分が選択されました。これで問題ありませんので、[Submit]を押します。

スクリーンショット 2016-06-15 11.08.23.png

"what_day"が登録されました。
"None"は最初から登録されているIntentで、どれにもマッチしない場合を表します。

スクリーンショット 2016-06-15 11.10.48.png

左下"Train"ボタンを押して、例文を学習させます。

スクリーンショット 2016-06-15 11.25.41.png

左メニュー「Publish」から[Publish web service]を押すとURLが表示されます。
ここから、idとsubscription-keyを取得します。

スクリーンショット 2016-06-15 11.29.09.png

Intentに対する返答を実装する

ここまでで以下の流れができるようになっています。

[chat] 今日は何曜日ですか?
 ↓
[Bot Connector] Today what is the day of the week?
 ↓
[LUIS] Intent="what_day", Entity(datetime)="today"

これに対する返答をNode.jsで実装してやります。
サンプルコードは下記の通りです。
CommandDialogの代わりにLuisDialogを利用しています。id, subscription-keyは「アプリケーション設定 > アプリ設定」から渡すようにします。
単に返答を返すだけでなく、どのようなデータが受け渡されているかをログに出力してみました。

var restify = require('restify');
var builder = require('botbuilder');

var bot = new builder.BotConnectorBot({ appId: process.env.appId, appSecret: process.env.appSecret});
var url = 'https://api.projectoxford.ai/luis/v1/application?id=' + process.env.luisId
    + '&subscription-key=' + process.env.luisSubscriptionKey
var dialog = new builder.LuisDialog(url);

bot.add('/', dialog);

// Intent="what_day"の場合の処理
dialog.on('what_day', function(session, args) {
    console.log('message:');
    console.log(session.message);

    var date = builder.EntityRecognizer.findEntity(args.entities, 'builtin.datetime.date');
    console.log('date:');
    console.log(date);

    if (date != undefined && date.resolution != undefined) {
        var d = new Date(date.resolution.date);
        var day = '日月火水木金土'[d.getDay()];
        session.send('その日は「' + day + '曜日」です。');
    } else {
        session.send('日付を取得できませんでした。');
    }
});

// Intent="None"の場合の処理
dialog.onDefault(function(session, args) {
    console.log('args:');
    console.log(args);

    console.log('message:');
    console.log(session.message);

    session.send("質問を理解できませんでした。もう一度、少し表現を変えて質問してみてください。")
});

var server = restify.createServer();
server.post('/v1/messages', bot.listen());
server.listen(process.env.port || 8080, function () {
    console.log('%s listening to %s', server.name, server.url);
});

動作確認

スクリーンショット 2016-06-15 12.19.13.png

入力した文章を理解してもらえませんでした。

args:
{ intents: 
   [ { intent: 'None', score: 0.57440114 },
     { intent: 'what_day', score: 0.0471038148 } ],
  entities: [] }
message:
{ type: 'Message',
  id: '9UcWTbjioJI',
  conversationId: 'DFS1VbGtB9ae5Ez4m49dp5TFGUj6kP5ol81I6nu7AVEEJ3Il',
  created: '2016-06-15T03:15:44.8295028Z',
  language: 'en',
  text: '今日は何曜日ですか?',

ログを確認すると、LUISはこの文を'what_day'ではなく'None'だと解釈したようです。
Messageの内容を見ると、language: 'en'となっています。入力をそのまま英文として解釈したようですね。

ボットに対してこれから日本語を使うことを伝え、再度同じ質問をすると今度は期待した答えをくれました。

スクリーンショット 2016-06-15 12.18.01.png

message:
{ type: 'Message',
  id: 'GuWITxWtRCb',
  conversationId: '7Uj2OT5w85OUFhL9UNfzG2p8fF5wR78wFwaAVlDgCLs7om',
  created: '2016-06-15T03:17:29.3002618Z',
  sourceText: '今日は何曜日ですか?',
  sourceLanguage: 'ja',
  language: 'en',
  text: 'Today what is the day of the week?',
(中略)
date:
{ entity: 'today',
  type: 'builtin.datetime.date',
  startIndex: 0,
  endIndex: 4,
  resolution: { date: '2016-06-15' } }

sourceText → text と自動翻訳されているのが分かります。
また、翻訳された"today"がEntityとして解釈され、それがLUISによって"2016-06-15"と解決されていることも分かります。

Bot Connectorの設定項目に"Default Conversation Language"というのがあり、これに"ja"と入れることで言語切替なしでいけることを期待したのですが、そうなりませんでした。他の設定手段があるのでしょうか?

スクリーンショット 2016-06-15 11.48.18.png

それはさておき、他のパターンも試してみましょう。

スクリーンショット 2016-06-15 12.29.42.png

和暦も理解してくれるのはありがたいですね!

message:
{ type: 'Message',
  id: 'GQPdJkOyxrc',
  conversationId: '7Uj2OT5w85OUFhL9UNfzG2p8fF5wR78wFwaAVlDgCLs7om',
  created: '2016-06-15T03:31:41.7877018Z',
  sourceText: '平成28年6月16日は何曜日だっけ?',
  sourceLanguage: 'ja',
  language: 'en',
  text: '6/16/2016, what is the day of the week?',
(中略)
date:
{ entity: '6/16/2016',
  type: 'builtin.datetime.date',
  startIndex: 0,
  endIndex: 8,
  resolution: { date: '2016-06-16' } }

では、デタラメな質問を投げると…?

スクリーンショット 2016-06-15 13.31.58.png

Intentの判定には成功しましたが、Entityは取得できませんでした。
妥当な結果だと思います。

message:
{ type: 'Message',
  id: '7ZrZJP1tEcH',
  conversationId: '7Uj2OT5w85OUFhL9UNfzG2p8fF5wR78wFwaAVlDgCLs7om',
  created: '2016-06-15T04:31:46.4026778Z',
  sourceText: '私は何曜日でしょうか?',
  sourceLanguage: 'ja',
  language: 'en',
  text: 'I what what day of the week?',
(中略)
date:
null

このクオリティであれば、十分実用に耐えうるのではないでしょうか。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした