{
  "id": "NWu4v868lNmHFP8f",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Chatbot with RAG: Google Gemini & Supabase Vector Store",
  "tags": [],
  "nodes": [
    {
      "id": "de820c41-1447-4d2e-931c-2d3a35b3cd4e",
      "name": "\ud83d\udcd6 Complete Documentation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        -1280
      ],
      "parameters": {
        "width": 546,
        "height": 1016,
        "content": "## \ud83e\udde0 AI Chatbot with RAG: Gemini & Supabase\n\n### Who It's For\nSupport teams, internal knowledge management, and community managers who want an AI agent that answers questions based strictly on company documents.\n\n### What It Does\nThis is a complete Two-Part RAG (Retrieval-Augmented Generation) system.\n1. **Ingestion Phase:** Takes uploaded files, chunks the text, creates Gemini embeddings, and stores them in a Supabase Vector Store.\n2. **Chat Phase:** Provides a chat interface where an AI agent retrieves relevant document chunks from Supabase to answer user queries accurately, while remembering past interactions.\n\n### How It Works\n1. **Data Ingestion:** Documents uploaded via the Form Trigger are validated for size (<10MB), parsed, and split into 1000-character chunks.\n2. **Vectorization:** Gemini generates embeddings (`models/gemini-embedding-001`), which are stored in Supabase.\n3. **Query Processing:** When a user asks a question, the AI Agent checks the Postgres Chat Memory for context using unique session IDs. **Memory:** The chat trigger automatically generates a unique Session ID per browser window, keeping individual user conversations completely separate.\n4. **Retrieval & Generation:** The Agent retrieves the top 5 most relevant chunks and uses Gemini to generate a factual response.\n\n### How to Set Up\n1. Add your **Google Gemini API**, **Supabase**, and **Postgres** credentials.\n2. Ensure your database tables match the columns listed in the \"DATABASE SETUP\" note.\n3. Open the **Upload Knowledge Base Form**, click \"Test step\", and submit a document.\n4. Open the **User Chat Trigger** chat window and ask a question to test the agent!\n\n### Version Info\n**Status:** \u2705 Production Ready\n**Features:** \u2022 Top-K Vector Search \u2022 File Validation \u2022 Global Error Handling"
      },
      "typeVersion": 1
    },
    {
      "id": "16da605b-d5aa-48a3-a3d7-d42df02780d7",
      "name": "Group: Chat Phase",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        -1280
      ],
      "parameters": {
        "color": 5,
        "width": 716,
        "height": 450,
        "content": "### \ud83d\udcac 1. QUERY PHASE (Chatbot)\nHandles user questions, retrieves top 5 relevant context chunks from Supabase, and uses Gemini to formulate answers."
      },
      "typeVersion": 1
    },
    {
      "id": "e860373e-caf1-4527-bc60-ac60246f1459",
      "name": "Group: Ingestion Phase",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        -1280
      ],
      "parameters": {
        "color": 6,
        "width": 1250,
        "height": 568,
        "content": "### \ud83d\udcda 2. INGESTION PHASE (Knowledge Base)\nValidates file size, chunks text to 1000 characters, generates embeddings, and stores vectors."
      },
      "typeVersion": 1
    },
    {
      "id": "f9583e72-3865-4a39-aba7-2dc22d3ae84e",
      "name": "Database Schema",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1824,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 854,
        "height": 574,
        "content": "\u26a0\ufe0f **ACTION REQUIRED**\nRun this SQL in your database editor FIRST:\n\n### DATABASE SETUP (SQL)\nRun this in your database SQL editor before running the workflow:\n```\n-- pgvector extension\nCREATE EXTENSION IF NOT EXISTS vector;\n\n-- documents table\nCREATE TABLE your_documents_table (\n  id bigserial PRIMARY KEY,\n  content text NOT NULL,\n  metadata jsonb,\n  embedding vector(768), \n  created_at timestamp DEFAULT now()\n);\n\nCREATE INDEX ON your_documents_table USING ivfflat (embedding vector_cosine_ops);\n\n-- chat history table\nCREATE TABLE your_chat_history_table (\n  id bigserial PRIMARY KEY,\n  session_id text NOT NULL,\n  role text NOT NULL,\n  content text NOT NULL,\n  created_at timestamp DEFAULT now()\n);\n\nCREATE INDEX ON your_chat_history_table(session_id);\n\n-- \u26a0\ufe0f 768 matches models/gemini-embedding-001.\n-- If you change the embedding model, update this dimension to match.\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "feb74a54-be06-4353-8dbd-6e833c2b3a57",
      "name": "Group: Error Handling",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2720,
        -672
      ],
      "parameters": {
        "color": 2,
        "width": 450,
        "height": 280,
        "content": "### \ud83d\udea8 GLOBAL ERROR HANDLER\nDynamically catches workflow failures (e.g., API timeouts, bad PDFs). Connect a Slack/Email node to the Format node to notify your team."
      },
      "typeVersion": 1
    },
    {
      "id": "eacf9a0d-2e7d-4b5b-9ef7-587c9ce7b36a",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        2784,
        -560
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "bc93d142-f1fe-4a2e-8f49-81b3ef9bb8ee",
      "name": "Format Error Alert",
      "type": "n8n-nodes-base.set",
      "position": [
        2992,
        -560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "error-msg-format",
              "name": "alertMessage",
              "type": "string",
              "value": "=\ud83d\udea8 Workflow Failed | Node: {{ $json.execution.lastNodeExecuted }} | Error: {{ $json.error.message }}\n\n_(Route this to Slack, Teams, or Email)_"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "649735ea-42b7-4b7b-ba52-fbce434f6c01",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        2016,
        -992
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-2.5-flash"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e53c7d58-ba05-46df-ba2b-310736ded966",
      "name": "User Chat Trigger",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        1936,
        -1200
      ],
      "parameters": {
        "public": true,
        "options": {
          "allowFileUploads": true
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "711501ed-dab7-406f-84a4-7506405ecab9",
      "name": "Knowledge-Base AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2192,
        -1200
      ],
      "parameters": {
        "options": {
          "systemMessage": "You are a helpful AI assistant with access to a knowledge base. When answering questions:\n1. Always search the knowledge base first using the available tools\n2. If the knowledge base contains relevant information, use it to provide accurate answers\n3. Be concise and helpful in your responses\n4. Always cite the source when using information from the knowledge base\n5. If the vector search returns low-confidence results or no relevant results, DO NOT make up information. State clearly that the knowledge base lacks this info."
        }
      },
      "typeVersion": 3.1
    },
    {
      "id": "6d98a3c7-00d3-411e-8c65-16d5131fcfe0",
      "name": "Persistent Chat History",
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "position": [
        2176,
        -992
      ],
      "parameters": {
        "tableName": "your_chat_history_table"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "15c01a12-aee8-40f2-87ea-b64e505884d5",
      "name": "Supabase Retriever",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        2304,
        -992
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "topK": 5,
        "options": {},
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "your_documents_table",
          "cachedResultName": "your_documents_table"
        },
        "toolDescription": "Search the knowledge base for relevant information. Use this tool to find answers to user questions from uploaded documents."
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e806ca61-6ac3-44fc-bc34-50841f5b86e1",
      "name": "Upload Knowledge Base Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        2672,
        -1168
      ],
      "parameters": {
        "options": {},
        "formTitle": "Upload Your Knowledge Base",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "Upload Documents",
              "acceptFileTypes": ".pdf,.txt,.docx,.pptx"
            }
          ]
        },
        "responseMode": "lastNode",
        "formDescription": "Please upload your documents to build the knowledge base.\n\n\u2705 **Accepted:** .pdf, .txt, .docx, .pptx\n\u26a0\ufe0f **Maximum Size:** 10MB"
      },
      "typeVersion": 2.5
    },
    {
      "id": "948c5e58-37b1-402f-8e19-261ca39716ce",
      "name": "File < 10MB?",
      "type": "n8n-nodes-base.if",
      "position": [
        3104,
        -1168
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "fef8a5e5-6d06-4338-ba7f-6a8fcb5f8f0d",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.fileSize }}",
              "rightValue": 0
            },
            {
              "id": "1",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ $json.fileSize }}",
              "rightValue": 1048576
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "10657006-8e06-4234-a27f-b25301b1dbac",
      "name": "Parse File Size",
      "type": "n8n-nodes-base.code",
      "position": [
        2880,
        -1168
      ],
      "parameters": {
        "jsCode": "\n  const sizeStr = Object.values($input.all()[0]?.binary)?.[0]?.fileSize ?? \"0 B\";\n\n  const [value, unit] = sizeStr.split(\" \");\n\n  const units = {\n    B: 1,\n    KB: 1024,\n    MB: 1024 * 1024,\n    GB: 1024 * 1024 * 1024,\n  };\n\n  return {json: {fileSize:parseFloat(value) * (units[unit] || 1)}};"
      },
      "typeVersion": 2
    },
    {
      "id": "98fc5471-4908-465a-9dfe-b6f4a04aafc5",
      "name": "Reject Upload",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        3088,
        -1056
      ],
      "parameters": {
        "errorMessage": "File too large. Please upload a file smaller than 10MB."
      },
      "typeVersion": 1
    },
    {
      "id": "2dd5a7cc-a2cb-4d8f-b265-f95174dc1fc1",
      "name": "Supabase Inserter",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        3216,
        -1168
      ],
      "parameters": {
        "mode": "insert",
        "options": {},
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "your_documents_table",
          "cachedResultName": "your_documents_table"
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": false,
      "typeVersion": 1.3
    },
    {
      "id": "e4f8d9b1-5a2a-4c2f-b4b1-8b2d1c1a2d3e",
      "name": "Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3440,
        -1168
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "\u2705 Success! Your document has been processed and added to the knowledge base."
      },
      "typeVersion": 1.1
    },
    {
      "id": "87a7358c-12f6-4ea6-997a-7e6e9fc1c10a",
      "name": "Document Parser",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        3328,
        -1008
      ],
      "parameters": {
        "options": {},
        "dataType": "binary",
        "textSplittingMode": "custom"
      },
      "typeVersion": 1.1
    },
    {
      "id": "35b7da0c-a563-4ce1-b972-3d49a44cf70f",
      "name": "Text Chunker",
      "type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
      "position": [
        3360,
        -832
      ],
      "parameters": {
        "chunkSize": 1000,
        "separator": "\n\n",
        "chunkOverlap": 100
      },
      "typeVersion": 1
    },
    {
      "id": "a947b9e4-b994-4064-a00d-e7bf03f92cf5",
      "name": "Gemini Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        3072,
        -864
      ],
      "parameters": {
        "modelName": "models/gemini-embedding-001"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "b1b4800c-a5e2-428f-9cf7-f8002d4eec92",
  "connections": {
    "File < 10MB?": {
      "main": [
        [
          {
            "node": "Supabase Inserter",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reject Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Text Chunker": {
      "ai_textSplitter": [
        [
          {
            "node": "Document Parser",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Format Error Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Document Parser": {
      "ai_document": [
        [
          {
            "node": "Supabase Inserter",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Parse File Size": {
      "main": [
        [
          {
            "node": "File < 10MB?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Retriever",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Supabase Inserter",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Inserter": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "User Chat Trigger": {
      "main": [
        [
          {
            "node": "Knowledge-Base AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Retriever": {
      "ai_tool": [
        [
          {
            "node": "Knowledge-Base AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Persistent Chat History": {
      "ai_memory": [
        [
          {
            "node": "Knowledge-Base AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Knowledge-Base AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Upload Knowledge Base Form": {
      "main": [
        [
          {
            "node": "Parse File Size",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}