DifyをAPI使って利用する
このページの話
APIを使ってチャットボットと会話しよう
こんにちは、今回は、APIを使ってチャットボットと会話する方法を紹介します。プログラミングの知識がなくても、APIを使えば簡単にチャットボットとやり取りができるんです。
APIって何?
API (Application Programming Interface) とは、アプリケーション同士が情報をやり取りするための仕組みのことです。例えば、天気予報のアプリを作るとき、自分で天気のデータを収集するのは大変ですよね。でも、天気予報のAPIを使えば、簡単に天気のデータを取得することができます。
今回は、Dify.aiというサービスが提供するAPIを使って、チャットボットとやり取りしてみましょう。
APIキーを取得しよう
Dify.aiのAPIを使うには、まずAPIキーを取得する必要があります。APIキーは、Dify.aiのウェブサイトからサインアップすることで取得できます。
取得したAPIキーは、絶対に他人に教えないようにしましょう。APIキーが漏洩すると、他人があなたになりすましてAPIを使うことができてしまいます。
APIキーは、サーバーサイドで管理するのがおすすめです。クライアントサイド(ブラウザ上)で管理すると、APIキーが漏洩するリスクが高くなります。
リクエストを送ってみよう
APIキーが取得できたら、早速チャットボットにメッセージを送ってみましょう。Dify.aiのAPIでは、/chat-messagesというエンドポイントにPOSTリクエストを送ることで、チャットボットとやり取りができます。
例えば、以下のようなJSONデータをリクエストのボディに含めてPOSTリクエストを送ると、チャットボットから返事が返ってきます。
{
"inputs": {},
"query": "こんにちは!今日の天気はどうですか?",
"response_mode": "streaming",
"conversation_id": "",
"user": "tanaka-123",
"files": []
}
-
queryには、チャットボットに送信するメッセージを指定します。 -
response_modeは、streamingにするとタイプライターのようにストリーミングでレスポンスが返ってきます。blockingにすると、処理が完了してからレスポンスが返ってきます。 -
userには、ユーザーを識別するためのIDを指定します。任意の文字列を指定できます。 -
conversation_idには、会話を継続するためのIDを指定します。空文字列にすると、新しい会話が始まります。前回のレスポンスのconversation_idを指定することで、前回までの会話を踏まえた返答をしてくれます。
リクエストを送信するには、以下のようなコードを書きます。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "こんにちは!今日の天気はどうですか?",
"response_mode": "streaming",
"conversation_id": "",
"user": "tanaka-123",
"files": []
}'
{api_key}の部分は、取得したAPIキーに置き換えてください。
レスポンスを見てみよう
リクエストを送信すると、以下のようなレスポンスが返ってきます。
{
"id": "3f6d8f8d-9d8f-4d8f-9d8f-3f6d8f8d9d8f",
"object": "chat.completion",
"created": 1625890000,
"text": "こんにちは!今日の東京の天気は晴れのち曇りで、最高気温は28度、最低気温は20度の予想です。洗濯物を外に干すなら、午前中がおすすめですよ。",
"conversation_id": "abcd1234"
}
-
idは、このレスポンスを識別するためのIDです。 -
objectは、このレスポンスの種類を表します。 -
createdは、このレスポンスが生成された日時のタイムスタンプです。 -
textが、チャットボットからの返答です。 -
conversation_idは、次の会話で使うためのIDです。
conversation_idを指定してリクエストを送ることで、前回の会話を踏まえた返答をしてくれます。
以下のように、conversation_idを指定してリクエストを送ってみましょう。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "ありがとうございます!ところで、明日の天気はどうなりそうですか?",
"response_mode": "streaming",
"conversation_id": "abcd1234",
"user": "tanaka-123",
"files": []
}'
すると、以下のようなレスポンスが返ってきます。
{
"id": "8d9d8f3f-8f9d-4d8f-9d8f-3f6d8f8d9d8f",
"object": "chat.completion",
"created": 1625890060,
"text": "明日の東京の天気は雨の予想です。最高気温は25度、最低気温は18度となっています。傘を持っていくことをおすすめします。洗濯物は部屋干しが良さそうですね。",
"conversation_id": "abcd1234"
}
前回の会話を踏まえた返答になっていることが分かります。
画像も送ってみよう
テキストだけでなく、画像を送ることもできます。画像を送るには、filesパラメータを使います。
例えば、以下のようなリクエストを送ると、画像を送ることができます。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "この画像に写っているのは何の花ですか?",
"response_mode": "streaming",
"conversation_id": "abcd1234",
"user": "tanaka-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://example.com/tulip.jpg"
}
]
}'
filesパラメータには、画像のURLを指定します。typeはimage固定です。transfer_methodは、remote_urlにするとURLを指定できます。local_fileにすると、ローカルのファイルをアップロードできます。
まとめ
以上が、Dify.aiのAPIを使ってチャットボットと会話する方法の詳細です。
- APIキーを取得する
-
/chat-messagesエンドポイントにPOSTリクエストを送る - レスポンスの
conversation_idを指定することで、会話を継続できる - 画像も送ることができる
チャットボットAPIのレスポンスを理解しよう
前回の記事では、APIを使ってチャットボットにメッセージを送信する方法を紹介しました。今回は、チャットボットから返ってくるレスポンスの内容について、具体例を交えながら詳しく見ていきましょう。
レスポンスの形式
チャットボットからのレスポンスは、リクエストのresponse_modeパラメータの値によって2つの形式があります。
-
blocking: レスポンスがCompletionResponseオブジェクトで返ってきます。 -
streaming: レスポンスがChunkCompletionResponseストリームで返ってきます。
ChatCompletionResponse
CompletionResponseオブジェクトは、以下のようなプロパティを持っています。
{
"message_id": "1b3c2d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e",
"conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
"mode": "chat",
"answer": "こんにちは!今日は晴れていますね。",
"metadata": {},
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
},
"retriever_resources": [],
"created_at": 1705395332
}
-
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
mode: Appのモード(chatで固定) -
answer: チャットボットの返答 -
metadata: メタデータ -
usage: モデルの使用情報(プロンプトとレスポンスのトークン数) -
retriever_resources: 引用と帰属のリスト -
created_at: メッセージの作成タイムスタンプ(例: 1705395332)
ChunkChatCompletionResponse
ChunkCompletionResponseストリームは、text/event-stream形式でチャンクごとにレスポンスが返ってきます。各チャンクはdata:で始まり、2つの改行文字\n\nで区切られます。
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "こんに", "created_at": 1705398420}\n\n
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "ちは!", "created_at": 1705398421}\n\n
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "今日は", "created_at": 1705398422}\n\n
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "晴れてい", "created_at": 1705398423}\n\n
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "ますね。", "created_at": 1705398424}\n\n
data: {"event": "message_end", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "metadata": {}, "usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30}, "retriever_resources": []}\n\n
チャンクの構造は、eventの値によって異なります。
event: message
messageイベントは、チャットボットの返答がチャンクごとに返ってくることを表します。
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
answer: チャットボットの返答のチャンク -
created_at: チャンクの作成タイムスタンプ(例: 1705395332)
event: message_file
message_fileイベントは、チャットボットが画像などのファイルを返したことを表します。
data: {"event": "message_file", "id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "type": "image", "belongs_to": "assistant", "url": "https://example.com/image.png", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d"}\n\n
-
id: ファイルを識別するためのユニークなID -
type: ファイルのタイプ(現在はimageのみ) -
belongs_to: ファイルの所有者(現在はassistantのみ) -
url: ファイルのURL -
conversation_id: 会話を識別するためのID
event: message_end
message_endイベントは、チャットボットの返答が終了したことを表します。
data: {"event": "message_end", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "metadata": {}, "usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30}, "retriever_resources": []}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
metadata: メタデータ -
usage: モデルの使用情報 -
retriever_resources: 引用と帰属のリスト
event: message_replace
message_replaceイベントは、チャットボットの返答が不適切なコンテンツを含んでいたため、置き換えられたことを表します。
data: {"event": "message_replace", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "answer": "不適切な発言があったため、メッセージを削除しました。", "created_at": 1705395332}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
answer: 置き換え後の返答 -
created_at: イベントの作成タイムスタンプ(例: 1705395332)
event: error
errorイベントは、ストリーミング中にエラーが発生したことを表します。エラーイベントを受信するとストリームは終了します。
data: {"event": "error", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "status": 500, "code": "internal_server_error", "message": "An internal server error occurred."}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
status: HTTPステータスコード -
code: エラーコード -
message: エラーメッセージ
レスポンスの処理方法
レスポンスの処理方法は、プログラミング言語によって異なります。ここでは、JavaScriptを例に説明します。
response_modeがblockingの場合は、fetch関数を使ってレスポンスを取得できます。
const response = await fetch('https://api.example.com/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
query: 'こんにちは!',
response_mode: 'blocking'
})
});
const data = await response.json();
console.log(data.answer);
response_modeがstreamingの場合は、fetch関数のオプションに{mode: 'cors'}を指定し、レスポンスのbodyプロパティからReadableStreamを取得します。
const response = await fetch('https://api.example.com/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
query: 'こんにちは!',
response_mode: 'streaming'
})
}, {mode: 'cors'});
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
while (true) {
const {value, done} = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n\n');
for (const line of lines) {
if (line.startsWith('data:')) {
const data = JSON.parse(line.slice(5));
if (data.event === 'message') {
console.log(data.answer);
} else if (data.event === 'message_end') {
console.log('会話が終了しました。');
}
}
}
}
ReadableStreamから読み取ったチャンクをTextDecoderでデコードし、\n\nで分割することで、各イベントのデータを取得できます。
まとめ
APIを使ってチャットボットと会話する際は、レスポンスの形式を理解しておくことが重要です。レスポンスには、チャットボットの返答だけでなく、メタデータやエラー情報なども含まれています。
response_modeがblockingの場合は、レスポンスが一度に返ってきます。streamingの場合は、チャンクごとにレスポンスが返ってくるため、リアルタイム性が高くなります。
レスポンスの処理方法は、プログラミング言語によって異なります。JavaScriptを例に説明しましたが、他の言語でも同様の処理を行うことができます。
チャットボットAPIを使いこなすには、レスポンスの形式だけでなく、リクエストのパラメータやエラーハンドリングなども理解しておく必要があります。公式のAPIドキュメントをしっかり読んで、自分だけのチャットボットを作ってみてくださいね。
補足
チャットボットAPIのリクエストとレスポンスの具体例
前回の記事では、チャットボットAPIのレスポンスの形式について詳しく解説しました。今回は、リクエストとレスポンスの具体例を見ていきましょう。
リクエストの例
チャットボットにメッセージを送信するリクエストは、以下のようになります。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}'
-
query: チャットボットに送信するメッセージ -
response_mode: レスポンスの形式(blockingまたはstreaming) -
conversation_id: 会話を識別するためのID(空の場合は新しい会話が開始されます) -
user: ユーザーを識別するためのID -
files: 画像などのファイルを添付する場合に指定します
レスポンスの例(Blocking Mode)
response_modeがblockingの場合、レスポンスは以下のようになります。
{
"event": "message",
"message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
"conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
"mode": "chat",
"answer": "iPhone 13 Pro Max specs are listed heere:...",
"metadata": {
"usage": {
"prompt_tokens": 1033,
"prompt_unit_price": "0.001",
"prompt_price_unit": "0.001",
"prompt_price": "0.0010330",
"completion_tokens": 128,
"completion_unit_price": "0.002",
"completion_price_unit": "0.001",
"completion_price": "0.0002560",
"total_tokens": 1161,
"total_price": "0.0012890",
"currency": "USD",
"latency": 0.7682376249867957
},
"retriever_resources": [
{
"position": 1,
"dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
"dataset_name": "iPhone",
"document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
"document_name": "iPhone List",
"segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
"score": 0.98457545,
"content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
}
]
},
"created_at": 1705407629
}
-
answer: チャットボットの返答 -
metadata: メタデータ(使用したトークン数や料金、応答時間など) -
retriever_resources: 返答の生成に使用された情報源
レスポンスの例(Streaming Mode)
response_modeがstreamingの場合、レスポンスは以下のようにチャンクごとに返ってきます。
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}}
-
workflow_started: ワークフローの開始イベント -
node_started: ノードの開始イベント -
node_finished: ノードの終了イベント -
workflow_finished: ワークフローの終了イベント -
message: チャットボットの返答のチャンク -
message_end: チャットボットの返答の終了イベント
ストリーミングモードでは、チャットボットの返答がチャンクごとに返ってくるため、リアルタイムに返答を表示することができます。
まとめ
以上が、チャットボットAPIのリクエストとレスポンスの具体例です。
リクエストでは、queryパラメータにチャットボットに送信するメッセージを指定します。response_modeパラメータで、レスポンスの形式を指定できます。
レスポンスは、response_modeの値によって形式が異なります。blockingの場合は一度にすべての返答が返ってきますが、streamingの場合はチャンクごとに返答が返ってきます。
ストリーミングモードでは、workflow_startedやnode_startedなどのイベントも返ってくるため、チャットボットの内部処理の流れを知ることができます。
実際にAPIを使ってチャットボットを作る際は、これらの例を参考にしながら、自分のユースケースに合わせてリクエストとレスポンスの処理を実装していきましょう。
ストリーミングモードのレスポンスイベントを理解しよう
チャットボットAPIのストリーミングモードでは、さまざまなイベントがレスポンスとして返ってきます。これらのイベントを理解することで、チャットボットの動作をより詳細に把握することができます。
message イベント
messageイベントは、チャットボットの返答がチャンクごとに返ってくるイベントです。
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
answer: チャットボットの返答のチャンク -
created_at: チャンクの作成タイムスタンプ(例: 1705395332)
message_file イベント
message_fileイベントは、チャットボットが画像などのファイルを返したことを表すイベントです。
data: {"event": "message_file", "id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "type": "image", "belongs_to": "assistant", "url": "https://example.com/image.png", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d"}\n\n
-
id: ファイルを識別するためのユニークなID -
type: ファイルのタイプ(現在はimageのみ) -
belongs_to: ファイルの所有者(現在はassistantのみ) -
url: ファイルのURL -
conversation_id: 会話を識別するためのID
message_end イベント
message_endイベントは、チャットボットの返答が終了したことを表すイベントです。
data: {"event": "message_end", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "metadata": {"usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30}, "retriever_resources": []}}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
metadata: メタデータ(使用したトークン数や情報源など)
message_replace イベント
message_replaceイベントは、チャットボットの返答が不適切なコンテンツを含んでいたため、置き換えられたことを表すイベントです。
data: {"event": "message_replace", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "answer": "不適切な発言があったため、メッセージを削除しました。", "created_at": 1705395332}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
conversation_id: 会話を識別するためのID -
answer: 置き換え後の返答 -
created_at: イベントの作成タイムスタンプ(例: 1705395332)
workflow_started イベント
workflow_startedイベントは、ワークフローの開始を表すイベントです。
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}\n\n
-
task_id: リクエストを追跡するためのタスクID -
workflow_run_id: ワークフローの実行を識別するためのユニークなID -
event:workflow_startedで固定 -
data: 詳細情報-
id: ワークフローの実行を識別するためのユニークなID -
workflow_id: 関連するワークフローのID -
sequence_number: アプリ内で自動増加するシーケンス番号(1から開始) -
created_at: イベントの作成タイムスタンプ(例: 1705395332)
-
node_started イベント
node_startedイベントは、ノードの実行開始を表すイベントです。
data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}\n\n
-
task_id: リクエストを追跡するためのタスクID -
workflow_run_id: ワークフローの実行を識別するためのユニークなID -
event:node_startedで固定 -
data: 詳細情報-
id: ワークフローの実行を識別するためのユニークなID -
node_id: ノードのID -
node_type: ノードのタイプ -
title: ノードの名前 -
index: 実行シーケンス番号(トレースノードシーケンスの表示に使用) -
predecessor_node_id: 前のノードのID(キャンバス上の実行パスの表示に使用) -
inputs: ノードで使用される前のノードの変数の内容 -
created_at: イベントの作成タイムスタンプ(例: 1705395332)
-
node_finished イベント
node_finishedイベントは、ノードの実行終了を表すイベントです。
data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}\n\n
-
task_id: リクエストを追跡するためのタスクID -
workflow_run_id: ワークフローの実行を識別するためのユニークなID -
event:node_finishedで固定 -
data: 詳細情報-
id: ワークフローの実行を識別するためのユニークなID -
node_id: ノードのID -
node_type: ノードのタイプ -
title: ノードの名前 -
index: 実行シーケンス番号(トレースノードシーケンスの表示に使用) -
predecessor_node_id: 前のノードのID(キャンバス上の実行パスの表示に使用) -
inputs: ノードで使用される前のノードの変数の内容 -
process_data: ノードの処理データ(オプション) -
outputs: 出力の内容(オプション) -
status: 実行状態(running、succeeded、failed、stopped) -
error: エラーの理由(オプション) -
elapsed_time: 使用された合計秒数(オプション) -
execution_metadata: メタデータ-
total_tokens: 使用されたトークン数(オプション) -
total_price: 合計コスト(オプション) -
currency: 通貨(例:USD、RMB)(オプション)
-
-
created_at: イベントの作成タイムスタンプ(例: 1705395332)
-
workflow_finished イベント
workflow_finishedイベントは、ワークフローの実行終了を表すイベントです。
data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}\n\n
-
task_id: リクエストを追跡するためのタスクID -
workflow_run_id: ワークフローの実行を識別するためのユニークなID -
event:workflow_finishedで固定 -
data: 詳細情報-
id: ワークフローの実行を識別するためのユニークなID -
workflow_id: 関連するワークフローのID -
status: 実行状態(running、succeeded、failed、stopped) -
outputs: 出力の内容(オプション) -
error: エラーの理由(オプション) -
elapsed_time: 使用された合計秒数(オプション) -
total_tokens: 使用されたトークン数(オプション) -
total_steps: 合計ステップ数(デフォルトは0) -
created_at: 開始時刻 -
finished_at: 終了時刻
-
error イベント
errorイベントは、ストリーミング処理中に発生した例外を表すイベントです。エラーイベントを受信するとストリームは終了します。
data: {"event": "error", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "status": 500, "code": "internal_server_error", "message": "An internal server error occurred."}\n\n
-
task_id: リクエストを追跡するためのタスクID -
message_id: メッセージを識別するためのユニークなID -
status: HTTPステータスコード -
code: エラーコード -
message: エラーメッセージ
ping イベント
pingイベントは、接続を維持するために10秒ごとに送信されるイベントです。
エラーコード
ストリーミングモードでは、以下のようなエラーコードが返ってくる可能性があります。
-
404: 会話が存在しない -
400, invalid_param: パラメータの入力が異常 -
400, app_unavailable: アプリの設定が利用できない -
400, provider_not_initialize: 利用可能なモデルクレデンシャル設定がない -
400, provider_quota_exceeded: モデル呼び出しクオータが不足している -
400, model_currently_not_support: 現在のモデルが利用できない -
400, completion_request_error: テキスト生成に失敗した -
500: 内部サーバーエラー
まとめ
チャットボットAPIのストリーミングモードでは、さまざまなイベントがレスポンスとして返ってきます。これらのイベントを理解することで、チャットボットの動作をより詳細に把握することができます。
特に、messageイベントとmessage_endイベントを追跡することで、チャットボットの返答をリアルタイムに処理することができます。
また、workflow_startedやnode_startedなどのイベントを追跡することで、チャットボットの内部処理の流れを知ることができます。
エラーハンドリングも忘れずに行いましょう。errorイベントを監視し、適切にエラーを処理することが重要です。
ストリーミングモードを使いこなすことで、より高度なチャットボットアプリケーションを開発することができるでしょう。
チャットボットにファイルを送信しよう
チャットボットAPIでは、テキストだけでなく画像などのファイルも送信することができます。ファイルを送信することで、チャットボットに画像を理解させたり、画像とテキストを組み合わせた高度な処理を行ったりすることができます。
ファイルアップロードAPI
ファイルを送信するには、まずファイルをアップロードする必要があります。ファイルのアップロードには、/files/uploadエンドポイントを使用します。
現在サポートされているファイル形式は、png、jpg、jpeg、webp、gifです。アップロードされたファイルは、現在のエンドユーザーのみが使用できます。
リクエスト
/files/uploadエンドポイントへのリクエストは、multipart/form-data形式で行います。
以下のパラメータを指定します。
-
file(必須): アップロードするファイル -
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
リクエストの例を以下に示します。
curl -X POST 'https://api.dify.ai/v1/files/upload' \
--header 'Authorization: Bearer {api_key}' \
--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \
--form 'user=abc-123'
-
{api_key}は、実際のAPIキーに置き換えてください。 -
localfileは、アップロードするファイルのパスに置き換えてください。 -
typeには、ファイルのMIMEタイプを指定してください。
レスポンス
アップロードが成功すると、サーバーはファイルのIDと関連情報を返します。
{
"id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
"name": "example.png",
"size": 1024,
"extension": "png",
"mime_type": "image/png",
"created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
"created_at": 1577836800
}
-
id: ファイルのID -
name: ファイル名 -
size: ファイルサイズ(バイト) -
extension: ファイルの拡張子 -
mime_type: ファイルのMIMEタイプ -
created_by: アップロードしたユーザーのID -
created_at: アップロード日時のタイムスタンプ(例: 1705395332)
エラーコード
ファイルのアップロードでは、以下のようなエラーが発生する可能性があります。
-
400, no_file_uploaded: ファイルが指定されていない -
400, too_many_files: 現在は1つのファイルのみ受け付けている -
400, unsupported_preview: ファイルがプレビューをサポートしていない -
400, unsupported_estimate: ファイルが見積もりをサポートしていない -
413, file_too_large: ファイルが大きすぎる -
415, unsupported_file_type: サポートされていないファイル形式 -
503, s3_connection_failed: S3サービスに接続できない -
503, s3_permission_denied: S3へのファイルアップロードの権限がない -
503, s3_file_too_large: ファイルがS3のサイズ制限を超えている -
500: 内部サーバーエラー
ファイル送信API
アップロードしたファイルは、/chat-messagesエンドポイントを使ってチャットボットに送信することができます。
リクエストボディのfilesパラメータに、アップロードしたファイルの情報を指定します。
{
"inputs": {},
"query": "この画像に写っているのは何ですか?",
"response_mode": "blocking",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "local_file",
"upload_file_id": "72fa9618-8f89-4a37-9b33-7e1178a24a67"
}
]
}
-
type: ファイルのタイプ(現在はimageのみ) -
transfer_method:local_fileを指定することで、アップロード済みのファイルを指定できます -
upload_file_id: アップロードしたファイルのID
まとめ
ファイルアップロードAPIを使うことで、チャットボットに画像などのファイルを送信することができます。
ファイルをアップロードするには、/files/uploadエンドポイントにmultipart/form-data形式でリクエストを送信します。アップロードが成功すると、ファイルのIDと関連情報が返されます。
アップロードしたファイルは、/chat-messagesエンドポイントのfilesパラメータに指定することで、チャットボットに送信することができます。
ファイル送信機能を使いこなすことで、より高度なチャットボットアプリケーションを開発することができるでしょう。ぜひ活用してみてください。
チャットボットの返答に対してフィードバックを送ろう
チャットボットの返答が適切かどうかは、ユーザーによって異なります。ユーザーからのフィードバックを収集することで、チャットボットの返答の質を向上させることができます。
Dify.aiのチャットボットAPIでは、/messages/:message_id/feedbacksエンドポイントを使って、ユーザーがチャットボットの返答に対してフィードバックを送信することができます。
リクエスト
/messages/:message_id/feedbacksエンドポイントへのリクエストは、以下のようなものになります。
curl -X POST 'https://api.dify.ai/v1/messages/:message_id/feedbacks \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"rating": "like",
"user": "abc-123"
}'
-
{api_key}は、実際のAPIキーに置き換えてください。 -
:message_idは、フィードバックを送信するメッセージのIDに置き換えてください。
リクエストボディには、以下のパラメータを指定します。
-
rating(必須): フィードバックの種類を指定します。-
"like": 高評価(いいね!) -
"dislike": 低評価 -
null: 高評価を取り消す
-
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
フィードバックの送信が成功すると、以下のようなレスポンスが返ります。
{
"result": "success"
}
resultは常に"success"が返ります。
ユースケース
チャットボットの返答に対してフィードバックを送信することで、以下のようなことができます。
- ユーザーの好みに合わせたチャットボットの返答の最適化
- 不適切な返答の検出と修正
- ユーザーのエンゲージメントの向上
以下は、JavaScriptでフィードバック機能を実装する例です。
async function sendFeedback(messageId, rating, user) {
const response = await fetch(`https://api.dify.ai/v1/messages/${messageId}/feedbacks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}'
},
body: JSON.stringify({
rating,
user
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.result); // "success"
}
// いいね!を送信する
sendFeedback('1a2b3c4d', 'like', 'abc-123').catch(console.error);
// 低評価を送信する
sendFeedback('5e6f7g8h', 'dislike', 'abc-123').catch(console.error);
// 高評価を取り消す
sendFeedback('1a2b3c4d', null, 'abc-123').catch(console.error);
この例では、sendFeedback関数を定義して、メッセージID、フィードバックの種類、ユーザーIDを引数に取ります。fetch関数を使って、/messages/:message_id/feedbacksエンドポイントにPOSTリクエストを送信します。
レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認します。エラーが発生した場合は、catchブロックでエラーをハンドリングします。
まとめ
/messages/:message_id/feedbacksエンドポイントを使うことで、ユーザーがチャットボットの返答に対してフィードバックを送信することができます。
フィードバックには、高評価(いいね!)、低評価、高評価の取り消しの3種類があります。
フィードバックを収集することで、チャットボットの返答の質を向上させたり、ユーザーのエンゲージメントを高めたりすることができます。
JavaScriptでは、fetch関数を使ってフィードバックを送信することができます。レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認します。
フィードバック機能を適切に実装することで、よりユーザーに寄り添ったチャットボットアプリケーションを開発することができるでしょう。ぜひ活用してみてください。
チャットボットの返答に対する次の質問の提案を取得しよう
チャットボットとの会話では、ユーザーが次に何を質問すればいいのか迷ってしまうことがあります。そんな時は、/messages/{message_id}/suggestedエンドポイントを使って、次の質問の提案を取得することができます。
リクエスト
/messages/{message_id}/suggestedエンドポイントへのリクエストは、以下のようなものになります。
curl --location --request GET 'https://api.dify.ai/v1/messages/{message_id}/suggested?user=abc-123& \
--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
--header 'Content-Type: application/json'
-
{message_id}は、提案を取得するメッセージのIDに置き換えてください。 -
ENTER-YOUR-SECRET-KEYは、実際のAPIキーに置き換えてください。
クエリパラメータには、以下のものを指定します。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
次の質問の提案の取得が成功すると、以下のようなレスポンスが返ります。
{
"result": "success",
"data": [
"a",
"b",
"c"
]
}
-
resultは常に"success"が返ります。 -
dataは、次の質問の提案のリストです。
ユースケース
次の質問の提案を取得することで、以下のようなことができます。
- ユーザーが次に何を質問すればいいのか迷っている時に、適切な質問を提案する
- ユーザーとチャットボットの会話を活性化させる
- ユーザーの興味関心を引き出し、エンゲージメントを高める
以下は、JavaScriptで次の質問の提案を取得する例です。
async function getSuggestedQuestions(messageId, user) {
const response = await fetch(`https://api.dify.ai/v1/messages/${messageId}/suggested?user=${user}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer ENTER-YOUR-SECRET-KEY',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.result); // "success"
console.log(data.data); // ["a", "b", "c"]
}
// 次の質問の提案を取得する
getSuggestedQuestions('1a2b3c4d', 'abc-123').catch(console.error);
この例では、getSuggestedQuestions関数を定義して、メッセージIDとユーザーIDを引数に取ります。fetch関数を使って、/messages/{message_id}/suggestedエンドポイントにGETリクエストを送信します。
レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認し、dataプロパティに次の質問の提案のリストが入っていることを確認します。エラーが発生した場合は、catchブロックでエラーをハンドリングします。
取得した次の質問の提案は、チャットボットのUIに表示したり、ユーザーの入力の補完に使ったりすることができます。
まとめ
/messages/{message_id}/suggestedエンドポイントを使うことで、チャットボットの返答に対する次の質問の提案を取得することができます。
次の質問の提案を取得するには、メッセージIDとユーザーIDを指定してGETリクエストを送信します。レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認し、dataプロパティに次の質問の提案のリストが入っていることを確認します。
次の質問の提案を適切に活用することで、ユーザーとチャットボットの会話をより自然で活発なものにすることができるでしょう。ぜひ試してみてください。
チャットボットの会話履歴を取得しよう
チャットボットアプリケーションでは、ユーザーとの会話履歴を保存しておくことが重要です。会話履歴を参照することで、ユーザーの質問の文脈を理解したり、過去の質問と回答を振り返ったりすることができます。
Dify.aiのチャットボットAPIでは、/messagesエンドポイントを使って、会話履歴を取得することができます。
リクエスト
/messagesエンドポイントへのリクエストは、以下のようなものになります。
curl -X GET 'https://api.dify.ai/v1/messages?user=abc-123&conversation_id=' \
--header 'Authorization: Bearer {api_key}'
-
{api_key}は、実際のAPIキーに置き換えてください。
クエリパラメータには、以下のものを指定します。
-
conversation_id(必須): 会話のID -
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります) -
first_id(オプション): 現在のページの最初のチャットレコードのID(デフォルトはnull) -
limit(オプション): 一度のリクエストで返す会話履歴のメッセージ数(デフォルトは20)
会話履歴は、スクロールロード形式で返されます。最初のページでは、最新のlimit件のメッセージが返されます(逆順)。
レスポンス
会話履歴の取得が成功すると、以下のようなレスポンスが返ります。
{
"limit": 20,
"has_more": false,
"data": [
{
"id": "a076a87f-31e5-48dc-b452-0061adbbc922",
"conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
"inputs": {
"name": "dify"
},
"query": "iphone 13 pro",
"answer": "The iPhone 13 Pro, released on September 24, 2021, features a 6.1-inch display with a resolution of 1170 x 2532. It is equipped with a Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard) processor, 6 GB of RAM, and offers storage options of 128 GB, 256 GB, 512 GB, and 1 TB. The camera is 12 MP, the battery capacity is 3095 mAh, and it runs on iOS 15.",
"message_files": [],
"feedback": null,
"retriever_resources": [
{
"position": 1,
"dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
"dataset_name": "iPhone",
"document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
"document_name": "iPhone List",
"segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
"score": 0.98457545,
"content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
}
],
"created_at": 1705569239
}
]
}
-
limitは、返されるメッセージ数の上限です。入力値がシステムの上限を超えた場合は、システムの上限値が返されます。 -
has_moreは、次のページがあるかどうかを示すブール値です。 -
dataは、メッセージのリストです。各メッセージには以下のプロパティがあります。-
id: メッセージのID -
conversation_id: 会話のID -
inputs: ユーザー入力パラメータ -
query: ユーザー入力/質問の内容 -
message_files: メッセージに添付されたファイルのリスト-
id: ファイルのID -
type: ファイルの種類(現在はimageのみ) -
url: プレビュー画像のURL -
belongs_to: ファイルの所有者(userまたはassistant)
-
-
answer: 応答メッセージの内容 -
created_at: 作成日時のタイムスタンプ(例: 1705395332) -
feedback: フィードバック情報-
rating: 高評価ならlike、低評価ならdislike
-
-
retriever_resources: 引用と帰属のリスト
-
ユースケース
会話履歴を取得することで、以下のようなことができます。
- ユーザーとチャットボットの過去の会話を振り返る
- ユーザーの質問の文脈を理解する
- チャットボットの返答の品質を評価する
以下は、JavaScriptで会話履歴を取得する例です。
async function getConversationHistory(conversationId, user, firstId = null, limit = 20) {
const params = new URLSearchParams({ conversation_id: conversationId, user, first_id: firstId, limit });
const response = await fetch(`https://api.dify.ai/v1/messages?${params}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.data); // メッセージのリスト
console.log(data.has_more); // 次のページがあるかどうか
}
// 会話履歴を取得する
getConversationHistory('cd78daf6-f9e4-4463-9ff2-54257230a0ce', 'abc-123').catch(console.error);
この例では、getConversationHistory関数を定義して、会話ID、ユーザーID、最初のメッセージID(オプション)、取得件数(オプション)を引数に取ります。fetch関数を使って、/messagesエンドポイントにGETリクエストを送信します。
レスポンスが成功した場合は、dataプロパティにメッセージのリストが入っていることを確認します。また、has_moreプロパティを確認することで、次のページがあるかどうかを判断することができます。
取得した会話履歴は、チャットボットのUIに表示したり、分析に使ったりすることができます。
まとめ
/messagesエンドポイントを使うことで、チャットボットの会話履歴を取得することができます。
会話履歴を取得するには、会話ID、ユーザーID、最初のメッセージID(オプション)、取得件数(オプション)を指定してGETリクエストを送信します。レスポンスが成功した場合は、dataプロパティにメッセージのリストが入っていることを確認します。また、has_moreプロパティを確認することで、次のページがあるかどうかを判断することができます。
会話履歴を適切に活用することで、ユーザーとチャットボットの会話をより自然で文脈に沿ったものにすることができるでしょう。ぜひ試してみてください。
チャットボットの会話一覧を取得しよう
チャットボットアプリケーションでは、ユーザーが過去に行った会話の一覧を表示することが重要です。会話一覧を表示することで、ユーザーは過去の会話を振り返ったり、続きから会話を再開したりすることができます。
Dify.aiのチャットボットAPIでは、/conversationsエンドポイントを使って、会話一覧を取得することができます。
リクエスト
/conversationsエンドポイントへのリクエストは、以下のようなものになります。
curl -X GET 'https://api.dify.ai/v1/conversations?user=abc-123&last_id=&limit=20'
クエリパラメータには、以下のものを指定します。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります) -
last_id(オプション): 現在のページの最後の会話のID(デフォルトはnull) -
limit(オプション): 一度のリクエストで返す会話数(デフォルトは最新の20件) -
pinned(オプション):trueの場合はピン留めされた会話のみ、falseの場合はピン留めされていない会話のみを返す
デフォルトでは、最新の20件の会話が返されます。
レスポンス
会話一覧の取得が成功すると、以下のようなレスポンスが返ります。
{
"limit": 20,
"has_more": false,
"data": [
{
"id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
"name": "New chat",
"inputs": {
"book": "book",
"myName": "Lucy"
},
"status": "normal",
"created_at": 1679667915
},
{
"id": "hSIhXBhNe8X1d8Et"
// ...
}
]
}
-
limitは、返される会話数の上限です。入力値がシステムの上限を超えた場合は、システムの上限値が返されます。 -
has_moreは、次のページがあるかどうかを示すブール値です。 -
dataは、会話のリストです。各会話には以下のプロパティがあります。-
id: 会話のID -
name: 会話の名前(デフォルトでは、会話の最初のユーザー入力のスニペット) -
inputs: ユーザー入力パラメータ -
introduction: 会話の紹介文 -
created_at: 作成日時のタイムスタンプ(例: 1705395332)
-
ユースケース
会話一覧を取得することで、以下のようなことができます。
- ユーザーが過去に行った会話を一覧表示する
- 過去の会話を検索する
- 過去の会話を続きから再開する
以下は、JavaScriptで会話一覧を取得する例です。
async function getConversations(user, lastId = null, limit = 20, pinned = null) {
const params = new URLSearchParams({ user, last_id: lastId, limit });
if (pinned !== null) {
params.append('pinned', pinned);
}
const response = await fetch(`https://api.dify.ai/v1/conversations?${params}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.data); // 会話のリスト
console.log(data.has_more); // 次のページがあるかどうか
}
// 会話一覧を取得する
getConversations('abc-123').catch(console.error);
// ピン留めされた会話のみを取得する
getConversations('abc-123', null, 20, true).catch(console.error);
この例では、getConversations関数を定義して、ユーザーID、最後の会話ID(オプション)、取得件数(オプション)、ピン留めフィルタ(オプション)を引数に取ります。fetch関数を使って、/conversationsエンドポイントにGETリクエストを送信します。
レスポンスが成功した場合は、dataプロパティに会話のリストが入っていることを確認します。また、has_moreプロパティを確認することで、次のページがあるかどうかを判断することができます。
取得した会話一覧は、チャットボットのUIに表示したり、検索機能の実装に使ったりすることができます。
まとめ
/conversationsエンドポイントを使うことで、チャットボットの会話一覧を取得することができます。
会話一覧を取得するには、ユーザーID、最後の会話ID(オプション)、取得件数(オプション)、ピン留めフィルタ(オプション)を指定してGETリクエストを送信します。レスポンスが成功した場合は、dataプロパティに会話のリストが入っていることを確認します。また、has_moreプロパティを確認することで、次のページがあるかどうかを判断することができます。
会話一覧を適切に活用することで、ユーザーにとって使いやすいチャットボットアプリケーションを開発することができるでしょう。ぜひ試してみてください。
会話を削除しよう
チャットボットアプリケーションでは、ユーザーが不要になった会話を削除できるようにすることが重要です。会話を削除することで、ユーザーは会話一覧をすっきりと保つことができます。
Dify.aiのチャットボットAPIでは、/conversations/:conversation_idエンドポイントを使って、会話を削除することができます。
リクエスト
/conversations/:conversation_idエンドポイントへのリクエストは、以下のようなものになります。
curl -X DELETE 'https://api.dify.ai/v1/conversations/:conversation_id' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"user": "abc-123"
}'
-
{api_key}は、実際のAPIキーに置き換えてください。 -
:conversation_idは、削除する会話のIDに置き換えてください。
リクエストボディには、以下のパラメータを指定します。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
会話の削除が成功すると、以下のようなレスポンスが返ります。
{
"result": "success"
}
resultは常に"success"が返ります。
ユースケース
会話を削除することで、以下のようなことができます。
- ユーザーが不要になった会話を削除する
- 会話一覧をすっきりと保つ
- ストレージ容量を節約する
以下は、JavaScriptで会話を削除する例です。
async function deleteConversation(conversationId, user) {
const response = await fetch(`https://api.dify.ai/v1/conversations/${conversationId}`, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
},
body: JSON.stringify({ user })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.result); // "success"
}
// 会話を削除する
deleteConversation('10799fb8-64f7-4296-bbf7-b42bfbe0ae54', 'abc-123').catch(console.error);
この例では、deleteConversation関数を定義して、会話IDとユーザーIDを引数に取ります。fetch関数を使って、/conversations/:conversation_idエンドポイントにDELETEリクエストを送信します。
レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認します。
会話を削除した後は、会話一覧を再取得して、削除された会話が表示されないようにしましょう。
まとめ
/conversations/:conversation_idエンドポイントを使うことで、チャットボットの会話を削除することができます。
会話を削除するには、会話IDとユーザーIDを指定してDELETEリクエストを送信します。レスポンスが成功した場合は、resultプロパティに"success"が入っていることを確認します。
会話削除機能を適切に実装することで、ユーザーにとって使いやすいチャットボットアプリケーションを開発することができるでしょう。ぜひ試してみてください。
会話の名前を変更しよう
チャットボットアプリケーションでは、ユーザーが会話の名前を自由に変更できるようにすることが重要です。会話の名前を変更することで、ユーザーは会話の内容を簡単に思い出すことができます。
Dify.aiのチャットボットAPIでは、/conversations/:conversation_id/nameエンドポイントを使って、会話の名前を変更することができます。
リクエスト
/conversations/:conversation_id/nameエンドポイントへのリクエストは、以下のようなものになります。
curl -X POST 'https://api.dify.ai/v1/conversations/:conversation_id/name' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Chat vs AI",
"user": "abc-123"
}'
-
{api_key}は、実際のAPIキーに置き換えてください。 -
:conversation_idは、名前を変更する会話のIDに置き換えてください。
リクエストボディには、以下のパラメータを指定します。
-
name(オプション): 会話の新しい名前。auto_generateがtrueの場合は省略可能。 -
auto_generate(オプション):trueの場合、会話の名前を自動生成する。デフォルトはfalse。 -
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
会話の名前の変更が成功すると、以下のようなレスポンスが返ります。
{
"id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
"name": "Chat vs AI",
"inputs": {},
"introduction": "",
"created_at": 1705569238
}
-
id: 会話のID -
name: 変更後の会話の名前 -
inputs: ユーザー入力パラメータ -
introduction: 会話の紹介文 -
created_at: 作成日時のタイムスタンプ(例: 1705395332)
ユースケース
会話の名前を変更することで、以下のようなことができます。
- ユーザーが会話の内容を簡単に思い出せるようにする
- 会話一覧をわかりやすくする
- 会話の検索性を高める
以下は、JavaScriptで会話の名前を変更する例です。
async function renameConversation(conversationId, name, user, autoGenerate = false) {
const response = await fetch(`https://api.dify.ai/v1/conversations/${conversationId}/name`, {
method: 'POST',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name, user, auto_generate: autoGenerate })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.name); // 変更後の会話の名前
}
// 会話の名前を変更する
renameConversation('cd78daf6-f9e4-4463-9ff2-54257230a0ce', 'New chat name', 'abc-123').catch(console.error);
// 会話の名前を自動生成する
renameConversation('cd78daf6-f9e4-4463-9ff2-54257230a0ce', '', 'abc-123', true).catch(console.error);
この例では、renameConversation関数を定義して、会話ID、新しい名前、ユーザーID、自動生成フラグ(オプション)を引数に取ります。fetch関数を使って、/conversations/:conversation_id/nameエンドポイントにPOSTリクエストを送信します。
レスポンスが成功した場合は、nameプロパティに変更後の会話の名前が入っていることを確認します。
会話の名前を変更した後は、会話一覧を再取得して、変更後の名前が表示されるようにしましょう。
まとめ
/conversations/:conversation_id/nameエンドポイントを使うことで、チャットボットの会話の名前を変更することができます。
会話の名前を変更するには、会話ID、新しい名前、ユーザーID、自動生成フラグ(オプション)を指定してPOSTリクエストを送信します。レスポンスが成功した場合は、nameプロパティに変更後の会話の名前が入っていることを確認します。
会話の名前変更機能を適切に実装することで、ユーザーにとって使いやすいチャットボットアプリケーションを開発することができるでしょう。ぜひ試してみてください。
音声をテキストに変換しよう
チャットボットアプリケーションでは、ユーザーが音声で入力することができると便利です。音声入力に対応することで、ユーザーの利便性が向上し、より自然な会話が可能になります。
Dify.aiのチャットボットAPIでは、/audio-to-textエンドポイントを使って、音声をテキストに変換することができます。
リクエスト
/audio-to-textエンドポイントへのリクエストは、multipart/form-data形式で行います。
以下のパラメータを指定します。
-
file(必須): 音声ファイル。サポートされている形式は以下の通りです。mp3mp4mpegmpgam4awavwebm- ファイルサイズの上限は15MBです。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
リクエストの例を以下に示します。
curl -X POST 'https://api.dify.ai/v1/audio-to-text' \
--header 'Authorization: Bearer {api_key}' \
--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]'
-
{api_key}は、実際のAPIキーに置き換えてください。 -
localfileは、アップロードする音声ファイルのパスに置き換えてください。 -
typeには、音声ファイルのMIMEタイプを指定してください。
レスポンス
音声からテキストへの変換が成功すると、以下のようなレスポンスが返ります。
{
"text": "こんにちは、今日は晴れですね。"
}
-
text: 変換されたテキスト
ユースケース
音声をテキストに変換することで、以下のようなことができます。
- ユーザーが音声で入力した内容をチャットボットに伝える
- 音声ファイルをテキストに変換して、分析や検索に利用する
- 音声ファイルをテキストに変換して、文字起こしを行う
以下は、JavaScriptで音声をテキストに変換する例です。
async function convertAudioToText(audioFile, user) {
const formData = new FormData();
formData.append('file', audioFile);
formData.append('user', user);
const response = await fetch('https://api.dify.ai/v1/audio-to-text', {
method: 'POST',
headers: {
'Authorization': 'Bearer {api_key}'
},
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.text); // 変換されたテキスト
}
// 音声ファイルを選択するためのinput要素を取得する
const fileInput = document.getElementById('audio-file');
// ファイルが選択された時の処理
fileInput.addEventListener('change', async (event) => {
const audioFile = event.target.files[0];
await convertAudioToText(audioFile, 'abc-123');
});
この例では、convertAudioToText関数を定義して、音声ファイルとユーザーIDを引数に取ります。FormDataオブジェクトを使って、音声ファイルとユーザーIDをリクエストボディに含めます。fetch関数を使って、/audio-to-textエンドポイントにPOSTリクエストを送信します。
レスポンスが成功した場合は、textプロパティに変換されたテキストが入っていることを確認します。
音声ファイルを選択するためのinput要素を取得し、ファイルが選択された時にconvertAudioToText関数を呼び出しています。
まとめ
/audio-to-textエンドポイントを使うことで、音声をテキストに変換することができます。
音声をテキストに変換するには、音声ファイルとユーザーIDを指定してmultipart/form-data形式でPOSTリクエストを送信します。レスポンスが成功した場合は、textプロパティに変換されたテキストが入っていることを確認します。
音声入力に対応することで、ユーザーの利便性が向上し、より自然な会話が可能になります。ぜひ試してみてください。
テキストを音声に変換しよう
チャットボットアプリケーションでは、テキストを音声に変換することで、よりリアルな会話体験を提供することができます。テキストを音声に変換することで、ユーザーは読むだけでなく、聞くこともできるようになります。
Dify.aiのチャットボットAPIでは、/text-to-audioエンドポイントを使って、テキストを音声に変換することができます。
リクエスト
/text-to-audioエンドポイントへのリクエストは、以下のようなものになります。
curl --location --request POST 'https://api.dify.ai/v1/text-to-audio' \
--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
--form 'text=Hello Dify;user=abc-123;streaming=false
-
ENTER-YOUR-SECRET-KEYは、実際のAPIキーに置き換えてください。
リクエストボディには、以下のパラメータを指定します。
-
text(必須): 音声に変換するテキスト -
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります) -
streaming(オプション): ストリーミング出力を有効にするかどうか(trueまたはfalse)
レスポンス
テキストから音声への変換が成功すると、以下のようなレスポンスが返ります。
Content-Type: audio/wav
[binary data]
レスポンスのContent-Typeはaudio/wavになります。レスポンスボディには、変換された音声データのバイナリデータが含まれます。
ユースケース
テキストを音声に変換することで、以下のようなことができます。
- チャットボットの返答を音声で再生する
- テキストを音声に変換して、オーディオブックを作成する
- テキストを音声に変換して、アクセシビリティを向上させる
以下は、JavaScriptでテキストを音声に変換する例です。
async function convertTextToAudio(text, user, streaming = false) {
const formData = new FormData();
formData.append('text', text);
formData.append('user', user);
formData.append('streaming', streaming);
const response = await fetch('https://api.dify.ai/v1/text-to-audio', {
method: 'POST',
headers: {
'Authorization': 'Bearer ENTER-YOUR-SECRET-KEY'
},
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const audio = new Audio(url);
audio.play();
}
// テキストを音声に変換する
convertTextToAudio('こんにちは、今日は晴れですね。', 'abc-123').catch(console.error);
この例では、convertTextToAudio関数を定義して、テキスト、ユーザーID、ストリーミングフラグ(オプション)を引数に取ります。FormDataオブジェクトを使って、テキスト、ユーザーID、ストリーミングフラグをリクエストボディに含めます。fetch関数を使って、/text-to-audioエンドポイントにPOSTリクエストを送信します。
レスポンスが成功した場合は、blobオブジェクトを取得し、URL.createObjectURLメソッドを使って、音声データのURLを作成します。Audioオブジェクトを使って、音声を再生します。
まとめ
/text-to-audioエンドポイントを使うことで、テキストを音声に変換することができます。
テキストを音声に変換するには、テキスト、ユーザーID、ストリーミングフラグ(オプション)を指定してPOSTリクエストを送信します。レスポンスが成功した場合は、audio/wav形式の音声データが返されます。
テキストを音声に変換することで、よりリアルな会話体験を提供することができます。ぜひ試してみてください。
アプリケーション情報を取得しよう
チャットボットアプリケーションを開発する際は、アプリケーションの設定や機能、入力パラメータなどの情報を取得する必要があります。これらの情報を取得することで、アプリケーションの初期化や、ユーザーインターフェイスの構築を行うことができます。
Dify.aiのチャットボットAPIでは、/parametersエンドポイントを使って、アプリケーション情報を取得することができます。
リクエスト
/parametersエンドポイントへのリクエストは、以下のようなものになります。
curl -X GET 'https://api.dify.ai/v1/parameters?user=abc-123'
クエリパラメータには、以下のものを指定します。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
アプリケーション情報の取得が成功すると、以下のようなレスポンスが返ります。
{
"opening_statement": "Hello!",
"suggested_questions_after_answer": {
"enabled": true
},
"speech_to_text": {
"enabled": true
},
"retriever_resource": {
"enabled": true
},
"annotation_reply": {
"enabled": true
},
"user_input_form": [
{
"paragraph": {
"label": "Query",
"variable": "query",
"required": true,
"default": ""
}
}
],
"file_upload": {
"image": {
"enabled": false,
"number_limits": 3,
"detail": "high",
"transfer_methods": [
"remote_url",
"local_file"
]
}
},
"system_parameters": {
"image_file_size_limit": "10"
}
}
-
opening_statement: チャットボットの開始時のメッセージ -
suggested_questions: 開始時に表示する提案質問のリスト -
suggested_questions_after_answer: 回答後に提案質問を表示するかどうかの設定-
enabled: 有効かどうか
-
-
speech_to_text: 音声認識の設定-
enabled: 有効かどうか
-
-
retriever_resource: 引用と帰属の設定-
enabled: 有効かどうか
-
-
annotation_reply: アノテーション返信の設定-
enabled: 有効かどうか
-
-
user_input_form: ユーザー入力フォームの設定-
text-input: テキスト入力コントロールの設定-
label: 変数の表示ラベル名 -
variable: 変数ID -
required: 必須かどうか -
default: デフォルト値
-
-
paragraph: 段落テキスト入力コントロールの設定-
label: 変数の表示ラベル名 -
variable: 変数ID -
required: 必須かどうか -
default: デフォルト値
-
-
select: ドロップダウンコントロールの設定-
label: 変数の表示ラベル名 -
variable: 変数ID -
required: 必須かどうか -
default: デフォルト値 -
options: オプションの値のリスト
-
-
-
file_upload: ファイルアップロードの設定-
image: 画像の設定(現在はpng,jpg,jpeg,webp,gifのみサポート)-
enabled: 有効かどうか -
number_limits: 画像の数の上限(デフォルトは3) -
transfer_methods: 転送方法のリスト(remote_url,local_fileのいずれかを選択する必要があります)
-
-
-
system_parameters: システムパラメータ-
image_file_size_limit: 画像ファイルのアップロードサイズの上限(MB)
-
ユースケース
アプリケーション情報を取得することで、以下のようなことができます。
- アプリケーションの初期化
- ユーザーインターフェイスの構築
- 入力パラメータの検証
- ファイルアップロードの設定
以下は、JavaScriptでアプリケーション情報を取得する例です。
async function getApplicationParameters(user) {
const params = new URLSearchParams({ user });
const response = await fetch(`https://api.dify.ai/v1/parameters?${params}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.opening_statement); // チャットボットの開始時のメッセージ
console.log(data.user_input_form); // ユーザー入力フォームの設定
console.log(data.file_upload); // ファイルアップロードの設定
}
// アプリケーション情報を取得する
getApplicationParameters('abc-123').catch(console.error);
この例では、getApplicationParameters関数を定義して、ユーザーIDを引数に取ります。fetch関数を使って、/parametersエンドポイントにGETリクエストを送信します。
レスポンスが成功した場合は、opening_statementプロパティにチャットボットの開始時のメッセージが入っていることを確認します。また、user_input_formプロパティにユーザー入力フォームの設定が、file_uploadプロパティにファイルアップロードの設定が入っていることを確認します。
取得したアプリケーション情報を使って、アプリケーションの初期化やユーザーインターフェイスの構築を行うことができます。
まとめ
/parametersエンドポイントを使うことで、チャットボットアプリケーションの設定や機能、入力パラメータなどの情報を取得することができます。
アプリケーション情報を取得するには、ユーザーIDを指定してGETリクエストを送信します。レスポンスが成功した場合は、各種設定や機能の情報が返されます。
取得したアプリケーション情報を使って、アプリケーションの初期化やユーザーインターフェイスの構築を行うことができます。ぜひ活用してみてください。
アプリケーションのメタ情報を取得しよう
チャットボットアプリケーションでは、さまざまなツールを使ってユーザーとのインタラクションを行います。これらのツールには、アイコンが設定されていることがあります。アプリケーションのメタ情報を取得することで、これらのツールアイコンを取得し、ユーザーインターフェイスに表示することができます。
Dify.aiのチャットボットAPIでは、/metaエンドポイントを使って、アプリケーションのメタ情報を取得することができます。
リクエスト
/metaエンドポイントへのリクエストは、以下のようなものになります。
curl -X GET 'https://api.dify.ai/v1/meta?user=abc-123' \
-H 'Authorization: Bearer {api_key}'
-
{api_key}は、実際のAPIキーに置き換えてください。
クエリパラメータには、以下のものを指定します。
-
user(必須): ユーザーを識別するためのID(アプリケーション内で一意である必要があります)
レスポンス
アプリケーションのメタ情報の取得が成功すると、以下のようなレスポンスが返ります。
{
"tool_icons": {
"dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
"api_tool": {
"background": "#252525",
"content": "😁"
}
}
}
-
tool_icons: ツールアイコンの情報-
tool_name: ツールの名前-
icon: アイコンの情報(オブジェクトまたは文字列)- オブジェクトの場合:
-
background: 背景色(16進数形式) -
content: 絵文字
-
- 文字列の場合:
- アイコンのURL
- オブジェクトの場合:
-
-
レスポンスには、ツールの名前とそのアイコンの情報が含まれています。アイコンの情報は、オブジェクトまたは文字列で表されます。オブジェクトの場合は、背景色と絵文字が指定されます。文字列の場合は、アイコンのURLが指定されます。
ユースケース
アプリケーションのメタ情報を取得することで、以下のようなことができます。
- ツールアイコンをユーザーインターフェイスに表示する
- ツールアイコンを使ってユーザーとのインタラクションを行う
以下は、JavaScriptでアプリケーションのメタ情報を取得する例です。
async function getApplicationMetaInfo(user) {
const params = new URLSearchParams({ user });
const response = await fetch(`https://api.dify.ai/v1/meta?${params}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer {api_key}',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data.tool_icons); // ツールアイコンの情報
// ツールアイコンをユーザーインターフェイスに表示する
for (const [toolName, iconInfo] of Object.entries(data.tool_icons)) {
const iconElement = document.createElement('div');
iconElement.classList.add('tool-icon');
if (typeof iconInfo === 'string') {
iconElement.innerHTML = `<img src="${iconInfo}" alt="${toolName}">`;
} else {
iconElement.style.backgroundColor = iconInfo.background;
iconElement.textContent = iconInfo.content;
}
document.body.appendChild(iconElement);
}
}
// アプリケーションのメタ情報を取得する
getApplicationMetaInfo('abc-123').catch(console.error);
この例では、getApplicationMetaInfo関数を定義して、ユーザーIDを引数に取ります。fetch関数を使って、/metaエンドポイントにGETリクエストを送信します。
レスポンスが成功した場合は、tool_iconsプロパティにツールアイコンの情報が入っていることを確認します。
その後、tool_iconsオブジェクトを走査して、各ツールのアイコンをユーザーインターフェイスに表示しています。アイコンの情報が文字列の場合は、<img>要素を使ってアイコン画像を表示します。オブジェクトの場合は、<div>要素を使ってアイコンを表示します。
まとめ
/metaエンドポイントを使うことで、チャットボットアプリケーションのメタ情報を取得することができます。
アプリケーションのメタ情報を取得するには、ユーザーIDを指定してGETリクエストを送信します。レスポンスが成功した場合は、ツールアイコンの情報が返されます。
取得したツールアイコンの情報を使って、ユーザーインターフェイスにアイコンを表示したり、ユーザーとのインタラクションを行ったりすることができます。ぜひ活用してみてください。
チャットボットAPIを使ってみよう
チャットボットアプリケーションを開発する際は、APIを使ってチャットボットとの通信を行う必要があります。ここでは、Dify.aiのチャットボットAPIを例に、リクエストの送信方法とレスポンスの構造について解説します。
リクエストの送信
チャットボットにメッセージを送信するには、/chat-messagesエンドポイントにPOSTリクエストを送信します。リクエストのボディには、以下のようなJSONデータを含めます。
{
"inputs": {},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}
-
inputs: アプリケーションで定義された変数の値を指定します。 -
query: ユーザーの入力やメッセージを指定します。 -
response_mode: レスポンスの返し方を指定します。streamingにするとリアルタイムにストリーミングで返ってきます。blockingにすると、処理が完了してからレスポンスが返ってきます。 -
conversation_id: 会話を続けるためのIDを指定します。前回のメッセージのconversation_idを指定することで、前回までの会話を踏まえた返答をしてくれます。 -
user: ユーザーを識別するためのIDを指定します。 -
files: 画像などのファイルを添付する場合に指定します。
リクエストを送信するには、以下のようなcURLコマンドを使用します。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}'
レスポンスの構造
ブロッキングモード
response_modeをblockingにした場合、レスポンスは以下のような構造になります。
{
"event": "message",
"message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
"conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
"mode": "chat",
"answer": "iPhone 13 Pro Max specs are listed heere:...",
"metadata": {
"usage": {
"prompt_tokens": 1033,
"prompt_unit_price": "0.001",
"prompt_price_unit": "0.001",
"prompt_price": "0.0010330",
"completion_tokens": 128,
"completion_unit_price": "0.002",
"completion_price_unit": "0.001",
"completion_price": "0.0002560",
"total_tokens": 1161,
"total_price": "0.0012890",
"currency": "USD",
"latency": 0.7682376249867957
},
"retriever_resources": [
{
"position": 1,
"dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
"dataset_name": "iPhone",
"document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
"document_name": "iPhone List",
"segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
"score": 0.98457545,
"content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
}
]
},
"created_at": 1705407629
}
-
event: イベントの種類(message固定) -
message_id: メッセージを識別するためのID -
conversation_id: 会話を識別するためのID -
mode: アプリケーションのモード(chat固定) -
answer: チャットボットの返答 -
metadata: メタデータ-
usage: 使用量に関する情報 -
retriever_resources: 検索に使用したリソースの情報
-
-
created_at: メッセージの作成日時
ストリーミングモード
response_modeをstreamingにした場合、レスポンスは以下のようにチャンクごとにストリーミングされます。
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
data: {"event": "message", "message_id": : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
data: {"event": "message", "message_id": : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}}
各チャンクはdata:で始まり、その後にJSONデータが続きます。チャンクの種類はeventの値で判別できます。
-
workflow_started: ワークフローの開始 -
node_started: ノードの開始 -
node_finished: ノードの終了 -
workflow_finished: ワークフローの終了 -
message: チャットボットの返答(チャンクごとに分割されて送られてくる) -
message_end: チャットボットの返答の終了
エラーハンドリング
リクエストの送信時にエラーが発生した場合、以下のようなエラーコードとメッセージが返ってきます。
-
404, Conversation does not exists: 指定された会話が存在しない -
400, invalid_param: パラメータの指定が不正 -
400, app_unavailable: アプリケーションが利用できない -
400, provider_not_initialize: モデルの認証情報が設定されていない -
400, provider_quota_exceeded: モデルの呼び出しクオータが不足している -
400, model_currently_not_support: 指定されたモデルが利用できない -
400, completion_request_error: テキストの生成に失敗した -
500, internal server error: 内部サーバーエラー
エラーが発生した場合は、エラーコードとメッセージを確認して、適切に対処する必要があります。
まとめ
Dify.aiのチャットボットAPIを使うことで、簡単にチャットボットとの通信を行うことができます。
リクエストを送信する際は、/chat-messagesエンドポイントにPOSTリクエストを送信します。リクエストのボディには、ユーザーの入力やメッセージ、レスポンスの返し方、会話を識別するためのIDなどを指定します。
レスポンスの構造は、レスポンスの返し方によって異なります。ブロッキングモードではJSONオブジェクトが返ってきますが、ストリーミングモードではチャンクごとにデータが送られてきます。
エラーが発生した場合は、エラーコードとメッセージを確認して、適切に対処する必要があります。
APIを使いこなすことで、より高度なチャットボットアプリケーションを開発することができるでしょう。
チャットアプリケーションへのメッセージ送信APIの使い方
この記事では、チャットアプリケーションへのメッセージ送信API /chat-messages の使用方法について説明します。このAPIを利用して、ユーザーからの入力や質問をチャットアプリケーションに送信し、さまざまな応答モードで結果を受け取ることができます。
ユースケース
このAPIを使用するユースケースとして、以下のシナリオが考えられます:
-
ユーザー入力の送信:
- ユーザーがチャットボットに質問や指示を送信する。
-
変数値の入力:
- アプリケーションが定義する複数の変数に対して値を入力し、チャットボットがそれに応じた応答を生成する。
-
応答モードの選択:
- 応答を逐次的に受け取るストリーミングモードと、全ての処理が完了した後に応答を受け取るブロッキングモードの選択。
-
ファイルの送信:
- ユーザーが画像ファイルを送信し、それに基づいて質問や指示を行う。
-
会話の継続:
- 過去のチャット履歴に基づいて会話を継続するための会話IDの使用。
以下では、各リクエストパラメータについて詳しく説明し、具体的なコード例を提供します。
リクエストボディ
| Name | Type | Description |
|---|---|---|
| query | string | ユーザー入力/質問の内容。 |
| inputs | object | アプリケーションが定義する複数の変数値を含むオブジェクト。デフォルトは空のオブジェクト。 |
| response_mode | string | 応答の返却モード。ストリーミングモード(推奨)またはブロッキングモードが選択可能。 |
| user | string | ユーザー識別子。エンドユーザーのアイデンティティを定義するために使用され、アプリケーション内で一意に定義される必要がある。 |
| conversation_id | string | 会話ID。以前のチャット記録に基づいて会話を続けるために、前のメッセージの会話IDを渡す必要がある。 |
| files | array[object] | ファイルリスト。テキスト理解と質問応答を組み合わせたファイル(画像)の入力に適しており、モデルがビジョン機能をサポートしている場合のみ利用可能。 |
| auto_generate_name | bool | タイトルの自動生成。デフォルトはtrue。falseに設定すると、会話のリネームAPIを呼び出して自動生成をtrueに設定することで非同期タイトル生成を実現可能。 |
例:シンプルなメッセージ送信
{
"query": "こんにちは、今日の天気は?",
"response_mode": "streaming",
"user": "user123"
}
例:変数値を含むメッセージ送信
{
"query": "特定の変数を使用した計算を行いたい",
"inputs": {
"var1": 10,
"var2": 20
},
"response_mode": "blocking",
"user": "user456"
}
例:画像ファイルを送信するメッセージ
{
"query": "この画像について説明して",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://example.com/image.jpg"
}
],
"response_mode": "streaming",
"user": "user789"
}
応答モード
応答モードは、チャットアプリケーションがどのように応答を返すかを決定します。以下の2つのモードがあります:
-
ストリーミングモード:
- サーバーから逐次的に応答を受け取るモード。タイプライターのような出力が実現されます。SSE(Server-Sent Events)を使用します。
-
ブロッキングモード:
- 処理が完了した後に応答を受け取るモード。処理が長時間に及ぶ場合、リクエストが中断される可能性があります。Cloudflareの制限により、リクエストが100秒後に中断されることがあります。
ストリーミングモードの例
以下のコードは、ストリーミングモードで応答を受け取る例です:
fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: "こんにちは、今日の天気は?",
response_mode: "streaming",
user: "user123"
})
})
.then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
console.log(decoder.decode(value));
return reader.read().then(processText);
});
})
.catch(error => console.error('Error:', error));
ブロッキングモードの例
以下のコードは、ブロッキングモードで応答を受け取る例です:
fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: "計算をしてください",
inputs: {
var1: 10,
var2: 20
},
response_mode: "blocking",
user: "user456"
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
結論
このAPI /chat-messages を使用することで、ユーザー入力や変数値、ファイルを送信し、さまざまな応答モードで結果を受け取ることができます。この記事の例を参考に、チャットアプリケーションでのメッセージ送信を実装してみてください。
チャットアプリケーションへのメッセージ送信APIの使い方
この記事では、チャットアプリケーションへのメッセージ送信API /chat-messages の使用方法について説明します。このAPIを利用して、ユーザーからの入力や質問をチャットアプリケーションに送信し、さまざまな応答モードで結果を受け取ることができます。
ユースケース
このAPIを使用するユースケースとして、以下のシナリオが考えられます:
-
ユーザー入力の送信:
- ユーザーがチャットボットに質問や指示を送信する。
-
変数値の入力:
- アプリケーションが定義する複数の変数に対して値を入力し、チャットボットがそれに応じた応答を生成する。
-
応答モードの選択:
- 応答を逐次的に受け取るストリーミングモードと、全ての処理が完了した後に応答を受け取るブロッキングモードの選択。
-
ファイルの送信:
- ユーザーが画像ファイルを送信し、それに基づいて質問や指示を行う。
-
会話の継続:
- 過去のチャット履歴に基づいて会話を継続するための会話IDの使用。
以下では、各リクエストパラメータについて詳しく説明し、具体的なコード例を提供します。
リクエストボディ
| Name | Type | Description |
|---|---|---|
| query | string | ユーザー入力/質問の内容。 |
| inputs | object | アプリケーションが定義する複数の変数値を含むオブジェクト。デフォルトは空のオブジェクト。 |
| response_mode | string | 応答の返却モード。ストリーミングモード(推奨)またはブロッキングモードが選択可能。 |
| user | string | ユーザー識別子。エンドユーザーのアイデンティティを定義するために使用され、アプリケーション内で一意に定義される必要がある。 |
| conversation_id | string | 会話ID。以前のチャット記録に基づいて会話を続けるために、前のメッセージの会話IDを渡す必要がある。 |
| files | array[object] | ファイルリスト。テキスト理解と質問応答を組み合わせたファイル(画像)の入力に適しており、モデルがビジョン機能をサポートしている場合のみ利用可能。 |
| auto_generate_name | bool | タイトルの自動生成。デフォルトはtrue。falseに設定すると、会話のリネームAPIを呼び出して自動生成をtrueに設定することで非同期タイトル生成を実現可能。 |
例:シンプルなメッセージ送信
{
"query": "こんにちは、今日の天気は?",
"response_mode": "streaming",
"user": "user123"
}
例:変数値を含むメッセージ送信
{
"query": "特定の変数を使用した計算を行いたい",
"inputs": {
"var1": 10,
"var2": 20
},
"response_mode": "blocking",
"user": "user456"
}
例:画像ファイルを送信するメッセージ
{
"query": "この画像について説明して",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://example.com/image.jpg"
}
],
"response_mode": "streaming",
"user": "user789"
}
応答モード
応答モードは、チャットアプリケーションがどのように応答を返すかを決定します。以下の2つのモードがあります:
-
ストリーミングモード:
- サーバーから逐次的に応答を受け取るモード。タイプライターのような出力が実現されます。SSE(Server-Sent Events)を使用します。
-
ブロッキングモード:
- 処理が完了した後に応答を受け取るモード。処理が長時間に及ぶ場合、リクエストが中断される可能性があります。Cloudflareの制限により、リクエストが100秒後に中断されることがあります。
ストリーミングモードの例
以下のコードは、ストリーミングモードで応答を受け取る例です:
fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}'
},
body: JSON.stringify({
query: "こんにちは、今日の天気は?",
response_mode: "streaming",
user: "user123"
})
})
.then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
console.log(decoder.decode(value));
return reader.read().then(processText);
});
})
.catch(error => console.error('Error:', error));
ブロッキングモードの例
以下のコードは、ブロッキングモードで応答を受け取る例です:
fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}'
},
body: JSON.stringify({
query: "計算をしてください",
inputs: {
var1: 10,
var2: 20
},
response_mode: "blocking",
user: "user456"
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
応答形式
応答形式は、応答モードによって異なります。ブロッキングモードでは、CompletionResponse オブジェクトが返されます。ストリーミングモードでは、ChunkCompletionResponse ストリームが返されます。
ブロッキングモードの応答例
{
"event": "message",
"message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
"conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
"mode": "chat",
"answer": "iPhone 13 Pro Max specs are listed here:...",
"metadata": {
"usage": {
"prompt_tokens": 1033,
"prompt_unit_price": "0.001",
"prompt_price_unit": "0.001",
"prompt_price": "0.0010330",
"completion_tokens": 128,
"completion_unit_price": "0.002",
"completion_price_unit": "0.001",
"completion_price": "0.0002560",
"total_tokens": 1161,
"total_price": "0.0012890",
"currency": "USD",
"latency": 0.7682376249867957
},
"retriever_resources": [
{
"position": 1,
"dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
"dataset_name": "iPhone",
"document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
"document_name": "iPhone List",
"segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
"score": 0.98457545,
"content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
}
]
},
"
timestamp": "2023-10-02T09:21:15.982Z"
}
ストリーミングモードの応答例
ストリーミングモードでは、応答が逐次的に返されるため、以下のように部分的な応答を受け取ります:
{
"event": "message",
"message_id": "12345678-90ab-cdef-1234-567890abcdef",
"conversation_id": "abcdef12-3456-7890-abcd-ef1234567890",
"mode": "chat",
"answer": "The iPhone 13 Pro Max specs are listed here:...",
"metadata": {},
"timestamp": "2023-10-02T09:21:15.982Z"
}
まとめ
このAPIを利用することで、ユーザー入力や変数値をチャットアプリケーションに送信し、様々な応答モードで結果を受け取ることができます。ストリーミングモードとブロッキングモードの両方を適切に利用することで、ユーザーにスムーズな体験を提供することができます。具体的なユースケースに応じて、リクエストボディや応答形式を調整し、効果的にAPIを活用してください。
補足1:ストリーミングモードでAPIをアプリに組み込む
ストリーミングモードでAPIをアプリに組み込むには、JavaScript(特にReact)を使用した具体的な例を以下に示します。この例では、チャットアプリケーションのメッセージ送信とリアルタイムでの応答表示を実装します。
1. 必要な依存関係のインストール
まず、Reactアプリケーションを作成し、必要なパッケージをインストールします。create-react-appを使用して新しいReactプロジェクトを作成する手順は以下の通りです。
npx create-react-app chat-app
cd chat-app
npm install
2. ストリーミングモードでメッセージを送信するコンポーネントの作成
次に、ストリーミングモードでメッセージを送信し、リアルタイムで応答を受け取るためのコンポーネントを作成します。
src/components/Chat.jsというファイルを作成し、以下のコードを追加します。
import React, { useState } from 'react';
const Chat = () => {
const [input, setInput] = useState('');
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
setInput('');
setIsLoading(true);
const response = await fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}', // APIキーを追加してください
},
body: JSON.stringify({
query: input,
response_mode: 'streaming',
user: 'user123'
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let botMessage = { role: 'bot', content: '' };
reader.read().then(function processText({ done, value }) {
if (done) {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
return;
}
botMessage.content += decoder.decode(value);
setMessages((prevMessages) => [...prevMessages.slice(0, -1), botMessage]);
return reader.read().then(processText);
});
};
return (
<div>
<div>
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
{message.content}
</div>
))}
{isLoading && <div className="message bot">...</div>}
</div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="メッセージを入力"
/>
<button type="submit">送信</button>
</form>
</div>
);
};
export default Chat;
3. メインアプリケーションにチャットコンポーネントを追加
次に、メインのアプリケーションファイルにこのコンポーネントを追加します。
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Chat from './components/Chat';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>チャットアプリケーション</h1>
</header>
<Chat />
</div>
);
}
export default App;
4. スタイリングの追加
必要に応じてスタイリングを追加します。例えば、src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
.message {
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.message.user {
background-color: #007bff;
color: white;
text-align: left;
}
.message.bot {
background-color: #e0e0e0;
color: black;
text-align: left;
}
5. サーバー側のエンドポイント設定
この例では、/chat-messagesエンドポイントを利用していますが、実際のAPIエンドポイントに合わせて変更してください。
まとめ
これで、ストリーミングモードでチャットメッセージを送信し、リアルタイムで応答を受け取る機能がReactアプリケーションに組み込まれました。必要に応じて、更に機能を拡張したり、スタイリングを改善してください。
補足2:ストリーミングを途中で停止する
ストリーミングを途中で停止するためには、Fetch APIを使用している場合、AbortControllerを利用することでリクエストを中断することができます。以下の例では、ユーザーが「停止」ボタンをクリックすることでストリーミングを途中で停止する機能を実装します。
1. チャットコンポーネントの更新
AbortControllerを使用してリクエストを管理するようにチャットコンポーネントを更新します。
import React, { useState, useRef } from 'react';
const Chat = () => {
const [input, setInput] = useState('');
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const abortControllerRef = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
setInput('');
setIsLoading(true);
// AbortControllerのインスタンスを作成
const abortController = new AbortController();
abortControllerRef.current = abortController;
const response = await fetch('/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}', // APIキーを追加してください
},
body: JSON.stringify({
query: input,
response_mode: 'streaming',
user: 'user123'
}),
signal: abortController.signal // リクエストにシグナルを追加
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let botMessage = { role: 'bot', content: '' };
reader.read().then(function processText({ done, value }) {
if (done) {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
abortControllerRef.current = null;
return;
}
botMessage.content += decoder.decode(value);
setMessages((prevMessages) => [...prevMessages.slice(0, -1), botMessage]);
return reader.read().then(processText);
}).catch((error) => {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Fetch error:', error);
}
setIsLoading(false);
abortControllerRef.current = null;
});
};
const handleAbort = () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort(); // リクエストを中断
setIsLoading(false);
}
};
return (
<div>
<div>
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
{message.content}
</div>
))}
{isLoading && <div className="message bot">...</div>}
</div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="メッセージを入力"
/>
<button type="submit">送信</button>
{isLoading && <button type="button" onClick={handleAbort}>停止</button>}
</form>
</div>
);
};
export default Chat;
2. ユーザーインターフェースの更新
このコードでは、メッセージ送信時に「停止」ボタンが表示され、ユーザーがそのボタンをクリックすると、現在のストリーミングリクエストが中断されます。中断後、isLoadingフラグをfalseに設定し、ロード状態を解除します。
まとめ
これで、ストリーミングモードでメッセージを送信中にユーザーがリクエストを中断する機能が追加されました。AbortControllerを利用することで、ユーザーは不要なストリーミングを簡単に停止することができます。この機能はユーザーエクスペリエンスの向上に寄与します。
ChunkChatCompletionResponse
ChunkChatCompletionResponseは、アプリから出力されるストリームチャンクを返します。Content-Typeはtext/event-streamです。各ストリーミングチャンクは、data:で始まり、2つの改行文字(\n\n)で区切られます。
チャンクの構造
以下はチャンクの一例です:
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
イベントの種類
ChunkChatCompletionResponseに含まれるイベントの種類は次の通りです:
-
event: message
- 説明: LLMがテキストチャンクを返すイベント。テキストがチャンクごとに分割されて出力されます。
-
フィールド:
-
task_id(string): リクエストトラッキング用のタスクID -
message_id(string): 一意のメッセージID -
conversation_id(string): 会話ID -
answer(string): LLMが返したテキストチャンクの内容 -
created_at(int): 作成タイムスタンプ(例: 1705395332)
-
-
event: message_file
- 説明: ツールによって新しいファイルが作成されたことを示すイベント
-
フィールド:
-
id(string): ファイルの一意のID -
type(string): ファイルの種類。現在は「image」のみ許可されています -
belongs_to(string): 所属先。ここでは「assistant」のみ -
url(string): ファイルのリモートURL -
conversation_id(string): 会話ID
-
-
event: message_end
- 説明: ストリーミングの終了を示すイベント。このイベントを受信すると、ストリーミングが終了したことを意味します。
-
フィールド:
-
task_id(string): リクエストトラッキング用のタスクID -
message_id(string): 一意のメッセージID -
conversation_id(string): 会話ID -
metadata(object): メタデータ -
usage(Usage): モデルの使用情報 -
retriever_resources(array[RetrieverResource]): 引用と帰属リスト
-
例
以下は、さまざまなイベントの例です:
- messageイベント:
data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
- message_fileイベント:
data: {"event": "message_file", "id": "9b8b9c37-1a23-4f50-a2df-7f2327f6e6e9", "type": "image", "belongs_to": "assistant", "url": "https://example.com/image.png", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2"}\n\n
- message_endイベント:
data: {"event": "message_end", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "message_id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {}, "usage": {}, "retriever_resources": []}\n\n
これらのイベントに基づいて、アプリケーションはストリーミングされたメッセージを処理し、必要に応じてUIを更新することができます。
ChunkChatCompletionResponseの使用方法とユースケース
ChunkChatCompletionResponseは、リアルタイムでチャットアプリケーションの応答を受け取るために使用されます。このセクションでは、これらのストリーミングチャンクをどのように利用するかについて説明し、具体的なユースケースとコード例を提供します。
ユースケース
-
リアルタイムチャット応答の表示:
- ユーザーがチャットメッセージを送信すると、アプリケーションはリアルタイムで応答を受け取り、画面に表示します。
-
画像ファイルの処理:
- チャットボットが画像ファイルを生成し、そのURLをユーザーに提供します。
-
ストリーミングの停止:
- ユーザーが望むタイミングでストリーミングを停止し、処理を中断します。
具体的なコード例
以下の例では、AbortControllerを使用してリアルタイムでチャットメッセージをストリーミングし、ユーザーが望むタイミングでストリーミングを停止できるようにします。
1. チャットコンポーネントの作成
src/components/Chat.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useRef } from 'react';
const Chat = () => {
const [input, setInput] = useState('');
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const abortControllerRef = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
setInput('');
setIsLoading(true);
// AbortControllerのインスタンスを作成
const abortController = new AbortController();
abortControllerRef.current = abortController;
const response = await fetch('https://api.dify.ai/v1/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}', // APIキーを追加してください
},
body: JSON.stringify({
query: input,
response_mode: 'streaming',
user: 'user123'
}),
signal: abortController.signal // リクエストにシグナルを追加
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let botMessage = { role: 'bot', content: '' };
reader.read().then(function processText({ done, value }) {
if (done) {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
abortControllerRef.current = null;
return;
}
const chunk = JSON.parse(decoder.decode(value));
if (chunk.event === 'message') {
botMessage.content += chunk.answer;
} else if (chunk.event === 'message_end') {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
abortControllerRef.current = null;
}
return reader.read().then(processText);
}).catch((error) => {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Fetch error:', error);
}
setIsLoading(false);
abortControllerRef.current = null;
});
};
const handleAbort = () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort(); // リクエストを中断
setIsLoading(false);
}
};
return (
<div>
<div>
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
{message.content}
</div>
))}
{isLoading && <div className="message bot">...</div>}
</div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="メッセージを入力"
/>
<button type="submit">送信</button>
{isLoading && <button type="button" onClick={handleAbort}>停止</button>}
</form>
</div>
);
};
export default Chat;
2. メインアプリケーションにチャットコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Chat from './components/Chat';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>チャットアプリケーション</h1>
</header>
<Chat />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
.message {
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.message.user {
background-color: #007bff;
color: white;
text-align: left;
}
.message.bot {
background-color: #e0e0e0;
color: black;
text-align: left;
}
まとめ
この例では、ストリーミングモードでチャットメッセージを送信し、リアルタイムで応答を受け取る機能をReactアプリケーションに組み込みました。AbortControllerを使用することで、ユーザーが望むタイミングでストリーミングを停止することができます。これにより、ユーザーエクスペリエンスを向上させることができます。
メッセージコンテンツ置換イベント (`message_replace`)
チャットアプリケーションの開発において、ユーザーの安全性とコンテンツの品質を確保するために、出力コンテンツのモデレーションは非常に重要です。この記事では、出力コンテンツのモデレーションが有効な場合に、フラグが立てられたコンテンツをプリセットの返信に置き換えるイベントであるmessage_replaceについて詳しく説明します。
message_replaceイベントとは?
message_replaceイベントは、チャットアプリケーションにおいて、出力コンテンツのモデレーションが有効な場合に発生します。このイベントは、フラグが立てられたコンテンツがプリセットの返信に置き換えられることを示します。これにより、適切でないコンテンツがユーザーに表示されるのを防ぐことができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- message_id (string): 一意のメッセージID。
- conversation_id (string): 会話ID。会話のコンテキストを保持するために使用されます。
- answer (string): 置換されたコンテンツ。元のLLMの返信テキストを直接置き換えます。
- created_at (int): 作成タイムスタンプ(例: 1705395332)。
イベントの構造
以下は、message_replaceイベントの例です:
data: {"event": "message_replace", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "message_id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "This message has been replaced due to content moderation.", "created_at": 1705398420}\n\n
message_replaceイベントのユースケース
-
ユーザー保護:
- ユーザーが不適切なコンテンツを受け取らないようにするため。
-
コンテンツ品質の維持:
- アプリケーションのコンテンツ品質を高めるため。
-
法的リスクの軽減:
- 不適切なコンテンツによる法的リスクを軽減するため。
具体的な実装例
以下のコード例では、message_replaceイベントを処理し、コンテンツが置き換えられた場合にユーザーに通知する方法を示します。
1. チャットコンポーネントの作成
src/components/Chat.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useRef } from 'react';
const Chat = () => {
const [input, setInput] = useState('');
const [messages, setMessages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const abortControllerRef = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
setInput('');
setIsLoading(true);
// AbortControllerのインスタンスを作成
const abortController = new AbortController();
abortControllerRef.current = abortController;
const response = await fetch('https://api.dify.ai/v1/chat-messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {api_key}', // APIキーを追加してください
},
body: JSON.stringify({
query: input,
response_mode: 'streaming',
user: 'user123'
}),
signal: abortController.signal // リクエストにシグナルを追加
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let botMessage = { role: 'bot', content: '' };
reader.read().then(function processText({ done, value }) {
if (done) {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
abortControllerRef.current = null;
return;
}
const chunk = JSON.parse(decoder.decode(value));
if (chunk.event === 'message') {
botMessage.content += chunk.answer;
} else if (chunk.event === 'message_replace') {
botMessage.content = chunk.answer; // メッセージ内容を置き換える
} else if (chunk.event === 'message_end') {
setMessages((prevMessages) => [...prevMessages, botMessage]);
setIsLoading(false);
abortControllerRef.current = null;
}
return reader.read().then(processText);
}).catch((error) => {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Fetch error:', error);
}
setIsLoading(false);
abortControllerRef.current = null;
});
};
const handleAbort = () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort(); // リクエストを中断
setIsLoading(false);
}
};
return (
<div>
<div>
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
{message.content}
</div>
))}
{isLoading && <div className="message bot">...</div>}
</div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="メッセージを入力"
/>
<button type="submit">送信</button>
{isLoading && <button type="button" onClick={handleAbort}>停止</button>}
</form>
</div>
);
};
export default Chat;
2. メインアプリケーションにチャットコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Chat from './components/Chat';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>チャットアプリケーション</h1>
</header>
<Chat />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
.message {
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.message.user {
background-color: #007bff;
color: white;
text-align: left;
}
.message.bot {
background-color: #e0e0e0;
color: black;
text-align: left;
}
まとめ
この例では、message_replaceイベントを使用して、不適切なコンテンツがフラグされた場合にプリセットの返信に置き換える方法を示しました。この機能は、ユーザーの安全性とコンテンツの品質を確保するために重要です。また、AbortControllerを使用することで、ユーザーが望むタイミングでストリーミングを停止することができ、ユーザーエクスペリエンスを向上させることができます。
ワークフロースタートイベント (`workflow_started`)
チャットアプリケーションや自動化ツールにおいて、ワークフローが開始されたことを通知するイベントは重要です。この記事では、ワークフローが開始されたことを示すworkflow_startedイベントについて詳しく説明します。
workflow_startedイベントとは?
workflow_startedイベントは、アプリケーション内でワークフローが実行を開始したことを示すイベントです。このイベントを受信することで、ワークフローの開始を追跡し、必要な処理を行うことができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- workflow_run_id (string): ワークフロー実行の一意のID。
-
event (string): 固定値として
workflow_started。 - data (object): 詳細情報を含むオブジェクト。
- id (string): ワークフロー実行の一意のID。
- workflow_id (string): 関連するワークフローのID。
- sequence_number (int): アプリケーション内で1から始まる自己増加の連番。
- created_at (timestamp): 作成タイムスタンプ(例: 1705395332)。
イベントの構造
以下は、workflow_startedイベントの例です:
data: {"event": "workflow_started", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "workflow_run_id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "data": {"id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "workflow_id": "workflow123", "sequence_number": 1}, "created_at": 1705398420}\n\n
workflow_startedイベントのユースケース
-
ワークフローの開始をログに記録:
- ワークフローがいつ開始されたかを追跡し、ログに記録します。
-
開始時の通知:
- ワークフローの開始時にユーザーやシステム管理者に通知します。
-
初期化処理:
- ワークフロー開始時に必要な初期化処理を実行します。
具体的な実装例
以下のコード例では、workflow_startedイベントを処理し、ワークフローが開始されたことをユーザーに通知する方法を示します。
1. ワークフローコンポーネントの作成
src/components/Workflow.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useEffect } from 'react';
const Workflow = () => {
const [workflows, setWorkflows] = useState([]);
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/workflows');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'workflow_started') {
setWorkflows((prevWorkflows) => [...prevWorkflows, data]);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>ワークフロー一覧</h1>
<ul>
{workflows.map((workflow, index) => (
<li key={index}>
<strong>Workflow ID:</strong> {workflow.data.workflow_id}<br />
<strong>Run ID:</strong> {workflow.workflow_run_id}<br />
<strong>Sequence Number:</strong> {workflow.data.sequence_number}<br />
<strong>Started At:</strong> {new Date(workflow.created_at * 1000).toLocaleString()}
</li>
))}
</ul>
</div>
);
};
export default Workflow;
2. メインアプリケーションにワークフローコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Workflow from './components/Workflow';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>ワークフローアプリケーション</h1>
</header>
<Workflow />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
}
まとめ
この例では、workflow_startedイベントを使用して、ワークフローが開始されたことをリアルタイムで表示する方法を示しました。EventSourceを利用してサーバーからのイベントを受信し、ワークフローの詳細をユーザーに通知することができます。このアプローチにより、ユーザーはワークフローの進行状況をリアルタイムで把握することができます。
ノード実行開始イベント (`node_started`)
チャットアプリケーションや自動化ツールにおいて、ワークフローの各ノードが実行を開始したことを通知するイベントは重要です。この記事では、ノードが実行を開始したことを示すnode_startedイベントについて詳しく説明します。
node_startedイベントとは?
node_startedイベントは、ワークフロー内の特定のノードが実行を開始したことを示すイベントです。このイベントを受信することで、ワークフローの進行状況を詳細に追跡し、各ノードの状態をモニタリングすることができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- workflow_run_id (string): ワークフロー実行の一意のID。
-
event (string): 固定値として
node_started。 - data (object): 詳細情報を含むオブジェクト。
- id (string): ワークフロー実行の一意のID。
- node_id (string): ノードのID。
- node_type (string): ノードの種類。
- title (string): ノードの名前。
- index (int): 実行順序番号。トレースノードの順序を表示するために使用されます。
- predecessor_node_id (string): (オプション)先行ノードID。キャンバス表示の実行パスに使用されます。
- inputs (array[object]): ノードで使用される全ての前ノード変数の内容。
- created_at (timestamp): 開始のタイムスタンプ(例: 1705395332)。
イベントの構造
以下は、node_startedイベントの例です:
data: {"event": "node_started", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "workflow_run_id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "data": {"id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "node_id": "node123", "node_type": "action", "title": "Send Email", "index": 2, "predecessor_node_id": "node122", "inputs": [{"variable": "email", "value": "user@example.com"}]}, "created_at": 1705398420}\n\n
node_startedイベントのユースケース
-
ノードの開始をログに記録:
- ノードがいつ開始されたかを追跡し、ログに記録します。
-
開始時の通知:
- ノードの開始時にユーザーやシステム管理者に通知します。
-
進行状況のモニタリング:
- ワークフロー内の各ノードの進行状況をリアルタイムでモニタリングします。
具体的な実装例
以下のコード例では、node_startedイベントを処理し、ノードが実行を開始したことをユーザーに通知する方法を示します。
1. ノードコンポーネントの作成
src/components/Node.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useEffect } from 'react';
const Node = () => {
const [nodes, setNodes] = useState([]);
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/workflows');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'node_started') {
setNodes((prevNodes) => [...prevNodes, data]);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>ノード実行リスト</h1>
<ul>
{nodes.map((node, index) => (
<li key={index}>
<strong>Node Title:</strong> {node.data.title}<br />
<strong>Node ID:</strong> {node.data.node_id}<br />
<strong>Node Type:</strong> {node.data.node_type}<br />
<strong>Sequence Number:</strong> {node.data.index}<br />
<strong>Started At:</strong> {new Date(node.created_at * 1000).toLocaleString()}
</li>
))}
</ul>
</div>
);
};
export default Node;
2. メインアプリケーションにノードコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Node from './components/Node';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>ワークフローアプリケーション</h1>
</header>
<Node />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
}
まとめ
この例では、node_startedイベントを使用して、ノードが実行を開始したことをリアルタイムで表示する方法を示しました。EventSourceを利用してサーバーからのイベントを受信し、ノードの詳細をユーザーに通知することができます。このアプローチにより、ユーザーはワークフローの進行状況をリアルタイムで把握することができます。
ノード実行完了イベント (`node_finished`)
自動化ワークフローにおいて、各ノードの実行が完了したことを追跡することは重要です。この記事では、ノードが実行を完了したことを示すnode_finishedイベントについて詳しく説明します。
node_finishedイベントとは?
node_finishedイベントは、ワークフロー内の特定のノードが実行を完了したことを示すイベントです。このイベントは、ノードの実行が成功したか失敗したか、またはその他の状態で完了したかを示します。この情報を利用して、ワークフローの進行状況を監視し、必要なアクションを取ることができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- workflow_run_id (string): ワークフロー実行の一意のID。
-
event (string): 固定値として
node_finished。 - data (object): 詳細情報を含むオブジェクト。
- id (string): ワークフロー実行の一意のID。
- node_id (string): ノードのID。
- node_type (string): ノードの種類。
- title (string): ノードの名前。
- index (int): 実行順序番号。トレースノードの順序を表示するために使用されます。
- predecessor_node_id (string): (オプション)先行ノードID。キャンバス表示の実行パスに使用されます。
- inputs (array[object]): ノードで使用される全ての前ノード変数の内容。
- process_data (json): (オプション)ノードの処理データ。
- outputs (json): (オプション)出力内容。
-
status (string): 実行の状態。
running、succeeded、failed、stoppedのいずれか。 - error (string): (オプション)エラーの理由。
- elapsed_time (float): (オプション)実行にかかった総時間(秒)。
- execution_metadata (json): メタデータ。
- total_tokens (int): (オプション)使用されたトークン数。
- total_price (decimal): (オプション)総コスト。
- currency (string): (オプション)通貨(例: USD、RMB)。
- created_at (timestamp): 開始のタイムスタンプ(例: 1705395332)。
イベントの構造
以下は、node_finishedイベントの例です:
data: {"event": "node_finished", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "workflow_run_id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "data": {"id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "node_id": "node123", "node_type": "action", "title": "Send Email", "index": 2, "predecessor_node_id": "node122", "inputs": [{"variable": "email", "value": "user@example.com"}], "status": "succeeded", "outputs": {"result": "Email Sent"}, "created_at": 1705398420}}\n\n
node_finishedイベントのユースケース
-
ノードの完了をログに記録:
- ノードがいつ完了したか、そしてその状態を追跡し、ログに記録します。
-
完了時の通知:
- ノードの完了時にユーザーやシステム管理者に通知します。
-
進行状況のモニタリング:
- ワークフロー内の各ノードの進行状況をリアルタイムでモニタリングし、特定の状態に基づいてアクションをトリガーします。
-
エラーハンドリング:
- ノードが失敗した場合、その理由を記録し、必要なエラーハンドリングを実行します。
具体的な実装例
以下のコード例では、node_finishedイベントを処理し、ノードが実行を完了したことをユーザーに通知する方法を示します。
1. ノードコンポーネントの作成
src/components/Node.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useEffect } from 'react';
const Node = () => {
const [nodes, setNodes] = useState([]);
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/workflows');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'node_finished') {
setNodes((prevNodes) => [...prevNodes, data]);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>ノード実行完了リスト</h1>
<ul>
{nodes.map((node, index) => (
<li key={index}>
<strong>Node Title:</strong> {node.data.title}<br />
<strong>Node ID:</strong> {node.data.node_id}<br />
<strong>Node Type:</strong> {node.data.node_type}<br />
<strong>Sequence Number:</strong> {node.data.index}<br />
<strong>Status:</strong> {node.data.status}<br />
{node.data.status === 'failed' && <strong>Error:</strong> {node.data.error}<br />}
<strong>Elapsed Time:</strong> {node.data.elapsed_time} seconds<br />
<strong>Started At:</strong> {new Date(node.created_at * 1000).toLocaleString()}
</li>
))}
</ul>
</div>
);
};
export default Node;
2. メインアプリケーションにノードコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Node from './components/Node';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>ワークフローアプリケーション</h1>
</header>
<Node />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
}
まとめ
この例では、node_finishedイベントを使用して、ノードが実行を完了したことをリアルタイムで表示する方法を示しました。EventSourceを利用してサーバーからのイベントを受信し、ノードの詳細をユーザーに通知することができます。このアプローチにより、ユーザーはワークフローの進行状況をリアルタイムで把握し、適切なアクションを取ることができます。
ワークフロー実行完了イベント (`workflow_finished`)
ワークフローの全体的な進行状況と完了時の状態を追跡することは、ビジネスプロセスの管理において非常に重要です。この記事では、ワークフローが実行を完了したことを示すworkflow_finishedイベントについて詳しく説明します。
workflow_finishedイベントとは?
workflow_finishedイベントは、ワークフローの全体的な実行が完了したことを示すイベントです。このイベントは、ワークフローの実行が成功したか失敗したか、またはその他の状態で完了したかを示します。この情報を利用して、ワークフローの全体的な進行状況を監視し、必要なアクションを取ることができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- workflow_run_id (string): ワークフロー実行の一意のID。
-
event (string): 固定値として
workflow_finished。 - data (object): 詳細情報を含むオブジェクト。
- id (string): ワークフロー実行の一意のID。
- workflow_id (string): 関連するワークフローのID。
-
status (string): 実行の状態。
running、succeeded、failed、stoppedのいずれか。 - outputs (json): (オプション)出力内容。
- error (string): (オプション)エラーの理由。
- elapsed_time (float): (オプション)実行にかかった総時間(秒)。
- total_tokens (int): (オプション)使用されたトークン数。
- total_steps (int): デフォルトは0。
- created_at (timestamp): 開始時間。
- finished_at (timestamp): 終了時間。
イベントの構造
以下は、workflow_finishedイベントの例です:
data: {"event": "workflow_finished", "task_id": "d3c54a29-2e34-4c4b-81f7-0db0e8f5e708", "workflow_run_id": "b6715f78-2f6d-4cbf-b7a4-f5e4baf1d8b3", "data": {"id": "b6715f78-2f6d-4cbf-b7a4-f5e4baf1d8b3", "workflow_id": "workflow123", "status": "succeeded", "outputs": {"result": "Workflow Completed Successfully"}, "created_at": 1705401840, "finished_at": 1705401900, "elapsed_time": 60}}\n\n
workflow_finishedイベントのユースケース
-
ワークフローの完了をログに記録:
- ワークフローがいつ完了したか、そしてその状態を追跡し、ログに記録します。
-
完了時の通知:
- ワークフローの完了時にユーザーやシステム管理者に通知します。
-
進行状況のモニタリング:
- ワークフロー全体の進行状況をリアルタイムでモニタリングし、特定の状態に基づいてアクションをトリガーします。
-
エラーハンドリング:
- ワークフローが失敗した場合、その理由を記録し、必要なエラーハンドリングを実行します。
具体的な実装例
以下のコード例では、workflow_finishedイベントを処理し、ワークフローが実行を完了したことをユーザーに通知する方法を示します。
1. ワークフローコンポーネントの作成
src/components/Workflow.jsというファイルを作成し、以下のコードを追加します。
import React, { useState, useEffect } from 'react';
const Workflow = () => {
const [workflows, setWorkflows] = useState([]);
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/workflows');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'workflow_finished') {
setWorkflows((prevWorkflows) => [...prevWorkflows, data]);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>ワークフロー実行完了リスト</h1>
<ul>
{workflows.map((workflow, index) => (
<li key={index}>
<strong>Workflow ID:</strong> {workflow.data.workflow_id}<br />
<strong>Status:</strong> {workflow.data.status}<br />
{workflow.data.status === 'failed' && <strong>Error:</strong> {workflow.data.error}<br />}
<strong>Elapsed Time:</strong> {workflow.data.elapsed_time} seconds<br />
<strong>Started At:</strong> {new Date(workflow.data.created_at * 1000).toLocaleString()}<br />
<strong>Finished At:</strong> {new Date(workflow.data.finished_at * 1000).toLocaleString()}
</li>
))}
</ul>
</div>
);
};
export default Workflow;
2. メインアプリケーションにワークフローコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import Workflow from './components/Workflow';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>ワークフローアプリケーション</h1>
</header>
<Workflow />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
}
まとめ
この例では、workflow_finishedイベントを使用して、ワークフローが実行を完了したことをリアルタイムで表示する方法を示しました。EventSourceを利用してサーバーからのイベントを受信し、ワークフローの詳細をユーザーに通知することができます。このアプローチにより、ユーザーはワークフローの進行状況をリアルタイムで把握し、適切なアクションを取ることができます。
エラーイベント (`error`) およびピンイベント (`ping`)
ストリーミングプロセス中に発生する例外や接続の維持に関するイベントは、システムの健全性と信頼性を確保するために重要です。この記事では、errorイベントとpingイベントについて詳しく説明します。
errorイベントとは?
errorイベントは、ストリーミングプロセス中に例外が発生したことを示すイベントです。このイベントを受信すると、ストリームは終了します。エラーの詳細情報を提供することで、トラブルシューティングや適切なエラーハンドリングを行うことができます。
フィールドの説明
- task_id (string): リクエストトラッキング用のタスクID。後述するStop Generate APIで使用されます。
- message_id (string): 一意のメッセージID。
- status (int): HTTPステータスコード。
- code (string): エラーコード。
- message (string): エラーメッセージ。
イベントの構造
以下は、errorイベントの例です:
data: {"event": "error", "task_id": "d3c54a29-2e34-4c4b-81f7-0db0e8f5e708", "message_id": "msg123", "status": 500, "code": "internal_server_error", "message": "An unexpected error occurred"}
errorイベントのユースケース
-
エラーログの記録:
- 発生したエラーの詳細をログに記録し、後からトラブルシューティングを行います。
-
ユーザー通知:
- エラー発生時にユーザーに通知し、適切なフィードバックを提供します。
-
エラーハンドリング:
- エラーの種類に応じた適切なハンドリングを実装し、システムの信頼性を向上させます。
pingイベントとは?
pingイベントは、接続を維持するために10秒ごとに送信されるイベントです。これにより、接続の状態を確認し、タイムアウトを防ぐことができます。
イベントの構造
以下は、pingイベントの例です:
data: {"event": "ping"}
pingイベントのユースケース
-
接続の維持:
- 定期的に送信されることで、接続が確立されたままであることを確認します。
-
接続状態の監視:
-
pingイベントを受信することで、接続が正常であることを確認します。
-
-
タイムアウト防止:
- 長時間の接続でタイムアウトが発生しないようにします。
具体的な実装例
以下のコード例では、errorイベントとpingイベントを処理する方法を示します。
1. イベントハンドラーの作成
src/components/EventHandlers.jsというファイルを作成し、以下のコードを追加します。
import React, { useEffect } from 'react';
const EventHandlers = () => {
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'error') {
console.error(`Error: ${data.message} (Status: ${data.status}, Code: ${data.code})`);
alert(`エラーが発生しました: ${data.message}`);
} else if (data.event === 'ping') {
console.log('Ping received, connection is alive.');
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>イベントハンドラー</h1>
<p>ストリーミングプロセス中のイベントを監視します。</p>
</div>
);
};
export default EventHandlers;
2. メインアプリケーションにイベントハンドラーを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import EventHandlers from './components/EventHandlers';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>イベントハンドラーアプリケーション</h1>
</header>
<EventHandlers />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
p {
font-size: 1.2em;
}
まとめ
この例では、errorイベントとpingイベントを使用して、ストリーミングプロセス中の接続の維持とエラーハンドリングを行う方法を示しました。EventSourceを利用してサーバーからのイベントを受信し、適切なログと通知を行うことで、システムの信頼性とユーザー体験を向上させることができます。
エラーハンドリング
APIを利用する際には、さまざまなエラーが発生する可能性があります。適切なエラーハンドリングを行うことで、ユーザー体験を向上させ、システムの信頼性を保つことができます。この記事では、APIから返される一般的なエラーとその対応方法について説明します。
一般的なエラーとその説明
以下は、APIを利用する際に発生する可能性のある一般的なエラーコードとその説明です。
404: Conversation does not exist
- 説明: 指定された会話が存在しない場合に返されます。
- 対処方法: 正しい会話IDを使用していることを確認します。
400: invalid_param, abnormal parameter input
- 説明: パラメータが無効または異常な入力があった場合に返されます。
- 対処方法: APIドキュメントを参照し、必要なパラメータが正しく入力されていることを確認します。
400: app_unavailable, App configuration unavailable
- 説明: アプリの設定が利用できない場合に返されます。
- 対処方法: アプリの設定が正しく構成されていることを確認します。
400: provider_not_initialize, no available model credential configuration
- 説明: モデルの認証情報が設定されていない場合に返されます。
- 対処方法: 使用するモデルの認証情報が正しく設定されていることを確認します。
400: provider_quota_exceeded, model invocation quota insufficient
- 説明: モデルの呼び出しクォータが不足している場合に返されます。
- 対処方法: モデルのクォータが十分であることを確認し、必要に応じてクォータを追加購入します。
400: model_currently_not_support, current model unavailable
- 説明: 現在のモデルが利用できない場合に返されます。
- 対処方法: 利用可能なモデルを確認し、適切なモデルを使用します。
400: completion_request_error, text generation failed
- 説明: テキスト生成リクエストが失敗した場合に返されます。
- 対処方法: リクエストの内容を確認し、再試行します。
500: internal server error
- 説明: サーバー内部でエラーが発生した場合に返されます。
- 対処方法: サーバーの状態を確認し、問題が解決するまで待機します。再発する場合は、サポートに問い合わせます。
具体的な実装例
以下のコード例では、APIリクエスト中に発生するエラーを処理する方法を示します。
1. APIリクエストとエラーハンドリング
src/components/ApiRequest.jsというファイルを作成し、以下のコードを追加します。
import React, { useState } from 'react';
const ApiRequest = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const handleRequest = async () => {
try {
const res = await fetch('https://api.dify.ai/v1/some-endpoint', {
method: 'GET',
headers: {
'Authorization': 'Bearer {api_key}', // APIキーを追加してください
}
});
if (!res.ok) {
const errorData = await res.json();
throw new Error(`Error ${res.status}: ${errorData.message}`);
}
const data = await res.json();
setResponse(data);
} catch (err) {
setError(err.message);
}
};
return (
<div>
<h1>APIリクエストとエラーハンドリング</h1>
<button onClick={handleRequest}>リクエスト送信</button>
{response && <pre>{JSON.stringify(response, null, 2)}</pre>}
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
};
export default ApiRequest;
2. メインアプリケーションにコンポーネントを追加
src/App.jsファイルを以下のように更新します。
import React from 'react';
import ApiRequest from './components/ApiRequest';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>APIエラーハンドリングアプリケーション</h1>
</header>
<ApiRequest />
</div>
);
}
export default App;
3. スタイリングの追加
src/App.cssファイルに以下のスタイルを追加します。
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
padding: 20px;
color: white;
}
p {
font-size: 1.2em;
color: red;
}
まとめ
この例では、APIリクエスト中に発生する一般的なエラーを処理する方法を示しました。適切なエラーハンドリングを実装することで、ユーザーに対して適切なフィードバックを提供し、システムの信頼性を向上させることができます。エラーメッセージをわかりやすく表示し、必要なアクションを取ることで、問題解決が迅速に行えるようになります。
チャットメッセージ送信APIのリクエストとレスポンスの詳細
このガイドでは、チャットアプリケーションにおけるメッセージ送信API /chat-messages のリクエストとレスポンスについて説明します。具体的なエラーハンドリングの方法や、ストリーミングモードでの実装例も含まれています。
リクエスト
リクエストの構造
以下の例では、curlコマンドを使用してAPIにPOSTリクエストを送信しています。
curl -X POST 'https://api.dify.ai/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}'
リクエストパラメータの説明
- inputs (object): 必要に応じて指定する入力パラメータ。デフォルトは空のオブジェクト。
- query (string): ユーザーからの質問やメッセージの内容。
-
response_mode (string): 応答モード。
streamingかblockingを指定。 - conversation_id (string): 会話ID。省略可。
- user (string): ユーザー識別子。
- files (array[object]): ファイルリスト。画像ファイルのURLを含む。
ストリーミングモードのレスポンス
ストリーミングモードでは、応答が部分的にリアルタイムで返されます。以下のように、イベントごとにデータが送信されます。
イベントの種類と例
workflow_started イベント
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}\n\n
node_started イベント
data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}\n\n
node_finished イベント
data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}\n\n
workflow_finished イベント
data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": 1, "created_at": 1679586595, "finished_at": 1679976595}}\n\n
message イベント
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard
)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}}
エラーハンドリング
ストリーミングプロセス中に発生する可能性のあるエラーと、それに対する対処方法を以下に示します。
一般的なエラーとその説明
- 404: Conversation does not exist: 指定された会話が存在しない。
- 400: invalid_param, abnormal parameter input: パラメータが無効または異常な入力があった。
- 400: app_unavailable, App configuration unavailable: アプリの設定が利用できない。
- 400: provider_not_initialize, no available model credential configuration: モデルの認証情報が設定されていない。
- 400: provider_quota_exceeded, model invocation quota insufficient: モデルの呼び出しクォータが不足している。
- 400: model_currently_not_support, current model unavailable: 現在のモデルが利用できない。
- 400: completion_request_error, text generation failed: テキスト生成リクエストが失敗した。
- 500: internal server error: サーバー内部でエラーが発生した。
エラーイベントの処理
以下のコード例では、errorイベントを処理し、適切なエラーメッセージを表示する方法を示します。
import React, { useState, useEffect } from 'react';
const EventHandlers = () => {
const [events, setEvents] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const eventSource = new EventSource('https://api.dify.ai/v1/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event === 'error') {
console.error(`Error: ${data.message} (Status: ${data.status}, Code: ${data.code})`);
setError(`エラーが発生しました: ${data.message}`);
} else if (data.event === 'ping') {
console.log('Ping received, connection is alive.');
} else {
setEvents((prevEvents) => [...prevEvents, data]);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
setError('接続中にエラーが発生しました。');
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>イベントハンドラー</h1>
<ul>
{events.map((event, index) => (
<li key={index}>
<strong>Event:</strong> {event.event}<br />
<strong>Data:</strong> {JSON.stringify(event.data)}
</li>
))}
</ul>
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
};
export default EventHandlers;
まとめ
このガイドでは、チャットメッセージ送信APIのリクエストとレスポンスの詳細、およびエラーハンドリングの方法について説明しました。適切なエラーハンドリングを実装することで、ユーザーに対して適切なフィードバックを提供し、システムの信頼性を向上させることができます。また、ストリーミングモードでのリアルタイムな応答処理により、ユーザーエクスペリエンスを向上させることができます。
ストリーミングモードのレスポンスの具体例
ストリーミングモードのレスポンスは、APIやサービスからリアルタイムで部分的にデータが送信される方法です。これは、ユーザーがすぐにデータを受け取り始めることができるため、応答の待ち時間を短縮し、インタラクティブな体験を提供するのに役立ちます。以下に、具体的なイベントの種類とその意味、またそれをどのように処理するかについて説明します。
イベントの種類とその意味
-
workflow_started イベント:
- 意味: ワークフローが開始されたことを示します。
- 例:
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
-
node_started イベント:
- 意味: ワークフローの特定のノード(ステップ)が開始されたことを示します。
- 例:
data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
-
node_finished イベント:
- 意味: ワークフローの特定のノード(ステップ)が完了したことを示します。
- 例:
data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
-
workflow_finished イベント:
- 意味: ワークフローが完了したことを示します。
- 例:
data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": 1, "created_at": 1679586595, "finished_at": 1679976595}}
-
message イベント:
- 意味: メッセージの一部が送信されたことを示します。このイベントは、メッセージが部分的に送信される際に複数回発生します。
- 例:
data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595} data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595} data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
-
message_end イベント:
- 意味: メッセージの送信が完了したことを示します。
- 例:
data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}}
ストリーミングモードのレスポンスを処理する方法
ストリーミングモードのレスポンスを処理するには、EventSourceを使用してリアルタイムでデータを受信し、各イベントに対して適切なアクションを実行します。以下は、Reactを使った例です。
import React, { useState, useEffect } from 'react';
const StreamingResponseHandler = () => {
const [events, setEvents] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const eventSource = new EventSource('https://api.example.com/stream');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.event) {
case 'workflow_started':
console.log('Workflow started:', data);
break;
case 'node_started':
console.log('Node started:', data);
break;
case 'node_finished':
console.log('Node finished:', data);
break;
case 'workflow_finished':
console.log('Workflow finished:', data);
break;
case 'message':
console.log('Message:', data);
setEvents((prevEvents) => [...prevEvents, data.answer]);
break;
case 'message_end':
console.log('Message end:', data);
break;
default:
console.warn('Unknown event:', data);
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
setError('接続中にエラーが発生
しました。');
eventSource.close();
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<h1>ストリーミングレスポンスハンドラー</h1>
{error && <p style={{ color: 'red' }}>{error}</p>}
<ul>
{events.map((event, index) => (
<li key={index}>{event}</li>
))}
</ul>
</div>
);
};
export default StreamingResponseHandler;
まとめ
ストリーミングモードのレスポンスは、リアルタイムでデータを受信するために使用されます。各イベントに対して適切な処理を実装することで、ワークフローの進行状況やメッセージの部分的な応答をリアルタイムでユーザーに提供できます。Reactを使った例では、EventSourceを利用してイベントを受信し、各イベントに応じた処理を行います。これにより、ユーザーは即座にフィードバックを得ることができ、インタラクティブな体験を提供できます。