【GAS】ChatGPTと連携するチャットボットを作る!

Google Apps Script

どーも!marusukeです!

OpenAI APIと連携して簡易的なChatGPTのように使えるチャットボットを作成しました!

ぜひ、コピペして利用してみてください!

以下のようにスプレッドシートのカスタムメニュー「チャットボット」から使えるようになります!

chatbot_demo
免責事項:この記事は参考情報の提供を目的としています。実際の決定や行動は自己責任でお願いします

仕組みについて(データの流れ)

以下のようなデータの流れになっています

  1. ユーザーがモデルを選択し、チャット画面に聞きたいことを入力する
  2. GASがユーザーからの入力された情報(入力テキストとモデル)をOpenAI APIにリクエストする
  3. OpenAI APIからのレスポンスから回答をチャット画面に表示する

必要な作業

完成させるまでに必要な手順は以下です!

  • OpenAI APIにログインし、API keyを取得する
  • チャットボット用のスプレッドシートにGASコードを貼り付ける
  • スプレッドシート内に「MODEL」シートを作成し、利用するモデルにチェックをつける
  • スプレッドシート内に「COFIG」シートを作成し、取得したAPIキーを貼り付ける
    • 初めて実行する際には認証が必要になります。その時の認証方法は以下の記事をご覧ください

これでスプレッドシートでチャットボットが利用できるようになります!

OpenAI APIにログインし、API keyを取得する

以下の記事に方法をまとめました!

トークン(文章内の言葉の単位)によってAPIの料金が発生します。API料金については以下の公式ページをご覧ください

Just a moment...

チャットボットのコード

GASコードは以下のようになっています

  • GASコード
    • カスタムメニューを表示する関数
    • チャット画面を表示する関数
    • OpenAI APIを叩く関数
    • APIキーをシートから取得する関数
    • OpenAI APIからのレスポンスから回答を取得する関数
  • チャットボットUI用のHTML

GASコードから説明していきます!

GASコード(コピペ用)

main.gs(ファイル名はなんでも良いです)

// カスタムメニューを表示する関数
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu("チャットボット")
    .addItem("チャットボットを開く", "showChatbotModal")
    .addToUi();
}


// チャット画面を表示する関数
function showChatbotModal() {
  var html = HtmlService.createHtmlOutputFromFile("chatbot_ui")
    .setWidth(700)
    .setHeight(700);
  SpreadsheetApp.getUi().showModalDialog(html, "ChatGPT Bot");
}


// OpenAI APIからのレスポンスから回答を取得する関数
function getChatbotResponse(userMessage, selectedModel) {
  var apiKey = getApiKey();
  var user = Session.getActiveUser().getEmail();
  var openaiPrompt = "";

  if (!selectedModel) {
    throw new Error("No model selected.");
  }
  
  // ChatGptApiにリクエストしてレスポンスを取得
  var response = requestChatGptApi(selectedModel, openaiPrompt, userMessage, apiKey);
  var data = JSON.parse(response);

  return data.choices[0].message.content;
}


// OpenAI APIを叩く関数
function requestChatGptApi(model, metaPronpt, userPronpt, apiKey){
  var url = "https://api.openai.com/v1/chat/completions";
  var payload = "";

  // modelなしは"gpt-3.5-turbo"がデフォルト
  if(!model){
    model = "gpt-3.5-turbo";
  }

  // メタプロンプトがある場合のpayload
  if(metaPronpt){
    payload = {
      model: model,
      messages: [
          { role: "developer", "content": metaPronpt},
          { role: "user", content: userPronpt }
      ],
    };
  }

  // メタプロンプトがない場合のpayload
  if(!metaPronpt){
    var payload = {
      model: model,
      messages: [
        // { role: "developer", "content": metaPronpt},
        { role: "user", content: userPronpt }
      ],
    };
  }
  
  var options = {
    method: "post",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json"
    },
    payload: JSON.stringify(payload)
  };
  
  var response = UrlFetchApp.fetch(url, options);
  return response;
}


// APIキーをシートから取得する関数
function getApiKey() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CONFIG");
  if (!sheet) throw new Error("CONFIGシートが見つかりません");
  
  var data = sheet.getDataRange().getValues();
  for (var i = 0; i < data.length; i++) {
    if (data[i][0] === "openAiApiKey") {
      return data[i][1];
    }
  }
  throw new Error("openAiApiKeyがCONFIGシートに設定されていません");
}

チャットボットUI用のHTML(コピペ用)

chatbot_ui.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ChatGPT Bot</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    /* ローディングドットのアニメーション */
    .dot-flashing {
      display: inline-block;
      width: 10px;
      height: 10px;
      margin-left: 2px;
      background-color: gray;
      border-radius: 50%;
      animation: flash 1.5s infinite;
    }
    .dot-flashing:nth-child(2) {
      animation-delay: 0.2s;
    }
    .dot-flashing:nth-child(3) {
      animation-delay: 0.4s;
    }
    @keyframes flash {
      0% { opacity: 1; }
      50% { opacity: 0.2; }
      100% { opacity: 1; }
    }
  </style>
</head>
<body class="flex items-center justify-center h-screen bg-gray-100">
  <div class="w-[700px] h-[564px] bg-white rounded-lg shadow-lg p-4">
    
    <!-- モデル選択のプルダウン -->
    <label for="model-select" class="block text-sm font-medium text-gray-700">モデルを選択</label>
    <select id="model-select" class="w-full border p-2 rounded mb-4"></select>

    <div id="chat-box" class="h-[380px] overflow-y-auto border p-2 bg-gray-50 rounded mb-4"></div>
    <div class="flex">
      <input id="user-input" type="text" class="flex-1 border p-2 rounded-l" placeholder="メッセージを入力">
      <button onclick="sendMessage()" class="bg-blue-500 text-white px-4 rounded-r">送信</button>
    </div>
  </div>

  <script>
    function sendMessage() {
      var inputField = document.getElementById("user-input");
      var message = inputField.value.trim();
      if (!message) return;

      var selectedModel = document.getElementById("model-select").value; // 選択されたモデルを取得
      var chatBox = document.getElementById("chat-box");

      // ユーザーのメッセージを追加
      chatBox.innerHTML += `<div class="text-right mb-2"><span class="inline-block bg-blue-100 text-blue-700 p-2 rounded-lg">${message}</span></div>`;
      inputField.value = "";

      // ローディングメッセージを追加
      var loadingMessage = document.createElement("div");
      loadingMessage.id = "loadingMessage";
      loadingMessage.classList.add("text-left", "mb-2");
      loadingMessage.innerHTML = `<span class="inline-block bg-gray-100 text-gray-700 p-2 rounded-lg">
        <span class="dot-flashing"></span>
        <span class="dot-flashing"></span>
        <span class="dot-flashing"></span>
      </span>`;
      chatBox.appendChild(loadingMessage);
      chatBox.scrollTop = chatBox.scrollHeight;

      // Google Apps Scriptの関数を呼び出し
      google.script.run.withSuccessHandler(function(response) {
        // ローディングメッセージを削除
        loadingMessage.remove();

        // ボットのレスポンスを表示
        chatBox.innerHTML += `<div class="text-left mb-2"><span class="inline-block bg-gray-100 text-gray-700 p-2 rounded-lg">${response}</span></div>`;
        chatBox.scrollTop = chatBox.scrollHeight;
      }).getChatbotResponse(message, selectedModel);
    }

    function loadModels() {
      google.script.run.withSuccessHandler(function(models) {
        var modelSelect = document.getElementById("model-select");
        modelSelect.innerHTML = ""; // 既存のオプションをクリア
        models.forEach(function(model) {
          var option = document.createElement("option");
          option.value = model;
          option.textContent = model;
          modelSelect.appendChild(option);
        });
      }).getAvailableModels();
    }

    // ページ読み込み時にモデルリストを取得
    window.onload = loadModels;
  </script>
</body>
</html>

これらのGASコードとHTMLを貼り付けたら、次はスプレッドシート内に必要なシートを準備していきます!

スプレッドシート内に「MODEL」シートを作成する

以下のように「MODEL」シートを作成します

以下の内容を貼り付ければ、上記の画像と同じになります(チェックボックスがTRUEとFALSEになります。必要に応じてチェックボックスに変更してください)

IsAvailable	Model
TRUE	gpt-3.5-turbo-0125
FALSE	gpt-4o
TRUE	gpt-4o-mini
TRUE	gpt-4
TRUE	gpt-4-turbo

上記のモデルだけでなく、APIで利用できるモデルを記載し、チェックボックスにチェックをつければ(またはTRUEにすれば)、チャットボットで利用できるようになります!

※このチャットボットでは、画像をアップロード機能がないため、画像生成系のモデルは利用できないです。予めご了承くださいませm(_ _)m

ここまで完了したら、もう一息です!次は、「COFIG」シートを作成します!

スプレッドシート内に「COFIG」シートを作成する

以下のように「CONFIG」シートを作成します

A列にopenAiApiKeyと入力し、B列に取得したAPIキーを貼り付けます

チャットボットのスプレッドシートを公開しました!「MODEL」や「CONFIG」シートなどをコピペで簡単に作りたい方はこちらをご覧ください!

GASチャットボット

これでチャットボットを利用できるようになりました!

初めてチャットボットを実行するときは認証が必要になります。以下の記事を参考に認証をしてみてください

以上です!

ここまで読んでいただきありがとうございました!

次は、利用料金が見えるようにする方法を記事にしようと考えています!

では!

コメント

タイトルとURLをコピーしました