blog試したこと・調べたこと・感じたことを発信するITエンジニアの日記です。仕事とは直接関係ないけど興味あることを模索していきます。この広告は、90日以上更新していないブログに表示しています。Serviceここ最近、私の中で"チャットボット"がホットなテーマになってます。日本人ってチャット好きですよね。きっかけは1冊の本です。見るお盆休みはだらだらと過ごしてしまったので、何か1つぐらいはブログ更新しないとなぁと思いつつ見切り発車で書いていきます。MakerでノンプログラミングでFAQチャットボットを作ってみます。ノンプログラミングです。お盆休みにあんまり頭を使わずにできる最大限の成果物。ブログ書きながら作っていこうと思います。最終的にうまくいくかどうかはわかりません。30分で終わるかどうかもわかりません。それでは始めていきます。Serviceを作成します。Previewですね。新規作成は特に難しくなく作成、必要事項の入力とサクサクっと進めていきましょう。Serviceがデプロイ開始されます。デプロイ時間はあっという間。トイレに行く暇もないぐらいすぐにデプロイ完了します。Serviceを開くと、初期設定できます。password)を行う必要があるので、アプリケーションIDとパスワードを生成します。パスワードは1回しか表示されないので、メモしておきます。Answerを選びます。これでCreateすればオッケーです。途中の入力項目は説明する必要もないと思うので説明はかなり省略してます。agree"して"OK"します。Makerの生成の両方ができます。時間がかかるので、グルグルしている間にトイレ行けます。戻ってきたら終わっているはずです。Serviceは完成です。ソースコードがちらりと見えていますね。Functionsなので、ここから編集もすることができます。今回はノンプログラミングなので、ソースコードには見向きもしませんが。MakerのDialogを生成して呼んでいるだけのようです。ノンプログラミングなのでソースコード見なくてもいいですよ。Serviceからは一旦離れます。今の状態だと、"hi"と質問すると"hello"と返すという何とも残念なFAQボットちゃんなので、もう少し賢くしていきます。Makerのページにアクセスして設定していきます。MakerFAQの元ネタとなる情報をインプットしていく必要があるので、何かネタを...最近、キングコング西野さんのことが気になっているので、彼が宣伝しているパインアメについてのFAQにしましょう。私にはステマソングを作る歌唱力もないので、その代わりにパインアメボットを作ってみるということで。ネタが決まったので、さっそくパインアメのサイトからFAQの情報を探します。少ない...もっと情報たくさんあった方が面白いけど、30分という時間では無理なので、このFAQを題材にすることにします。Makerに読み込ませていく設定をしていきます。"Setting"のURLsにパインアメのサイトURLを入力します。Retrain"します。パインアメの問い合わせ情報を学習してもらうわけです。これで少しパインアメについて賢くなったわけです。賢くなったかどうかテストしてみます。"Test"を開くと、チャット形式の画面になるので、そこから問い合わせ情報にあった内容を入れてみます。このとき、完全に一致する文章じゃなくてもある程度反応してくれます。よしよし、パインアメFAQボットの脳みそ部分ができてきました。テストがオッケーなら、Publishします。Serviceと融合させて、パインアメ子にしていきましょう。あ、勝手に命名しました。ダサいってのはわかっていますが、名前を考える時間ないんので。Makerはつながってます。パインアメ子にアクセスしてみます。デフォルトでは、SkypeがChannel設定されているので、Skypeで会話してみます。ChannelsからSkypeを選択して、パインアメ子にコンタクトします。Skypeから適当に問い合わせをしてみると、ちゃんと答えてくれます。表示名がパインアメ子になってほしかったのに、適当に付けたIDになっているのが少し残念。Serviceを使うことで、簡単にFAQボットが作成できる基盤が構築できることがわかりました。簡単なものであれば、サクッとノンプログラミングでできてしまいますが、おそらくそれだけで対応できることなんて少ないと思うので、これを基本にプログラム追加して賢いFAQボットを作成していくのがよいかと思います。Frameworkでちゃんと作りこんでいくのも手としてありますので、私の書いた過去記事も参照してみてください。多くの情報を集めてよりよい判断が出来ているだろうか?情報集めに必死になって時間切れになっていないだろうか?働き方改革と銘打って勤務時間の短縮やテレワークなど様々な方法を企業は取り組んでいるが、個人個人がムダなことをそぎ落として、成果に直接結びつくことのみに注力することが一番大切なのではないかと思う。今回の私が読んだ「仮説思考」には方法がまさに記述されている。エンジニアとして、「仮説思考」は身につけないといけない考え方なので、興味を持った方は是非読んでみてほしいと思います。Framework書店でチャットボットの書籍が目にとまり読んでみました。ついでに試してみたくなってやってみました。きっかけはそれだけですが、思った以上に作るの楽しいです。機能としてはシンプルなBotに仕上がりました。基本ができれば、あとは好みで機能を拡張していけば良いです。引っかかる要素がある方は気軽に読んでください。ゴール表題の通り、作成するのはお天気ボットです。天気情報を教えてくれるだけの単純なボットです。一応、自然言語を解析しているので、ある程度の文章のばらつきや曖昧さがあっても反応はしてくれます。場所の情報がインプットされていなかったら聞いてくれます。完成品のイメージです。1枚目がPCのSkypeから、2枚目、3枚目がスマホのSkypeからです。天気情報のアイコンがかなり荒くなってしまいました。(画像のサイズの変え方がわからなかった)北海道と指定すると、よくわからないところを検索結果として返して来ます。これは、天気APIに対する呼び出し方が悪いのでそこをもう少し工夫する必要がありそうです。これぐらいは愛嬌ということで、今はこのままです。Frameworkを用いて1から作成することにしました。Serviceは、今回作成したBotのデプロイ先として利用していて、VSTSでソースコード管理しデプロイする構成を採用してます。APIを使用しています。天気情報の取得には、OpenWeatherMapAPIを使うことにしました。Serviceについてもある程度試してみたのでまた今度、記載したいと思います。作成していった流れに沿って説明していきます。Frameworkへの登録AzureへのデプロイSkypeからテスト何度も言いますがかなり長文です。今までの中で群を抜いて長文なので読むのに時間がかかると思います。Frameworkを開発するための環境設定を行なっていきます。MS公式サイトを参考に構築してます。2017を使っていきます。VS2017をインストールします。私は、現時点でPreview版ですがVersion15.3をインストールしました。機能的には、Community版で問題ないかと思います。最新の情報は英語での記載が多いので、私はVS2017を英語表記で使ってます。説明も英語表記で記載しています。インストールが完了したら各種extensionsを最新にしておきましょう。書いてますが、特にUpdateが必要なものはなかったです。Studioのプロジェクトテンプレートをダウンロードします。ダウンロードサイトは、下記です。Dialog.http://aka.ms/bf-bc-vsdialogtemplateそれぞれダウンロードしたら、zip形式のままテンプレートの所定の格納先に配置します。Solutions]-[Locations]から確認することが出来ます。デフォルトでは、下記になっています。出来たので、早速作成していきます。最初はとりあえず動くものを作成するところまでやっておき、少しずつ機能拡張して、完成イメージに近づけていきます。Studioを起動します。起動したら、新しくプロジェクトを作成していきます。Applicationが選択できるようになっています。作成が出来れば、下記のように新しくソリューションとプロジェクトが構成されます。NuGetでパッケージを最新化を行なっておきます。Builderをアップデートします。執筆時点では、Version3.9が最新でした。これで概ね動くはずです。RepositoryへPushしておきます。細かい手順は、過去に記事にしている内容を参照いただければと思います。ExplorerからVSTSへConnectしてPushするだけです。ninna2.hatenablog.com実行及びデバッグ作成したプロジェクトを実行していくのですが、Botにアクセスするためには、チャットをエミュレートするエミュレータが必要です。公式のエミュレータとし“botframework-emulator”が提供されていますので、インストールします。現時点での最新は、Version3.5.29です。github.com作成したプロジェクトを実行していきます。実行は、VS2017から実行(F5)で出来ます。Chrome"になっていたのでブラウザ側でエラー表記が出ました。Bot自身の問題ではないので無視しても良いかとは思いますが、IEでアクセスするようすれば、正常にアクセス出来るのでその方が良いかと思います。Botが起動したので、"botframework-emulator"からアクセスしてテストしてみます。emulatorの左上部にURLを入力する箇所があるので、規定値の"http://localhost:3979/api/messages"と入力してConnectします。AppIDやPasswordを入力する箇所がありますがローカルでのアクセスには使いませんのでブランクで構いません。接続後に、チャット入力(左下)してみると、入力した文字数を返してくれるはずです。ブレイクポイントを貼っておけば止めれます。これでローカルで開発できるようになりました。デプロイするための環境設定ローカルでの開発、実行、デバッグができるようになったので、この初期BotアプリケーションをAzure上にデプロイするしていきます。初期の段階からデプロイする設定を固めておけば、後から困ることもないので、本格的に作成する前にしっかり設定を入れていきます。Serviceで動きます。PaaS上で動くのでサーバの設定とかほとんど気にせず公開することが出来ます。Serviceにデプロイする方法は3種類あります。ServiceへVS2017から直接アプリケーションを発行する方法です。個人的に開発して試しに乗せてみるみたいな使い方としては良いですが、ちゃんとした開発ではあまりやらない方法かと思います。下記のサイトに詳しく書いてあるのでお手軽に試したい場合はやってみてください。App)を先に作成し、リポジトリと連携させる方法です。ソースコード管理と連携しているので、リポジトリにPushするたびにデプロイされることになります。設定については、公式サイトに載っているので参考にしてみてください。Ripositoryでソースコード管理をしている場合には、VSTSからビルド・デプロイする方法もあります。App"用のテンプレートがあるので、必要事項を入力していくだけで簡単にCI/CDパイプラインが構築できます。Onにしておけば、Pushするたびにビルドが走り、Azureへデプロイするように構成を出来ます。ビルドとデプロイを同時に行う構成にしてますが、分けることも可能なので、ビルドして承認してデプロイみたいなフローも柔軟に組めます。VSTSについては、過去記事にも取り上げているので参考にしてみてください。ninna2.hatenablog.com私はこの方法でデプロイの構成を組んでます。AzureにデプロイしたBotのテストローカルで実行した方法と同様に、Azureに載せた初期Botアプリケーションもbotframework-emulatorを起動してテストを行なってみます。ServiceのURLに"/api/messages"を付与したものに書き換えれば繋ぐことができるはずです。ここまで確認できれば、ローカルで開発し、PushするとAzureへのデプロイするところまでいつでも出来ます。アプリケーションの概要さて、開発環境も整いましたので、お天気Botを本格的にコーディングしていきます。どのような構成にしようか試行錯誤した結果、下記のような構成になりました。全体のソースコードはGitHubに公開してます。APIを呼び出して日本語から英語に翻訳します。domains"としてすでに構築された"Weather"は英語でのみ提供されているので、日本語から英語に翻訳してLUISに渡します。LUISで自然言語の解釈をした上で天気情報だと判断したら天気APIを呼び出してます。Location情報が入力されていない場合には、入力を促すようにしています。Location情報が入力されたら、天気情報を取得します。天気情報を取得するAPIは、OpenWeatherMapAPIを使っていて天気情報と天気アイコンを取得して返してます。このような流れのものを作っていきます。Service)はAzure上に構築した上で、APIKeyを取得する必要があります。登録を行なって、その上で、Botに組み込んでいきます。APIの公式は下記です。Portal(http://portal.azure.com)にアクセスして追加していきます。説明を省略しましたが、わかるはずです。APIの公式を参照ください。デプロイできるとこのような感じでURLが付与されます。ここまでできるとほぼ使える状態なので、あとはAPIKeyの確認をします。APIのKeyは10分しか有効期間がないらしく、アプリから実行する際には、10分おきに再取得する必要があるようです。実装もそうなってます。APIの実装は、下記のサイトを参考にさせてもらいました。参考にさせてもらったというかほとんど真似た、少し自分でわかりやすくしたという表現の方が正しいかもしれません。APIポイントを解説しておきます。スマホだとソースコード読みにくいですね。PCでじっくり見てもらった方がよいかもしれません。APIを呼び出すためのクラスとしてService/MessageTranslatorServiceを作成しています。中身はシンプルで、Translateというメソッドのみ提供しています。引数は翻訳するテキストをインプットにしています。Translateの処理の中身は、Keyの有効期間を確認(RefreshTokenメソッドに実装)してHTTPClientで呼び出しているだけです。結果はXML形式で返ってくるので、文字列を取り出して返却するようにすれば完成です。}}このサービスの呼び出しは、Controller/MessagesControllerから行います。LUISを呼び出す前に翻訳を行います。activityの中身を直接翻訳して差し替えてます。後続処理これで日本語で入力されたチャットメッセージをLUISに渡す前に翻訳してから、LUISに流すことができそうです。APIに限らずAPIKeyはWeb.Configに記載するようにしています。この辺りの実装方法はもっとちゃんと考えないといけないかもしれないです。APIで入力された文字列の翻訳ができたので、英文を解析するLUIS部分の実装をやっていきます。LUISもAzureのサービスですので、まずは登録して使えるようにしてから、Botアプリケーションに組み込んでいきます。LUISの登録LUISを始めるには、公式ページ(https://www.luis.ai/home)から登録していきます。初回登録のやり方は割愛します。Azureのアカウントがあれば簡単に出来るはずです。App]から、新しく作成していきます。今回は、英語版を使いたいので、CultureはEnglishにします。日本語がどれぐらい使えるのかはまた今度やってみたいと思います。domains]を選択します。事前構築済みのものが色々でてくるので、下の方にある"Weather"をAddします。これで天気に関するIntentsとEntitiesが作成されます。Intentsが文章の意味や意図の部分で、Entitiesがその中でのキーワードのような感じです。"Weather"では、Intentとして"Weather.GetCondition",“Weather.GetForcast"の2つが、Entityとして"Weather.Locaton"が登録されます。文章を解析して、意図としてConditionに関連しているのか、Forcastに関連しているのか判別してくれて、文章の中に、Locationに関するキーワードが含まれていて、それがなんなのかを解析してくれるというわけです。Intentsが1枚目、Entitiesが2枚目です。簡単にちゃんと文章(英語)が解析されるかテストしてみます。Test]で[Train]させてから、文章を入力します。kyoto?“とか入れてみたら、ちゃんと解析して判別してくれています。ここまで出来れば、Publishしてアプリケーションから使える状態にしていきます。App]-[Piblish]します。URLが発行されるのでブラウザからアクセスしてみます。その際に"q=“の後ろに解析したい文章をつけると結果がちゃんと返ってきます。URLの"apps/“の後ろの部分の文字列がAppID、"subscription-key="の後ろがAPIKeyになります。Web.configに記載します。これで、LUISは使えるようになりました。LUISとの連携LUISとの連携部分は、LuisDialogというクラスを継承して作っていきます。あるDialogは削除してしまって構いません。Dialog/RootLuisDialogというクラスを作成します。LuisDialog<object>{・・・}LuisIntentというタグをつけることで、解析結果によって呼び出すメソッドを変えることが出来ます。今回は、2つのIntentどちらの場合も、天気APIを呼び出すようにするので、下記のようになります。どちらにも該当しない場合は"None"に振り分けられます。result){・・・}中の処理には、FormFlowを使っています。説明するのすごく難しいので、公式サイトの例を読んでもらうのが良いかと思います。docs.microsoft.comFormFlowを使うとあるクラス(今回の場合はWeatherQueryクラス)に定義されたプロパティを埋めていく処理を簡単(!?)に実装できます。入力がされていないプロパティがあったら、入力を促すようにできるわけです。Locationは今回必須なので、解析した結果にLocationが入力されていない場合に、"どこの天気が知りたいの?"と聞くようにしています。全てのプロパティが揃えば、後続処理(天気APIの呼び出し)を行うようにしています。天気APIの呼び出し処理}連携の最後は、Controller/MessageControllerから呼び出すようにします。APIで翻訳するの処理の後に処理を追加します。}・・・ポイントだけ説明しましたが、これでLUISとの連携ができました。APIで翻訳した文章を自然言語の解析を行なって、文章の意味とキーワードを抽出できたので、天気情報を取得する処理に次はつなげていきたいと思います。実装もかなり進んできました。LUISによる自然言語処理で言葉の意図とキーワードの抽出ができたので、その情報を元に天気情報を取得する部分を作っていきます。天気情報を取得するAPIはいくつかありますが、無料で使用することができるOpenWeatherMapAPIを使用します。無料版はいくつか制約がありますが無料版でいきたいと思います。OpenWeatherMapAPIの登録アクセスするにはやはりAPIKeyが必要なので、ユーザ登録をしてAPIKeyを取得します。OpenWeatherMapAPIの公式サイトのにアクセスします。openweathermap.orgユーザ登録はメールアドレスのみで出来ます。登録後にAPIKeyをメモっておいてください。実装は、下記のソースコードを大いに参考にさせていただきました。OpenWeatherMAPService/OpenWeatherMapServiceにAPIアクセス用のサービスクラスを作成しています。GetWeatherAsyncメソッドにて、OpenWeatherMapAPIにアクセスして情報を取得して、返ってきたjsonをクラスに読み込んでいます。処理としては単純です。}}呼び出し側は、FromFlowの処理とが終わった後の処理部分(RootLuisDialogクラスのResumeAfterFormDialog)で呼び出しています。呼び出し後に天気アイコンのIDから、アイコン画像を引っ張ってきています。APIで日本語から英語に翻訳して、そのセンテンスをLUISが解釈してOpenWeatherMapAPIにて天気情報を取得する一連の流れが出来ました。Frameworkへお天気Botアプリケーションが完成したのでこいつをSkypeから呼べるようにしていきたいと思います。Frameworkへの登録を行い、Connectorから呼び出します。Frameworkへの登録は、下記から行います。Azureのアカウントがあればサインイン出来るはずです。必要事項は適時入力します。ここで重要なのはEndpointの設定です。”/api/messages"を付与したアドレスです。このアドレスが間違っているとうまく連携できません。AppIDとPasswordを生成します。Passwordは1回しか表示されないのでメモるの忘れないでください。全ての入力できたら[Register]で登録完了します。Azureへのデプロイさて、登録すると[Test]というタブが現れるので早速テストしてみたくなるのですが、先ほど取得したKey情報をお天気Botアプリケーション側に埋め込まないと動きません。Appにデプロイしてください。RipositoryにPushしたら自動的にデプロイされます。Skypeからテストこれで最後です。Channelから初期設定として存在しているSkypeをクリックしてSkypeと連携します。Skypeからお天気Botにメッセージを送って天気情報を返してくれたら成功です。うまくいかない場合は、Endpointが合っているか、AppIDなどの情報がちゃんと記載されているかを確認してみてください。