AWS Lambda

LambdaとSlackを連携させてカラーパレットBot作成してみた

はじめに

お久しぶりです。ヤコです。
今回はLambdaとSlackを連携させてカラーパレットBot作成してみたということで、人生初、Lambdaをいじってみました。

カラーパレットBotってどういうもの??

ユーザーがコマンドを打ったら、イイ感じに適当な色の組み合わせを選んでBotが返してくれます。(絵描きが重宝するヤツ)
個人的に欲しいナと思って作成を決意しました。

想定している動きとしては、こちらがSlackでコマンドを入力するとそれに合わせてbotが自動的に色を5色選び出力してくれる、といったものです。

Lambdaとは

もう皆さんご存じだと思われますが、一応簡単に。
・サーバーの構築や管理を行わずにコードを実行できるAWSのサービス
・イベント駆動(何かが起こったときだけ動く)
・使った分だけお金発生(従量課金)、毎月100万クエリは無料

今回使用するもの

・Slack(コミュニケーションチャットツール)
・Lambda
・API Gateway
結構シンプルな構成ですね。

作成

①Lambdaでの作業

まずはLambdaで関数を作成します。
AWSのアプリケーションからLambdaを選択し、[関数を作成]をクリック。

名前を付けて、[関数を作成]。
ランタイムはpythonにしておきます。

作成できたら、[コード]の欄が画像↓のようになっていることを確認。

ここに必要なコードを書き込んでいきます。
(私にpythonの知識がなさすぎるのと今回は作るモノがモノなので、AIに手伝ってもらいました。)
かなり長いので飛ばしてもらって大丈夫です。

import json
import random
import urllib.parse
import colorsys

def lambda_handler(event, context):
    try:
        print("カラーパレット生成開始")

        # 常にランダム生成
        colors = generate_harmonious_diverse_palette()
        print(f"生成された色: {colors}")

        # Slack返答を作成
        slack_response = create_color_hex_response(colors)

        return {
            'statusCode': 200,
            'headers': {'Content-Type': 'application/json'},
            'body': json.dumps(slack_response)
        }

    except Exception as e:
        print(f"エラー発生: {str(e)}")
        return {
            'statusCode': 500,
            'headers': {'Content-Type': 'application/json'},
            'body': json.dumps({
                'response_type': 'ephemeral',
                'text': f'エラーが発生しました: {str(e)}'
            })
        }

def generate_harmonious_diverse_palette():
    """調和を保ちつつ多様性のあるパレット生成"""

    harmony_patterns = [
        'analogous_extended',    # 拡張類似色
        'split_complementary',   # 分割補色
        'triadic_soft',         # ソフト三角配色
        'tetradic_muted',       # ミュート四角配色
    ]

    pattern = random.choice(harmony_patterns)
    print(f"選択された調和パターン: {pattern}")

    if pattern == 'analogous_extended':
        return generate_analogous_extended()
    elif pattern == 'split_complementary':
        return generate_split_complementary()
    elif pattern == 'triadic_soft':
        return generate_triadic_soft()
    else:
        return generate_tetradic_muted()

def generate_analogous_extended():
    """拡張類似色パレット"""
    base_hue = random.randint(0, 360)
    colors = []

    # メイン色系3色
    for i in range(3):
        hue = (base_hue + i * 20) % 360
        saturation = random.uniform(0.5, 0.8)
        value = random.uniform(0.6, 0.9)
        color = create_color_from_hue(hue, saturation, value)
        colors.append(color)

    # アクセント色1色
    accent_hue = (base_hue + 150 + random.randint(-30, 30)) % 360
    accent_color = create_color_from_hue(accent_hue, random.uniform(0.6, 0.8), random.uniform(0.7, 0.9))
    colors.append(accent_color)

    # ニュートラル色1色
    neutral_hue = (base_hue + random.randint(-15, 15)) % 360
    neutral_color = create_color_from_hue(neutral_hue, random.uniform(0.2, 0.4), random.uniform(0.7, 0.95))
    colors.append(neutral_color)

    return colors

def generate_split_complementary():
    """分割補色パレット"""
    base_hue = random.randint(0, 360)
    colors = []

    # メイン色系2色
    colors.append(create_color_from_hue(base_hue, random.uniform(0.6, 0.8), random.uniform(0.7, 0.9)))
    colors.append(create_color_from_hue((base_hue + random.randint(-20, 20)) % 360, random.uniform(0.5, 0.7), random.uniform(0.6, 0.8)))

    # 分割補色2色
    complement_base = (base_hue + 180) % 360
    split1 = (complement_base - 30) % 360
    split2 = (complement_base + 30) % 360

    colors.append(create_color_from_hue(split1, random.uniform(0.5, 0.7), random.uniform(0.6, 0.8)))
    colors.append(create_color_from_hue(split2, random.uniform(0.5, 0.7), random.uniform(0.6, 0.8)))

    # ニュートラル色1色
    neutral_color = create_color_from_hue(random.randint(0, 360), random.uniform(0.1, 0.3), random.uniform(0.8, 0.95))
    colors.append(neutral_color)

    return colors

def generate_triadic_soft():
    """ソフト三角配色パレット"""
    base_hue = random.randint(0, 360)
    colors = []

    hue1 = base_hue
    hue2 = (base_hue + 120 + random.randint(-15, 15)) % 360
    hue3 = (base_hue + 240 + random.randint(-15, 15)) % 360

    colors.append(create_color_from_hue(hue1, random.uniform(0.6, 0.8), random.uniform(0.7, 0.9)))
    colors.append(create_color_from_hue(hue2, random.uniform(0.5, 0.7), random.uniform(0.6, 0.8)))
    colors.append(create_color_from_hue(hue3, random.uniform(0.5, 0.7), random.uniform(0.6, 0.8)))

    # 低彩度の調和色2色
    colors.append(create_color_from_hue((hue1 + 30) % 360, random.uniform(0.3, 0.5), random.uniform(0.7, 0.9)))
    colors.append(create_color_from_hue((hue2 + 30) % 360, random.uniform(0.3, 0.5), random.uniform(0.7, 0.9)))

    return colors

def generate_tetradic_muted():
    """ミュート四角配色パレット"""
    base_hue = random.randint(0, 360)
    colors = []

    hues = [base_hue, (base_hue + 90) % 360, (base_hue + 180) % 360, (base_hue + 270) % 360]

    for hue in hues[:4]:
        saturation = random.uniform(0.4, 0.6)
        value = random.uniform(0.5, 0.8)
        color = create_color_from_hue(hue, saturation, value)
        colors.append(color)

    # アクセント色1色
    accent_hue = random.choice(hues)
    accent_color = create_color_from_hue(accent_hue, random.uniform(0.7, 0.8), random.uniform(0.8, 0.9))
    colors.append(accent_color)

    return colors

def create_color_from_hue(hue, saturation, value):
    """HSV値から16進数カラーコードを生成"""
    rgb = colorsys.hsv_to_rgb(hue/360, saturation, value)
    hex_color = '#{:02x}{:02x}{:02x}'.format(
        int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255)
    )
    return hex_color

def create_color_hex_response(colors):
    """超シンプル版の色見本表示"""

    attachments = []

    for i, color in enumerate(colors):
        color_hex_url = f"https://www.color-hex.com/color/{color.replace('#', '')}"

        attachments.append({
            "color": color,
            "fields": [
                {
                    "title": f"色 {i+1}",
                    "value": f"<{color_hex_url}|{color}>",
                    "short": True
                }
            ]
        })

    color_list = " • ".join(colors)

    attachments.append({
        "color": "#F5F5F5",
        "text": f"**全カラー:** {color_list}\nカラーコードをクリックで詳細表示"
    })

    return {
        'response_type': 'ephemeral',
        'text': '*ランダムカラーパレット*',
        'attachments': attachments
    }

内容としては、
Slackのスラッシュコマンドなどからデータを取得

コマンドに対して5色をランダムに選択

Slackで表示する形式に整形

という内容になっています。
配色パターンなどについても記載されています。


こんな感じで、Slack上でもどんな色が選ばれたのか視覚的にわかりやすい感じで出力するようにしました。
また、選ばれた色がどんな色なのか、「Color-Hex.com」というサイトで確認できるようにリンクも併せて記載するよう設定しています。

関数を入力できたら、画面左の[Deploy]をクリック。
([test]でテストも可能です)

右側にある関数のARNは後ほど使うので、どこかにコピっておきます。

これで、Lambdaの作業は一旦終わりです。

②API Gatewayでの作業

続いてサービス一覧からAPI Gatewayへ移動します。
※Amazon API GatewayはAPIの作成や管理を簡単に行えるAWSのサービス

左カラムの[API]⇒[API作成]をクリック。

API タイプを選択
⇒Lambdaを使っているので、[HTTP API]で構築。


API名を決めて、[統合]で[Lambda]を選択。
Lambda関数が選択できるようになるので、先ほど作成した関数を一覧から選ぶか、直接入力します。


ルートの設定は
ANY = すべてのHTTPメソッドを受け付ける
/{proxy+} = プロキシ統合(すべてのパスを受け付ける)
にしてます。
その他はデフォルトの設定のままです。


作成できたら左カラムの[stage]から、ステージの詳細を確認し、[URLを呼び出す]の欄にあるURLをメモしておいてください。

念のためLambdaの画面に戻り、作成した関数の概要画面で
画像のようにAPI Gatewayが表示されていることを確認してください。

AWS側の作業もここでいったん終了です。

③Slackと連携

最後に作成した関数をSlackと連携させ、Botアプリを作成します。

Slackの[app]から[アプリを追加する]を選択
画面右上の[Slack Marketplaceで開く]をクリック


画面右のメニューから[構築]を選択→[create new app]→[From scratch]
アプリの名前とworkspaceを選択し、アプリを作成してください。

作成できたら下にスクロールして
[Display Information]でアプリアイコンを変更したりできます。

各項目の設定をざっと書いていきます
【App Home】

・Home Tab→オフ
・Messages Tab→オン ※コマンド送る用にオンにします

【Slash Commands】
[create new command]

Commandは自分がわかりやすいように適当に設定してください。
今回は
/palette
に設定しました。
Request URLの欄に先ほどAPIGateway作成時にメモした呼び出しURLを記載します。

【OAuth & Permissions】
Bot Token Scopes
・commands ※スラッシュコマンド権限
・chat:write ※メッセージ投稿権限(Bot User作成用)

上記の項目が設定し終わったら、【install app】でslackにインストールを実行してください。

slackの画面に戻り、アプリ一覧に作成したアプリが出てきたら成功です。
アプリのメッセージに移動してコマンドを打ってみましょう。

/palette
を入力すると...


 無事カラーパレットが作成されています!!!
色を表示してくれるリンクもちゃんと機能しているようです。

数回コマンドを打ってみても、毎回ちゃんと違うものが出力されてますね。
イイ感じです(⌒∇⌒)

さいごに

おつかれさまでした。
初めてLambda触りましたが、楽しいですね。
私はpythonの知識が皆無なので、コード書くところでどうしても詰まりますが、知識がある人が使えば複雑な仕様のアプリも作成できそうでよさげです。
というかLambdaとAmazon API Gatewayの組みあわせがあれば割となんでも作れそうですね。なんといってもサーバーレスでお手軽ですし、クエリがそれほど多くなければ基本無料なので。
今回はカラーパレットという需要があまりなさそうな個人利用すぎるアプリを作りましたが、応用させれば便利なアプリを作り放題かと。
みなさんも是非作ってみてはいかがでしょうか。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA