21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

UL Systems (ウルシステムズ)Advent Calendar 2018

Day 14

Mattermostの「褒めbot」をLambdaとPythonで作ってみた

Last updated at Posted at 2018-12-13

「褒めbot」を作ってみた経緯

  • Mattermost(マッターモスト)は、Slack互換を謳ったオープンソースのチャット型コミュニケーションツールです。「Slackだと、チャットの内容が社外サーバへ飛んでしまうため、セキュリティ的にNG。チャットは導入したいけど、自分で管理できるプライベートな環境で構築したい。」などの理由からMattermostを使い始めている人も多いのではないでしょうか。まさに私もそうでした。
  • 私はMattermostをEC2で立てたので、「せっかくAWSだしLambdaでも使ってサクッとbotでも作るか!作るなら褒めbotでコミュニケーションしやすい環境にしておきたいなぁ。心理的安全性、大切。まずはチームにポジティブな雰囲気を!」と思い、作ってみることにしました。
  • 実際、作ってみると、少ない手順でサクッと作ることができるし、ほどよくいろんな要素を使って作るので、「これはQiitaにちょうどいいかも?」ってことで、作り方を共有します!

「褒めbot」の概要

  • 「褒チャンネル」に投稿があったら、褒め言葉を返すbotを作ります。完成形はこんなイメージです。
    image.png

  • AWSの構成は以下の通りです。
    image.png

  • 動作検証バージョンは以下の通りです。

  • Mattermost 5.3.1

  • Python 3.7 (Lambda)

「褒めbot」を作る4つの手順

作る手順は以下の4STEPです。

  1. Mattermostで、内向きのウェブフック(Incoming Webhook)を作成する
  2. Lambda関数を作成する
  3. API Gatewayを設定する
  4. Mattermostで、外向きのウェブフック(Outgoing Webhook)を作成する

Mattermostのインストールやセットアップについては、この記事では取り扱いません。以下の@terukizmさんの記事が参考になるので、参照してください。

それでは、ひとつずつ説明していきます!

1. Mattermostで、内向きのウェブフック(Incoming Webhook)を作成する

  • まずは、botが投稿に使うURLを払い出します。Mattermostの統合機能の画面を開き、内向きのウェブフックを作成します。(投稿先の「褒チャンネル」は先に作成しておきます。)内向きのウェブフックを作成するとURLが払い出されるので、次の手順でLambda関数に組み込みます。
    image.png

2. Lambda関数を作成する

  • 次に「褒めbot」の本体となるLambda関数を作成します。
    image.png

  • コードは以下の通りです。WEBHOOK_URLに前の手順で払い出したURLを指定します。(オレオレ証明書を使っている場合は、最後のコメントアウトしてある方のコードを使います。)

lambda_function.py
import json
import urllib.request
import ssl

# 内向きのウェブフックのURL
WEBHOOK_URL = "https://example.com/hooks/abcdefghij" # ここに内向きのウェブフックで払い出したURLを指定する

def lambda_handler(event, context):
    # リクエストヘッダをJSONにする。
    req_headers = {
        "Content-Type": "application/json",
    }
    # JSONにメッセージをつめる。
    req_json = {
        "text": "いいね! :+1:",
    }

    # リクエストを生成してMattermostへ投げる。
    req = urllib.request.Request(WEBHOOK_URL, json.dumps(req_json).encode(), req_headers)
    urllib.request.urlopen(req)

    # オレオレ証明書を回避する必要がある場合は、こちらのコードを使う。
    # (contextを設定した上で、リクエストを生成してMattermostへ投げる。)
#    req = urllib.request.Request(WEBHOOK_URL, json.dumps(req_json).encode(), req_headers)
#    context = ssl._create_unverified_context()
#    urllib.request.urlopen(req, context=context)

  • いったん作成したLambda関数をテストしてみます。(最初のテストの前にテストイベントを作成する必要がありますが、デフォルトで作成すれば大丈夫です。)以下のようにMattermostへの投稿ができればここまでの手順はOKです!
    image.png

3. API Gatewayを設定する

  • 今度は、「褒チャンネル」に投稿があったときに呼び出す先のAPIを作成します。API Gatewayの設定は、「API→リソース→メソッド」の順に設定し、最後に作成したAPIをデプロイするという流れです。まず、APIを作成します。
    image.png

  • 次にリソースを作成します。ここのリソース名がAPIのURLに含まれます。
    image.png

  • 作成したリソースの中に、メソッド(POST)を作成して、前の手順のLambda関数が呼び出されるように設定します。
    image.png

  • 作成したAPIをデプロイします。ここのステージ名がAPIのURLに含まれます。
    image.png

  • ステージのURLと、リソース名をつなげたものが、Mattermostから呼び出すAPIとなるので、次の手順でMattermostに設定します。
    image.png

4. Mattermostで、外向きのウェブフック(Outgoing Webhook)を作成する

  • 最後の手順として、「褒チャンネル」に投稿があったときにbotのAPIを呼び出す設定をします。Mattermostの統合機能の画面を開き、外向きのウェブフックを作成します。コールバックURLに、前の手順の[ステージのURL]/[リソース名]を指定します。また、トリガーワードは指定せず、すべての投稿でbotが呼び出されるようにします。
    image.png

  • これで手順は完了です。「褒チャンネル」に投稿してみて、以下のようにbotから褒め言葉が返ってくればOKです!
    image.png

「褒めbot」をもう少しブラッシュアップ

これだけだとちょっと味気ないので、もう少しブラッシュアップして、以下の機能を作ります。

  1. アイコンを設定する
  2. いろんな褒め言葉をランダムに投稿する

1. アイコンを設定する

  • アイコンは、内向きのウェブフックのプロフィール画像で指定します。
    image.png

  • 私は「褒めbot」の作成にあわせて「褒めスタンプ」のカスタム絵文字も作ったので、カスタム絵文字が保存されているURLをブラウザのデベロッパーツールで調べて指定しました。
    image.png

2. いろんな褒め言葉をランダムに投稿する

  • 今のままだと「いいね!」しか褒め言葉がないので、いろんな褒め言葉をランダムに投稿するように修正します。Lambda関数を修正しますが、直接修正すると「褒チャンネル」に即反映されてしまい、おかしな動作になる可能性があります。そこで、Lambda関数を修正する前にエイリアスを使って、「褒チャンネル」からのリクエストを受け付けるバージョンを切り離します。Lambda関数の新しいバージョンを発行した上で、以下のようにエイリアスを作成します。
    image.png

  • API Gateway側の設定もprodを呼び出すように修正します。修正した後、APIをデプロイすると「褒チャンネル」の投稿に対して、Lambda関数の最新バージョンではなく、prodのバージョンでbotが動くようになります。
    image.png

  • 次に、Lambda関数を修正します。修正後のコードは以下の通りです。

lambda_function.py
import json
import urllib.request
import ssl
import random

# 内向きのウェブフックのURL
WEBHOOK_URL = "https://example.com/hooks/abcdefghij" # ここに内向きのウェブフックで払い出したURLを指定する

def lambda_handler(event, context):
    # リクエストヘッダをJSONにする。
    req_headers = {
        "Content-Type": "application/json",
    }
    # メッセージの候補リストを作成する。
    msg_list = [
        "いいね! :+1:",
        "# :homeru:",
        "ありがとー! :thankyou:",
        "えらい! :erai:",
        "すごい! :sugoi:",
        "# :kansha:",
        "さすがです :tada:",
    ]
    # JSONにランダムにメッセージをつめる。
    req_json = {
        "text": random.choice(msg_list),
        # チャンネルを指定して投稿もできるので、
        # 修正後にLambdaのテストをしておきたいときは
        # 自分へのダイレクトメッセージとするとよい。
#        "channel": "@hoge.hoge",
    }

    # リクエストを生成してMattermostへ投げる。
    req = urllib.request.Request(WEBHOOK_URL, json.dumps(req_json).encode(), req_headers)
    urllib.request.urlopen(req)

    # オレオレ証明書を回避する必要がある場合は、こちらのコードを使う。
    # (contextを設定した上で、リクエストを生成してMattermostへ投げる。)
#    req = urllib.request.Request(WEBHOOK_URL, json.dumps(req_json).encode(), req_headers)
#    context = ssl._create_unverified_context()
#    urllib.request.urlopen(req, context=context)

  • Lambda関数の修正が完了したら、エイリアスprodが指すバージョンを最新版である$LATESTに切り替えます。
    image.png

  • 「褒チャンネル」に投稿してみて、以下のように新しく増やした褒め言葉がランダムに返ってくればOKです!
    image.png

  • この記事では、シンプルなbot作成までを書きました。ブラッシュアップはしたものの、まだまだ他にも機能を追加できます(公式ドキュメント Outgoing Webhooks — Mattermost documentation # Create an Outgoing Webhook)。例えば、投稿された内容からuser_nametextを拾って、発言したユーザや発言内容で処理を振り分けてみたり…など、色々と考えられるので、また試してみたいと思います!

「褒めbot」を作ってみた結果

  • 「褒めbot」を実際に、1ヶ月くらい運用しているのですが、どんな雰囲気かというと…
    image.png

 ① 最初は面白がって使ってくれた!
 ② 機能が物足りなくて、すぐ飽きたので改善(記事のブラッシュアップ)。チームの雰囲気もイイ感じ!
 ③ でも盛り上がりは一時的で、すぐ特定の人しか使わなくなる…。それでもこの段階では、個々の進捗や学びが共有できていた。
 ④ がスケジュールに切羽詰まり始め、投稿ゼロの日が発生…過疎化してしまう。チームの雰囲気もちょっと微妙に…。
 ⑤ いま、また盛り上がるように自作自演から再開中!

  • …と、思いっきり作り方の記事を書いておいてー、って感じですが、あくまでツールはツールでしかないです。「褒めbot」は、チームの雰囲気作りや情報共有を助けてはくれますが、人間系での布教活動は忘れてはいけません。④のような時期にこそ、自分から「褒チャンネル」を盛り上げることが大切なのだと思いました。私も引き続きがんばります!
21
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?