Microsoft Bot Framework + IBM Watson = ...バイリンガルボット

このトピックを続けて、Linux用Microsoft Bot Frameworkで二言語Node.JSボットを作成した成功体験を共有したい思います。 顧客は、大規模な取引ネットワーク向けの質問と回答の形式でシンプルなソーシャルボットを開発するタスクを受け取りましたが、難易度は異なりました。ボットは英語とアラビア語のバイリンガルでなければなりません。 ただし、以下に示すように、問題を解決するためのツールを選択することにより、開発が容易になり、楽しく、面白くなりました。



以前と同様に、フレームワークの選択は、ボットの構築と展開を大幅に促進する膨大な機能を備えたMicrosoft Bot Frameworkを優先して行われました:ダイアログのフローの管理、アクションのトリガー、状態の保存、カラフルなインタラクティブメッセージ、Facebook Messenger、Skypeなどのチャネルの簡単な接続、Webchatなど。 判明したように、非常にシンプルで便利なローカライズメカニズムもあります(以下について)。



ユーザーメッセージの意味を認識するために、LUIS、IBM Watson、Google Dialogflow(Api.ai)などのAIシステムを使用できます。BotBuilderがLUISを使用する方が自然で便利です。BotFrameworkに組み込まれているメソッド、クラスなどがあります。 ただし、LUISにはまだアラビア語がありません。これは、顧客の要求に応じてボットが機能する第2言語です。 したがって、選択はIBM Watsonに委ねられました。IBMWatsonは、機能、安定性、および使いやすさがはるかに向上していることが判明しました。 顧客は当初、2つのボットを作成する可能性を考えていましたが、IBM WatsonとBot Frameworkの非常に多様なツールにより、機能を1つに簡単に組み合わせることができました。 次に、これを行う方法について説明します。



プロジェクトを配置して実行する新しいフォルダーを選択します。



npm init
      
      





ボットの構築、ワトソンへの接続、非同期リクエストに必要なパッケージをインストールします。



 npm install dotenv npm install restify npm install botbuilder npm install watson-developer-cloud npm install request-promise
      
      





app.js



ファイルを作成し、次のコードをコピーします。



アプリケーションコード:
 var restify = require('restify'); var builder = require('botbuilder'); var Conversation = require('watson-developer-cloud/conversation/v1'); // watson sdk require('dotenv').config({ silent: true }); var contexts; var workspace = process.env.WORKSPACE_ID; // Setup Restify Server var server = restify.createServer(); server.listen(process.env.port || process.env.PORT || 3978, function() { console.log('%s listening to %s', server.name, server.url); }); // Create the service wrapper var conversation = new Conversation({ username: process.env.WATSON_USERNAME, password: process.env.WATSON_PASSWORD, url: process.env.WATSON_URL + process.env.WORKSPACE_ID + '/message?version=2017-05-26', version_date: Conversation.VERSION_DATE_2017_05_26 }); // Create chat connector for communicating with the Bot Framework Service var connector = new builder.ChatConnector({ appId: process.env.MICROSOFT_APP_ID, appPassword: process.env.MICROSOFT_APP_PASSWORD }); // Listen for messages from users server.post('/api/messages', connector.listen()); // Create your bot with a function to receive messages from the user var bot = new builder.UniversalBot(connector, function(session) { let payload = { workspace_id: workspace, context: [], input: { text: session.message.text } }; let conversationContext = { workspaceId: workspace, watsonContext: {} }; if (!conversationContext) { conversationContext = {}; } payload.context = conversationContext.watsonContext; conversation.message(payload, function(err, response) { if (err) { console.log(err); session.send(err); } else { console.log(JSON.stringify(response, null, 2)); session.send(response.output.text); conversationContext.watsonContext = response.context; } }); });
      
      





これは、実際に構築できるベースです。 ここで、ボットを作成する前に、ユーザーと会話オブジェクトを作成します。 会話は 、ユーザーの応答をWatsonに送信するために使用されます。Watsonは、その中で意図とエンティティのペアを認識します。 変数WATSON_URLおよびWORKSPACE_IDは、おそらく既に理解しているように、 .env



ファイルに保存されます。



 # Bot Framework Credentials MICROSOFT_APP_ID=... MICROSOFT_APP_PASSWORD=... #Watson Url WATSON_URL=https://gateway.watsonplatform.net/conversation/api/v1/workspaces/ WATSON_USERNAME=... WATSON_PASSWORD=... WORKSPACE_ID=<UUID>
      
      





ワークスペース(ワークスペース)は、トレーニングされたモデルを使用して、ユーザーとの会話をより簡単に、サービスのインスタンスに関連付けます。 このモデルは、1つの言語用に作成およびトレーニングされます。 別の言語の場合、2番目のワークスペースを作成する必要があります 。 簡単なスクリプトを実行することで、利用可能なワークスペースのリストとその識別子を取得できます。



workspaces.js
 // This loads the environment variables from the .env file require('dotenv-extended').load(); var Conversation = require('watson-developer-cloud/conversation/v1'); // watson sdk var conversation = new Conversation({ username: process.env.WATSON_USERNAME, password: process.env.WATSON_PASSWORD, version_date: Conversation.VERSION_DATE_2017_05_26 }); conversation.listWorkspaces(function(err, response) { if (err) { console.error(err); } else { console.log(JSON.stringify(response, null, 2)); } });
      
      





 node workspaces.js
      
      





Microsoft Bot Frameworkのローカライズメカニズムを使用するに 、まずユーザーがどの言語で連絡しているかを調べる必要があります。 そして、ここでもワトソンは私たちの助けになります。その武器庫には、翻訳、認識、分類、変換などのための膨大な量のあらゆる種類のAPIあります言語識別するための APIもあります。 これを使用するには、このAPIへのリクエストを処理する小さなモジュールを作成します。



language.js
 var request = require("request-promise"); module.exports.Detect = async function LanguageDetect(text) { let options = { baseUrl: "https://watson-api-explorer.mybluemix.net", uri: "/language-translator/api/v2/identify", method: "GET", qs: { // Query string like ?text=some text text: text }, json: true }; try { let result = await request(options); return result.languages[0].language; } catch (err) { console.error(err); } };
      
      







メインアプリケーションでこのモジュールを接続します。



 var language = require('./language');
      
      





まず、ボットの主な機能である行を挿入して現在の言語を決定し、対応するロケールを設定します。 BotBuilder SDKには、各ユーザーのこのプロパティを保存または取得するためのsession.preferredLocale()



メソッドが用意されています。



 // Detect language en/ar first and set correspondent locale let locale = await language.Detect(session.message.text); session.preferredLocale(locale);
      
      





認識された言語のリストは、このAPIをテストできるWatson API Explorerで表示できます。



言語ごとに、2つの個別の会話オブジェクトを作成します。



英語とアラビア語の会話オブジェクト
 // Get Watson service wrapper for English var conversation_en = new Conversation({ username: process.env.WATSON_USERNAME, password: process.env.WATSON_PASSWORD, url: process.env.WATSON_URL + process.env.WORKSPACE_ID_EN + '/message?version=2017-05-26', version_date: Conversation.VERSION_DATE_2017_05_26 }); // Get Watson service wrapper for Arabic var conversation_ar = new Conversation({ username: process.env.WATSON_USERNAME, password: process.env.WATSON_PASSWORD, url: process.env.WATSON_URL + process.env.WORKSPACE_ID_AR + '/message?version=2017-05-26', version_date: Conversation.VERSION_DATE_2017_05_26 });
      
      







ご注意 注: .env



ファイルには、1つのWORKSPACE_ID



ではなく、2つの変数WORKSPACE_ID_EN



およびWORKSPACE_ID



ます。


これらのオブジェクトは変更されないため、 app.jsの先頭に配置するか、別のファイルに配置できます。 次に、ロケール定義コードの後に​​、 会話変数を初期化する行を挿入し、 ワークスペース変数も変更します。特定の言語に応じて動的に変更されるようになりました。



app.jsの変更
 // Detect language en/ar first and set correspondent locale let locale = await language.Detect(session.message.text); session.preferredLocale(locale); let workspace = (locale == "ar") ? process.env.WORKSPACE_ID_AR : process.env.WORKSPACE_ID_EN; // Get Watson service wrapper according to the locale let conversation = (locale == "ar") ? conversation_ar : conversation_en; // Prepare Watson request let payload = { workspace_id: workspace, context: [], input: { text: session.message.text } }; let conversationContext = { workspaceId: workspace, watsonContext: {} }; ...
      
      





デフォルトでは、Bot Builder SDKローカリゼーションシステムはファイルベースであり、ディスクに保存されたJSONファイルを使用してボットが複数の言語をサポートできるようにします。 デフォルトでは、ローカリゼーションシステムは、 builder.Prompts.choice()



session.send()



などのメソッドを呼び出すときに、ファイル./locale/<>/index.json



でボットメッセージを探します./locale/<>/index.json



言語タグは、必要な選択されたロケールを表しますメッセージを探します。 次のスクリーンショットは、英語とアラビア語のプロジェクトディレクトリ構造を示しています。



画像



このJSONファイルの構造は、ローカライズされたテキスト文字列へのメッセージ識別子の単純なマッピング(対応)です。 事前にローカライズされたテキスト文字列ではなく、メッセージ識別子がsession.send()



メソッドに渡されると、ボットはメッセージのローカライズされたバージョンを自動的に取得します。



 session.send("greeting_message");
      
      





メッセージIDによってローカライズされたテキスト文字列を取得する別の方法は、 session.localizer.gettext()



を呼び出すことです。 使いやすくするために、 Sessionクラスの拡張機能を作成し、Qtのtr()



関数のようなラッパーを作成しました(JavaScriptは時々非常に便利です!)。 ここで、{name}、{id}、{phone}などのトークンの置換を実装できます。



tr()拡張関数
 const { Session } = require('botbuilder'); // Object extension function for strings localization (translation) Session.prototype.tr = function (text) { return this.localizer.gettext(this.preferredLocale(), text) .replace("{name}", this.userName()); }; // Object extension function to get user id Session.prototype.userId = function () { return this.message.address.user.id; }; // Object extension function to get user name Session.prototype.userName = function () { return this.message.address.user.name; };
      
      





これで、ユーザーへの回答を任意の言語で簡単に実装できます。 単純なボットを質問と回答の形式で実装する場合、Watsonの間違いない利点は ワークスペースの 言語に関係なく、認識されたインテントエンティティのペアをすべての言語( 教えているように )で返すことができることです 。 したがって、可能な回答は、両方の言語の 単一の JSオブジェクトとして便利に編成され、関数の連想配列として機能します。



責任あるオブジェクト
 var responses = { // Responses object "greeting": { "no_entities": async function (session) { session.send("greeting_message"); }, }, "purchase": { "sale-stop": async function (session) { session.send("3_sales_end_dates"); }, "product-sale": async function (session) { session.send("4_sale_still_running"); }, /** @param {Session} session */ "price-product": async function (session) { session.send(session.tr("6_product_prices")); }, "price": async function (session) { session.send(session.tr("6_product_prices")); }, }, "inquiry": { "job": async function (session) { session.send("5_job_opportunity"); }, ... }, ... }
      
      





これで、Watsonへの要求後に呼び出されるコールバックを書き換えることができます。



ワトソンリクエストコールバック関数
 // Send request to Watson conversation.message(payload, async function (err, response) { if (err) { console.log(err); session.send(err); } else { // Generate response to user according to Watson intent-entity pairs let processed = false; // Get intent let intent = (response.intents[0]) ? response.intents[0].intent : undefined; for(i = 0; i < response.entities.length; i++) { // Process single entity in response let entity = (response.entities[i]) ? response.entities[i].entity : undefined; // Process single entity in response if (responses[intent] && responses[intent][entity]) { await responses[intent][entity](session, intent, [response.entities[i]]); processed = true; break; } } // Message was not recognized if(!processed) { session.send(session.tr("get_started")); } conversationContext.watsonContext = response.context; } });
      
      





これはこの関数の簡単なバージョンです。実際のプロジェクトでは、もちろん、より複雑です。



それだけです! バイリンガルボットができました。 起動後、結果を楽しむことができます-ボットの自動応答:










All Articles