今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

Microsoft Bot Frameworkで簡単なBotを作ってみる (2) ~1つのフレーズだけに答えてくれるBot~

前回の記事でMicrosoft Bot Frameworkと、どのようなbotを作りたいかを簡単に説明しましたので、今回からは実際にbotを作成していきたいと思います。

今回のゴール

前回、電力の使用状況を教えてくれるbotを作るとの述べましたが、まずは一番シンプルなものを作ってみます。今回実装するのはこれだけです。

  1. 「電気使用状況は?」と聞くと、現在の東京電力の電気使用状況を教えてくれる
  2. それ以外の言葉を投げかけると、botは理解できないので"てへぺろ"をする

その後、コードをAzureにデプロイし、更にBot Connectorを使って自分のBotとSkypeで会話することを目標にしてみたいと思います。

環境準備

公式ドキュメントに沿って環境を準備していきます。簡単に手順を書いておくと、

  1. Visual Studio 2015の最新版をインストールする
  2. http://aka.ms/bf-bc-vstemplateからBotのテンプレートをダウンロードして、“%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#"に保存する
  3. 新規プロジェクト作成画面で、Visual C#の下に Bot Applicationというテンプレートが出てくるので、それを選択する
  4. ソリューションエクスプローラからプロジェクトを右クリック --> NuGet パッケージの管理 から、Microsoft.Bot.Builderをインストールします

f:id:kanohk:20160616231557p:plain

以上でコードを書く環境が整いました。ちなみに、このテンプレートは、送った文字数を数えて教えてくれるbotがサンプルとして実装されています。

デバッグ方法

デバッグには Bot Framework Emulator というものを使います。
https://aka.ms/bf-bc-emulator このURLからダウンロードできます。
試しに、先ほど作ったプロジェクトをビルドして試しに会話してみましょう。
なぜかビルドエラーができるので、MessagesController.csの9行目の
using Microsoft.Bot.Connector.Utilities;
を削除してからF5を押してビルドします。そしてBot Framework Emulatorを開くと、画像のように会話できます!
f:id:kanohk:20160616232428p:plain
画面左側がチャット画面、画面右側がその際にユーザとBotの間でやり取りされるJSON形式のデータです。

Botをいじったら、ローカルでビルドしてこのEmulatorで動作確認・デバッグを繰り返してコードを完成させていきます。

返答を変えてみる

さっそく、英語で文字数を教えてくるのではなく、「電力使用状況は?」といったら電力使用状況を、それ以外の言葉だったらてへぺろをさせるように変更してみます。
入力されたメッセージを受け取って、返事を返す部分の処理は、MessageController.csのMessagesController::Postという関数で行われています。
これが、その部分です。

        public async Task<Message> Post([FromBody]Message message)
        {
            if (message.Type == "Message")
            {
                // calculate something for us to return
                int length = (message.Text ?? string.Empty).Length;

                // return our reply to the user
                return message.CreateReplyMessage($"You sent {length} characters");
            }
            else
            {
                return HandleSystemMessage(message);
            }
        }

単純ですね。messageという変数には、ユーザーが打ったテキストも含め、様々な情報が格納されています。具体的には、先ほどのエミュレータの画面右側JSON部分に表示されていた情報が、ここに格納されます。他にどんな情報が渡されているか見てみたい方は、エミュレータで確認してみてください。
message.CreateReplyMessage()という関数で、実際にユーザーに返す返答を作成しています。

message.TypeはMessage以外にも存在していて、例えばユーザがbotとの会話画面を開いた場合はmessage.Type = "BotAddedToConversation"となります。今回は、TypeがMessage以外の場合の処理はいじらずそのままにしておきます。
変更を加えたコードがこちらになります。

        public async Task<Message> Post([FromBody]Message message)
        {
            if (message.Type == "Message")
            {

                Message reply = null;
                if (message.Text == "電力使用状況は?")
                {
                    // 実際の電力使用状況を取得する部分は後ほど追加します
                    reply = message.CreateReplyMessage("???kWです");
                }
                else
                {
                    reply = message.CreateReplyMessage("(。・ ω<)ゞてへぺろ♡");
                }
                return reply;
            }
            else
            {
                return HandleSystemMessage(message);
            }
        }

実際にこれをビルドして、エミュレータで会話してみた結果が以下になります。
f:id:kanohk:20160616234254p:plain
ちゃんと返答が意図したとおりになっていますね!!

電力使用状況を取得する

では最後に、Yahoo!から提供されている電力使用状況APIを使用して実際の電力使用状況を取得してみましょう。
アプリケーションIDを発行後、次のURLにアクセスするとJSON形式のデータが取得できます。
http://setsuden.yahooapis.jp/v1/Setsuden/latestPowerUsage?appid=<アプリケーションID> &area=tokyo&output=json
コードは、とりあえず適当にこんな感じで。。

        private int? GetElectricityUsage()
        {
            int? result = null;
            try
            {
                var requestUrl = @"http://setsuden.yahooapis.jp/v1/Setsuden/latestPowerUsage?appid=<アプリケーションID>&area=tokyo&output=json";
                var request = WebRequest.Create(requestUrl);
                var response = request.GetResponse();
                var rawJson = new StreamReader(response.GetResponseStream()).ReadToEnd();
                var json = JObject.Parse(rawJson);
                result = (int)json["ElectricPowerUsage"]["Usage"]["$"];
            }
            catch
            {
                // Do nothing.
            }
            return result;
        }

先ほどのPost関数に、GetElectricityUsage()で取得した値を埋め込めば、完成です!
エミュレータでもこのように動くことを確認しました。
f:id:kanohk:20160617024327p:plain

Azureにコードをデプロイ

現時点でコードは書き終えたので、このコードをAzureにデプロイしていきます。
このドキュメント通りに操作すると、すぐにデプロイできます。
リンク先の画像見るとなんとなく手順はわかると思うので、詳細は省略します。

Bot ConnectorでSkypeにデプロイ

Bot Frameworkの Register a botページから、先ほどAzureに上げたbotを登録します。
Botの名前などを指示通り入力していくだけです。endpointに関しては、https://***.azurewebsites.net/api/messages というような形を指定します。
登録が終わると、Botの管理画面が表示され、そこに次のようにApp IDとシークレットキーが表示されるかと思います。
http://docs.botframework.com/images/connector-getstarted-subscription-keys.png
Web.configの以下の箇所にIDとシークレットキーを入力する箇所があるので、そこを書き換えて再びAzureに公開します。

  <appSettings>
    <!-- update these with your appid and one of your appsecret keys-->
    <add key="AppId" value="YourAppId" />
    <add key="AppSecret" value="YourAppSecret" />
  </appSettings>

Bot管理ページに Test connection to your bot という箇所があるので、そこに何かを入力してSendをクリックしてみます。
画像の通り、何かしら答えが帰ってきていればAzureにアップロードしたBotに正しく接続できています!
f:id:kanohk:20160617021642p:plain

さて、いよいよSkypeにbotを登録します。
画面右側の Add another channelからSkype Addを選択します。
f:id:kanohk:20160617021819p:plain

すると、画面に指示が表示されるので、上から順番に従っていきます。ちょっとステップ数が多くて面倒くさいですが。。英語ですが指示は丁寧に書いてあるので、需要がない限り詳細の説明は省略しますね。
登録が終わると、次のような画面が表示されてBotを自分のSkypeに追加できるようになります。下のPublishボタンを押すとこのbotが公開されるようなのですが、このbotは公開したくないので今回はPublishしないでおきます。
f:id:kanohk:20160617023010p:plain

動作確認

さて、これですべての作業が終わりました。Skypeに追加したbotに話しかけてみます。
f:id:kanohk:20160617023838p:plain
無事、Skype上でbotが動いていることが確認できました。やったね!

ソースコード

今回のコードは、この場所に置いておきます。
https://github.com/kanoh-k/ElectricityBot/blob/a753a5b89fd0726eaaf297b19cb721b02cea97f4/ElectricityBot/Controllers/MessagesController.cs


次回は、「電力使用状況は?」と聞くと「どの電力会社について知りたいですか?」とbotが聞き返してくるような、"会話"の実装に挑戦してみたいと思います。
www.madopro.net

Bot Framework V3と日本語のLUISを使ったサンプルをお探しの方はこちらもどうぞ。
www.madopro.net