見出し画像

AIチャットくんをchatGPTで自作してみる

chatGPT によるコーディングで、chatGPTで返信するLINEボットを作りました。要するに AIチャットくんのDIYです
※本稿はAIチャットくんと直接の関係は無く作成されたものであり、応答や仕様は異なります

画像はEイメージです

微調整以外はすべてお任せしました。結果的に自分で書くより早いし、綺麗なコードになりました(だと思います)。

目的

今回制作するものは、chatGPTと会話できるLINEボットです。LINEのMessaging APIを使うと、ユーザーにメッセージを送信したり、何らかのアプリケーションでユーザーのメッセージに反応したりできます。何らかのアプリケーションとして、GPTによる返信を行うアプリをGoogle Apps Script (GAS) で作りました。GPTによる返信は、OpenAI のAPIで行えます

GASである理由は、以前使ったことがある+無料(すごい)だからです。
※緩い制約はあるにせよ何故ずっと無料なのか理解できません。騙されてるのだろうか

コード全体(完成版)

先に完成版です

const LINE_CHANNEL_ACCESS_TOKEN = 'LINEチャンネルのアクセストークン';
const OPENAI_API_KEY = 'OPENAIのAPIキー';
const OPENAI_API_URL = 'https://api.openai.com/v1/chat/completions';

const SPREADSHEET_ID = 'スプレッドシートのID';
const SHEET_NAME = 'Sheet1';

function doPost(e) {
  const json = JSON.parse(e.postData.contents);
  const userMessage = json.events[0].message.text;
  const userId = json.events[0].source.userId;

  if (userMessage.toLowerCase() === 'start') {
    clearSpreadsheet(userId);
  }

  writeToSpreadsheet(userId, 'user', userMessage);

  const chatGPTResponse = fetchChatGPTResponse(userMessage, userId);
  writeToSpreadsheet(userId, 'assistant', chatGPTResponse);

  reply(chatGPTResponse, json.events[0].replyToken);
}

function writeToSpreadsheet(userId, sender, message) {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  const newRow = [userId, sender, message, new Date()];
  sheet.appendRow(newRow);
}

function clearSpreadsheet(userId) {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  const numRows = sheet.getLastRow();

  for (let i = numRows; i >= 2; i--) {
    if (sheet.getRange(i, 1).getValue() === userId) {
      sheet.deleteRow(i);
    }
  }
}

function fetchChatGPTResponse(message, userId) {
  // 以前の会話を含むプロンプトを作成
  const messages = getPreviousMessages(userId);
  messages.push({"role": "user", "content": message});
  
  const data = {
    'model' : 'gpt-3.5-turbo',
    'messages': messages,
  };

  const options = {
    'method': 'POST',
    'headers': {
      'Authorization': "Bearer " + OPENAI_API_KEY,
      'Content-Type':'application/json; charset=UTF-8'
    },
    'payload': JSON.stringify(data),
    'muteHttpExceptions':true
  };
  
  const response = UrlFetchApp.fetch(OPENAI_API_URL, options);
  const jsonResponse = JSON.parse(response.getContentText());
  const chatGPTReply = jsonResponse.choices[0].message.content;

  return chatGPTReply;
}

// userIdに基づいて、Googleスプレッドシートから以前の会話を取得する関数
function getPreviousMessages(userId) {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName(SHEET_NAME);
  const numRows = sheet.getLastRow();
  const messages = [];
  const defaultMessage = "こんにちは。"
  messages.push({"role":"user", "content": defaultMessage});

  for (let i = 2; i <= numRows; i++) {
    if (sheet.getRange(i, 1).getValue() === userId) {
      const sender = sheet.getRange(i, 2).getValue();
      const message = sheet.getRange(i, 3).getValue();
      messages.push({"role":sender, "content": message});
    }
  }
  return messages;
}

function reply(replyText, replyToken) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  const replyMessage = {
  'replyToken': replyToken,
  'messages': [{'type': 'text', 'text': replyText}]
  };

  const options = {
    'method': 'post',
    'headers': {
      'Authorization': "Bearer " + LINE_CHANNEL_ACCESS_TOKEN,
      'Content-Type': 'application/json'
    },
    'payload': JSON.stringify(replyMessage)
  };

  UrlFetchApp.fetch(url, options);
}

GASにコピペして使う場合、冒頭にある自分で取得したLINEのトークンとOPENAIのAPIキー、スプレッドシートのIDを入力してください

制作過程

モデルとしてGPT4を選択し、コーディングをGPTにお願いします。うまいプロンプトは書けないので、プロンプトを考えるのもGPTにお任せします

こちらを使用させていただきました

最初にこのプロンプトを打てば、必要なことは聞いてくれます。あとはコミュニケーションの問題。

一度の応答で三つ追加質問を考えてくれる。
確かに、どれくらいサポートして欲しいか伝えてなかった。
それに微妙にすれ違ってる気がするので訂正しておこう

私のコミュニケーション力が低いのかもしれない。でもGPTはちゃんと意を汲んでくれたようです。追加の質問もなし、ほんとにいいの?

満を持してコードを書いてもらいます。

コード途中で途切れるとコードブロックが解除される。インデントが大変なことになってる…



このコードでは、Google Apps ScriptでLINEボットを作成し、ChatGPTと連携してユーザーのメッセージに応答しています。`doPost`関数がLINEからのイベントを受け取り、その後、`fetchChatGPTResponse`関数でChatGPTから返信を取得し、`reply`関数でLINEボットがユーザーに返信します。

また、`resetChatGPTContext`関数で、ユーザーが「新たな会話を始める」と入力した場合、会話コンテキストをリセットし、新しい会話が始まります。「終了する」と入力されるまで、会話を続けることができます。

最後に、LINE Developersのチャンネル設定でWebhook URLを設定します。Google Apps Scriptでプロジェクトを公開し、ウェブアプリケーションURLを取得します。そのURLをLINE Developersのチャンネル設定のWebhook URLに設定してください。

これで、Google Apps Scriptを使用してLINEボットを作成し、ユーザーからのメッセージに対してChatGPTで返信する機能が実装できました。

凄い、ありがとうGPT!

と思ったら想定したものとちょっと機能が違うみたいです。
機能の修正をお願いしてみます

怒涛の返信が返ってきた

スプレッドシートとの連携方法を定義ししたうえ、必要なヘッダーを適宜手設定してる。柔軟さに親切心すら感じます。

「ここまでくればデバックだ。あとは頑張るね、GPT」

と言いたいところですが、エラーの相談にも乗ってくれるようです。なんて優しいんだ。

ここまでしてもらえました。

最終的には、この後さらに修正を加えて最終版のコードに至りました。

変更点はGPTのAPI周りの部分のみです。モデル名やユーザーとの過去の返信をやり取りする際の書き方が異なったので、OpenAIのAPIのドキュメントを参照して書き直しました。
この辺りは最新のドキュメントに従うしかないですね。

よかったことと課題

LINE のボットは作ったことがありませんでしたが、GPTに頼り続けたら完成できました。
特に便利だと感じたのは、必要となる関数、その関数名や変数名、スプレッドシートとの連携をどうするかといったフレームワークを考えてくれたことです。エラー修正は面倒ですが、悩む時間がない分比較的短時間で終えられました。

課題があるとすれば、適切なプロンプトで意図を伝えるのが難しかったことです。これは慣れるしかなさそうですが、普段からプログラムを書いたり仕様書を作ってる方々ならもっとうまくコミュニケーションが取れるのだと思います。
そうは言っても、知らない単語や機能は聞けば教えてくれるので、あまり問題にはなりませんでした。

参考にさせていただきました↓


この記事が気に入ったらサポートをしてみませんか?