はじめに
こんにちはミナミ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に入っているデータはroleとcontentを持っています。
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は簡単にアプリが作成できて大変良い言語だなと思いました。
この基本的なアプリを作れるようになったら、少しプロンプトを変えるだけでいろんな応用が利くと思います。
是非みなさんもいろんなアプリを作成してみてください。
では!
コメント