【初心者向け】簡単なチャットアプリを作成する【Next.jsでchatGPTのAPIを動かす/第4回】

Next.jsでchatGPTのAPIを使う

はじめに

こんにちはミナミ73です!
前前回はNext.jsの環境構築、前回はchatGPTのAPIの設定まで行いました。
今回はついに本題です。
前回設定したAPIを使って実際にAIと会話するアプリの開発を行います。


筆者の環境
・OS:Windows11
・CPU:Ryzen9 3900X
・エディタ:VScode
・Next.jsではapp router使ってます

今回作るアプリの完成画面です。
簡易的な会話ができるだけのチャット画面です。
デフォルトで関西弁で返すように設定しています。

Next.jsでchatGPTのチャット画面を作成する

APIエンドポイントを作成する

my-app/app/配下にapi/chat-gpt-api/route.tsを作成する。(以下の画像のようになる。)

route.tsの中身は以下のようにします。

import { OpenAIStream, StreamingTextResponse } from 'ai'
import OpenAI from 'openai'


export async function POST(req: Request) {
    try {
        const { messages } = await req.json()

        const initialMessages = messages.slice(0, -1)
        const currentMessage = messages[messages.length - 1]
        const openai = new OpenAI({
        apiKey: process.env.OPENAI_API_KEY || '',
        })

        const response = await openai.chat.completions.create({
            model: 'gpt-3.5-turbo-1106',
            stream: true,
            max_tokens: 150,
            messages: [
            ...initialMessages,
            {
                ...currentMessage
            },
            ],
        })
        const stream = OpenAIStream(response);
        return new StreamingTextResponse(stream);

    } catch (error) {
        // エラーレスポンスを返す
        return new Response(JSON.stringify({ error: 'API request failed' }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
        });
    }
}

ここで投げてきたメッセージを受け取り、デフォルトの設定とメッセージに分けます。
後で説明しますが、今回はinitialMessageが「関西弁で話して」currentMessageが「こんにちは」などのユーザ入力になります。

const { messages } = await req.json()

const initialMessages = messages.slice(0, -1)
const currentMessage = messages[messages.length - 1]

次にここで前回設定したAPIキーを取得し、設定します。

const openai = new OpenAI({
 apiKey: process.env.OPENAI_API_KEY || '',
})

ここで実際にメッセージをchatGPTに投げてレスポンスを受け取ります。
また、ここでモデルの設定や、一回で受け取る最大のトークン数なども設定します。
今回はモデルが、gpt-3.5-turbo-1106、最大のトークン数が150としました。(かなりテスト用の設定です。)
返答の受け取りはstream形式で受け取ります。(生成されたら順番に少しずつ文字も受け取る)

const response = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo-1106',
    stream: true,
    max_tokens: 150,
    messages: [
       ...initialMessages,
    {
       ...currentMessage
    },
    ],
})
const stream = OpenAIStream(response);
return new StreamingTextResponse(stream);

フロント側を作成する

my-app/app/pages.tsx(もしくは自作のコンポーネントなど)に以下のコードを書きます。
デザインはchatGPTさんに作成してもらった簡単なものになります。

'use client'

import { useChat } from 'ai/react';
import { Message } from 'ai/react';

export default function Home() {
  const prompt = `
  関西弁で話してください。
  `;

  const initialMessages: Message[] = [
    { id: 'initial-1', role: 'system', content: prompt}
  ];


  const { messages, input, handleSubmit,setInput } = useChat({
    api: '/api/chat-gpt-api',
    initialMessages: initialMessages // useChatフックに初期メッセージをす
  });

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">

    <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-left">
      <div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col w-full md:w-1/2">
        <div id="chatArea" className="mb-4 h-96 overflow-auto border p-4">
        {messages.map(message=>{
                if(message.role == 'assistant'){
                    return (<div><span>AI:{message.content}</span></div>)
                }else if(message.role == 'user'){
                  return (<div><span>USER:{message.content}</span></div>)
                }
            })}
        </div>

        <div className="mb-6">
          <form onSubmit={(e) => {
            e.preventDefault()
            handleSubmit(e)
            setInput('')
          }
            }>
            <input
              className="shadow appearance-none border rounded w-4/5 py-2 px-3 mx-2 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
              id="message" type="text" placeholder="メッセージを入れてください" value={input} onChange={(e) => setInput(e.target.value)} />
              <button
              className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
              type="submit" >
              送信
            </button>
          </form>
        </div>

        <div className="flex items-center justify-between">

        </div>
      </div>
    </main>
  </div>
  );
}

まずuse clientを指定します。
chatGPTのapiはクライアントコンポーネントでしか動かないそうなのでこれを宣言する必要があります。

'use client'

次にchatGPTのAPIを使うための設定です。
先頭で指定しているpromptがデフォルトでchatGPTに投げる文になります。
ここでは「関西弁で話してください。」としているので、基本的に関西弁で返答を返してくれます。
initialMessageでライブラリで指定されているMessageという型でこのプロンプトを設定します。
ここでroleはsystemにしてください。
roleは「user,system,assistant」の3つがあります。userはユーザ入力、systemは今回のようなデフォルトでのAIの性格を定義するもの、assistantがAIからの返答になります。
次にuseChatで使うAPIエンドポイントの設定や、initialMessageの設定をします。
ここで受け取っているmessagesにユーザの入力や、initialMessage、AIの返答などが入ってきます。
handleSubmitで実際にメッセージを投げてAIからの返答を得るアクションを起こします。

  const prompt = `
  関西弁で話してください。
  `;

  const initialMessages: Message[] = [
    { id: 'initial-1', role: 'system', content: prompt}
  ];


  const { messages, input, handleSubmit,setInput } = useChat({
    api: '/api/chat-gpt-api',
    initialMessages: initialMessages // useChatフックに初期メッセージをす
  });

次にHTML部分です。
デザインはchatGPTさんに作ってもらった単純なものなので説明を割愛します。
チャットの表示部分について
messagesに入っているデータはrolecontentを持っています。
roleは先ほど説明した役割で、contentが実際のメッセージになります。
それをmap関数を使って順番に表示しています。

{messages.map(message=>{     
 if(message.role == 'assistant'){
          return (<div><span>AI:{message.content}</span></div>)
  }else if(message.role == 'user'){
     return (<div><span>USER:{message.content}</span></div>)
  }
})}

次に、フォームについてです。
inputに入力するとsetInputで自動的にchatGPTに投げるプロンプトに入っていきます。
送信ボタンを押すとformがsubmitされて、onSubmitの関数が実行されます。
そこでhandleSubmitが実行され、メッセージが先ほど作成したAPIエンドポイントに投げられます。

<form onSubmit={(e) => {
  e.preventDefault()
  handleSubmit(e)
  setInput('')
}
  }>
  <input
    className="shadow appearance-none border rounded w-4/5 py-2 px-3 mx-2 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
    id="message" type="text" placeholder="メッセージを入れてください" value={input} onChange={(e) => setInput(e.target.value)} />
    <button
    className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
    type="submit" >
    送信
  </button>
</form>

実際に動かす

これでプログラムは完成です。
保存したら、npm run devで動かしてみましょう。

npm run dev

実行できたらhttp://localhost:3000/にアクセスして動作を確認しましょう。

入力欄にメッセージを入れて、送信してください。
こんな感じで返答が返ってきたら成功です。

最後に

今回はついにチャットのできるアプリの完成まで出来ました。
4回にわたって書いてきましたが、Next.jsは簡単にアプリが作成できて大変良い言語だなと思いました。
この基本的なアプリを作れるようになったら、少しプロンプトを変えるだけでいろんな応用が利くと思います。
是非みなさんもいろんなアプリを作成してみてください。

では!

コメント

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