#どういう記事?
Azure素人の自分がMicrosoft AzureのBot FrameworkとCognitive Serviceと触れ合いながら、難易度も人への接し方も**“やさしい”**チャットボットを作ってみた際の備忘録の第3部です。どんなチャットボットを作るのかを含め、これまでの手順は第1部、第2部にございます。
PowerPointで記録していたものをQiita化してみたものになるので、そんな感じの画像が頻出します。
Qiita初心者なので、書き方が下手でも広い心で許してほしいです。そして全体的にゆるいです。
アジェンダ
以下の5部構成になります。この記事は第3部にあたります。
- Bot Frameworkでチャットボットを作ってみよう!
- ボットをAzure(クラウド)にデプロイしてみよう!
- Cognitive Serviceでテキスト分析をしてみよう!←イマココ
- Twitterからつぶやきをとってきてみよう!
- LINE経由でボットと話してみよう!
なお、公式ドキュメントに沿って作りましたので、それらのリンクを張り付けつつ、辿った道筋通りに書いていきます。
その筋の方からすると遠回りだったり野暮ったかったりすると思いますが、ご容赦ください。
2. Cognitive Serviceでテキスト分析をしてみよう!
これまで、第1部で作ったソースコードを、第2部でAzure(クラウド)上へデプロイしましたので、今回はユーザーから受け取ったコメントをAzure Cognitive ServiceのText Analyticsを使って、ネガティブorポジティブの判定をしてみたいと思います(図中の赤枠部分)。
2.1 参考ドキュメント
クイック スタート:Text Analytics クライアント ライブラリを使用する
今回の作業は公式ドキュメントのクイック スタート:Text Analytics クライアント ライブラリを使用するを参考にしています。
なお、最新のプレビュー バージョンは 3.0-previewとのことですが、今回は安定版である2.1を使ってみました。
2.2 前提条件
まずは上記リンク内の「前提条件」の部分に従って、以下を準備します。
- Microsoft Azure のサブスクリプション
- Visual Studio IDE
- Text Analytics リソースの作成(キーとエンドポイントを取得)
Microsoft Azure のサブスクリプションの準備
第2部で準備済みかと思いますので、それを使います。
Visual Studio IDE
第1部で使ったVisual Studio 2019を使います。
Text Analytics リソースの作成(キーとエンドポイントを取得)
Azure portal を使用して Cognitive Services リソースを作成するのクイックスタートに沿って、Text Analyticsリソースを作成します。こちらは割とつまずくところもなく、公式ドキュメントそのままで作成可能なので、そちらを参照いただいても大丈夫かと思います。
新しい Azure Cognitive Services リソースを作成する
リンク先の新しい Azure Cognitive Services リソースを作成するのところで、単一サービスリソースのタブから、Text Analyticsを選択します。
すると、AzurePortalへ自動で飛ばされ、TextAnalyticsリソース作成の画面に移りますので、それぞれ値を設定していきます。
-
名前
TextAnalyticsリソースの名前です。なんでもよいです。今回は例として、YasashiiBotTextAnalyticsとしています。 -
サブスクリプション
TextAnalyticsリソースをどのAzureサブスクリプションで作成するかということです。適切なものを選択してください。 -
場所
TextAnalyticsリソースをどのリージョンに配置するかということです。今回は東日本
を選択します。 -
価格レベル
価格レベルを選択します。今回はテストなので、一番下のレベルF0
を選択します。 -
リソースグループ
TextAnalyticsリソースをどのリソースグループに作成するかということです。今回は第2部で作成したリソースグループを選択しました。
全ての項目で設定ができたら、左下の作成ボタンをクリックします。
リソースのキーを取得する
少し待つと、デプロイが完了しました、という画面になりますので、リソースに移動ボタンをクリックします。
APIキーとエンドポイントが表示されます。後程使いますので、コピーしておいてください。
2.3 Text Analyticsの設定
ここから先、コードを書いていきますが、筆者はコーディング力は皆無(とりあえず動くものを作るだけ)なので、清く正しく美しいコードを書けるようになりたい方は、参考にしすぎないようにしてください。ごめんなさい。
公式ドキュメントだと、新しいアプリを作成するところからですが、第1部で作成済みなので、そちらを使っていきます。プロジェクトを開いて、ソリューションエクスプローラーからソリューション名を右クリックし、NuGetパッケージの管理を選択します。
NuGetパッケージマネージャーが開いたら、Microsoft.Azure.CognitiveServices.Language.TextAnalytics
と検索し、パッケージをインストールします。
公式ドキュメントではprogram.csへの追加の手順が記載されていますが、今回はEchoBot.csに全てまとめてしまおうと思うので、EchoBot.csの上の方(usingほげほげが書いてあるところ)に以下の通り追加します。これは、公式ドキュメントに書いてあるものと、EchoBot.csに元々書いてあったものの差分です。
using System;
using System.Net.Http;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models;
using Microsoft.Rest;
追加するとこんな感じになります。わかりやすいように、今回TextAnalytics連携のために追加したコードの上には、//for TextAalytics
と書いてあります。
次に、public class EchoBot
に、先ほど作成したTextAnalyticsのAPIキーとエンドポイント(リソースのキーを取得するで表示されたもの)を以下の通り追加します。
private static readonly string key = "<replace-with-your-text-analytics-key-here>";
private static readonly string endpoint = "<replace-with-your-text-analytics-endpoint-here>";
さて、いよいよ、TextAnalyticsとの連携部分を作っていきます。公式ドキュメントでは新しく.NET Core コンソールアプリを作った例になっているため、Mainメソッド(アプリを実行したらまず開始される部分)を書き換えるように書いてありますが、今回の場合はユーザーが話しかけてきたら発動するようにしたいので、以下の2行をOnMessageActivityAsync
のタスク内に追加します。
var client = authenticateClient();
sentimentAnalysisExample(client);
各メソッドの処理内容としては以下の通りです。
-
authenticateClient()
[新しい Azure Cognitive Services リソースを作成する](#新しい Azure Cognitive Services リソースを作成する)で作成したTextAnalyticsリソースを、このボットアプリから利用するための認証をする。 -
sentimentAnalysisExample(client)
authenticateClient()で認証されたTextAnalyticsリソースを使って、任意のメッセージの感情分析をして、スコアを得る。
追加するとこんな感じになります。この状態だと記載したメソッドの本体が存在しないため、赤い波線が出てエラーになってしまっていますが、一旦無視してください。
2.4 クライアントを認証する
このボットアプリから、先ほど作ったTextAnalyticsリソースを使えるように認証をするため、authenticateClient()の中身を作っていきます。以下のクラスを追加します。クラスなので、public class EchoBot
と同じレベル(クラス名の左側の深さを合わせる)で記載します。
class ApiKeyServiceClientCredentials : ServiceClientCredentials
{
private readonly string apiKey;
public ApiKeyServiceClientCredentials(string apiKey)
{
this.apiKey = apiKey;
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
request.Headers.Add("Ocp-Apim-Subscription-Key", this.apiKey);
return base.ProcessHttpRequestAsync(request, cancellationToken);
}
}
次に、先ほどエラーになっていたauthenticateClient
を呼び出せるようにしていきます。public class EchoBot
に戻って、以下を追加します。既にpublic class EchoBot
内にある、他のタスクと同じレベル(深さ)に記載します。
static TextAnalyticsClient authenticateClient()
{
ApiKeyServiceClientCredentials credentials = new ApiKeyServiceClientCredentials(key);
TextAnalyticsClient client = new TextAnalyticsClient(credentials)
{
Endpoint = endpoint
};
return client;
}
2.5 センチメント分析
次に、もう一つエラーになっていた、SentimentAnalysisExample() というメソッドを作成します。ここで、感情分析をするテキストの指定と、その結果の受け取りをします。以下のコードをpublic class EchoBot
に追加します。こちらも、既に存在している他のタスクと同じレベル(深さ)に記載します。
static void sentimentAnalysisExample(ITextAnalyticsClient client)
{
var result = client.Sentiment("I had the best day of my life.", "en");
Debug.WriteLine($"Sentiment Score: {result.Score:0.00}");
}
ここでは、サンプルとして、「I had the best day of my life.」という英語の文章の感情分析をしてみています。
ここで、Debug.WhiteLineの部分にエラーが出ていることに気づくかと思います。これは、拡張機能が不足している(上の方でusingしているものが、Debug.WhiteLineを使うのには足りていない)ために起きています。Debug部分にカーソルを合わせて、考えられる修正内容を表示するを選択し、using System.Diagnostics
の追加の提案を受け入れてください。すると自動的にソースコード上部にusing System.Diagnostics
が追加され、エラーも消えます。
さて、この状態で、一応ボットアプリ→TextAnalyticsリソースの利用はできるようになっていますので、一旦▶IIS Expressからローカルで実行し、Bot Framework Emulatorでボットに話しかけてみてください。
こんな感じで、出力画面にSentiment Scoreが出てきたら成功です。現時点では、ボットに話しかけたメッセージの分析ではなく、ソースコードに直接書いた「I had the best day of my life.」の分析結果ではありますが、きちんと値が返ってくれば、ボットアプリからTextAnalyticsリソースを利用し、分析結果を得ることができていることの確認ができます。
2.6 ユーザーのメッセージをTextAnalyticsで分析する
次に、ユーザーのメッセージをTextAnalyticsで分析するように、ソースコードを変更します。ユーザーのメッセージが入っているのはOnMessageActivityAsync
内のturnContext.Activity.Text
の部分ですので、これをSentimentAnalysisExampleメソッドに渡すように、コードを変更します。具体的には、sentimentAnalysisExampleの引数に、turnContext.Activity.Text
を追加します。
sentimentAnalysisExample(client,turnContext.Activity.Text);//引数turnContext.Activity.Textを追加
次に、受け取るsentimentAnalysisExample側も変更が必要ですので、以下の通り変更します。
static void sentimentAnalysisExample(ITextAnalyticsClient client, string message)//引数messageを追加
{
var result = client.Sentiment(message, "ja");//引数messageを分析対象にし、言語は日本語に設定
Debug.WriteLine($"User Message: {message}");//引数messageの内容を出力
Debug.WriteLine($"Sentiment Score: {result.Score:0.00}");
}
ここまで変更したら、またアプリを実行して、ボットに話しかけてみましょう。今度は日本語で、意味のある言葉を投げかけてみてください。
このように、話しかけた内容と、分析結果のスコアが返ってきていれば成功です!
2.7 現時点でのEchoBot.cs
現時点でのEchoBot.csのソースコードはこのような状態になります。
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.6.2
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
//for TextAnalytics
using System;
using System.Net.Http;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models;
using Microsoft.Rest;
using System.Diagnostics;
namespace YasashiiBot.Bots
{
public class EchoBot : ActivityHandler
{
//for TextAnalytics
private static readonly string key = "<replace-with-your-text-analytics-key-here>";
private static readonly string endpoint = "<replace-with-your-text-analytics-endpoint-here>";
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var replyText = $"Echo: {turnContext.Activity.Text}";
await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
//for TextAnalytics
var client = authenticateClient();
sentimentAnalysisExample(client,turnContext.Activity.Text);//引数turnContext.Activity.Textを追加
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var welcomeText = "Hello and welcome!";
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
}
}
}
//for TextAnalytics
static TextAnalyticsClient authenticateClient()
{
ApiKeyServiceClientCredentials credentials = new ApiKeyServiceClientCredentials(key);
TextAnalyticsClient client = new TextAnalyticsClient(credentials)
{
Endpoint = endpoint
};
return client;
}
//for TextAnalytics
static void sentimentAnalysisExample(ITextAnalyticsClient client, string message)//引数messageを追加
{
var result = client.Sentiment(message, "ja");//引数messageを分析対象にし、言語は日本語に設定
Debug.WriteLine($"User Message: {message}");//引数messageの内容を出力
Debug.WriteLine($"Sentiment Score: {result.Score:0.00}");
}
}
//for TextAnalytics
class ApiKeyServiceClientCredentials : ServiceClientCredentials
{
private readonly string apiKey;
public ApiKeyServiceClientCredentials(string apiKey)
{
this.apiKey = apiKey;
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
request.Headers.Add("Ocp-Apim-Subscription-Key", this.apiKey);
return base.ProcessHttpRequestAsync(request, cancellationToken);
}
}
}
以降の工程について
以降の工程はこのようになっています。
次回はTwitterと連携して、感情分析の結果がネガティブ判定だった場合、偉人さんのありがたいお言葉を返す部分を作ってみたいと思います。