AWS LambdaでHIPHOPを配信するLINEbotをつくる

AWSの勉強のために、AWS Lambda+LINEのMessaging API+spotifyAPIでおすすめのHIPHOPを配信するLINEbotを作成しました。

AWS、Messaging API、spotifyAPIのいずれも触ったことがない状態からのスタートでしたが、形にすることができたので開発の方法を紹介していきたいと思います。

## 1.完成したもの
まずは今回開発したプロダクト(?)を紹介します。
開発したのはLINEの公式アカウントで、何かしらのテキストを送信すると曲のアーティスト名、曲名、spotifyのURLが返ってくるというものです。  

送信される曲は、プレイリストの中からランダムで選択されています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/b54c2942-d699-2d19-7d9a-e8adf067ccd7.png" width=40%>

処理の全体の流れは以下のようになります。
1.ユーザーがLINE公式アカウントにメッセージを送信
2.LINEプラットフォームから設定したWebhook URL(AWSのAPI Gatewayで設定したエンドポイント)にWebhookイベントが送信
3.API GatewayがLambdaを呼び出す
4.Lambdaが実行されて応答を返す
![aws_structer-serverless1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/9d082211-44b7-de78-ab0e-440a78fb2061.png)

## 2.LINE公式アカウントの作成
まずはLINEの公式アカウントを作成します。
[LINE Developers](https://developers.line.biz/ja/)にアクセスして、「コンソールにログイン>アカウントを作成」からアカウントを作成してください。

### プロバイダーの作成
アカウントを作成してログインするとコンソール画面が開きます。
このコンソール画面からプロバイダーを作成します。指示に従って任意の名前でプロバイダーを作成しましょう。
![スクリーンショット 2024-08-19 19.19.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/7a0ce797-3bf2-369e-0089-50a378a11ac6.png)

### チャネルの作成
プロバイダーを作成したら、チャネルを作成します。  
「新規チャネル作成」というボタンを押すと以下のような画面が表示されるので「Messaging API」を選択してください。  
その後は任意のチャネル名などを登録してチャネル作成を完了しましょう！

![スクリーンショット 2024-08-19 19.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/f463fee1-4145-e582-6e70-5095e5497cde.png)

### チャネルアクセストークンの取得
アカウントが作成できたらMessaging APIの使用に必要なチャネルアクセストークンを取得します。「Messaging API設定」のタブに移動して「チャネルアクセストークン」の発行ボタンを押してチャネルアクセストークンを取得してください。このトークンは後ほど使用するので保存しておいてください。

## 3.Lambdaレイヤーの設定
AWS Lambdaの関数の作成を進めていきます。実際に関数のコードを書く前にLambdaレイヤーの設定を行います。

Lambdaレイヤーは、AWSのサイトで以下のように説明されています。
##### [レイヤーによる Lambda 依存関係の管理](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/chapter-layers.html)より
>Lambda レイヤーは、補助的なコードやデータを含む .zip ファイルアーカイブです。レイヤーには通常、ライブラリの依存関係、カスタムランタイム、または設定ファイルが含まれています。

基本的にはpythonなどで外部のライブラリを使用する際に、そのライブラリをインストールようなものという認識でよいでしょう。今回はLINEbot用のライブラリとspotifyAPIを使用するためのライブラリを使用するため、これらのLambdaレイヤーを作成する必要があります。

レイヤーとして定義することで、そのレイヤーは複数のLambda関数で使用することができます。

##### AWS公式サイトより
![スクリーンショット 2024-08-19 20.22.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/544ec29d-ff84-91e5-3424-1154bb14f516.png)

### zipファイルの作成
Lambdaレイヤーを作成するにはライブラリをzip形式でアップロードする必要があります。
ここで作成するzipファイルについて、基本的にはzipファイルを作成するOSとそれを実行するLambdaのOSは同一する必要があるので、ローカルでzipファイルを作成してしまうとうまくいかない可能性があります。

LambdaのOSはLinuxですが、自分はmacOSなのでAWSの仮想マシンサービスであるEC2でLinuxのインスタンスを作成してzipファイルの作成を行いました。

#### EC2とは
EC2とは、AWSの仮想マシンの提供サービスです。クラウド上にOS付きの仮想マシンを作成することができます。他の場所にあるコンピュータをインターネットを通して自分のPCから操作できるようなイメージです。

#### EC2のセッティング
起動状態にある仮想サーバーのことをインスタンスといいます。リモートに存在するサーバーに対して安全にアクセスするためにはSSHが利用されます。

まずはこのSSHによるログインに必要な秘密鍵の作成を行います。AWSコンソールにログインして、EC2の管理画面に進んでください。左のサイドバーの「キーペア」をクリックし、「キーペアを作成」から任意の名前でキーペアを作成してください。キーペアを作成すると、.pemファイルがダウンロードされます。このダウンロードされた.pemファイルを~/.sshに移動してください。

次にインスタンスを起動します。AWSコンソール画面に戻り、EC2のサイドバーに表示されている「インスタンス」をクリックして「インスタンスを起動」から任意の名前でインスタンスを作成します。AmazonマシンイメージとしてAmazon Linuxを選択し、キーペア(ログイン)の項目で先ほど作成したキーペアを選択します。

![スクリーンショット 2024-08-19 22.12.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/24fc7297-c9c9-bc77-f7e6-0b5e014ff5b4.png)

「インスタンス」の一覧に作成したインスタンスが表示されれば、完了です。

#### EC2からzipファイルを作成
先ほど作成したインスタンスにアクセスしてzipファイルを作成していきます。まずは以下のコマンドでEC2にログインしましょう。IPアドレスは、AWSコンソールで先ほど作成したインスタンスをクリックして詳細を表示し、「パブリックIPv4アドレス」と書かれているものです。
```
$ ssh -i ~/.ssh/keyname.pem ec2-user@<IP address>
```

ログインに成功したら、まずはpipをサーバーにインストールする必要があります。以下のコマンドでインストールスクリプトをダウンロードします。
```
$ curl -O https://bootstrap.pypa.io/get-pip.py
```

pythonを使用してスクリプトを実行します。
```
$ python3 get-pip.py --user
```

今回必要となるライブラリのline-bot-sdkをインストールしていきます。
インストール先となるフォルダを作成します
```
$ mkdir python
```
インストール先のディレクトリを指定してインストールします。
```
$ pip install line-bot-sdk　-t python
```
lsコマンドなどで/pythonの中身を確認してみましょう。ライブラリがインストールされているはずです。次にこのpythonディレクトリをzipファイルにします。
```
$ zip -r lineBot.zip python
```

これでzipファイルを作成することができました。ここで作成したzipファイルはEC2のインスタンス上にあるため、このzipファイルをローカルマシンへと転送します。scp(セキュアコピー)コマンドで転送します。以下のコマンドはローカルのルートディレクトリに転送するコードですが、パスは適宜変更してください。
```
scp -i ~/.ssh/mykey.pem ec2-user@<IPアドレス>:/home/ec2-user/python.zip ~/
```

spotipyというライブラリも使用するため、同様の手順でspotipyのzipも作成してください。

### Lambdaレイヤーの作成
zipファイルを作成することができたのでLambdaレイヤーの作成を行います。AWSコンソールでLambdaの画面に進んでください。左のサイドバーから「レイヤー」を選択して、「レイヤーの作成」を選択します。

任意の名前と説明を追加して、zipファイルをアップロードしてください。ここでアーキテクチャはx86_64を、ランタイムはpythonを選択してください。

![スクリーンショット 2024-08-19 22.45.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/f1e95132-b55e-68d3-fb15-425774d1d92e.png)

line-bot-sdk、spotipyの両方のレイヤーを作成したら完了です。

## 4.spotifyAPIのセッティング
[Spotify for Developers](https://developer.spotify.com/)からアカウントの作成を行なってください。
アカウントを作成したら「Dashboard」の「Create app」ボタンを選択します。Redirect URLはhttp://localhost:3000 として作成してください。

アプリを作成したら、Dashboardから作成したアプリを選択します。そこに表示されるClient IDとClient secretを後ほど使用するので保存してください。

## 5.Lambda関数の作成
準備が整ったのでLambda関数を作成します。関数のソースコードは以下の通りです。spotifyAPIを使用してplaylist_idで指定されたplaylistを取得して、乱数によってplaylistの中から曲を選択します。

LINEユーザーからテキストメッセージが送られると、取得した曲の情報を取り出して、LineBotApiのreply_messageメソッドを用いてそれらを送信します。replyTokenとはユーザーがメッセージを送信した時に発行されるトークンで、一度のみ使用することができるため、テキストメッセージと画像を両方送るにはreply_messageメソッドの第二引数を配列で与えます。

```python
import os
import json
from linebot import LineBotApi
from linebot.models import TextSendMessage, ImageSendMessage
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import random

LINE_CHANNEL_ACCESS_TOKEN = os.environ['LINE_CHANNEL_ACCESS_TOKEN']
LINE_BOT_API = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
client_credentials_manager = SpotifyClientCredentials(client_id=os.environ['SPOTIFY_CLIENT_ID'], client_secret=os.environ['SPOTIFY_CLIENT_CREDENTIAL'])
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
playlist = sp.playlist(playlist_id='041EEjr8FMkWlzbuKnSXYD')

def lambda_handler(event, context):
    try:
        if event['events'][0]['type'] == 'message':
            if event['events'][0]['message']['type'] == 'text':
                # get a random track from playlist
                random_number = random.randint(0, len(playlist['tracks']['items']) - 1)
                track = playlist['tracks']['items'][random_number]
                
                artist = track['track']['album']['artists'][0]['name']
                title = track['track']['name']
                url = track['track']['external_urls']['spotify']
                image_url = track['track']['album']['images'][0]['url']
                
                replyToken = event['events'][0]['replyToken']
                messageText = artist + ', \'' + title + '\'' + '\n' + url
                LINE_BOT_API.reply_message(replyToken, [TextSendMessage(text=messageText),ImageSendMessage(original_content_url=image_url, preview_image_url=image_url)])


    except Exception as e:
        print(e)
        return {'statusCode': 500, 'body': json.dumps('Exception occurred.')}

    return {'statusCode': 200, 'body': json.dumps('Reply ended normally.')}
```

注意点として、先ほど取得したLINEのアクセストークンやspotifyAPIのcredentialなどはLambdaの環境変数に設定しましょう。Lambda関数の設定の項目から環境変数を追加することが可能です。
![スクリーンショット 2024-08-19 23.11.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/013d5fac-bb51-fca7-e839-04e2a1303b2b.png)

今回はHIPHOPを配信するbotを作成するため、playlistとしてrapがまとまっているものを選択しましたが、任意のplaylistを指定することが可能です。playlist_idはspotifyアプリの共有リンクの「..../playlist/」以下の部分ですのでコードのplaylist_idの部分を置き換えることで任意のplaylistから配信することが可能です！

## 6.API Gatewayの作成
Lambda関数を作成することができたので、最後にエンドポイントが叩かれたらこのLambda関数を呼び出すAPI Gatewayを作成します。API GatewayはAPIを管理するサービスです。詳しくは以下の記事が参考になるかと思います。

https://qiita.com/shimajiri/items/2fb424629d9ddb9c9ef1

AWSコンソールからAPI Gatewayを選択し、「APIを作成」をクリックしてください。するとAPIタイプを選択する画面が表示されるので、REST APIを選択しましょう。

![スクリーンショット 2024-08-19 23.29.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/53591d06-a93c-a82d-85d4-ddbfa87a82ed.png)

APIを構築するとAPIの設定画面が表示されるので、そこで「メソッドの作成」を選択します。メソッドの詳細という画面でメソッドタイプとしてPOST、統合タイプとしてLambda関数、Lambda関数として先ほど作成したLambda関数を選択してメソッドを作成します。

![スクリーンショット 2024-08-19 23.31.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/45db08c6-34c4-9e82-1b12-9486ca13ade8.png)

メソッドの作成が完了したらデプロイボタンでデプロイします。デプロイが完了したら「ステージの詳細」という画面に「URLを呼び出す」という項目があるので、そこに表示されているURLを保存しましょう。

## 7.エンドポイントの設定
先ほど取得したURLがエンドポイントとなります。ここまではあくまでエンドポイントを作成しただけなので、最後にLINE側からこのエンドポイントを呼び出せるように設定を行います。最初に作成したLINE Developersのチャネルの画面を開いてMessaging APIのタブを選択してください。そのタブにある「Webhook設定」のWebhook URLの編集ボタンを押して、先ほど保存したURLを登録しましょう。Webhookの利用をONにしてください。

![スクリーンショット 2024-08-19 23.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820635/dabd0d4b-7759-abdf-0525-10de9e503fd3.png)

これで全ての設定が完了しました。チャネルの画面には公式ラインのQRコードがあるので、QRコードを読み取って友達追加して確認してみましょう。何かテキストを送ると曲の情報が返信されるはずです！

## まとめ
今回はLambdaを使って曲をおすすめするLINEbotを作成しました。複雑な設定が不要で簡単に関数を実行できるLambdaのありがたみがとても分かりました。アイデア次第で拡張の可能性はありそうです。