当サイトにはアフィリエイト広告が含まれます。なおレビューは私の感想を書いており、内容を指示するご依頼はお断りしています

Google Apps Script (GAS) とLINE Messaging APIでChatGPT連携Botを構築する完全ガイド

1. はじめに:AIとコミュニケーションの未来

近年、人工知能(AI)の進化は目覚ましく、特にChatGPTのような大規模言語モデルは、私たちの日常生活やビジネスにおいて革新的な変化をもたらしています。

本記事では、このChatGPTとLINEのメッセージング機能を組み合わせ、Google Apps Script (GAS) を用いて独自のLINE Botを構築する具体的な手順を詳細に解説します。

これにより、ユーザーはAIを活用したインタラクティブなコミュニケーションツールを自ら開発し、その可能性を最大限に引き出すことができます。

2. 開発環境の準備:LINE DevelopersとGoogleアカウント

LINE Botの開発には、LINE DevelopersコンソールとGoogleアカウントが必要です。

2.1 LINE Developersチャンネルの作成

LINE Developersコンソールにアクセスし、新規プロバイダーとMessaging APIチャンネルを作成します。ここでは、以下の情報を取得し、後の設定で利用します。

  • チャンネルID
  • チャンネルシークレット (Channel Secret)
  • チャンネルアクセストークン (Channel Access Token)

アカウントを作ると、こんな感じのメッセージが届きます。

2.2 Google Apps Script (GAS) プロジェクトのセットアップ

Googleスプレッドシートを開き、「拡張機能」メニューから「Apps Script」を選択して新しいGASプロジェクトを作成します。このGASプロジェクトが、LINEとChatGPTを連携させるためのコードの実行環境となります。

3. コア機能の実装:ChatGPT連携とスプレッドシートへのログ記録

3.1 スプレッドシートの準備

会話履歴の記録と設定情報の管理のため、Googleスプレッドシート内に「ChatLog」と「config」の2つのシートを作成します。

  • ChatLogシート: ユーザーからのメッセージ、Botの応答、タイムスタンプ、ユーザーIDなどを記録します。
  • configシート: ChatGPTのシステムメッセージなど、Botの動作に関する設定値を管理します。

3.2 GASコードの記述

GASエディタに以下の主要な関数を記述します。

// 定数設定 (スクリプト プロパティから取得)
const scriptProperties = PropertiesService.getScriptProperties();

const LINE_CHANNEL_ACCESS_TOKEN = scriptProperties.getProperty('LINE_CHANNEL_ACCESS_TOKEN');
const LINE_CHANNEL_SECRET = scriptProperties.getProperty('LINE_CHANNEL_SECRET');
const OPENAI_API_KEY = scriptProperties.getProperty('OPENAI_API_KEY');
const SPREADSHEET_ID = scriptProperties.getProperty('SPREADSHEET_ID');
const MAX_TOKEN = 500;
const MAX_LENGTH = 100; // 取得範囲広すぎるかも?

function doPost(e) {
  Logger.log('doPost function started.');

  const body = e.postData.contents; 
  
  const json = JSON.parse(body);
  const events = json.events;

  events.forEach(event => {
    if (event.type === 'message' && event.message.type === 'text') {
      const userId = event.source.userId;
      const userMessage = event.message.text;
      const replyToken = event.replyToken;

      // ユーザー情報を取得 (表示名)
      const profile = getLineProfile(userId); // replyTokenはgetLineProfileでは使用しないため削除
      const userName = profile ? profile.displayName : 'Unknown';

      // スプレッドシートにメッセージを記録
      logToSheet(userId, userName, userMessage, '');

      // ChatGPTにメッセージを送信し、返信を取得
      const chatGPTResponse = getChatGPTResponse(userId, userMessage);

      // スプレッドシートにChatGPTの返信を追記
      updateSheetResponse(userId, userMessage, chatGPTResponse);

      // LINEに返信
      replyToLine(replyToken, chatGPTResponse);
    }
  });
}


// LINEユーザーのプロフィール取得関数
function getLineProfile(userId) {
  const url = `https://api.line.me/v2/bot/profile/${userId}`;
  const options = {
    'method': 'get',
    'headers': {
      'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
    }
  };
  try {
    const response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText());
  } catch (e) {
    console.error('Failed to get LINE profile:', e.message);
    return null;
  }
}

// スプレッドシートに記録する関数
function logToSheet(userId, userName, userMessage, botResponse) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('ChatLog');
  const now = new Date();
  sheet.appendRow([now, userId, userName, userMessage, botResponse]);
}

// スプレッドシートの返信部分を更新する関数
function updateSheetResponse(userId, userMessage, botResponse) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('ChatLog');
  const data = sheet.getDataRange().getValues();
  for (let i = data.length - 1; i >= 0; i--) {
    if (data[i][1] === userId && data[i][3] === userMessage && data[i][4] === '') {
      sheet.getRange(i + 1, 5).setValue(botResponse);
      break;
    }
  }
}

// ChatGPT APIを叩く関数 (履歴を考慮したバージョン)
function getChatGPTResponse(userId, userMessage) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('ChatLog');
  const data = sheet.getDataRange().getValues();
  
  // configシートからシステムメッセージを読み込む
  const configSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('config');
  const systemMessageContent = configSheet.getRange('B1').getValue(); 

  let messages = [
    { role: "system", content: systemMessageContent }
  ];

  // 過去の会話履歴を取得
  let userHistory = [];
  for (let i = data.length - 1; i >= 0; i--) {
    if (data[i][1] === userId) {
      if (data[i][3]) userHistory.unshift({ role: "user", content: data[i][3] });
      if (data[i][4]) userHistory.unshift({ role: "assistant", content: data[i][4] });
      if (userHistory.length >= MAX_LENGTH) break;
    }
  }

  messages = messages.concat(userHistory);
  messages.push({ role: "user", content: userMessage });

  const url = "[https://api.openai.com/v1/chat/completions](https://api.openai.com/v1/chat/completions)";
  const options = {
    "method": "post",
    "headers": {
      "Authorization": "Bearer " + OPENAI_API_KEY,
      "Content-Type": "application/json"
    },
    "payload": JSON.stringify({
      "model": "gpt-4o", 
      "messages": messages,
      "temperature": 0.8,
      "max_tokens": MAX_TOKEN 
    })
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const jsonResponse = JSON.parse(response.getContentText());
    return jsonResponse.choices[0].message.content.trim();
  } catch (e) {
    console.error("ChatGPT API Error: " + e.message);
    return "ChatGPTとの通信でエラーが発生しました。";
  }
}

// LINEに返信する関数
function replyToLine(replyToken, message) {
  const url = "[https://api.line.me/v2/bot/message/reply](https://api.line.me/v2/bot/message/reply)";
  const options = {
    "method": "post",
    "headers": {
      "Authorization": "Bearer " + LINE_CHANNEL_ACCESS_TOKEN,
      "Content-Type": "application/json"
    },
    "payload": JSON.stringify({
      "replyToken": replyToken,
      "messages": [
        {
          "type": "text",
          "text": message
        }
      ]
    })
  };

  try {
    UrlFetchApp.fetch(url, options);
  } catch (e) {
    console.error("LINE Reply Error: " + e.message);
  }
}

// LINEにプッシュメッセージを送る関数(新しく追加)
function pushMessageToLine(userId, message) {
  const url = "[https://api.line.me/v2/bot/message/push](https://api.line.me/v2/bot/message/push)"; 
  const options = {
    "method": "post",
    "headers": {
      "Authorization": "Bearer " + LINE_CHANNEL_ACCESS_TOKEN,
      "Content-Type": "application/json"
    },
    "payload": JSON.stringify({
      "to": userId, 
      "messages": [
        {
          "type": "text",
          "text": message
        }
      ]
    })
  };

  try {
    UrlFetchApp.fetch(url, options);
    console.log(`Push message sent to ${userId}: ${message}`);
  } catch (e) {
    console.error("LINE Push Message Error: " + e.message);
  }
}

// 例えば、毎朝9時にプッシュメッセージを送る関数 (トリガー設定用)
function sendDailyMorningMessage() {
  // メッセージを送りたいユーザーのIDを指定する
  const targetUserId = "【ここにメッセージを送りたいLINEユーザーのIDを貼り付ける】"; // 例: Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  const messageContent = "おはよう!今日も一日頑張ろうな!"; // 送りたいメッセージ

  // プッシュメッセージ関数を呼び出す
  if (targetUserId && targetUserId !== "【ここにメッセージを送りたいLINEユーザーのIDを貼り付ける】") { 
    pushMessageToLine(targetUserId, messageContent);
  } else {
    console.warn("Target User ID is not set for daily morning message.");
  }
}
  • doPost(e)関数: LINEからのWebhookイベントを受け取り、メッセージ処理の起点となります。この関数内で、メッセージの解析、ユーザーIDの特定、応答メッセージの生成、およびログ記録のプロセスを制御します。
  • getChatGPTResponse(userId, userMessage)関数: OpenAIのChatGPT APIと連携し、ユーザーのメッセージに対する応答を生成します。会話の履歴を考慮することで、より自然な対話を実現します。システムメッセージはconfigシートから動的に読み込むように設定します。
  • replyToLine(replyToken, message)関数: ユーザーのメッセージに対してLINE Botから応答を送信します。これはWebhookイベント発生時にのみ利用可能です。
  • logToSheet(userId, userName, userMessage, botResponse)関数: 会話のログをGoogleスプレッドシートの「ChatLog」シートに記録します。
  • updateSheetResponse(userId, userMessage, botResponse)関数: 応答後にスプレッドシートの記録を更新し、Botの返信内容を追記します。
  • getLineProfile(userId)関数: LINEのプロフィールAPIを利用し、ユーザーの表示名などの情報を取得します。

4. デプロイとLINE Developersへの接続

GASプロジェクトをウェブアプリとしてデプロイすることで、インターネット上からアクセス可能なURLが生成されます。

  • 実行ユーザー: 「自分」
  • アクセスできるユーザー: 「全員」 この設定により、Botは開発者の権限で動作しつつ、LINEプラットフォームからのリクエストを受け付けることが可能になります。

デプロイ後、発行されたウェブアプリのURLをLINE Developersコンソールの「Messaging API設定」タブ内のWebhook URLに設定し、「検証」ボタンで接続を確認します。

試しにメッセージを送ってみました。

5. 応用機能:プッシュメッセージと時間主導型トリガー

構築したBotは、ユーザーからのメッセージに応答するだけでなく、能動的にメッセージを送信することも可能です。

  • pushMessageToLine(userId, message)関数: LINEのプッシュメッセージAPIを利用し、特定のユーザーIDに対して任意のメッセージを送信します。
  • 時間主導型トリガー: GASのトリガー機能を利用することで、pushMessageToLine関数を特定の時刻に自動実行させることが可能です。これにより、定時通知やリマインダーといった機能を実現できます。

6. まとめと今後の展望

本記事を通じて、Google Apps ScriptとLINE Messaging API、そしてChatGPTを組み合わせることで、高度な対話型Botを構築できることを示しました。

この基盤を元に、ユーザーはさらに多様な機能を Bot に追加し、パーソナルアシスタント、情報提供ツール、あるいはエンターテイメント Bot として、その可能性を無限に広げることができるでしょう。AI技術とコミュニケーションプラットフォームの融合は、私たちの生活をより豊かにする強力なツールとなるはずです。