IBM Cloud Advent Calendar 2018 12月16日分です。
序文
Slackのようなツールを、社内のサーバールーム内のサーバーや、自社用にリソース専有させたクラウド環境等で使いたいというニーズは常にあります。気づけば10年以上グループウェアの世界に、提案側、開発側、導入側、ユーザー側として携わり、ヘルプデスク組織の運営などもやってきました。新卒一年目にPHPでWikiシステムを一から作っていたなぁ...とか思い出はあります。
社外からの問い合わせやSNSへの対応は今後のネタとして残しておくとして、社内での会話からトラブルにならないように、ネガティブコメントを注視しておく必要があります。特にお客様とのトラブルに発展しないようにフォローできる仕組みを、IBM Cloudで使用可能なWatsonを用いて構築してみましょう。
準備
社内チャットシステムとして、Mattermostサーバーを用意します。
構築自体は、公式のオンラインドキュメント通りに実施しています。DBのパスワード等は変えます。
使用したMattermostは、無料で使えるOpen Source Team Editionで、バージョン5.6です。
外向きのWebhookを設定します。
Mattermost内に投稿先としてチームを作成し、チーム作成後「統合機能」の画面から、「外向きのWebhook」の設定を行います。
Mattermostにおける「外向きのWebhook」については、以前書いた記事がありますので、興味がありましたらご確認ください。
参考資料:Mattermost向けチャットボットをNode-REDとWatson Assistantで実装
タスク管理システムとして、Jira Software環境を用意します。
下記の手順を用いて構築しました。もちろん、ここではIBM Cloud IaaS上に構築していますが、自社のプライベートクラウドや社内のサーバールームでも構いません。後述のNode-RED環境から接続できれば良いです。
構築手順:IBM Cloudを用いてJIRA Softwareで、日々のタスク管理をはじめる。
Jiraに登録するタスクは、「課題」と言います。Redmineではチケットと言いますし、CRMなどでは、ToDoと言います。言い方の違いで意味は同じです。
カスタムフィールド作成
Jiraには感情分析した値を格納する項目がないため、感情分析した結果として「怒り」「嫌悪」「恐れ」「楽しみ」の4つの感情スコアの値を格納する追加項目、カスタムフィールドを作成します。また作成したカスタムフィールドIDを確認しておきます。
後述のサンプルコードでは、次のように設定しています。
カスタムフィールド名 | フィールドタイプ | カスタムフィールドID | Node-REDの「POST - Create Issue」の記述 |
---|---|---|---|
怒り | 数値フィールド | 10206 | "customfield_10206" |
嫌悪 | 数値フィールド | 10207 | "customfield_10207" |
恐れ | 数値フィールド | 10208 | "customfield_10208" |
楽しみ | 数値フィールド | 10209 | "customfield_10209" |
MattermostとJira Softwareのデータをつなぐために、Node-REDサーバーを用意します。
MattermostとJira Softwareの両方に接続できる環境に、Node-REDサーバーを構築します。MattermostとJira Softwaareの両方に接続できれば、パブリッククラウドやプライベートクラウド、社内のサーバールームでも構いません。Node-REDのインストールには、公式のオンラインドキュメントを使用しています。
Node-REDで実装
Node-REDに追加したノード
サーバーにNode-REDをインストールした後、標準では付属しないWatsonやJiraに接続するノードを追加します。
node-red-contrib-jira:https://flows.nodered.org/node/node-red-contrib-jira
node-red-node-watson:https://flows.nodered.org/node/node-red-node-watson
フロー図
処理の流れ
- Mattermostに投稿されたトリガーワード付きのメッセージをNode-REDで受信
- Node-REDで受信したメッセージを「Watson Language Translator」で日本語から英語に翻訳。翻訳する理由は、感情分析を行う「Watson Tone Analyzer」が2018年12月現在日本語未対応のため、英語に翻訳します。
- 「Watson Tone Analyzer」で感情分析します。
- 感情分析の結果、怒りのスコアが「0.05」以上の時に、タスク管理システムの「Jira」に課題として登録するためのJSON形式のデータを作成します。
- 作成したJSON形式のデータを「Jira」に渡し、要対応のネガティブコメントとして新規課題登録します。
サンプルコード
下記のサンプルコードをNode-REDで読み込み、「language translator」ノードや「tone analyzer」ノード、「jira-issue-create」ノードをそれぞれダブルクリックし設定します。
[{"id":"fa32047e.c96898","type":"tab","label":"感情分析によるタスク管理","disabled":false,"info":""},{"id":"d1690281.96fc","type":"http in","z":"fa32047e.c96898","name":"Mattermost POST","url":"/mmpost","method":"post","upload":false,"swaggerDoc":"","x":130,"y":40,"wires":[["272aba56.17d726"]]},{"id":"dcdc3ecc.d75f2","type":"debug","z":"fa32047e.c96898","name":"debug:Mattermost Imcoming Webhook","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":670,"y":40,"wires":[]},{"id":"272aba56.17d726","type":"function","z":"fa32047e.c96898","name":"Cut Trigger Word","func":"var message = msg.payload.text;\nvar cutmsg = message.slice(5);\nmsg.payload = cutmsg;\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":40,"wires":[["dcdc3ecc.d75f2","2f8329a9.bc1e56","ebe4c8a3.3ca2d8"]]},{"id":"2f8329a9.bc1e56","type":"watson-translator","z":"fa32047e.c96898","name":"","action":"translate","basemodel":"en-tr","domain":"general","srclang":"ja","destlang":"en","password":"","apikey":"","custom":"","domainhidden":"general","srclanghidden":"ja","destlanghidden":"en","basemodelhidden":"","customhidden":"","filetype":"forcedglossary","trainid":"","lgparams2":true,"neural":false,"default-endpoint":true,"service-endpoint":"https://gateway.watsonplatform.net/language-translator/api","x":150,"y":160,"wires":[["7e04a1f.8bdb26"]]},{"id":"7e04a1f.8bdb26","type":"watson-tone-analyzer-v3","z":"fa32047e.c96898","name":"","tones":"emotion","sentences":"true","contentType":"false","tone-method":"generalTone","interface-version":"2016-05-19","inputlang":"en","default-endpoint":false,"service-endpoint":"https://gateway-tok.watsonplatform.net/tone-analyzer/api","x":380,"y":160,"wires":[["32339235.6f97ce","27c3ad11.5e6372"]]},{"id":"32339235.6f97ce","type":"debug","z":"fa32047e.c96898","name":"debug:感情分析","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":600,"y":160,"wires":[]},{"id":"9db37b51.23bfb8","type":"jira-issue-create","z":"fa32047e.c96898","name":"","server":"667cbe9c.e4b3e","x":600,"y":240,"wires":[["cc2c73ae.2807d"]]},{"id":"27c3ad11.5e6372","type":"switch","z":"fa32047e.c96898","name":"","property":"response.document_tone.tone_categories[0].tones[0].score","propertyType":"msg","rules":[{"t":"gte","v":"0.05","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":130,"y":247,"wires":[["f132ac7a.3a2d1"],[]]},{"id":"ebe4c8a3.3ca2d8","type":"function","z":"fa32047e.c96898","name":"variable:issue subject","func":"var message = msg.payload;\nvar msg = {\n note: message\n };\n flow.set('desc',msg);\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":100,"wires":[[]]},{"id":"f132ac7a.3a2d1","type":"function","z":"fa32047e.c96898","name":"POST - Create Issue","func":"var desc = flow.get('desc');\nvar note = desc.note;\nvar angerscore = msg.response.document_tone.tone_categories[0].tones[0].score;\nvar disgustscore = msg.response.document_tone.tone_categories[0].tones[1].score;\nvar fearscore = msg.response.document_tone.tone_categories[0].tones[2].score;\nvar joyscore = msg.response.document_tone.tone_categories[0].tones[3].score;\nmsg.payload = {\n \"fields\": {\n \"project\":{\"key\":\"EMOTION\"},\n \"summary\":\"ネガティブコメントを確認\",\n \"description\":note,\n \"issuetype\":{\"id\": \"10002\"},\n \"customfield_10206\":angerscore,\n \"customfield_10207\":disgustscore,\n \"customfield_10208\":fearscore,\n \"customfield_10209\":joyscore\n }\n }\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":240,"wires":[["9db37b51.23bfb8"]]},{"id":"cc2c73ae.2807d","type":"debug","z":"fa32047e.c96898","name":"debug:Jira Create Issue","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":630,"y":300,"wires":[]},{"id":"667cbe9c.e4b3e","type":"jira-server","z":"","url":"http://jira-dev.kolinzlabs.com:8080/jira/rest/api/latest/","name":"Jira Server"}]
language translatorノードの設定
IBM Cloudにアクセスし、Watson Language TranslatorのAPI鍵とエンドポイントURLを確認し設定します。
tone analyzerノードの設定
IBM Cloudにアクセスし、Watson Tone AnalyzerのAPI鍵とエンドポイントURLを確認し設定します。
jira-issue-createノードの設定
「jira-issue-create」ノードの編集画面で、Jira Softwaare用APIへの接続設定を行います。のドキュメントに無いため接続設定におけるURLは、お使いのJira Software環境におけるJira REST APIのURLになります。
https://your-jira-url/rest/api/latest/
#動作確認
Mattermostにトリガーワード(サンプルコードでは、#help)をつけて、お客様から言われそうなメッセージを投稿します。Watson Tone Analyzerにより感情分析され、怒りや嫌悪といったネガティブコメントと判断された場合、Jira Softwareに新規課題として登録されることを確認できました。
#まとめ
Node-REDを使用することで、社内チャットシステムのMattermostとタスク管理システムのJira Softwareを繋げて、ネガティブコメントがあればフォロー用のタスク(課題)を自動登録する動きを確認することができました。この仕組は、Mattermostを外部向けのSNSに変更することで、マーケティング活動や広報業務にも応用できるかもしれません。(次回のネタにします。)