2023年3月30日木曜日

GAS で ChatGPT の API を利用した簡単な LINE bot を作ってみる

-----
・追記(2023-4-4)
複数回のやりとりができるバージョンを作りました → 「GAS で ChatGPT とやりとりできる簡単な LINE bot の作り方
-----

GAS (Google Apps Script) で ChatGPT の API を利用した簡単な LINE bot を作ってみました。

作ってみましたと言いつつ、コード自体は ChatGPT とやり取りしながらほぼ作ってもらいました。自分で作ると(どうせ自分で使うものだしと思って)疎かにしがちなエラー処理も付いています。


LINE Messaging API チャンネルの作成とアクセストークンの取得。及び、OpenAI の API キー取得は済んでる想定です。

それぞれ、GAS の「プロジェクトの設定」よりスクリプト プロパティとして追加・保存しておきます。プロパティ名は「Line_key」と「OpenAI_key」としてコード内で使っています。

ちなみに、OpenAI の API 使用は有料ですが、5ドル分(3か月有効)が無料枠として設けられているようです、たぶん。(正確に把握できているか自信がないので詳細は調べてみてください)


以下がコードになります。

function doPost(e) {
  try {
    const replyToken = getReplyToken(e);
    const englishMessage = getEnglishMessage(e);
    const requestMessage = [{'role': 'user', 'content': englishMessage}];
    const openAiParams = generateOpenAIParams(requestMessage);
    const response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', openAiParams);
    const resData = JSON.parse(response.getContentText());
    const replyMessage = resData.choices[0].message.content;
    const translatedMessage = LanguageApp.translate(replyMessage, "en", "ja");
    const replyContent = `${englishMessage}\n-----\n${translatedMessage}\n\n${replyMessage}`;
    const linePayload = generateLinePayload(replyToken, replyContent);
    sendLineMessage(linePayload);
  } catch (error) {
    console.error(`An error occurred: ${error}`);
  }
}

// pushメッセージからreplyTokenを取得する関数
function getReplyToken(e) {
  const event = JSON.parse(e.postData.contents).events[0];
  return event.replyToken;
}

// pushメッセージからリクエストメッセージを取得する関数
function getEnglishMessage(e) {
  const event = JSON.parse(e.postData.contents).events[0];
  const message = event.message;
  const messageContent = message.type === 'text' ? message.text : '';
  return LanguageApp.translate(messageContent, "", "en");
}

// OpenAIのリクエストパラメータを生成する関数
function generateOpenAIParams(requestMessage) {
  const openAiHeaders = {
    'Authorization': `Bearer ${PropertiesService.getScriptProperties().getProperty('OpenAI_key')}`,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  const openAiPayload = {
    'model': 'gpt-3.5-turbo', // 使用するモデル
    'max_tokens': 1024, // 生成する文章の最大トークン数
    'temperature': 1, // 生成された文章のランダムさを制御するパラメータ。値が高いほど、よりランダムな文章が生成される
    'messages': requestMessage // 生成する文章の元になるプロンプト
  };
  return {
    'method': 'POST',
    'headers': openAiHeaders,
    'payload': JSON.stringify(openAiPayload),
  };
}

// LINEに返信するメッセージを生成する関数
function generateLinePayload(replyToken, replyMessage) {
  return {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${PropertiesService.getScriptProperties().getProperty('Line_key')}`,
    },
    'payload': JSON.stringify({
      'replyToken': replyToken,
      'messages': [{
        'type': 'text',
        'text': replyMessage,
      }],
    }),
  };
}

// LINEにメッセージを送信する関数
function sendLineMessage(linePayload) {
  const response = UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', linePayload);
  const responseCode = response.getResponseCode();
  if (responseCode !== 200) {
    console.error(`LINE API returned an error: ${responseCode}`);
  }
}

動きとしては、メッセージを英語に翻訳して ChatGPT の API に投げ、英語で受け取った回答を日本語に翻訳して返信しています。質問は英語の方が精度が良いらしいのと、課金の計算元になるトークンのカウントが少なくてすむようです。

コード作成後にウェブアプリとして公開、URL を LINE Messaging API チャンネルで Webhook として設定します。

動かしてみるとこんな感じになります。


英語の勉強も兼ねて、この形式での返信にしています(笑)。


Google スプレッドシートにやりとりを格納して引き出すようにすれば、複数回のやりとりも可能そうです。(→ 作りました「GAS で ChatGPT とやりとりできる簡単な LINE bot の作り方」)

今後もいろいろ試しながら、あわよくば農業への利用の可能性を探っていきたいと思います。


***

ChatGPT、コードを書いてもらったり、説明してもらったりは本当にめちゃくちゃ便利ですね。あと、私のような素人はコードの改善点を指摘してもらえる機会も少ないのでとてもありがたいです。