{
  "name": "Bestpass - Vector Store Ingest",
  "nodes": [
    {
      "parameters": {
        "path": "upload-kb",
        "formTitle": "Upload Knowledge Base",
        "formDescription": "Faça upload do arquivo de conhecimento da Bestpass (.txt, .docx, .pdf)",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Arquivo da Base de Conhecimento",
              "fieldType": "file",
              "requiredField": true
            }
          ]
        },
        "options": {
          "respondWithOptions": {
            "values": {
              "respondWith": "text",
              "formSubmittedText": "✅ Arquivo enviado! Processando..."
            }
          }
        }
      },
      "id": "form-trigger",
      "name": "Formulário de Upload",
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.1,
      "position": [
        240,
        300
      ],
      "webhookId": "bestpass-kb-upload"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "file_id",
              "name": "file_id",
              "value": "={{ $json.file_name || 'bestpass-kb-' + Date.now() }}",
              "type": "string"
            },
            {
              "id": "file_extension",
              "name": "file_extension",
              "value": "={{ $json.file_name ? $json.file_name.split('.').pop().toLowerCase() : 'txt' }}",
              "type": "string"
            },
            {
              "id": "category",
              "name": "category",
              "value": "bestpass_kb",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "extract-metadata",
      "name": "Extrair Metadados",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "operation": "delete",
        "tableId": "documents",
        "filterType": "string",
        "filterString": "=metadata->>category=eq.bestpass_kb"
      },
      "id": "delete-old-docs",
      "name": "Limpar Documentos Antigos",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        680,
        300
      ],
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "id": "SUA_CREDENCIAL_SUPABASE",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "pdf-condition",
              "leftValue": "={{ $json.file_extension }}",
              "rightValue": "pdf",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-file-type",
      "name": "Detectar Tipo de Arquivo",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.1,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "operation": "pdf",
        "options": {}
      },
      "id": "extract-pdf",
      "name": "Extrair Texto PDF",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        1120,
        200
      ]
    },
    {
      "parameters": {
        "operation": "text",
        "options": {}
      },
      "id": "extract-text",
      "name": "Extrair Texto TXT/DOCX",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        1120,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "// Processar arquivo JSONL (um JSON por linha)\nconst input = $input.item(0);\nconst fileContent = input.json.data || input.binary.data.toString('utf-8');\n\nconst lines = fileContent.split('\\n').filter(line => line.trim());\nconst documents = [];\n\nfor (const line of lines) {\n  try {\n    // Tentar parsear como JSON\n    const obj = JSON.parse(line);\n    \n    // Formato esperado: {category, question, answer, keywords}\n    if (obj.question && obj.answer) {\n      const content = `Pergunta: ${obj.question}\\nResposta: ${obj.answer}`;\n      \n      documents.push({\n        json: {\n          pageContent: content,\n          metadata: {\n            category: obj.category || 'geral',\n            question: obj.question,\n            answer: obj.answer,\n            keywords: obj.keywords || [],\n            source: 'bestpass_kb'\n          }\n        }\n      });\n    }\n  } catch (e) {\n    // Se não for JSON, tratar como texto plano estruturado\n    continue;\n  }\n}\n\n// Se não conseguiu processar como JSONL, processar como texto plano\nif (documents.length === 0) {\n  // Dividir por separador ---\n  const blocks = fileContent.split(/\\n---+\\n/).filter(b => b.trim());\n  \n  for (const block of blocks) {\n    const lines = block.split('\\n').filter(l => l.trim());\n    let question = '';\n    let answer = '';\n    let category = 'geral';\n    let keywords = [];\n    \n    for (const line of lines) {\n      if (line.startsWith('Pergunta:')) {\n        question = line.replace('Pergunta:', '').trim();\n      } else if (line.startsWith('Resposta:')) {\n        answer = line.replace('Resposta:', '').trim();\n      } else if (line.startsWith('Categoria:')) {\n        category = line.replace('Categoria:', '').trim();\n      } else if (line.startsWith('Palavras-chave:')) {\n        keywords = line.replace('Palavras-chave:', '').trim().split(',').map(k => k.trim());\n      }\n    }\n    \n    if (question && answer) {\n      const content = `Pergunta: ${question}\\nResposta: ${answer}`;\n      documents.push({\n        json: {\n          pageContent: content,\n          metadata: {\n            category: category,\n            question: question,\n            answer: answer,\n            keywords: keywords,\n            source: 'bestpass_kb'\n          }\n        }\n      });\n    }\n  }\n}\n\nreturn documents;"
      },
      "id": "process-jsonl",
      "name": "Processar JSONL/Estruturado",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        600
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "combinationMode": "multiplex",
        "options": {}
      },
      "id": "merge-extracted",
      "name": "Merge Textos Extraídos",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "format-content",
              "name": "pageContent",
              "value": "={{ $json.data || $json.pageContent }}",
              "type": "string"
            },
            {
              "id": "set-metadata",
              "name": "metadata",
              "value": "={{ $json.metadata || { source: 'bestpass_kb', category: 'geral' } }}",
              "type": "object"
            }
          ]
        },
        "options": {}
      },
      "id": "format-documents",
      "name": "Formatar Documentos",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1560,
        300
      ]
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "embeddings",
      "name": "Azure OpenAI Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsAzureOpenAi",
      "typeVersion": 1,
      "position": [
        1780,
        500
      ],
      "credentials": {
        "azureOpenAiApi": {
          "id": "SUA_CREDENCIAL_AZURE",
          "name": "Azure OpenAI account"
        }
      }
    },
    {
      "parameters": {
        "chunkSize": 5000,
        "chunkOverlap": 0
      },
      "id": "text-splitter",
      "name": "Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
      "typeVersion": 1,
      "position": [
        1780,
        680
      ]
    },
    {
      "parameters": {
        "input": "={{ $json.pageContent }}"
      },
      "id": "document-loader",
      "name": "Document Loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1,
      "position": [
        1780,
        860
      ]
    },
    {
      "parameters": {
        "operation": "insert",
        "tableName": "documents"
      },
      "id": "insert-vectorstore",
      "name": "Inserir no Supabase",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1,
      "position": [
        1980,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "id": "SUA_CREDENCIAL_SUPABASE",
          "name": "Supabase account"
        }
      }
    }
  ],
  "pinData": {},
  "connections": {
    "Formulário de Upload": {
      "main": [
        [
          {
            "node": "Extrair Metadados",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair Metadados": {
      "main": [
        [
          {
            "node": "Limpar Documentos Antigos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpar Documentos Antigos": {
      "main": [
        [
          {
            "node": "Detectar Tipo de Arquivo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detectar Tipo de Arquivo": {
      "main": [
        [
          {
            "node": "Extrair Texto PDF",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Extrair Texto TXT/DOCX",
            "type": "main",
            "index": 0
          },
          {
            "node": "Processar JSONL/Estruturado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair Texto PDF": {
      "main": [
        [
          {
            "node": "Merge Textos Extraídos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair Texto TXT/DOCX": {
      "main": [
        [
          {
            "node": "Merge Textos Extraídos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Processar JSONL/Estruturado": {
      "main": [
        [
          {
            "node": "Merge Textos Extraídos",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Textos Extraídos": {
      "main": [
        [
          {
            "node": "Formatar Documentos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatar Documentos": {
      "main": [
        [
          {
            "node": "Inserir no Supabase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure OpenAI Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Inserir no Supabase",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Document Loader",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "Document Loader": {
      "ai_document": [
        [
          {
            "node": "Inserir no Supabase",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "bestpass-ingest-v1",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "bestpass-vectorstore-ingest",
  "tags": []
}
