目次
- 目次
- はじめに
- 上級クエストの目標
はじめに
上級クエストの題材は 初級・中級クエストを終了した状態を想定としています。まだの方はこちらのまとめから取り組みましょう!
上級クエストの目標
本記事は上級クエストの動画に沿って、解説していきますが、メインはコーディングの解説になります。 Azureの設定やデプロイ方法等については、動画を参考にしつつ、こちらの記事をご覧ください。
上級クエストではAIを使い、Botに「考える」という能力を付与することです。
中級クエストでは、ネガティブワードを定義して利用していました。
// ネガティブワードの定義 public string[] negativeWords = { "しんどい", "つらい", "たいへん" };
しかし、全てのネガティブワードを定義するのは難しいです。また、ここにポジティブワードを定義するとなると、処理が大変になります。
そこで、AzureのCognitive Services(Text Analytics)を使って、送られてきたメッセージを分析してもらい、文章全体がネガティブなのかポジティブなのかを判定してもらいます。
この動作をするBotを上級クエストで作っていきたいと思います!
1. Cognitive Serviceのアカウントを作成する
Azureのポータルを開いて「リソースの追加」から「Text Analytics」を選択します。
各項目に必要事項を設定し、リソース生成が終わったら、「キーとエンドポイント」を選択して、「キー1」と「エンドポイント」をメモ帳などにコピーしておきます。
「キー2」は「キー1」が利用できなくなったときに利用するため、今回は使用しません。
2. BotでText Analyticsを使えるようにする
2.1. Text Analyticsをインストール
BotでText Analyticsを利用するには「パッケージ」というText Analyticsを使うための呪文が入った宝箱を手に入れる必要があります。
Visual StudioでBotのソースを開きます。開いたら、ソリューションにあるEchoBotと書いてある部分を右クリックして「NuGetパッケージの管理」を押します。
検索に「CognitiveServices.Language.TextAnalytics」と入力します。画像と同じものを選択し、パッケージの追加をします。このとき「ライセンスの同意」の画面が表示されるかもしれません。表示されたら「同意する」を押して進みます。
追加が終わると、NuGetフォルダーにTextAnalyticsが追加されていると思います。
追加できたら、TextAnalyticsを使う準備をします。下のコードはTextAnalyticsのパッケージに含まれる呪文のうち、何を使うか。という宣言をしています。この宣言をしないと、一体「何の」「どの呪文」を使うかが分からないので、Botは呪文を使うことができません。
// TextAnalyticsを使うための呪文 using System; using System.Net.Http; using Microsoft.Rest; using Microsoft.Azure.CognitiveServices.Language.TextAnalytics; using Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models;
こんな感じで追加します。元から書かれている using 〜;
は消さないようにしてくださいね。今まで動いていたBotが動かなくなります。
2.2. キーとエンドポイントURL、呼出しの設定
次に「1.」で作成したCognitiveServiceのアカウントをTextAnalyticsで利用できるように設定していきます。
この設定を行うことで、自分が作ったBotのみが、自分が作成したTextAnalyticsにアクセスできるようになります。
(※ 今回はキー、エンドポイントURLをソースコードに直書きしますが、ソースコードを外部に公開するときには、Azure Key Vault というサービスを使い、安全に公開できるようにする必要があります。)
下のコードをソースに貼り付けます。貼り付けたら、「1.」でメモした「キー」と「エンドポイントURL」に置き換えてあげます。
// CognitiveServicesのキー private static readonly string key = "<メモしたkeyと置き換える>"; // CognitiveServicesのエンドポイントURL private static readonly string endpoint = "<メモしたエンドポイントURLと置き換える>";
初級・中級クエストで書いたコードはコメントアウトもしくは消しても大丈夫です👀
次に、Botを呼び出すための元を作っていきます。Botを呼び出すために以下の3つの作業を行います。
2.2.1. authenticateClient
メソッドの呼出部分を追記
2.2.2. ApiKeyServiceClientCredentials
クラスのコピー
2.2.3. authenticateClient
メソッドの作成
2.2.1. authenticateClient
メソッドの呼出部分
// authenticateClientを呼び出す部分
var client = authenticateClient();
貼り付けただけでは、エラーになりますが「3.」でメソッドの本体を作成することで解決します。
2.2.2. ApiKeyServiceClientCredentials
クラスのコピー
こちらのコードをコピーします。これはAzureの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); } }
記述場所は EchoBot
クラスと同じ階層になります。
画像を見ると、コードが少なくなっているように見えますが、折りたたんでいるだけなので、変わってないです!
2.2.3. authenticateClient
メソッドの作成
最後に、BotからTextAnalyticsを呼び出すための元を作成します。これを呼び出すことでCognitiveServiceを呼び出すためのクライアントが作成されます。
これを追加することで「1.」で追加したメソッドのエラーが解消されているはずです。
static TextAnalyticsClient authenticateClient() { var credentials = new ApiKeyServiceClientCredentials(key); var client = new TextAnalyticsClient(credentials) { Endpoint = endpoint }; return client; }
3. 実際にTextAnalyticsを使ってみる
ここまでこれば、あとは実際にAzure上のTextAnalyticsを呼び出しに行く部分を作成します。今回は「センチメント分析(Sentiment)」を使って見たいと思います。
まずは、センチメント分析を呼び出すメソッド「sentimentAnalysisExample」を作成します。後からアプリを実行してもらいログを確認するのですが、とても見にくいので動画とは違うコードが含まれています。これは少しでも見やすくするためなので、あってもなくても問題ないですが、あったほうが見やすいです👀
// Azureのセンチメント分析を実行するメソッド static void sentimentAnalysisExample(ITextAnalyticsClient client) { var result = client.Sentiment("I had the best day of my life.", "en"); Debug.WriteLine("----------------------------------------------"); Debug.WriteLine($"Sentiment Score: {result.Score:0.00}"); Debug.WriteLine("----------------------------------------------"); }
ただ、これをそのまま貼り付けても「Debug」という部分でエラーが発生すると思います。このエラーは「Debug」という呪文が使えるようになっていないため、使えません。というエラーになります。そのため自分で以下の using
を追記するか、エラーの解決から自動で入力してもらいエラーを解消しましょう。
using System.Diagnostics;
ちゃんとエラーが消えて、赤波がなくなっていればOKです!
そして、この sentimentAnalysisExample
メソッドを呼び出す部分を追加します。追加する場所は authenticateClient
メソッドを呼び出している下に追加してみます。
// センチメント分析の実行
sentimentAnalysisExample(client);
ここまで出来たら、ローカルで実行してみます。ローカルで実行して適当にBotに喋りかけてみます。喋りかけたらVisual Studioに戻り、アプリケーションの出力結果を見てみます。大体がVisual Studioを画面下部の方にあると思います。
その中で「Sentiment Score: 0.87」とあります。これが表示されていれば、無事Azureのセンチメント分析を実行することができています。
4. 送られてきたメッセージを分析させよう
次は実際にユーザーから送られてきたメッセージをセンチメント分析してみます。ここですることは大きく3つです。
4.1. sentimentAnalysisExample
メソッドを修正してメッセージを渡せるようにする。
4.2. メッセージをセンチメント分析させて結果をログに表示させてみる。
4.3. 分析の結果に応じてBotの反応を変えてみる。
4.1. sentimentAnalysisExampleメソッドを修正する
今の sentimentAnalysisExample
メソッドは client という変数しか受け取ることができません。下のコードの ITextAnalyticsClient client
という部分が1つの引数となっていて、これが呼び出している側の client
と紐付いています。
// Azureのセンチメント分析を実行するメソッド static void sentimentAnalysisExample(ITextAnalyticsClient client) // 呼び出しているところ // センチメント分析の実行 sentimentAnalysisExample(client);
なので、sentimentAnalysisExample
メソッドの引数に、メッセージを受け取れるように引数をもう1つ追加します。
// 修正前 static void sentimentAnalysisExample(ITextAnalyticsClient client) // 修正後 static void sentimentAnalysisExample(ITextAnalyticsClient client, string message)
さらに、3. 分析の結果に応じてBotの反応を変えてみる。
で分析した結果を利用してBotの反応を変える処理を実装します。その準備として、このメソッドが結果を返せるように修正をします。現時点でこの修正をするとエラーになると思いますが、次の修正で解決されます。
// 修正前 static void sentimentAnalysisExample(ITextAnalyticsClient client, string message) // 修正後 static double sentimentAnalysisExample(ITextAnalyticsClient client, string message)
そして、メッセージが受け取れるようになったところで、受け取ったメッセージでセンチメント分析を行うようにします。今回の場合はメッセージは日本語という設定なので en
→ ja
とします。
// 修正前 var result = client.Sentiment("I had the best day of my life.", "en"); Debug.WriteLine("----------------------------------------------"); Debug.WriteLine($"Sentiment Score: {result.Score:0.00}"); Debug.WriteLine("----------------------------------------------"); // 修正後 var result = client.Sentiment(message, "ja"); Debug.WriteLine("----------------------------------------------"); Debug.WriteLine($"User Message: {message}"); Debug.WriteLine($"Sentiment Score: {result.Score:0.00}"); Debug.WriteLine("----------------------------------------------"); return (double)result.Score;
4.2. メッセージをセンチメント分析させて結果をログに表示させてみる。
sentimentAnalysisExample
メソッドの修正が終わったら、そのメソッドを呼び出しているところでもメッセージを渡すように変更する必要があります。ユーザーから送られてきたメッセージは turnContext.Activity.Text
で取得することができます。
また、4.1.
の修正でセンチメント分析の結果を返すようにしたので、その結果も受け取るようにしましょう。
// 修正前 // センチメント分析の実行 sentimentAnalysisExample(client); // 修正後 // センチメント分析の実行 var score = sentimentAnalysisExample(client, turnContext.Activity.Text);
ここまでの修正で、コードはこのようになっていると思います。初級・中級のコードは省いて掲載しています。
・OnMessageActivityAsync
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { // authenticateClientを呼び出す部分 var client = authenticateClient(); // センチメント分析の実行 var score = sentimentAnalysisExample(client, turnContext.Activity.Text); var replyText = $"オウム: {turnContext.Activity.Text}"; await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken); }
・sentimentAnalysisExample
// Azureのセンチメント分析を実行するメソッド static double sentimentAnalysisExample(ITextAnalyticsClient client, string message) { var result = client.Sentiment(message, "ja"); Debug.WriteLine("----------------------------------------------"); Debug.WriteLine($"User Message: {message}"); Debug.WriteLine($"Sentiment Score: {result.Score:0.00}"); Debug.WriteLine("----------------------------------------------"); return (double)result.Score; }
ここまで出来たら、ローカルでBotを起動して実際にメッセージをセンチメント分析にかけてみます。今回は動画と同様「肩こりがしんどい」というメッセージを送信してみます。
そして、送信したら再度Visual Studioのアプリケーション出力部分を確認してみます。すると、送信したメッセージとそのメッセージを分析した結果(数値)が表示されていると思います。
これで、受け取ったメッセージで分析できていることが分かります。いろいろなメッセージを送ってみるのもいいですね!
4.3. 分析の結果に応じてBotの反応を変えてみる。
さて、上級クエストの終わりが近づいて来ました。最後はこの分析した結果(数値)を用いて、Botが送るメッセージに変化を持たせたいと思います!!
4.2.
で分析の結果を取得できるように変更をしました。この結果(数値)を用いてBotからの返信を変えてみます。
この結果(数値)は以下のような対応になっています。
なので、今回は 「0以上0.5以下」 ならばネガティブと見なして「いたわる言葉」を「0.5より大きく1以下」ならばポジティブと見なして「喜びの言葉」を返すようにしたいと思います。
判定の方法はこんな感じ
// センチメント分析の結果を判定 if (0.5 <= score) { // ポジティブ } else { // ネガティブ }
これを OnMessageActivityAsync
に組み込みます。前回の修正と合わせて実装すると以下のように修正できます。
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { // 返信する言葉を格納する変数を定義 var replyText = ""; // authenticateClientを呼び出す部分 var client = authenticateClient(); // センチメント分析の実行して結果を取得 var score = sentimentAnalysisExample(client, turnContext.Activity.Text); // センチメント分析の結果を判定 if (0.5 <= score) { // ポジティブ replyText = "やったね!すばらしい!"; } else { // ネガティブ replyText = "おつかれ!負けないで!"; } // 返信を送る await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken); }
修正したら、ローカルで実際に動かしてみます。送る文章は動画と同じで「肩こりがしんどい」と「昨日友達とたくさんゲームをしました。楽しかったです。」とします。
ちゃんと送られてきています。そしてVisual Studioのログも確認して、本当に数値通りに送られてきているか確認してみましょう。
それぞれで、ネガティブ、ポジティブ判定として送られてきていることが分かります。これで上級クエストクリアです🎉🎉🎉
他にも様々なAIがあるので、他のAIと組み合わせて見ると面白いと思うので、ぜひ挑戦してみてください!!