ChatGPT APIでちいかわ博士ちゃんLINEBotを作りたい

## 1.ChatGPTAPIを使ってLINEBotをつくりたい
前回、ChatGPTでサクッと初めてのコードを書けたことに調子に乗ったので、また新たな挑戦としてLINEBotにチャレンジします。
今回も夫婦のコミュニケーションをより良くするために、『ちいかわ』をテーマにLINEBotを作っていきます。

### 1-1．完成品はこちら
https://twitter.com/am003004/status/1663545415856427008?s=20

リッチメニューは良い感じですが、ChatGPTが全く思ってた設定でお話してくれません！

## 2.実装
### 2-1.今回使ったもの
1. JavaScript　Node.js
2. ChatGPT API
3. LINEMessaging API
4. リッチメニューエディタ

https://richmenu.app.e-chan.me/

### 2-2.準備
1.JavaScript　Node.jsのコードを書く環境を作る
私はGitHub Codespacesを使いました。

https://zenn.dev/dzeyelid/articles/5485cdeb2a1ada

2.Messaging APIの準備

3.ChatGPTAPIKeyの取得

4.参考にするコードを探す。
1から全部ChatGPTにコードを書かせるのは難しいので、ベースにするコードをネットなどから探します。

<details><summary> サンプルコード</summary>

```js
'use strict';

// ########################################
//               初期設定など
// ########################################

// モジュールの読み込み
const line = require('@line/bot-sdk');
const openai = require('openai');
const express = require('express');

const PORT = process.env.PORT || 3000;

// 設定
const config = {
  channelSecret: process.env.CHANNEL_SECRET || '作成したBotのチャネルシークレット',
  channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN || '作成したBotのチャネルアクセストークン',
};

// クライアントの作成
const client = new line.Client(config);

const gptConfig = new openai.Configuration({
  organization: process.env.OPENAI_ORGANIZATION || "取得したOrganization ID",
  apiKey: process.env.OPENAI_API_KEY || '取得したAPI key',
});

const gpt = new openai.OpenAIApi(gptConfig);

const makeCompletion = async (userMessage) => {
  const prompt = {
      role: "system", 
      content: "一般的なChatGPTのメッセージを返してください" // プロンプトを入力
  };

  userMessage.unshift(prompt);
  console.log(userMessage);
  return await gpt.createChatCompletion({
      model: "gpt-3.5-turbo",
      messages: userMessage,
      temperature: 0.5,
      n: 1
  });
};

// メッセージイベントの処理
async function handleEvent(event) {
  // テキストメッセージ以外は無視
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  const userMessage = [{
    role: "user",
    content: event.message.text
  }];

  // ChatGPT APIにリクエストを送る
  try {
    const completion = await makeCompletion(userMessage);
    // レスポンスから返答を取得
    const reply = completion.data.choices[0].message.content;
    // console.log(completion.data.choices[0].message.content); // レスポンスをみたいときにコメントアウトを外してください
    // 返答をLINEに送る
    return client.replyMessage(event.replyToken, {
      type: 'text',
      text: reply
    });
  } catch (error) {
    // エラーが発生した場合はログに出力
    console.error(error);
    return Promise.resolve(null);
  }
}

// ここ以降は理解しなくてOKです
const app = express();
app.get('/', (req, res) => res.send('Hello LINE BOT! (HTTP GET)'));
app.post('/webhook', line.middleware(config), (req, res) => {

  if (req.body.events.length === 0) {
    res.send('Hello LINE BOT! (HTTP POST)');
    console.log('検証イベントを受信しました！');
    return;
  } else {
    console.log('受信しました:', req.body.events);
  }

  Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});


app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);


```
</details>

こちらはChatGPTAPIを使ってLINEBotを作るコードになります。
今回はこちらのコード自体はあまりさわらず、ChatGPTのプロンプトをいじって、
LINEBotにキャラクターを作っていきます。


### 2-3.作成
お手本コードがChatGPTのAPIを使ってLINEMessaging APIに飛ばすコードだったので、
リッチメニューの作りこみとChatGPTの作り込を実施しました。

リッチメニュー
![Qiita2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/42176ba8-7db3-a314-25b0-3f8dceac685c.png)

リッチメニューエディターというツールを使って、
好きな画像に合わせて、タップ領域とアクションを自由に設定します。
参考記事はこちら

https://qiita.com/okinakamasayoshi/items/c342506bc216417fd30f

プロンプト
![kiita.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/c52d4de0-ce40-265a-2b37-f7f2ccfb3b9c.png)

こちらはChatGPTのキャラクタープロンプト
あなたはChatbotとして、ツンデレ女子高生のロールプレイを行います。 以下の制約条件を厳密に守ってロールプレイを行ってください。
制約条件:




実際にお手本コードにプロンプトを貼りましたが、
プロンプト通りお話してくれませんでした。
ChatGPTAPIでないところではちゃんと想定通りの話をしてくれたのになぜでしょう。

うーん上手くいかない！




## 3 .反省
ChatGPT APIのプロンプトはｽﾀｯｸﾁｬﾝというロボットを作ったときにも散々やっていたので油断していました。
ｽﾀｯｸﾁｬﾝの時は先人たちのわかりやすい解説の元、指定の場所に書き込むだけとか、アプリに入力だったのでこんなに苦戦しませんでしたが、やはりプログラムのお作法がわかっていない初心者には簡単ではないのですね。
精進します。