Dify Chat API 統合ガイド

Dify Chat API との統合に関する実践的なガイド。Node.js と curl の動作確認済みサンプルコードで、チャットボットや対話型 AI アプリケーションを構築できます。

このガイドでは、Dify Chat App API との統合に必要な、検証済みの動作するコード例を提供します。メッセージの送信、ストリーミングレスポンスの処理、会話の管理方法を学びます。

前提条件

開始する前に、以下が必要です:

  • Dify API キー(Dify アプリケーション設定から取得)
  • Base URL:https://api.dify.ai/v1(またはセルフホストインスタンスの URL)

認証

すべての API リクエストには、Authorization ヘッダーによる認証が必要です:

Authorization: Bearer {YOUR_API_KEY}

[!IMPORTANT] API キーはサーバーサイドにのみ保存してください。クライアントサイドのコードや公開リポジトリに公開しないでください。


チャットメッセージの送信

/chat-messages エンドポイントは、対話型インタラクションのコア API です。

ブロッキングモード

処理完了後に完全なレスポンスを返します。シンプルな統合に最適です。

curl の例:

curl -X POST 'https://api.dify.ai/v1/chat-messages' \
  --header 'Authorization: Bearer {YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "inputs": {},
    "query": "Dify とは何ですか?",
    "response_mode": "blocking",
    "conversation_id": "",
    "user": "user-123"
  }'

Node.js の例:

// sendMessage.js - チャットメッセージの送信(ブロッキングモード)
const DIFY_API_KEY = process.env.DIFY_API_KEY;
const DIFY_BASE_URL = 'https://api.dify.ai/v1';

async function sendMessage(query, conversationId = '', userId = 'user-123') {
  const response = await fetch(`${DIFY_BASE_URL}/chat-messages`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${DIFY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      inputs: {},
      query,
      response_mode: 'blocking',
      conversation_id: conversationId,
      user: userId,
    }),
  });

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return await response.json();
}

// 使用例
const result = await sendMessage('Dify とは何ですか?');
console.log('回答:', result.answer);
console.log('会話 ID:', result.conversation_id);

レスポンス例:

{
  "event": "message",
  "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
  "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
  "answer": "Dify はオープンソースの LLM アプリ開発プラットフォームです...",
  "created_at": 1705407629,
  "metadata": {
    "usage": {
      "total_tokens": 219,
      "total_price": "0.0001395"
    }
  }
}

ストリーミングモード(推奨)

Server-Sent Events (SSE) を介してレスポンスチャンクを返します。リアルタイムのタイプライター効果を提供します。

curl の例:

curl -N -X POST 'https://api.dify.ai/v1/chat-messages' \
  --header 'Authorization: Bearer {YOUR_API_KEY}' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "inputs": {},
    "query": "Dify とは何ですか?",
    "response_mode": "streaming",
    "conversation_id": "",
    "user": "user-123"
  }'

Node.js の例:

// streamMessage.js - ストリーミングレスポンス処理
const DIFY_API_KEY = process.env.DIFY_API_KEY;
const DIFY_BASE_URL = 'https://api.dify.ai/v1';

async function streamMessage(query, conversationId = '', userId = 'user-123') {
  const response = await fetch(`${DIFY_BASE_URL}/chat-messages`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${DIFY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      inputs: {},
      query,
      response_mode: 'streaming',
      conversation_id: conversationId,
      user: userId,
    }),
  });

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let fullAnswer = '';
  let convId = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split('\n').filter(line => line.startsWith('data:'));

    for (const line of lines) {
      try {
        const data = JSON.parse(line.slice(5));
        
        if (data.event === 'message') {
          // 各チャンクをリアルタイムで出力
          process.stdout.write(data.answer);
          fullAnswer += data.answer;
          convId = data.conversation_id;
        } else if (data.event === 'message_end') {
          console.log('\n--- ストリーム終了 ---');
          console.log('トークン使用量:', data.metadata?.usage);
        } else if (data.event === 'error') {
          throw new Error(data.message);
        }
      } catch (e) {
        // パースエラーを無視(ping イベントの可能性)
      }
    }
  }

  return { answer: fullAnswer, conversationId: convId };
}

// 使用例
const result = await streamMessage('AI を簡単に説明してください');
console.log('完全な回答:', result.answer);

会話リストの取得

ユーザーの会話リストを取得します。

curl の例:

curl -X GET 'https://api.dify.ai/v1/conversations?user=user-123&limit=20' \
  --header 'Authorization: Bearer {YOUR_API_KEY}'

Node.js の例:

// getConversations.js - 会話リストの取得
async function getConversations(userId = 'user-123', limit = 20) {
  const params = new URLSearchParams({ user: userId, limit: limit.toString() });
  
  const response = await fetch(`${DIFY_BASE_URL}/conversations?${params}`, {
    headers: {
      'Authorization': `Bearer ${DIFY_API_KEY}`,
    },
  });

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return await response.json();
}

// 使用例
const conversations = await getConversations();
console.log('会話リスト:', conversations.data);

レスポンス例:

{
  "limit": 20,
  "has_more": false,
  "data": [
    {
      "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
      "name": "新しいチャット",
      "status": "normal",
      "created_at": 1679667915,
      "updated_at": 1679667915
    }
  ]
}

メッセージ履歴の取得

特定の会話のチャット履歴を取得します。

curl の例:

curl -X GET 'https://api.dify.ai/v1/messages?user=user-123&conversation_id={CONVERSATION_ID}&limit=20' \
  --header 'Authorization: Bearer {YOUR_API_KEY}'

Node.js の例:

// getMessages.js - メッセージ履歴の取得
async function getMessages(conversationId, userId = 'user-123', limit = 20) {
  const params = new URLSearchParams({
    user: userId,
    conversation_id: conversationId,
    limit: limit.toString(),
  });

  const response = await fetch(`${DIFY_BASE_URL}/messages?${params}`, {
    headers: {
      'Authorization': `Bearer ${DIFY_API_KEY}`,
    },
  });

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return await response.json();
}

// 使用例
const messages = await getMessages('your-conversation-id');
for (const msg of messages.data) {
  console.log(`Q: ${msg.query}`);
  console.log(`A: ${msg.answer}\n`);
}

会話の継続

前のメッセージの conversation_id を渡すことで、会話のコンテキストを維持できます:

// 会話継続の例
let conversationId = '';

// 最初のメッセージ
const first = await sendMessage('機械学習について教えてください');
conversationId = first.conversation_id;

// 後続のメッセージはコンテキストを記憶
const followUp = await sendMessage('ディープラーニングとの違いは?', conversationId);
console.log(followUp.answer); // AI は以前の機械学習の議論を覚えています

ファイルアップロード

ファイル入力(画像、ドキュメント)が必要なアプリケーションには、Dify がファイルアップロード API を提供しています:

  1. ファイルをアップロードPOST /files/uploadmultipart/form-data で使用
  2. ファイルを参照:返された upload_file_id をチャットメッセージで使用

[!TIP] ファイルアップロードは主に、画像を分析できるビジョン対応モデル(GPT-4V など)で使用されます。対応フォーマットには PNG、JPG、JPEG、WEBP、GIF が含まれます。

詳細なファイルアップロードの実装については、Dify 公式 API ドキュメントを参照してください。


エラー処理

一般的なエラーコードと対処法:

ステータスエラーコード説明解決策
400invalid_param無効なパラメータリクエストボディの形式を確認
400provider_quota_exceededモデルクォータ超過API クレジットを確認
400model_currently_not_supportモデル利用不可別のモデルを使用
404conversation_not_exists会話が見つからない新しい会話を開始
500internal_server_errorサーバーエラー遅延後に再試行

Node.js エラー処理の例:

// errorHandling.js - エラー処理の例
async function safeSendMessage(query, conversationId = '') {
  try {
    return await sendMessage(query, conversationId);
  } catch (error) {
    if (error.message.includes('429')) {
      console.log('レート制限中。再試行前に待機...');
      await new Promise(r => setTimeout(r, 5000));
      return await sendMessage(query, conversationId);
    }
    
    if (error.message.includes('404')) {
      console.log('会話が見つかりません。新しい会話を開始...');
      return await sendMessage(query, '');
    }
    
    throw error;
  }
}

完全な例

以下は完全な Node.js チャットクライアントです:

// difyClient.js - 完全な Dify Chat クライアント
class DifyClient {
  constructor(apiKey, baseUrl = 'https://api.dify.ai/v1') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  async chat(query, conversationId = '', user = 'default-user', streaming = false) {
    const response = await fetch(`${this.baseUrl}/chat-messages`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        inputs: {},
        query,
        response_mode: streaming ? 'streaming' : 'blocking',
        conversation_id: conversationId,
        user,
      }),
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message || `HTTP ${response.status}`);
    }

    if (streaming) {
      return this._handleStream(response);
    }

    return await response.json();
  }

  async *_handleStream(response) {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const lines = decoder.decode(value).split('\n');
      for (const line of lines) {
        if (line.startsWith('data:')) {
          try {
            yield JSON.parse(line.slice(5));
          } catch (e) {}
        }
      }
    }
  }

  async getConversations(user = 'default-user', limit = 20) {
    const params = new URLSearchParams({ user, limit: String(limit) });
    const response = await fetch(`${this.baseUrl}/conversations?${params}`, {
      headers: { 'Authorization': `Bearer ${this.apiKey}` },
    });
    return await response.json();
  }

  async getMessages(conversationId, user = 'default-user', limit = 20) {
    const params = new URLSearchParams({ user, conversation_id: conversationId, limit: String(limit) });
    const response = await fetch(`${this.baseUrl}/messages?${params}`, {
      headers: { 'Authorization': `Bearer ${this.apiKey}` },
    });
    return await response.json();
  }
}

// 使用例
const client = new DifyClient(process.env.DIFY_API_KEY);

// ブロッキングモード
const result = await client.chat('こんにちは!');
console.log(result.answer);

// ストリーミングモード
for await (const chunk of await client.chat('物語を聞かせて', '', 'user-1', true)) {
  if (chunk.event === 'message') {
    process.stdout.write(chunk.answer);
  }
}

次のステップ