ChatGPTはどこまで雑な仕様でコードを書けるのかLINE Botを作らせてみた(GPT-4)

最近すっかりChatGPT(GPT-4)にハマっています。

GPT-4にバージョンアップして、日本語でのやり取りがとても自然になったのにも正直驚いていますが、それとプログラマー的にはもっと衝撃なのが「かなり雑な仕様でもちゃんと動くコードを書いてくれる」こと。

ということで、今回はChatGPTがどこまで雑な仕様でコードを書けるのか試してみることにしました。

題材としては、この間作った[AIレシピbot](https://qiita.com/__DASHi__/items/2c974e90f900a376f766)のGAS版を作らせてみることにしました。

https://qiita.com/__DASHi__/items/2c974e90f900a376f766

実験の手順としては、まずはカッチリ仕様を提示するバージョンで試してみて、徐々に提示する仕様を雑にしてみようかと思います。ChatGPTは文脈を記憶する特性があるので、毎回チャットをリセットして記憶を消去しています。使用したのはWeb版のChatGPT Pro(GPT-4)です。

結論を先に書くと、かなりヤバい結果です。めちゃくちゃ雑な**ほぼ丸投げの指示でもChatGPTは動くコードを返してきました。**

それでは、実験スタート！
## レベル１：しっかり仕様を提示→ほぼ完璧なコードを書いてきた

最初の指示は、ほとんど自然言語で書いた仮想コード、と言って良いぐらいの粒度で書いてみました。

このレベルの指示でコード書いてくれるだけでも、コメント読んでよしなにコード書いてくれる有能なアシスタントという感じで非常にありがたいのですが。

変数名は文章中に提示しておきましたが、宣言とかはお任せしてみる感じで。

指示：
> Google Apps Scriptで以下のスクリプトを書いてください。スクリプトはウェブアプリケーションとしてデプロイしています。
> - HTTP POSTメッセージを受信したら以下の処理を行う
> - 受信したメッセージから本文を取り出す
> - 受信したメッセージから項目replyTokenを取り出す
> - エンドポイント'https://api.openai.com/v1/chat/completions'にPOSTメッセージを送信する。
> - HTTPヘッダは以下の通り
> - "Content-Type: application/json"
> - "Authorization: Bearer $[OPENAI_API_KEY]"
> - HTTPボディは以下の通り
> - "model": "gpt-3.5-turbo"
> -  "messages": [{"role": "user", "content": [token]}]
> - HTTPリクエストのレスポンスが返ってきたら、レスポンスからchoises[0]'message']['content']を取り出す
> - エンドポイント'https://api.line.me/v2/bot/message/reply'にPOSTメッセージを送信する。
> - HTTPヘッダは以下の通り
> - "Content-Type: application/json"
> - "Authorization: Bearer $[LINE_MESSAGING_TOKEN]"
> - HTTPボディは以下の通り
> - "replyToken": [token]
> -  "messages": [{"type": "text", "content": [reply]}]

回答：
> 以下のスクリプトをGoogle Apps Scriptで実行してください。これは、ウェブアプリケーションとしてデプロイされたスクリプトを使用して、上記の指示に従って処理を行います。

```javascript
const OPENAI_API_KEY = 'YOUR_OPENAI_API_KEY';
const LINE_MESSAGING_TOKEN = 'YOUR_LINE_MESSAGING_TOKEN';

function doPost(e) {
  // Parse the incoming POST message
  const postData = JSON.parse(e.postData.contents);

  // Extract the text content and replyToken from the incoming message
  const text = postData.events[0].message.text;
  const replyToken = postData.events[0].replyToken;

  // Send a POST request to the OpenAI API
  const openaiResponse = callOpenAI(text);

  // Extract the content from the OpenAI response
  const reply = openaiResponse.choices[0].message.content;

  // Send a POST request to the LINE Messaging API
  replyToLine(replyToken, reply);
}

function callOpenAI(token) {
  const apiUrl = 'https://api.openai.com/v1/chat/completions';
  const data = {
    model: 'gpt-3.5-turbo',
    messages: [
      {
        role: 'user',
        content: token,
      },
    ],
  };

  const options = {
    method: 'post',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${OPENAI_API_KEY}`,
    },
    payload: JSON.stringify(data),
  };

  const response = UrlFetchApp.fetch(apiUrl, options);
  return JSON.parse(response.getContentText());
}

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

  const options = {
    method: 'post',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${LINE_MESSAGING_TOKEN}`,
    },
    payload: JSON.stringify(data),
  };

  UrlFetchApp.fetch(apiUrl
```

いやぁ優秀ですね。。。

憎たらしいことに、いい感じに関数化までしてきます。ここまで仕事してくれたら、個人開発の時とかかなり助かります。

## レベル２：細かい仕様を省いて指示

さっきの仕様からは文量を半分ぐらいに減らしてみました。果たしてChatGPTは行間が読めるのか。

**指示：**
> Google Apps Scriptで以下のスクリプトを書いてください。
> - HTTP POSTメッセージを受信したら以下の処理を行う
> - 受信したメッセージから本文とreplyTokenを取り出す
> - OPENAI APIにPOSTする
> - "model": "gpt-3.5-turbo"
> -  "messages": [{"role": "user", "content": [message]}]
> - レスポンスが返ってきたら、choises[0]['message']['content']を取り出す
> - LINE MESSAGING APIにPOSTする
> - "replyToken": [token]
> -  "messages": [{"type": "text", "content": [reply]}]

**回答：**
> 以下のGoogle Apps Scriptコードは、指定された要件に基づいて機能します。

```javascript
function doPost(e) {
  // HTTP POSTメッセージを受信したら以下の処理を行う
  const data = JSON.parse(e.postData.contents);

  // 受信したメッセージから本文とreplyTokenを取り出す
  const message = data.events[0].message.text;
  const replyToken = data.events[0].replyToken;

  // OPENAI APIにPOSTする
  const openaiResponse = sendToOpenAI(message);

  // レスポンスが返ってきたら、choises[0]['message']['content']を取り出す
  const reply = openaiResponse.choices[0].message.content;

  // LINE MESSAGING APIにPOSTする
  sendToLineMessagingAPI(replyToken, reply);
}

function sendToOpenAI(message) {
  const openaiUrl = "https://api.openai.com/v1/engines/gpt-3.5-turbo/completions";
  const openaiApiKey = "your_openai_api_key_here";

  const data = {
    model: "gpt-3.5-turbo",
    messages: [{ role: "user", content: message }],
  };

  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + openaiApiKey,
    },
    payload: JSON.stringify(data),
  };

  const response = UrlFetchApp.fetch(openaiUrl, options);
  return JSON.parse(response.getContentText());
}

function sendToLineMessagingAPI(replyToken, reply) {
  const lineUrl = "https://api.line.me/v2/bot/message/reply";
  const lineAccessToken = "your_line_access_token_here";

  const data = {
    replyToken: replyToken,
    messages: [{ type: "text", text: reply }],
  };

  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + lineAccessToken,
    },
    payload: JSON.stringify(data),
  };

  UrlFetchApp.fetch(lineUrl, options);
}
```

指示の文量が半減したぐらいでは余裕で行間読んできます。

あいかわらずきっちりコード書いてきますね。いやぁ恐ろしい。

## レベル３：かなりざっくりとした指示

次は、「こんな指示でコード書けたら本当にプログラマー商売上がったりだな」というレベルで指示を書いてみます。

まだ多少の用語は残していますが、これぐらいなら本職のエンジニアでなくても多少ググれば指示だせるでしょう、と思いつつ。

さすがのChatGPTでも無理だと思いますが、これできたら「アイデアはあるけど実装が分からない…」な人にはすごい武器になるでしょうね。

**指示：**
> Google Apps Scriptで以下のスクリプトを書いてください。
> - webhookを受信したら本文とreplyTokenを取り出してOPENAI APIにPOSTする
> - modelは"gpt-3.5-turbo"を使うこと
> - OPENAI APIレスポンスからメッセージ本文を取り出してLINE MESSAGING APIにPOSTする

**回答：**
> 以下は、Google Apps Scriptを使用して、webhookを受信し、OpenAI APIにPOSTリクエストを送信し、LINE Messaging APIにPOSTリクエストを送信するためのスクリプトです。まず、あなたのOpenAI APIキーとLINE Messaging APIキーを設定してください。

```javascript
// Set your OpenAI API key and LINE Messaging API key
const OPENAI_API_KEY = 'your_openai_api_key';
const LINE_API_KEY = 'your_line_messaging_api_key';

// Webhook event handler
function doPost(e) {
  const postData = JSON.parse(e.postData.contents);

  // Extract message text and replyToken from webhook event
  const messageText = postData.events[0].message.text;
  const replyToken = postData.events[0].replyToken;

  // Call OpenAI API
  const openAIResponse = callOpenAI(messageText);

  // Extract message from OpenAI API response
  const responseText = openAIResponse.choices[0].text.trim();

  // Send response to LINE Messaging API
  sendReply(replyToken, responseText);
}

// Call OpenAI API function
function callOpenAI(inputText) {
  const apiUrl = 'https://api.openai.com/v1/engines/gpt-3.5-turbo/completions';
  const prompt = inputText;

  const data = {
    prompt: prompt,
    max_tokens: 50,
    n: 1,
    stop: null,
    temperature: 1,
  };

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

  const response = UrlFetchApp.fetch(apiUrl, options);
  return JSON.parse(response.getContentText());
}

// Send reply to LINE Messaging API
function sendReply(replyToken, messageText) {
  const apiUrl = 'https://api.line.me/v2/bot/message/reply';
  const data = {
    replyToken: replyToken,
    messages: [
      {
        type: 'text',
        text: messageText,
      },
    ],
  };

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

  UrlFetchApp.fetch(apiUrl, options);
}
```

めちゃめちゃ書いてくるやん。

この程度で本当にコード書けるのか。。。うわ、これはかなりヤバい。

ちょっと恐ろしいですが、最終レベルももしかして合格するかも、という気がしてきました。

## 最終レベル：ほとんど丸投げでもちゃんと動くコードを提示してきた

最終レベルは無理ゲー中の無理ゲー、めちゃくちゃざっくりとした指示でコードを書かせてみることにしました。

これでChatGPTが動くコードを書けるなら、我々は真面目に危機感を抱かないといけないです。

**指示：**
> Google Apps Scriptで、LINEからメッセージを受信したらChatGPTに送信して、受け取った返信をLINEにリプライするコードを教えてください。

**回答：**
> Google Apps ScriptでLINEとChatGPTを連携させるためには、次の手順で実装が可能です。まず、LINE Messaging APIとOpenAI APIを利用するために、以下のリンクからGoogle Apps Scriptに必要なライブラリを導入してください。
> 
> LINE Messaging API用ライブラリ: 公式ドキュメント
> OpenAI API用ライブラリ: 公式ドキュメント
> 次に、以下のコードをGoogle Apps Scriptに貼り付けてください。ここでは、LINEのWebhookイベントでメッセージを受信し、ChatGPTに送信して、受け取った返信をLINEにリプライする機能を実装しています。

```javascript
// 必要なAPIキーを設定
const LINE_CHANNEL_ACCESS_TOKEN = 'YOUR_LINE_CHANNEL_ACCESS_TOKEN';
const OPENAI_API_KEY = 'YOUR_OPENAI_API_KEY';

// LINEからのWebhookイベントを処理
function doPost(e) {
  const jsonData = JSON.parse(e.postData.contents);
  const events = jsonData.events;
  
  events.forEach(event => {
    if (event.type === 'message' && event.message.type === 'text') {
      const userMessage = event.message.text;
      const replyToken = event.replyToken;
      
      // ChatGPTに質問を送信し、回答を取得
      const gptResponse = sendQuestionToChatGPT(userMessage);
      
      // 取得した回答をLINEにリプライ
      replyMessage(replyToken, gptResponse.choices[0].text);
    }
  });
}

// ChatGPTへの質問を送信
function sendQuestionToChatGPT(question) {
  const url = 'https://api.openai.com/v1/engines/davinci-codex/completions';
  const headers = {
    'Authorization': `Bearer ${OPENAI_API_KEY}`,
    'Content-Type': 'application/json'
  };
  const data = {
    prompt: question,
    max_tokens: 100,
    n: 1,
    stop: null,
    temperature: 1.0
  };
  const options = {
    method: 'post',
    headers: headers,
    payload: JSON.stringify(data)
  };
  
  const response = UrlFetchApp.fetch(url, options);
  return JSON.parse(response.getContentText());
}

// LINEにメッセージをリプライ
function replyMessage(replyToken, message) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  const headers = {
    'Authorization': `Bearer ${LINE_CHANNEL_ACCESS_TOKEN}`,
    'Content-Type': 'application/json'
  };
  const data = {
    replyToken: replyToken,
    messages: [{
      type: 'text',
      text: message
    }]
  };
  const options = {
    method: 'post',
    headers: headers,
    payload: JSON.stringify(data)
  };
  
  UrlFetchApp.fetch(url, options);
}
```

> コード内の YOUR_LINE_CHANNEL_ACCESS_TOKEN と YOUR_OPENAI_API_KEY を、それぞれ適切な値に置き換えてください。LINEMessaging APIとOpenAI APIのアクセストークンを取得するには、以下の手順に従ってください。
> 
> LINE Messaging APIのアクセストークンの取得:
> 
> LINE Developersコンソールにログインし、新規プロバイダとチャネル（Messaging API）を作成します。
> チャネル設定ページで、アクセストークン（ロングターム）を発行します。
> このアクセストークンをコード内の YOUR_LINE_CHANNEL_ACCESS_TOKEN に置き換えます。
> OpenAI APIキーの取得:
> 
> OpenAIのウェブサイトでアカウントを作成し、APIキーを取得します。
> このAPIキーをコード内の YOUR_OPENAI_API_KEY に置き換えます。
> これで、Google Apps Script上でLINEとChatGPTを連携させる準備が整いました。Webhook URLをLINEチャネルに設定することで、LINEからのメッセージをGoogle Apps Scriptが受け取り、ChatGPTに送信し、受け取った返信をLINEにリプライするようになります。
> 
> Webhook URLの設定方法は以下の通りです。
> 
> Google Apps Scriptのプロジェクトをデプロイして、Webアプリケーションとして公開します。
> 公開されたWebアプリケーションのURLをコピーします。これがWebhook URLです。
> LINE Developersコンソールで、先ほど作成したチャネルの設定ページに移動し、「Webhook送信」を有効にし、Webhook URLに先ほどのURLを入力します。
> これで、LINEからメッセージを受信すると、Google Apps Scriptで処理され、ChatGPTに送信され、返答がLINEにリプライされるようになります。

**絶句！**

指示が大雑把だったことから、こっちの知識レベルが低いと判断したのでしょう。かなり詳細な説明まで付けてきました。

しかも**このコード、しっかり動きます。**

もちろん最新のGPT-3.5ではなくdavinciを使っていたり、エンドポイントURLが古いものになっていたりしますが、それはChatGPT(GPT-4)が2021年9月までのデータしか学習していないので仕方がないでしょう。

あとは、最新情報をググって多少のコードの置き換え作業ができればGPT-3.5で動く完成品も全然簡単にできると思います。

## まとめ：数年以内に仕事がなくなると思って動いた方が良さそう

最初は「ChatGPT、かなりコード書けるな」と思ってお遊び感覚で始めた実験でしたが、レベルを上げれば上げるほど段々と怖くなってきました。

これからのプログラマー、エンジニアはクリエイティブなコードを書ける人、最新情報を取り込んだコードを爆速で書ける人でないと生き残れないかもしれません。

やばいよやばいよ。。。