{
  "name": "Polish AI RAG - Direct Qdrant (NO HF Space)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "rag-agent",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "webhook-1",
      "name": "Webhook: RAG Question",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "model": "anthropic/claude-3.5-sonnet",
        "options": {
          "baseURL": "https://openrouter.ai/api/v1",
          "temperature": 0.3
        }
      },
      "id": "openrouter-analyze",
      "name": "OpenRouter: Analyze Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        560,
        420
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "description": "Analyzes the user question and determines optimal top_k value (10-15)",
        "jsCode": "const question = $fromAI('question', 'User question', 'string');\nconst lowerQ = question.toLowerCase();\nconst result = { query: question, top_k: 10 };\nif (lowerQ.includes('szczeg\u00f3\u0142') || lowerQ.includes('jak')) result.top_k = 15;\nelse if (lowerQ.includes('przyk\u0142ad')) result.top_k = 12;\nreturn JSON.stringify(result, null, 2);"
      },
      "id": "code-tool-params",
      "name": "Code Tool: Build Parameters",
      "type": "@n8n/n8n-nodes-langchain.toolCode",
      "typeVersion": 1.3,
      "position": [
        680,
        420
      ]
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"query\": {\"type\": \"string\"},\n    \"top_k\": {\"type\": \"number\"}\n  },\n  \"required\": [\"query\", \"top_k\"]\n}"
      },
      "id": "output-parser",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        800,
        420
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.body.question }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "Jeste\u015b ekspertem analizy zapyta\u0144 u\u017cytkownik\u00f3w dla systemu RAG. Przeanalizuj pytanie i u\u017cyj narz\u0119dzia Build Parameters aby okre\u015bli\u0107 liczb\u0119 wynik\u00f3w (top_k: 10-15). Zwr\u00f3\u0107 JSON z query i top_k."
        }
      },
      "id": "agent-analyze",
      "name": "AI Agent: Analyze Question",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        480,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://router.huggingface.co/models/nomic-ai/nomic-embed-text-v1.5",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ \"Bearer \" + $env.HF_API_TOKEN }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"inputs\": \"search_query: \" + $json.output.query } }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 30000
        }
      },
      "id": "http-embedding",
      "name": "HTTP: Generate Embedding",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        720,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Przygotuj query dla Qdrant API\nconst embedding = $input.item.json;\nconst params = $('AI Agent: Analyze Question').item.json.output;\n\n// HF API zwraca embedding jako array lub nested array\nconst vector = Array.isArray(embedding[0]) ? embedding[0] : embedding;\n\n// Buduj Qdrant search request\nconst qdrantQuery = {\n  vector: {\n    name: \"dense\",\n    vector: vector\n  },\n  limit: params.top_k || 10,\n  with_payload: true,\n  score_threshold: 0.5\n};\n\nreturn {\n  json: {\n    qdrantQuery,\n    originalQuestion: $('Webhook: RAG Question').item.json.body.question,\n    top_k: params.top_k\n  }\n};"
      },
      "id": "code-prepare-qdrant",
      "name": "Code: Prepare Qdrant Query",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.QDRANT_URL }}/collections/wordpress_articles/points/search",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "api-key",
              "value": "={{ $env.QDRANT_API_KEY }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.qdrantQuery }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 60000
        }
      },
      "id": "http-qdrant",
      "name": "HTTP: Qdrant Search",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        1200,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format Qdrant results do formatu dla LLM\nconst response = $input.item.json;\nconst originalQuestion = $('Code: Prepare Qdrant Query').item.json.originalQuestion;\n\n// Sprawd\u017a czy s\u0105 wyniki\nif (!response || !response.result || response.result.length === 0) {\n  return {\n    json: {\n      context: 'Brak wynik\u00f3w. System RAG nie znalaz\u0142 odpowiednich artyku\u0142\u00f3w.',\n      hasResults: false,\n      resultCount: 0,\n      results: [],\n      originalQuestion\n    }\n  };\n}\n\nconst results = response.result;\n\n// Buduj formatowany kontekst\nlet context = `Znaleziono ${results.length} wynik\u00f3w z bazy wiedzy:\\n\\n`;\n\nconst formattedResults = [];\n\nresults.forEach((hit, index) => {\n  const payload = hit.payload || {};\n  \n  context += `--- Wynik ${index + 1} (Score: ${(hit.score * 100).toFixed(1)}%) ---\\n`;\n  context += `Tytu\u0142: ${payload.title || 'Brak tytu\u0142u'}\\n`;\n  context += `URL: ${payload.url || ''}\\n`;\n  context += `Typ sekcji: ${payload.section_type || 'content'}\\n`;\n  \n  if (payload.publication_date) {\n    context += `Data publikacji: ${payload.publication_date}\\n`;\n  }\n  \n  if (payload.tags && payload.tags.length > 0) {\n    context += `Tagi: ${payload.tags.join(', ')}\\n`;\n  }\n  \n  if (payload.categories && payload.categories.length > 0) {\n    context += `Kategorie: ${payload.categories.join(', ')}\\n`;\n  }\n  \n  context += `\\nTre\u015b\u0107:\\n${payload.text || ''}\\n\\n`;\n  \n  // Zapisz dla sources array\n  formattedResults.push({\n    title: payload.title || 'Brak tytu\u0142u',\n    url: payload.url || '',\n    score: hit.score,\n    text: payload.text || '',\n    section_type: payload.section_type || 'content'\n  });\n});\n\nreturn {\n  json: {\n    context,\n    hasResults: true,\n    resultCount: results.length,\n    results: formattedResults,\n    originalQuestion\n  }\n};"
      },
      "id": "code-format-results",
      "name": "Code: Format Qdrant Results",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        300
      ]
    },
    {
      "parameters": {
        "model": "anthropic/claude-3.5-sonnet",
        "options": {
          "baseURL": "https://openrouter.ai/api/v1",
          "temperature": 0.5
        }
      },
      "id": "openrouter-answer",
      "name": "OpenRouter: Answer Generator",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1800,
        420
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('Code: Format Qdrant Results').item.json.originalQuestion }}",
        "options": {
          "systemMessage": "Jeste\u015b pomocnym asystentem AI, kt\u00f3ry odpowiada na pytania u\u017cytkownik\u00f3w w j\u0119zyku polskim na podstawie kontekstu z bazy wiedzy RAG.\\n\\n=== PYTANIE U\u017bYTKOWNIKA ===\\n{{ $('Code: Format Qdrant Results').item.json.originalQuestion }}\\n\\n=== KONTEKST Z BAZY WIEDZY ===\\n{{ $('Code: Format Qdrant Results').item.json.context }}\\n\\n=== INSTRUKCJE ===\\n1. Odpowiedz zwi\u0119\u017ale i konkretnie w j\u0119zyku polskim\\n2. Bazuj TYLKO na dostarczonym kontek\u015bcie\\n3. Cytuj \u017ar\u00f3d\u0142a - podawaj tytu\u0142y artyku\u0142\u00f3w i linki\\n4. Uwzgl\u0119dnij score i daty publikacji\\n5. Je\u015bli brak odpowiedzi, powiedz wprost i zasugeruj przeformu\u0142owanie\\n6. U\u017cywaj formatowania markdown\\n7. Wyr\u00f3\u017cnij checklisty i key insights\\n\\nOdpowiedz teraz:"
        }
      },
      "id": "agent-answer",
      "name": "AI Agent: Generate Answer",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1680,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ {\n  \"question\": $('Code: Format Qdrant Results').item.json.originalQuestion,\n  \"answer\": $json.output,\n  \"sources\": $('Code: Format Qdrant Results').item.json.results.map(r => ({\"title\": r.title, \"url\": r.url, \"score\": r.score})),\n  \"sources_count\": $('Code: Format Qdrant Results').item.json.resultCount,\n  \"has_results\": $('Code: Format Qdrant Results').item.json.hasResults\n} }}",
        "options": {}
      },
      "id": "respond",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1920,
        300
      ]
    }
  ],
  "connections": {
    "Webhook: RAG Question": {
      "main": [
        [
          {
            "node": "AI Agent: Analyze Question",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter: Analyze Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Analyze Question",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code Tool: Build Parameters": {
      "ai_tool": [
        [
          {
            "node": "AI Agent: Analyze Question",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent: Analyze Question",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Analyze Question": {
      "main": [
        [
          {
            "node": "HTTP: Generate Embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: Generate Embedding": {
      "main": [
        [
          {
            "node": "Code: Prepare Qdrant Query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Prepare Qdrant Query": {
      "main": [
        [
          {
            "node": "HTTP: Qdrant Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: Qdrant Search": {
      "main": [
        [
          {
            "node": "Code: Format Qdrant Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Format Qdrant Results": {
      "main": [
        [
          {
            "node": "AI Agent: Generate Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter: Answer Generator": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Generate Answer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Generate Answer": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "direct-qdrant-v1"
}