ChatGPT + Lambda + LINE Messaging APIですゑひろがりずっぽいLINE Botを作ってみた

# はじめに

ChatGPTを用いた何かを作りたかったので、LINE Botを作成してみました。
プログラムはLambda（Node.js）で動作するように実装しております。

ただ真面目な返信をするBotだと面白くないので、お笑いコンビのすゑひろがりずさんのような返信をするBotにしました。現代の言葉を和風に言い換えて返信してくれます。

元ネタはこちらです。

<br />

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/aZjNh_GovGc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

# 開発手順

## LINE Botの作成

まずはLINE Developersのドキュメントに従って、チャネルアクセストークンの発行までを行います。

https://developers.line.biz/ja/docs/messaging-api/getting-started/

* LINE Developersコンソールにログイン
* 新規プロバイダーを作成
* チャネルを作成
* チャネルアクセストークンを発行

ドキュメントでは「任意の有効期間を指定できるチャネルアクセストークン」が推奨されていますが、今回は発行が簡単な「長期のチャネルアクセストークン」を用いております。

https://developers.line.biz/ja/docs/messaging-api/channel-access-tokens/#long-lived-channel-access-tokens

## AWS Lambda 関数の作成

主となるプログラムの部分ですが、以下のコードを記述しました。

```javascript
import { Configuration, OpenAIApi } from "openai";
import { Client, validateSignature } from "@line/bot-sdk";

const configuration = new Configuration({
    apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const channelSecret = process.env.LINE_CHANNEL_SECRET;
const lineClient = new Client({
    channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN,
    channelSecret: process.env.LINE_CHANNEL_SECRET,
});

export const handler = async (req) => {
    // 署名の検証（LINEからの接続であるか）
    const signature = req.headers["x-line-signature"];
    const bool = validateSignature(req.body, channelSecret, signature);
    if (!bool) throw new Error("invalid signature");

    // ChatGPTから回答を取得
    const body = JSON.parse(req.body);
    const completion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [
            {
                role: "system",
                content:
                    "今から話す言葉を和風に変換して漢字のみ使用してオウム返ししてください。",
            },
            { role: "user", content: body.events[0].message.text },
        ],
    });

    // LINEへ返信
    const replyText = completion.data.choices[0].message.content;
    await lineClient.replyMessage(body.events[0].replyToken, [
        { type: "text", text: replyText },
    ]);
    return { statusCode: 200 };
};
```

処理の流れは以下の通りです。

### 1. 署名の検証

LINEプラットフォームからのリクエストのみ受け付けるようにします。

https://developers.line.biz/ja/reference/messaging-api/#signature-validation

### 2. ChatGPTから回答を取得

ChatGPT（正確には OpenAI Chat API）を用いて、現代の言葉を和風に言い換えた回答を取得します。

https://platform.openai.com/docs/api-reference/chat/create

### 3. LINEへ返信

LINE Messaging APIを用いて、返信を送信します。

https://developers.line.biz/ja/docs/messaging-api/sending-messages/#reply-messages


## AWS Lambda レイヤーの作成

今回のプログラムでは **OpenAI API** と **LINE Messaging API** を用いるので、AWS Lambdaでそれぞれのレイヤーを作成します。レイヤーの作成手順は省略しますが、インストールしたライブラリをZipに圧縮してアップロードするだけです。
作成できたら、先ほど作成した関数にレイヤーを追加します。

### OpenAI API のライブラリ
https://github.com/openai/openai-node

```bash
npm install openai
```

### LINE Messaging API のライブラリ
https://github.com/line/line-bot-sdk-nodejs

```bash
npm install @line/bot-sdk --save
```

## AWS Lambda 環境変数の設定

3つの環境変数を設定します。今回は以下のような変数名で管理しております。

* LINE_CHANNEL_ACCESS_TOKEN
LINE Developersの画面で発行したチャネルアクセストークンを設定します。

* LINE_CHANNEL_SECRET
LINE Developersの画面からコピーして設定します。

* OPENAI_API_KEY
OpenAI APIの画面からAPIキーを発行して設定します。

https://platform.openai.com/account/api-keys

## AWS Lambda 関数URLの作成

Lambdaの管理画面から関数URLを作成して、外部から実行可能な状態にします。
今回は認証タイプを NONE にして誰でもアクセス可能としました。

## LINE Webhookの設定

LINE Developersの画面でWebhook URLに先ほど作成した関数URLを設定します。

## 動作確認

個人のLINEアカウントで作成したチャネルを友だち追加します。
メッセージを送信して返信があれば完了です。

# 完成イメージ

元ネタのような面白さはないですが、それっぽい返信になっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339770/4fc2a569-4db4-d703-f248-28080d2b3e3a.jpeg" width="300" />

上記の動作イメージは良い結果が得られた返信だけを抜粋しております。
思った通りの返信にならないことも多々ありました。
ChatGPTへの指示が難しかったです。。。