{
  "name": "Customer Embedding RAG Chat (Webhook-based)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "customer-embedding-chat",
        "responseMode": "responseNode",
        "options": {
          "binaryPropertyName": "data"
        }
      },
      "id": "webhook-trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract and validate chat input from webhook\nconst body = $json.body || $json;\nconst chatInput = body.chatInput || body.message;\nconst sessionId = body.sessionId || `session-${Date.now()}`;\nconst metadata = body.metadata || {};\n\n// Validate required fields\nif (!chatInput) {\n  throw new Error('chatInput is required');\n}\n\nif (!metadata.customerId) {\n  throw new Error('customerId is required in metadata');\n}\n\n// Extract customer information\nconst customerId = metadata.customerId;\nconst widgetId = metadata.widgetId || 'default';\nconst companyName = metadata.companyName || '';\n\n// Prepare for vector search\nreturn [{\n  json: {\n    chatInput,\n    sessionId,\n    customerId,\n    widgetId,\n    companyName,\n    metadata,\n    timestamp: new Date().toISOString(),\n    // Chat context for webhook response\n    isWebhookChat: true,\n    responseFormat: 'json'\n  }\n}];"
      },
      "id": "extract-webhook-data",
      "name": "Extract Webhook Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/embeddings",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.OPENAI_API_KEY }}"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "text-embedding-ada-002"
            },
            {
              "name": "input",
              "value": "={{ $json.chatInput }}"
            }
          ]
        },
        "options": {
          "timeout": 30000
        }
      },
      "id": "generate-query-embedding",
      "name": "Generate Query Embedding",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM search_customer_embeddings(\n  ARRAY{{ $json.data[0].embedding }}::vector(1536),\n  '{{ $('Extract Webhook Data').item(0).json.customerId }}',\n  0.7,\n  5\n);",
        "additionalFields": {}
      },
      "id": "vector-search",
      "name": "Vector Search Documents",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        900,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Build RAG context from search results\nconst searchResults = $json;\nconst chatData = $('Extract Webhook Data').item(0).json;\nconst embeddingData = $('Generate Query Embedding').item(0).json;\n\n// Process search results\nlet contextText = '';\nlet sourceCount = 0;\nlet hasRelevantContent = false;\n\nif (searchResults && Array.isArray(searchResults) && searchResults.length > 0) {\n  sourceCount = searchResults.length;\n  hasRelevantContent = true;\n  \n  // Build context from search results\n  const contexts = searchResults.map(result => {\n    const similarity = Math.round((result.similarity || 0) * 100);\n    return `[Kaynak ${similarity}% benzerlik]: ${result.content}`;\n  });\n  \n  contextText = contexts.join('\\n\\n');\n} else {\n  contextText = 'Belirli bir kaynak bulunamad\u0131. Genel bilgilerimle yan\u0131tlayaca\u011f\u0131m.';\n}\n\n// Prepare context for AI\nconst systemPrompt = `Sen ${chatData.companyName || '\u015firketin'} m\u00fc\u015fteri hizmetleri asistan\u0131s\u0131n. T\u00fcrk\u00e7e yan\u0131t ver.\n\nMevcut bilgiler:\n${contextText}\n\nKullan\u0131c\u0131 sorusu: ${chatData.chatInput}\n\nYan\u0131t\u0131n:\n- T\u00fcrk\u00e7e olmal\u0131\n- Dostane ve profesyonel ton kullan\n- Mevcut bilgilere dayal\u0131 yan\u0131t ver\n- E\u011fer bilgi yoksa, nazik\u00e7e belirt`;\n\nreturn [{\n  json: {\n    systemPrompt,\n    userQuery: chatData.chatInput,\n    contextText,\n    hasRelevantContent,\n    sourceCount,\n    searchResultCount: sourceCount,\n    customerId: chatData.customerId,\n    widgetId: chatData.widgetId,\n    sessionId: chatData.sessionId,\n    timestamp: chatData.timestamp,\n    tokensUsed: embeddingData.usage?.total_tokens || 0\n  }\n}];"
      },
      "id": "build-rag-context",
      "name": "Build RAG Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Bearer {{ $env.OPENAI_API_KEY }}"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "gpt-3.5-turbo"
            },
            {
              "name": "messages",
              "value": "={{ [{ \"role\": \"system\", \"content\": $json.systemPrompt }] }}"
            },
            {
              "name": "max_tokens",
              "value": 500
            },
            {
              "name": "temperature",
              "value": 0.7
            }
          ]
        },
        "options": {
          "timeout": 60000
        }
      },
      "id": "generate-ai-response",
      "name": "Generate AI Response",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format final webhook response\nconst aiResponse = $json;\nconst contextData = $('Build RAG Context').item(0).json;\nconst chatData = $('Extract Webhook Data').item(0).json;\n\n// Extract AI response text\nconst responseText = aiResponse.choices?.[0]?.message?.content || '\u00dczg\u00fcn\u00fcm, yan\u0131t olu\u015fturamad\u0131m.';\n\n// Generate follow-up prompts based on context\nconst followUpPrompts = [];\nif (contextData.hasRelevantContent) {\n  followUpPrompts.push(\n    'Bu konuda daha detayl\u0131 bilgi alabilir miyim?',\n    'Ba\u015fka hangi konularda yard\u0131mc\u0131 olabilirsiniz?',\n    'Bu bilgiyle ilgili \u00f6rnek verebilir misiniz?'\n  );\n} else {\n  followUpPrompts.push(\n    'Ba\u015fka bir konuda yard\u0131m edebilir misiniz?',\n    'Size hangi konularda soru sorabilirim?',\n    'Daha spesifik bir soru sorabilir miyim?'\n  );\n}\n\n// Prepare webhook response (ChatTrigger format compatible)\nconst webhookResponse = {\n  output: responseText,\n  followUpPrompts: followUpPrompts,\n  metadata: {\n    sessionId: chatData.sessionId,\n    customerId: chatData.customerId,\n    widgetId: chatData.widgetId,\n    hasRelevantContent: contextData.hasRelevantContent,\n    sourceCount: contextData.sourceCount,\n    responseTime: Date.now() - new Date(chatData.timestamp).getTime(),\n    tokensUsed: (contextData.tokensUsed || 0) + (aiResponse.usage?.total_tokens || 0),\n    timestamp: new Date().toISOString(),\n    // Webhook specific\n    responseType: 'webhook-chat',\n    success: true\n  }\n};\n\nreturn [{ json: webhookResponse }];"
      },
      "id": "format-webhook-response",
      "name": "Format Webhook Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1560,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "id": "webhook-response",
      "name": "Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1780,
        300
      ]
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract Webhook Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Webhook Data": {
      "main": [
        [
          {
            "node": "Generate Query Embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Query Embedding": {
      "main": [
        [
          {
            "node": "Vector Search Documents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vector Search Documents": {
      "main": [
        [
          {
            "node": "Build RAG Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build RAG Context": {
      "main": [
        [
          {
            "node": "Generate AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI Response": {
      "main": [
        [
          {
            "node": "Format Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Webhook Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true
  },
  "staticData": {},
  "tags": [],
  "triggerCount": 1,
  "updatedAt": "2025-09-29T15:17:43.099Z",
  "versionId": "1.0"
}