見出し画像

Next.js ServerActionsでDifyのチャットボットAPIを使ってみる

1.Difyのチャットボットを作成

関西弁のチャットボットアプリを作ってみる


いい感じに返してくれる
左の上から2番目のコマンドラインっぽいアイコンをクリック。右側のcurl POSTリクエストを参考にする。今回はStreamingをBlockingに置き換える。※Streamingは少しずつ回答が生成され、Blockingは一度に回答が生成される。


シークレットキーを作成

2.npx create-next-appでアプリ作成

3.ルートディレクトリに.env.localファイル作成

DIFY_API_KEY=xxxxxxxxxxxxxxxxx

4.DifyのAPIにfetchするServerActionを作成


こちらのcurlコマンドを参考にする。今回はfilesは入力しないので省く。

app/utils/dify.ts

"use server";

export async function sendDifyRequest(message: string, conversationId?: string): Promise<any> {
  try {
    const response = await fetch("https://api.dify.ai/v1/chat-messages", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.DIFY_API_KEY}`,
      },
      body: JSON.stringify({
        inputs: {},
        query: message,
        response_mode: "blocking",
        conversation_id: conversationId || "",
        user: "abc-123",
      }),
    });

    if (!response.ok) {
      throw new Error("Dify APIからのレスポンスが正常ではありません");
    }


    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error("Dify APIリクエストエラー:", error);
    throw new Error("Dify APIリクエスト中にエラーが発生しました");
  }
}

注意点:Difyは会話履歴がDifyサーバーに保存される。そのため、APIにはチャット履歴を入力する必要が無い。その代わりにconversation_idを指定する。一番最初はconversation_idは""(空)でリクエストを送り、レスポンスからconversation_idを受け取る。2回目以降のリクエストは1回目で受け取ったconversation_idを送信メッセージと一緒に送ればOK

APIから返ってくるレスポンス

5.page.tsxにチャット用のUIを作成

app/page.tsx

"use client";

import { useState } from "react";
import { sendDifyRequest } from "./utils/dify";

// メッセージの型を定義
interface Message {
  role: "user" | "assistant";
  content: string;
}

export default function Home() {
  const [message, setMessage] = useState("");
  const [history, setHistory] = useState<Message[]>([]);
  const [conversationId, setConversationId] = useState<string>("");

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!message.trim()) return;

    // ユーザーのメッセージを履歴に追加
    const newHistory = [...history, { role: "user", content: message }];
    setHistory(newHistory as Message[]);
    setMessage("");
    try {
      const result = await sendDifyRequest(message, conversationId);
      const answer = result.answer as string;
      const newConversationId = result.conversation_id as string;
      // AIの応答を履歴に追加
      setHistory([...newHistory, { role: "assistant", content: answer }] as Message[]);
      console.log(newConversationId);
      setConversationId(newConversationId);
    } catch (error) {
      console.error("エラー:", error);
    }
  };

  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">Dify API テスト</h1>
      <div className="mb-4 h-64 overflow-y-auto border p-2">
        {history.map((msg, index) => (
          <div key={index} className={`mb-2 ${msg.role === "user" ? "text-right" : "text-left"}`}>
            <span className={`inline-block p-2 rounded ${msg.role === "user" ? "bg-blue-100" : "bg-gray-100"}`}>
              {msg.content}
            </span>
          </div>
        ))}
      </div>
      <form onSubmit={handleSubmit} className="mb-4">
        <input
          type="text"
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          className="border p-2 mr-2"
          placeholder="メッセージを入力"
        />
        <button type="submit" className="bg-blue-500 text-white p-2 rounded">
          送信
        </button>
      </form>
    </div>
  );
}


いい感じにできた。しっかり、過去の会話履歴も反映されている。


いいなと思ったら応援しよう!