7. チャットボット(フロントエンド 2)

メッセージ表示処理

ファイル構成

my-app/
├── app/
│   ├── api/
│   │   └── chat/
│   │       └── route.ts
│   ├── interfaces/
│   │   └── Message.ts
│   └── page.tsx
├── styles/
│   └── globals.css
├── .env.local
├── tailwind.config.js
├── tsconfig.json
├── package.json
└── .gitignore

ページコンポーネント

チャット一覧データ定義

チャット一覧データ「messages」を定義します。

app/page.ts
// Messageインターフェースインポート
import { Message } from '@/app/interfaces/Message';

export default function Home() {
    const [inputMessage, setInputMessage] = useState<string>('');
    // チャット一覧データ定義
    const [messages, setMessages] = useState<Message[]>([]);
    ...
}
  • 「interfaces/Message.ts」をインポートが必要です。

チャット一覧表示

テキストボックスで入力したデータを setMessges() で設定し、チャット一覧に表示します。

app/page.ts
import { Message } from '@/app/interfaces/Message';

export default function Home() {
    ...

    const sendHandler = async () => {
        if (inputMessage.trim() === '') return;

        // チャットデータ作成
        const message: Message = { sender: 'user', message: inputMessage };
        // チャットデータ設定
        setMessages(prevMessages => [message, ...prevMessages]);

        setInputMessage('');
    };

    ...
}

チャットデータ表示

「messages」を繰り返し表示するよう、JSXを追加します。

app/page.ts
'use client';

import { useState, useRef, useEffect } from "react";
import { Message } from "@/app/interfaces/Message";

export default function Home() {
    ...

    return (
        <main className="flex flex-col justify-center">
            <div className="bg-white shadow-md p-4 z-10">
                <h1 className="text-2xl p-5">Gemini Chatbot</h1>
                ...
            </div>

            {/* メッセージ繰り返し  */}
            <div className="p-4 mb-4 overflow-y-scroll">
                {messages && messages.map((message, index) => (
                    <div
                        key={index}
                        className="m-3 p-5 border border-gray-100 rounded">
                        <span className={
                            `inline-block mb-2 me-3 px-3 py-1
                                rounded-full text-white
                                text-sm font-semibold
                                ${message.sender === 'user' ? 'bg-blue-600' : 'bg-gray-600'}
                            `}>
                            {message.sender === 'user' ? 'あなた' : 'ボット'}
                        </span>
                        <span>{message.message}</span>
                    </div>
                ))}
            </div>

        </main>
    );
}

動作確認

テキストボックスのデータを送信するたびに、メッセージが表示されました。

API通信

axiosインストール

「axios」パッケージをインストールします。

ターミナル
npm i axios

POSTリクエスト

axios で「/api/chat」に対して、「message」をPOSTリクエストします。

app/page.ts
    const sendHandler = async () => {
        if (inputMessage.trim() === '') return;

        const message: Message = { sender: 'user', content: inputMessage };
        setMessages(prevMessages => [message, ...prevMessages]);

        // /api/chat にPOSTリクエスト
        const uri = "/api/chat";
        const response = await axios.post(uri, message);
        console.log(response)
    };
  • await で非同期通信します。

ボットメッセージ追加

APIから受け取ったボットメッセージを、チャット一覧に追加します。

app/page.ts
    const sendHandler = async () => {
        if (inputMessage.trim() === '') return;

        const message: Message = { sender: 'user', content: inputMessage };
        setMessages(prevMessages => [message, ...prevMessages]);

        const uri = "/api/chat";
        const response = await axios.post(uri, message);
        
        // ボットメッセージをチャット一覧に追加
        const botMessage: Message = response.data.bot;
        setMessages(prevMessages => [botMessage, ...prevMessages]);

        setInputMessage('');
    };

動作確認

データを送信して、Gemini APIの回答が表示されるか確認してみましょう。

問題点

質問によっては、Gemini APIの回答がマークダウンでレスポンスされるため、思うような表示ができない問題があります。

これを解決するには、以下のような対策が考えられます。

  • マークダウンをHTMLで表示
  • マークダウンを整形
  • JSON、CSVなどの定型フォーマットでレスポンス