7
8

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 1 year has passed since last update.

LINE Messaging APIとOpenAI APIを連携させる

Last updated at Posted at 2023-02-12

やったこと

最近はやってるOpenAIにLINE経由で質問して回答を受け取れるようにしました!
接続イメージは以下の通り。
image.png

LINE Messaging APIとOpenAIの準備

LINE Messaging API

公式のガイドに沿って、LINE Developer Consle上でMessaging APIを作成します。

image.png

「Messasing API設定」タブからチャネルアクセストークンを確認しておきます。
image.png

Webhookの設定も必要なのですが、それはLambda構築後に実施します。

OpenAI

OpenAIのアカウントを作成します。
OpenAI APIのトップでサインアップを実施。
image.png

ログイン後、右上の「Personal」から「View API Keys」でAPI Keysを確認します。
image.png

以下の画面でAPI Keyを発行して確認します。
一度作ったものを画面上で再確認するのは不可能なので、別途しっかり管理する必要があります。
image.png

Lambda

関数の作成

AWS Lambda関数を作成します。
image.png

詳細設定から、最近(去年くらい?)用意された関数URLを有効化します。
以前はAPI Gatewayの設定とかが必要だったので、今回みたいにサクッと外部のAPIを連携させたいときは便利だなと思いました。
認証タイプは今回はとりあえずお試しなのでNONE、CORS設定にもチェックを入れます。
image.png

関数の作成を実施。
右下に関数URLが表示されているので、これをコピー。
image.png

LINE Developer ConsoleでWebhook URLを設定

LINE Developer Consoleで、作成したMessaging APIのWebhook URLに設定します。
image.png

ここまで書いて思い出しましたがMessaging APIは自動で応答メッセージがあるのでこれは無効化しておきます。
image.png

Layerの追加

今回、openai@line/bot-sdkをnode_modulesとして使うので、Lambdaレイヤーに追加します。
ローカルコンピューター上で「nodejs」ディレクトリを作成し、以下の通りnode_modulesをインストール。

Powershell
PS C:\Users\flets\OneDrive\node\nodejs> npm i @line/bot-sdk openai
PS C:\Users\flets\OneDrive\node\nodejs> npm ls
node@ C:\Users\flets\OneDrive\node
+-- @line/bot-sdk@7.5.2
`-- openai@3.1.0

PS C:\Users\flets\OneDrive\node\nodejs>

Zip圧縮してnodejs.zipを作成しておきます。
image.png

Lambdaコンソールの左のナビゲーションペインで「レイヤー」を選択し、右上の「レイヤーの作成」をクリック。
以下の通りレイヤー名を適当に入力して、nodejs.zipをアップロード元に設定して「作成」をクリック。
image.png

無事に作成されればOK。
image.png

以下の通り、先に作った関数にLayer追加しておきます。
image.png

ARN指定で追加しました。
image.png

コードの記述

以下の通り記述します。

モジュール呼び出し、トークン・Key設定

まず、handler関数の手前でLINEとOpenAIのモジュールをImportして、LINEのチャネルアクセストークンとOpenAIのAPI Keyも設定します。(直書きでごめんなさい)

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

//事前に確認したものを記述
const LINE_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const GPT_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
LINE Messaging APIとのやりとり

handler関数の中身を書きます。
まずは、LINE Messaging APIとやりとりする枠を書きます。

ガワを書く
export const handler = async(event) => {
  //LINEのMessaging APIに接続
  const client = new line.Client({
    channelAccessToken: LINE_TOKEN,
  });

  //LINEからWebhookでアクセスしてきたときのBodyをJSONに格納
  const reqBody = JSON.parse(event.body);
  console.log(reqBody)

  let message = {};

  //このあと、ここでOpenAIのAPIを呼び出してmessageの中身を埋めます

  //LINE Messaging APIでメッセージをPushする宛先
  const toToken = reqBody.events[0].source.userId;

  //メッセージをPush
  await client.pushMessage(toToken, message).catch((err) => {
    // error handling
    console.error(err);
  });

  //Webhookに対するResponse(200応答が必要らしい)
  const response = {
      statusCode: 200,
      body: JSON.stringify(message),
  };
  return response;
};
OpenAIのAPI呼び出し、messageへの格納

OpenAIのAPIにアクセスして、レスポンスデータをMessageに格納します。
LINEからのWebhookがテキストメッセージじゃないとダメなので、if分で分岐も一応入れておきます。

さっき「このあと~~」と書いた部分

//WebhookがテキストだったらOpenAIになげる
if (reqBody.events[0].message.type == "text") {
    //OpenAIアクセス設定
    const configuration = new Configuration({
      apiKey: GPT_KEY,
    });
    //オブジェクト作成
    const openai = new OpenAIApi(configuration);
    //APIアクセス、レスポンス格納
    //max_tokensを変えればレスポンスの最大文字数が変化
    //ただし、max_tokensの値が純粋な最大文字数ではないので注意
    //ただしLINE、OpenAIそれぞれで上限値ありなので要確認
    const response = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: reqBody.events[0].message.text,
      max_tokens: 1000,
      temperature: 0,
    });

    message = {
      type: "text",
      text: response.data.choices[0].text.trim()
    };
  } else {
  //LINEからのWebhookがテキストメッセージじゃなかった場合
    message = {
      type: "text",
      text: "テキストを入力してください。"
    };
  }
全文

全文は以下の通り。

myGptFunction全文
import line from "@line/bot-sdk";
import { Configuration, OpenAIApi } from "openai";

const LINE_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const GPT_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

export const handler = async(event) => {
    const client = new line.Client({
    channelAccessToken: LINE_TOKEN,
  });

  const reqBody = JSON.parse(event.body);
  console.log(reqBody)

  let message = {};

  if (reqBody.events[0].message.type == "text") {
    const configuration = new Configuration({
      apiKey: GPT_KEY,
    });
    const openai = new OpenAIApi(configuration);
    const response = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: reqBody.events[0].message.text,
      max_tokens: 1000,
      temperature: 0,
    });

    message = {
      type: "text",
      text: response.data.choices[0].text.trim()
    };
  } else {
    message = {
      type: "text",
      text: "テキストを入力してください。"
    };
  }

  const toToken = reqBody.events[0].source.userId;

  await client.pushMessage(toToken, message).catch((err) => {
    // error handling
    console.error(err);
  });
    const response = {
        statusCode: 200,
        body: JSON.stringify(message),
    };
    return response;
};

これでコンソール画面上でDeployを実施。
上部に「関数myGptFunctionが正常に更新されました」と表示されればOK!

動作確認

無事に動きました!
image.png

とりあえず作ってみましたが結構面白いので、しばらくこれでChatGPTで遊んでみようと思います。

参考

ほぼ以下2つのコピペです。
OpenAIのAPI Reference
LINE Messaging APIのAPI Reference

7
8
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
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?