まくろぐ

LUIS (4) botbuilder-ai ライブラリを使って LUIS の API を利用する

更新:
作成:
Microsoft は Node.js で作成したボットアプリから LUIS API を利用するための botbuilder-ai パッケージを提供しています。この Node パッケージを使用することで、REST API を意識せずに LUIS の機能を利用できるようになります。

こちらの記事(Node.js から LUIS の API を利用する) では、自力で LUIS の REST API を呼び出すための URL を構築していました。 ここでは、botbuilder-ai パッケージを使用して、もっと手軽に LUIS の機能を呼び出してみます。

☝️ ワンポイント 残念ながら botbuilder-ai が提供している LuisRecognizer などのクラスは、チャットボットの実装に使用する TurnContext オブジェクトに依存した設計になっています。 そのため、単純なコンソールアプリケーションから botbuilder-ai パッケージを使用することは難しく、チャットボットの実装でしか利用できません。

LUIS のエンドポイント情報(接続情報)を確認しておく

LUIS API を使用するには、下記のような LUIS アプリの APP ID やエンドポイント情報が必要です。

  • APP ID: c39eb4df-fbcf-224f-b8b7-a0ee445d11b3
  • エンドポイント: https://japaneast.api.cognitive.microsoft.com
  • エンドポイントキー(サブスクリプションキー): c9162c5c0b5edff5270feb6145618acb

APP ID とエンドポイントキーは、LUIS ポータル から対象のアプリケーションを開き、下記のように確認できます。

  • APP ID: MANAGEタブ → Application Information
  • エンドポイント: MANAGEタブ → Keys and EndpointsEndpoint カラムの URL の前半部分。
  • エンドポイントキー: MANAGEタブ → Keys and EndpointsKey 1 カラム

LUIS のエンドポイントキーは、Azure ポータル に作成した LUIS リソースキー の項目に表示されるものと同じです。 念のため、同一のものが表示されているか確認しておくとよいでしょう。

☝️ ワンポイント LUIS ポータル上の Endpoint Keys で、Starter_Key (管理者用キー)以外のリソースが表示されない場合は、Azure ポータルで作成した LUIS リソース(のキー)と、LUIS ポータルで作成した LUIS アプリの関連付けができていない可能性があります。 先に、LUIS ポータル上の Keys and Endpoints から関連付けを行ってください。

botbuilder-ai パッケージのインストール

LuisRecognizer クラスは、botbuilder-ai という Node パッケージで提供されています。 botbuilder-ai パッケージは、npm コマンドで簡単にインストールすることができます。

botbuilder-ai のインストール
$ npm install botbuilder-ai --save

上記のように --save オプションを付けて実行することで、ついでに package.json に依存情報を追記しておくことができます。

botbuilder-ai を使用する

LUIS サービスへの接続情報は、最終的には環境変数(Azure 上では App Service で設定できる)や .bot ファイルで管理することになると思いますが、最初はハードコーディングして動作確認するのがよいでしょう。 まずは、botbuild-ai モジュールの基本的な使い方を学ぶことにフォーカスしましょう。

ベースとする Bot クラス

ボット本体は、こちらで作成した Bot クラス (bot.js) をベースに作成することにします。 もともとのコードは下記のようなオウム返し実装になっており、ここに LUIS API の呼び出しを加えていきます。

bot.js (元のコード)
const { ActivityTypes } = require('botbuilder');

class Bot {
  async onTurn(turnContext) {
    const type = turnContext.activity.type;
    if (type === ActivityTypes.Message) {
      const text = turnContext.activity.text;
      await turnContext.sendActivity(`You said "${text}"`);
    } else {
      await turnContext.sendActivity(`[${type} event detected]`);
    }
  }
}

exports.Bot = Bot;

このクラスの onTurn メソッドは、パラメータで TurnContext オブジェクトを受け取るので、これを LuisRecognizer クラスに渡すことで LUIS への問い合わせを行うことができます。

LuisRecognizer クラスをインスタンス化する

LUIS の API を利用するには、botbuilder-ai パッケージに含まれている LuisRecognizer クラスを使用します。 このクラスのインスタンスを作成するには、下記のような接続情報オブジェクトが必要です。

const luisEndpoint = {
  applicationId: 'c39eb4df-fbcf-224f-b8b7-a0ee445d11b3',
  endpoint: 'https://japaneast.api.cognitive.microsoft.com',
  endpointKey: 'c9162c5c0b5edff5270feb6145618acb'
};

こちらの記事で作成した config.js モジュールを使用すると、.bot ファイルに記述した LUIS 接続情報を簡単に取得することができます。

const config = require('./config.js');
const luisEndpoint = config.loadLuisEndpoint('your-luis-app-name');

例えば、Bot クラスのコンストラクタ内で、下記のように LuisRecognizer インスタンスを生成すればよいでしょう。

bot.js
const { ActivityTypes } = require('botbuilder');
const { LuisRecognizer } = require('botbuilder-ai');

class Bot {
  /**
   * Bot コンストラクタ。
   * LUIS の接続情報を使って、LuisRecognizer オブジェクトを初期化します。
   */
  constructor(config) {
    const luisEndpoint = {
      applicationId: 'c39eb4df-fbcf-224f-b8b7-a0ee445d11b3',
      endpoint: 'https://japaneast.api.cognitive.microsoft.com',
      endpointKey: 'c9162c5c0b5edff5270feb6145618acb'
    };
    const luisOptions = {};
    this.luisRecognizer = new LuisRecognizer(luisEndpoint, luisOptions, true);
  }

  // ...
}

LuisRecognizer クラスの基本的な使い方

LuisRecognizer#recognize() メソッドに TurnContext オブジェクトを渡すと、LUIS による自然言語解析の結果 RecognizerResult を取得することができます。 RecognizerResult オブジェクトの intents プロパティを参照すると、LUIS によって認識されたユーザーの意図(インテント)の配列データを取得できます。

[
  { "intent": "SearchMeaning", "score": 0.8440653 },
  { "intent": "BookConference", "score": 0.1042322 },
  ...
]

一番スコアの高い(それらしい)トップインテントは、LuisRecognizer.topIntent() ユーティリティ関数を使って取り出すことができます。 まずはトップインテントを取り出し、その意図に応じて各エンティティを取り出すとよいでしょう。

bot.js(応答部分の抜粋)
class Bot {
  /**
   * Every conversation turn calls this method.
   * @param {TurnContext} turnContext Contains all the data needed for
   * processing the conversation turn.
   */
  async onTurn(turnContext) {
    if (turnContext.activity.type === ActivityTypes.Message) {
      // LUIS による認識結果を取得
      const result = await this.luisRecognizer.recognize(turnContext);
      const topIntent = LuisRecognizer.topIntent(result);
      const topIntentName = topIntent.intent;
      const topIntentScore = topIntent.score;
      const entities = result.entities;

      // どんなインテントだと認識したのか表示(デバッグ用)
      await turnContext.sendActivity(`意図: ${JSON.stringify(topIntent)}`);

      // インテントの種類に応じてエンティティを取り出す
      let response = '';
      switch (topIntentName) {
      case 'SearchMeaning':
        const words = entities['Word'];
        if (words) {
          response = `${words[0]} の意味は〇〇〇です。`;
        } else {
          response = '単語の意味を知りたいのですね。';
        }
        break;
      case 'None':
        response = '理解できませんでした。';
        break;
      }
      await turnContext.sendActivity(response);
    } else {
      await turnContext.sendActivity(`[${turnContext.activity.type} event detected]`);
    }
  }
}

例えば、チャットクライアントから XYZの意味は何ですか? と入力すると、このボットは下記のように応答します。

意図: {"intent": "SearchMeaning", "score": 0.8440653}
xyz の意味は〇〇〇です。

LUIS サービスが行ってくれるのは、上記のような意図の認識(例では SearchMeaning)と、単語の抽出(例では xyz)だけなので、ここから先の「単語の意味を検索する部分」は別の仕組みを使って実装する必要があります。 その仕組みが完成すれば、上記の○○○の部分に実際の意味を表示することができます。

ちなみに、LUIS は意図を認識できないと、デフォルトで None インテントを返します。 例えば、チャットクライアントから いあ!いあ!くとぅるふ ふたぐん! と入力すると、ボットは下記のような応答を返すことになります。

意図: {"intent": "None", "score": 0.489056647}
理解できませんでした。
☝️ ワンポイント 「いあ!いあ!くとぅるふ ふたぐん!」は、クトゥルフ神話に登場する詠唱呪文のひとつです。

(応用) デフォルトインテントを置き換える

LUIS はインテントを判別できなかった場合、デフォルトインテントとして { intent: "None", score: 0 } を返します。 LuisRecognizer.topIntent() メソッドで、RecognizerResult オブジェクトから トップインテントを取り出す時に、オプションパラメーターを指定すると、デフォルトのインテントを None 以外の任意のインテントに置き換えることができます。

const result = await this.luisRecognizer.recognize(turnContext);
const topIntent = LuisRecognizer.topIntent(result, 'Greet', 0.75);

関連記事

まくろぐ
サイトマップまくへのメッセージ