5. チャットボット(バックエンド 2)

バックエンドAPI作成

Next.jsをバックエンドとして、POSTリクエストに対応したAPIを作成します。

仕様

項目 エンドポイント HTTPメソッド JSON
チャット送受信 /api/chat/ POST { message: Message}
  1. Next.js APIサーバに、メッセージをPOSTリクエスト
  2. Gemini APIにメッセージをリクエスト
  3. Gemini APIのレスポンスデータ取得
  4. Next.js APIサーバがデータをレスポンス

ファイル構成

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

Next.js API作成

ファイル作成

ルーティングファイル「app/api/chat/route.ts」を作成します。

POSTリクエスト

POSTリクエストAPIを作成します。

app/api/chat/route.ts
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
    
}

POSTデータの「message」を非同期取得します。

app/api/chat/route.ts
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
    // POSTデータ取得
    const message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });
}

レスポンス

取得したメッセージを、レスポンスします。

app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
    const message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });

    // メッセージをレスポンス
    const data = {
        client: message,
   }
    return NextResponse.json(data);
}

データモデル

データモデルとは

データモデルはデータ構造を定義し、データ管理するための概念です。データベース設計やシステム開発において、データの整合性や効率的なデータアクセスするために重要な設計です。モデルファイルを定義しておくことで、プログラムの効率化やバグを防ぎやすくなります。

TypeScriptの利用

TypeScriptには、データの形状を定義するために「インターフェース (interface)」と「型エイリアス (type)」があります。

Interface
interface User {
  id: number;
  name: string;
  email: string;
  isActive?: boolean; // optional property
}

const user: User = {
  id: 1,
  name: "John Doe",
  email: "[email protected]"
};
Type
type User = {
  id: number;
  name: string;
  email: string;
  isActive?: boolean; // optional property
};

const user: User = {
  id: 1,
  name: "John Doe",
  email: "[email protected]"
};

データモデル作成

インターフェイス作成

「app/interfaces/Message.ts」ファイルを作成します。

インターフェイス定義

「sender」「content」を定義します。

app/interface/Message.ts
export interface Message {
    sender: 'user' | 'bot';
    message: string;
}
  • 「content」は string型
  • 「sender」は「user」「bot」の2種類のstring型

Messageインターフェイス利用

POST送信されたデータをMessage型で定義します。

app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
// Messagインターフェイス読み込み
import { Message } from "@/app/interfaces/Message";

export async function POST(req: NextRequest) {
    // Message型で定義
    const message:Message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });

    // メッセージをレスポンス
    const data = {
        client: message,
   }
    return NextResponse.json(data);
}

Postman

POSTリクエスト作成

POSTリクエストを作成します。

http://localhost:3000/api/chat

JSONデータ設定

「Body」タブで「raw」「JSON」で設定し、POSTするJSONデータを記述します。

レスポンス確認

【Send】ボタンをクリックすると、APIからJSONデータがレスポンスされました。

Gemini APIの利用

Gemini API処理

チャット履歴

チャット履歴「history」を用意します。データ型は「@google/generative-ai」のContentとします。

app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
// Contentインポート
import { Content } from "@google/generative-ai";
import { Message } from "@/app/interfaces/Message";

const history: Content = [];
...

APIキー読み込み

.env.local から Gemini APIキーを読み込みます。

app/api/chat/route.ts
export async function POST(req: NextRequest) {
    // Gemini APIキーを読み込み
    const API_KEY = process.env.GEMINI_API_KEY;
    if (!API_KEY) return NextResponse.json({ error: "Not found API KEY" });

    const message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });
    ...
}

Gemini API連携

Gemni APIにプロンプトをリクエストし、ボットメッセージをレスポンスします。

app/api/chat/route.ts
import { NextRequest, NextResponse } from "next/server";
import { Content, GoogleGenerativeAI } from "@google/generative-ai";
import { Message } from "@/app/interfaces/Message";

const history: Content[] = [];

export async function POST(req: NextRequest) {
    const API_KEY = process.env.GEMINI_API_KEY;
    if (!API_KEY) return NextResponse.json({ error: "Not found API KEY" });

    // POSTデータ取得
    const message:Message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });

    // Gemni APIにリクエスト
    const genAI = new GoogleGenerativeAI(API_KEY);
    const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
    const chat = model.startChat({ history: history });

    try {
        const result = await chat.sendMessage(message.content);
        if (!result) return NextResponse.json({ error: "Not found message" });
        // ボットメッセージ
        const botMessage: Message = {
            sender: "bot",
            content: result.response.text()
        }

        const data = {
            client: message,
            // ボットメッセージ
            bot: botMessage,
        }

        return NextResponse.json(data);
    } catch (error) {
        console.log(error)
        return NextResponse.json({ error: "Gemini API error" });
    }
}
  • try-catchを利用して、Exception処理

Postman

動作確認

Postmanでチャットメッセージを変更して、Gemini APIでレスポンスを確認してみましょう。

ソース

app/api/chat/route.ts
import { NextRequest, NextResponse } from "next/server";
import { Content, GoogleGenerativeAI } from "@google/generative-ai";
import { Message } from "@/app/interfaces/Message";

const history: Content[] = [];

export async function POST(req: NextRequest) {
    const API_KEY = process.env.GEMINI_API_KEY;
    if (!API_KEY) return NextResponse.json({ error: "Not found API KEY" });

    const message:Message = await req.json();
    if (!message) return NextResponse.json({ error: "Not found message" });

    const genAI = new GoogleGenerativeAI(API_KEY);
    const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
    const chat = model.startChat({ history: history });

    try {
        const result = await chat.sendMessage(message.content);
        if (!result) return NextResponse.json({ error: "Not found message" });

        const botMessage: Message = {
            sender: "bot",
            content: result.response.text()
        }

        const data = {
            client: message,
            bot: botMessage,
        }

        return NextResponse.json(data);
    } catch (error) {
        return NextResponse.json({ error: "Gemini API error" });
    }
}