From 0e5e87ba60f063549566023fdd19ad1896fde5bc Mon Sep 17 00:00:00 2001 From: Cole Medin <47287758+coleam00@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:19:39 -0500 Subject: [PATCH] n8n Full Stack App with Streamlit + Claude + Supabase --- .gitignore | 3 +- .../Supabase_RAG_AI_Agent_Basic_Auth.json | 740 ++++++++++++++++ .../Supabase_RAG_AI_Agent_Supabase_Auth.json | 835 ++++++++++++++++++ .../n8n-streamlit-agent-basic-auth.py | 59 ++ n8n-streamlit-agent/n8n-streamlit-agent.py | 118 +++ n8n-streamlit-agent/prompts.txt | 19 + n8n-streamlit-agent/requirements.txt | 70 ++ 7 files changed, 1843 insertions(+), 1 deletion(-) create mode 100644 n8n-streamlit-agent/Supabase_RAG_AI_Agent_Basic_Auth.json create mode 100644 n8n-streamlit-agent/Supabase_RAG_AI_Agent_Supabase_Auth.json create mode 100644 n8n-streamlit-agent/n8n-streamlit-agent-basic-auth.py create mode 100644 n8n-streamlit-agent/n8n-streamlit-agent.py create mode 100644 n8n-streamlit-agent/prompts.txt create mode 100644 n8n-streamlit-agent/requirements.txt diff --git a/.gitignore b/.gitignore index e2319c2..c5547f5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ creds credentials credentials.json token.json -node_modules \ No newline at end of file +node_modules +venv \ No newline at end of file diff --git a/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Basic_Auth.json b/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Basic_Auth.json new file mode 100644 index 0000000..de28b25 --- /dev/null +++ b/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Basic_Auth.json @@ -0,0 +1,740 @@ +{ + "name": "Supabase RAG AI Agent", + "nodes": [ + { + "parameters": { + "model": "gpt-4o-mini", + "options": {} + }, + "id": "b98c17c5-3bef-4378-8d81-61b127711661", + "name": "OpenAI Chat Model", + "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", + "typeVersion": 1, + "position": [ + 860, + 520 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "model": "gpt-4o-mini", + "options": {} + }, + "id": "e850aa69-1910-4986-99f2-214a8759b777", + "name": "OpenAI Chat Model1", + "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", + "typeVersion": 1, + "position": [ + 1880, + 460 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "jsonMode": "expressionData", + "jsonData": "={{ $json.data }}", + "options": { + "metadata": { + "metadataValues": [ + { + "name": "=file_id", + "value": "={{ $('Set File ID').item.json.file_id }}" + } + ] + } + } + }, + "id": "9f5b6c56-58f6-4ae5-96fd-f3efd9b35fd6", + "name": "Default Data Loader", + "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader", + "typeVersion": 1, + "position": [ + 2020, + 1000 + ] + }, + { + "parameters": { + "model": "text-embedding-3-small", + "options": {} + }, + "id": "5eaf6315-fcd0-4a4d-a1b3-37f5793f6e5c", + "name": "Embeddings OpenAI1", + "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", + "typeVersion": 1, + "position": [ + 1860, + 1000 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "name": "user_documents", + "description": "Contains all the user's documents that you can check for context to answer user questions." + }, + "id": "b3868e8d-fbce-4c16-8174-0e5475cfffba", + "name": "Retrieve Documents", + "type": "@n8n/n8n-nodes-langchain.toolVectorStore", + "typeVersion": 1, + "position": [ + 1660, + 280 + ] + }, + { + "parameters": { + "content": "## Agent Tools for RAG", + "height": 528.85546469693, + "width": 583.4552380860637, + "color": 4 + }, + "id": "d4a657c6-2f17-4071-8cee-0b1b12f74b1c", + "name": "Sticky Note", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 1480, + 160 + ] + }, + { + "parameters": { + "content": "## Tool to Add a Google Drive File to Vector DB", + "height": 671.8877842322804, + "width": 2070.8894079025763, + "color": 5 + }, + "id": "38517d9e-61cf-4b36-bbb2-607a04e870c8", + "name": "Sticky Note1", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 260, + 700 + ] + }, + { + "parameters": { + "operation": "download", + "fileId": { + "__rl": true, + "value": "={{ $('Set File ID').item.json.file_id }}", + "mode": "id" + }, + "options": { + "googleFileConversion": { + "conversion": { + "docsToFormat": "text/plain" + } + } + } + }, + "id": "d9e3d812-9158-44e2-b9e9-8c28c5cd0921", + "name": "Download File", + "type": "n8n-nodes-base.googleDrive", + "typeVersion": 3, + "position": [ + 1360, + 880 + ], + "executeOnce": true, + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "triggerOn": "specificFolder", + "folderToWatch": { + "__rl": true, + "value": "1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC", + "mode": "list", + "cachedResultName": "Meeting Notes", + "cachedResultUrl": "https://drive.google.com/drive/folders/1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC" + }, + "event": "fileCreated", + "options": {} + }, + "id": "6c24f48d-2a8e-471d-b477-dd9576e57eec", + "name": "File Created", + "type": "n8n-nodes-base.googleDriveTrigger", + "typeVersion": 1, + "position": [ + 320, + 780 + ], + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "triggerOn": "specificFolder", + "folderToWatch": { + "__rl": true, + "value": "1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC", + "mode": "list", + "cachedResultName": "Meeting Notes", + "cachedResultUrl": "https://drive.google.com/drive/folders/1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC" + }, + "event": "fileUpdated", + "options": {} + }, + "id": "7bf930ea-3810-40e3-a252-c13da33660db", + "name": "File Updated", + "type": "n8n-nodes-base.googleDriveTrigger", + "typeVersion": 1, + "position": [ + 320, + 1000 + ], + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "operation": "text", + "options": {} + }, + "id": "81e0f199-024b-489d-88dd-e7bf6c3a453b", + "name": "Extract Document Text", + "type": "n8n-nodes-base.extractFromFile", + "typeVersion": 1, + "position": [ + 1620, + 880 + ], + "alwaysOutputData": true + }, + { + "parameters": { + "model": "text-embedding-3-small", + "options": {} + }, + "id": "c0f6a1f6-5732-48e3-8830-bb78263bd352", + "name": "Embeddings OpenAI", + "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", + "typeVersion": 1, + "position": [ + 1700, + 560 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": {}, + "id": "8920aea0-c877-47b3-9026-d8ab57e8579d", + "name": "Postgres Chat Memory", + "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat", + "typeVersion": 1, + "position": [ + 1000, + 520 + ], + "notesInFlow": false, + "credentials": { + "postgres": { + "id": "tzFFADvpFiUtaZtb", + "name": "Supabase Postgres" + } + } + }, + { + "parameters": { + "options": {} + }, + "id": "ed70601e-e7e9-4fc5-af9f-bdf4a931fc48", + "name": "Recursive Character Text Splitter", + "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter", + "typeVersion": 1, + "position": [ + 2020, + 1200 + ] + }, + { + "parameters": { + "operation": "delete", + "tableId": "documents", + "filterType": "string", + "filterString": "=metadata->>file_id=like.*{{ $json.file_id }}*" + }, + "id": "bd9eb3dc-75b9-4577-a210-1951988a389e", + "name": "Delete Old Doc Rows", + "type": "n8n-nodes-base.supabase", + "typeVersion": 1, + "position": [ + 1060, + 880 + ], + "alwaysOutputData": true, + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "assignments": { + "assignments": [ + { + "id": "10646eae-ae46-4327-a4dc-9987c2d76173", + "name": "file_id", + "value": "={{ $json.id }}", + "type": "string" + } + ] + }, + "options": {} + }, + "id": "0b439eba-c467-475b-a1a2-481f636f37fe", + "name": "Set File ID", + "type": "n8n-nodes-base.set", + "typeVersion": 3.4, + "position": [ + 740, + 880 + ] + }, + { + "parameters": { + "content": "## RAG AI Agent with Chat Interface", + "height": 464.8027193303974, + "width": 1035.6381264595484 + }, + "id": "7c003acd-f420-474f-9547-33e13c3c357f", + "name": "Sticky Note2", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 432.49413148117685, + 220 + ] + }, + { + "parameters": { + "tableName": { + "__rl": true, + "value": "documents", + "mode": "list", + "cachedResultName": "documents" + }, + "options": { + "queryName": "match_documents" + } + }, + "id": "1bda5922-bcfb-489c-a0fb-516d9496d54a", + "name": "Supabase Vector Store", + "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase", + "typeVersion": 1, + "position": [ + 1540, + 440 + ], + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "options": {} + }, + "id": "dd1086c5-e813-49ea-971f-ba01ccc6f803", + "name": "Respond to Webhook", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [ + 1300, + 300 + ] + }, + { + "parameters": { + "assignments": { + "assignments": [ + { + "id": "9a9a245e-f1a1-4282-bb02-a81ffe629f0f", + "name": "chatInput", + "value": "={{ $json?.chatInput || $json.body.chatInput }}", + "type": "string" + }, + { + "id": "b80831d8-c653-4203-8706-adedfdb98f77", + "name": "sessionId", + "value": "={{ $json?.sessionId || $json.body.sessionId}}", + "type": "string" + } + ] + }, + "options": {} + }, + "id": "4076ba7c-931d-40f5-872d-c9b2dc669ab1", + "name": "Edit Fields", + "type": "n8n-nodes-base.set", + "typeVersion": 3.4, + "position": [ + 740, + 300 + ] + }, + { + "parameters": { + "promptType": "define", + "text": "={{ $json.chatInput }}", + "options": { + "systemMessage": "You are a personal assistant who helps answer questions from a corpus of documents when you don't know the answer yourself." + } + }, + "id": "50003c9d-29bf-4d0e-9e04-a49804742dc8", + "name": "RAG AI Agent", + "type": "@n8n/n8n-nodes-langchain.agent", + "typeVersion": 1.6, + "position": [ + 960, + 300 + ] + }, + { + "parameters": { + "mode": "insert", + "tableName": { + "__rl": true, + "value": "documents", + "mode": "list", + "cachedResultName": "documents" + }, + "options": { + "queryName": "match_documents" + } + }, + "id": "6c7181ba-9e33-4972-83b4-0efaac7e16a2", + "name": "Insert into Supabase Vectorstore", + "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase", + "typeVersion": 1, + "position": [ + 1900, + 780 + ], + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "public": true, + "options": {} + }, + "id": "e448d46a-7a01-436c-bebd-0cd21c2bfcb3", + "name": "When chat message received", + "type": "@n8n/n8n-nodes-langchain.chatTrigger", + "typeVersion": 1.1, + "position": [ + 480, + 300 + ], + "webhookId": "e985d15f-b2f6-456d-be15-97e0b1544a40" + }, + { + "parameters": { + "httpMethod": "POST", + "path": "invoke_agent", + "authentication": "headerAuth", + "responseMode": "responseNode", + "options": {} + }, + "id": "b575cc9f-71c7-4406-936c-ca39e6eff09b", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 2, + "position": [ + 480, + 500 + ], + "webhookId": "67fc16e5-4a6d-4c00-b7a1-db48c4511e9f", + "credentials": { + "httpHeaderAuth": { + "id": "XivCWajQ7dANnQvl", + "name": "Header Auth account" + } + } + } + ], + "pinData": {}, + "connections": { + "OpenAI Chat Model": { + "ai_languageModel": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_languageModel", + "index": 0 + } + ] + ] + }, + "OpenAI Chat Model1": { + "ai_languageModel": [ + [ + { + "node": "Retrieve Documents", + "type": "ai_languageModel", + "index": 0 + } + ] + ] + }, + "Retrieve Documents": { + "ai_tool": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_tool", + "index": 0 + } + ] + ] + }, + "Download File": { + "main": [ + [ + { + "node": "Extract Document Text", + "type": "main", + "index": 0 + } + ] + ] + }, + "File Created": { + "main": [ + [ + { + "node": "Set File ID", + "type": "main", + "index": 0 + } + ] + ] + }, + "Embeddings OpenAI": { + "ai_embedding": [ + [ + { + "node": "Supabase Vector Store", + "type": "ai_embedding", + "index": 0 + } + ] + ] + }, + "Extract Document Text": { + "main": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "main", + "index": 0 + } + ] + ] + }, + "Embeddings OpenAI1": { + "ai_embedding": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "ai_embedding", + "index": 0 + } + ] + ] + }, + "Default Data Loader": { + "ai_document": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "ai_document", + "index": 0 + } + ] + ] + }, + "Postgres Chat Memory": { + "ai_memory": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_memory", + "index": 0 + } + ] + ] + }, + "Recursive Character Text Splitter": { + "ai_textSplitter": [ + [ + { + "node": "Default Data Loader", + "type": "ai_textSplitter", + "index": 0 + } + ] + ] + }, + "Delete Old Doc Rows": { + "main": [ + [ + { + "node": "Download File", + "type": "main", + "index": 0 + } + ] + ] + }, + "Set File ID": { + "main": [ + [ + { + "node": "Delete Old Doc Rows", + "type": "main", + "index": 0 + } + ] + ] + }, + "File Updated": { + "main": [ + [ + { + "node": "Set File ID", + "type": "main", + "index": 0 + } + ] + ] + }, + "Supabase Vector Store": { + "ai_vectorStore": [ + [ + { + "node": "Retrieve Documents", + "type": "ai_vectorStore", + "index": 0 + } + ] + ] + }, + "Edit Fields": { + "main": [ + [ + { + "node": "RAG AI Agent", + "type": "main", + "index": 0 + } + ] + ] + }, + "RAG AI Agent": { + "main": [ + [ + { + "node": "Respond to Webhook", + "type": "main", + "index": 0 + } + ] + ] + }, + "When chat message received": { + "main": [ + [ + { + "node": "Edit Fields", + "type": "main", + "index": 0 + } + ] + ] + }, + "Webhook": { + "main": [ + [ + { + "node": "Edit Fields", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": true, + "settings": { + "executionOrder": "v1" + }, + "versionId": "3c35c49a-bc44-4379-b6f0-109f579f79bc", + "meta": { + "templateCredsSetupCompleted": true, + "instanceId": "620f0d7e3114cb344761d7d45a21ef2a32096f91d8696e7057756042e1999e2c" + }, + "id": "cri0nBz0U55sWr4I", + "tags": [] +} \ No newline at end of file diff --git a/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Supabase_Auth.json b/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Supabase_Auth.json new file mode 100644 index 0000000..347287c --- /dev/null +++ b/n8n-streamlit-agent/Supabase_RAG_AI_Agent_Supabase_Auth.json @@ -0,0 +1,835 @@ +{ + "name": "Supabase RAG AI Agent Custom Auth", + "nodes": [ + { + "parameters": { + "model": "gpt-4o-mini", + "options": {} + }, + "id": "20216b42-d5fa-4d1e-a4fb-9549834fea99", + "name": "OpenAI Chat Model", + "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", + "typeVersion": 1, + "position": [ + 940, + 520 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "model": "gpt-4o-mini", + "options": {} + }, + "id": "1e53e934-c7fa-4650-8f5e-106102a9494d", + "name": "OpenAI Chat Model1", + "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", + "typeVersion": 1, + "position": [ + 1880, + 460 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "jsonMode": "expressionData", + "jsonData": "={{ $json.data }}", + "options": { + "metadata": { + "metadataValues": [ + { + "name": "=file_id", + "value": "={{ $('Set File ID').item.json.file_id }}" + } + ] + } + } + }, + "id": "a766868e-c847-48b9-8b61-dcd5fcd9e280", + "name": "Default Data Loader", + "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader", + "typeVersion": 1, + "position": [ + 2020, + 1000 + ] + }, + { + "parameters": { + "model": "text-embedding-3-small", + "options": {} + }, + "id": "23255e75-bfdb-46ac-8244-98c5e518bafe", + "name": "Embeddings OpenAI1", + "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", + "typeVersion": 1, + "position": [ + 1860, + 1000 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": { + "name": "user_documents", + "description": "Contains all the user's documents that you can check for context to answer user questions." + }, + "id": "62ca6e95-73ff-459c-8e29-6b38d12895c8", + "name": "Retrieve Documents", + "type": "@n8n/n8n-nodes-langchain.toolVectorStore", + "typeVersion": 1, + "position": [ + 1660, + 280 + ] + }, + { + "parameters": { + "content": "## Agent Tools for RAG", + "height": 528.85546469693, + "width": 583.4552380860637, + "color": 4 + }, + "id": "53866fd6-ca7f-4174-b438-809c6d06eec0", + "name": "Sticky Note", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 1480, + 160 + ] + }, + { + "parameters": { + "content": "## Tool to Add a Google Drive File to Vector DB", + "height": 671.8877842322804, + "width": 2070.8894079025763, + "color": 5 + }, + "id": "de4b8d94-b4aa-4b72-b9ac-70b3cf624eb7", + "name": "Sticky Note1", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 260, + 700 + ] + }, + { + "parameters": { + "operation": "download", + "fileId": { + "__rl": true, + "value": "={{ $('Set File ID').item.json.file_id }}", + "mode": "id" + }, + "options": { + "googleFileConversion": { + "conversion": { + "docsToFormat": "text/plain" + } + } + } + }, + "id": "705a761d-6b10-4e98-8aad-b21413f60005", + "name": "Download File", + "type": "n8n-nodes-base.googleDrive", + "typeVersion": 3, + "position": [ + 1360, + 880 + ], + "executeOnce": true, + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "triggerOn": "specificFolder", + "folderToWatch": { + "__rl": true, + "value": "1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC", + "mode": "list", + "cachedResultName": "Meeting Notes", + "cachedResultUrl": "https://drive.google.com/drive/folders/1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC" + }, + "event": "fileCreated", + "options": {} + }, + "id": "b22ee4d4-b310-426f-b1ca-82ef62fe2f07", + "name": "File Created", + "type": "n8n-nodes-base.googleDriveTrigger", + "typeVersion": 1, + "position": [ + 320, + 780 + ], + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "triggerOn": "specificFolder", + "folderToWatch": { + "__rl": true, + "value": "1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC", + "mode": "list", + "cachedResultName": "Meeting Notes", + "cachedResultUrl": "https://drive.google.com/drive/folders/1914m3M7kRzkd5RJqAfzRY9EBcJrKemZC" + }, + "event": "fileUpdated", + "options": {} + }, + "id": "91fc8df8-1c77-4e58-b723-ecfb756b148a", + "name": "File Updated", + "type": "n8n-nodes-base.googleDriveTrigger", + "typeVersion": 1, + "position": [ + 320, + 1000 + ], + "credentials": { + "googleDriveOAuth2Api": { + "id": "cfNochbuJikPwwl2", + "name": "Google Drive account" + } + } + }, + { + "parameters": { + "operation": "text", + "options": {} + }, + "id": "ed74944a-418e-42c8-9a36-5d280dfa02f1", + "name": "Extract Document Text", + "type": "n8n-nodes-base.extractFromFile", + "typeVersion": 1, + "position": [ + 1620, + 880 + ], + "alwaysOutputData": true + }, + { + "parameters": { + "model": "text-embedding-3-small", + "options": {} + }, + "id": "4a2ab29f-026a-4e67-9e70-cb647e901360", + "name": "Embeddings OpenAI", + "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", + "typeVersion": 1, + "position": [ + 1700, + 560 + ], + "credentials": { + "openAiApi": { + "id": "JJjD91oisPv9cs01", + "name": "OpenAi account" + } + } + }, + { + "parameters": {}, + "id": "d3e47e92-65f7-483c-a730-13bcb26b26c5", + "name": "Postgres Chat Memory", + "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat", + "typeVersion": 1, + "position": [ + 1060, + 520 + ], + "notesInFlow": false, + "credentials": { + "postgres": { + "id": "tzFFADvpFiUtaZtb", + "name": "Supabase Postgres" + } + } + }, + { + "parameters": { + "options": {} + }, + "id": "45a38eca-0093-4263-932a-b915b81909c4", + "name": "Recursive Character Text Splitter", + "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter", + "typeVersion": 1, + "position": [ + 2020, + 1200 + ] + }, + { + "parameters": { + "operation": "delete", + "tableId": "documents", + "filterType": "string", + "filterString": "=metadata->>file_id=like.*{{ $json.file_id }}*" + }, + "id": "699533ea-e91e-4229-bd70-c9cb718411af", + "name": "Delete Old Doc Rows", + "type": "n8n-nodes-base.supabase", + "typeVersion": 1, + "position": [ + 1060, + 880 + ], + "alwaysOutputData": true, + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "assignments": { + "assignments": [ + { + "id": "10646eae-ae46-4327-a4dc-9987c2d76173", + "name": "file_id", + "value": "={{ $json.id }}", + "type": "string" + } + ] + }, + "options": {} + }, + "id": "ec2f04ff-2824-4b0f-ac57-740a6a103f3d", + "name": "Set File ID", + "type": "n8n-nodes-base.set", + "typeVersion": 3.4, + "position": [ + 740, + 880 + ] + }, + { + "parameters": { + "content": "## RAG AI Agent with Chat Interface", + "height": 464.8027193303974, + "width": 1397.1362723489267 + }, + "id": "12172aa3-12ff-46da-9883-c5bd45920259", + "name": "Sticky Note2", + "type": "n8n-nodes-base.stickyNote", + "typeVersion": 1, + "position": [ + 65.97988322897118, + 220 + ] + }, + { + "parameters": { + "tableName": { + "__rl": true, + "value": "documents", + "mode": "list", + "cachedResultName": "documents" + }, + "options": { + "queryName": "match_documents" + } + }, + "id": "84b6ba04-1409-4eb8-8530-7fc5f450fae6", + "name": "Supabase Vector Store", + "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase", + "typeVersion": 1, + "position": [ + 1540, + 440 + ], + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "options": {} + }, + "id": "9606a05d-8ab1-4aeb-9855-a69c29c09fe0", + "name": "Respond to Webhook", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [ + 1300, + 300 + ] + }, + { + "parameters": { + "public": true, + "options": {} + }, + "id": "64a6fef1-b254-4f39-9684-e29c9a4ff1b2", + "name": "When chat message received", + "type": "@n8n/n8n-nodes-langchain.chatTrigger", + "typeVersion": 1.1, + "position": [ + 120, + 300 + ], + "webhookId": "21ffce44-9a14-4739-a143-808087431b7f" + }, + { + "parameters": { + "assignments": { + "assignments": [ + { + "id": "9a9a245e-f1a1-4282-bb02-a81ffe629f0f", + "name": "chatInput", + "value": "={{ $json?.chatInput || $('Webhook').item.json.body.chatInput }}", + "type": "string" + }, + { + "id": "b80831d8-c653-4203-8706-adedfdb98f77", + "name": "sessionId", + "value": "={{ $json?.sessionId || $('Webhook').item.json.body.sessionId }}", + "type": "string" + } + ] + }, + "options": {} + }, + "id": "145612c9-aae5-4743-a0d2-085ce7741e5e", + "name": "Edit Fields", + "type": "n8n-nodes-base.set", + "typeVersion": 3.4, + "position": [ + 740, + 300 + ] + }, + { + "parameters": { + "promptType": "define", + "text": "={{ $json.chatInput }}", + "options": { + "systemMessage": "You are a personal assistant who helps answer questions from a corpus of documents when you don't know the answer yourself." + } + }, + "id": "2e950dc6-8be1-4067-a1d4-a6265f6cd6c0", + "name": "RAG AI Agent", + "type": "@n8n/n8n-nodes-langchain.agent", + "typeVersion": 1.6, + "position": [ + 960, + 300 + ] + }, + { + "parameters": { + "mode": "insert", + "tableName": { + "__rl": true, + "value": "documents", + "mode": "list", + "cachedResultName": "documents" + }, + "options": { + "queryName": "match_documents" + } + }, + "id": "379f7875-c08e-4352-8958-7cf2606ba07c", + "name": "Insert into Supabase Vectorstore", + "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase", + "typeVersion": 1, + "position": [ + 1900, + 780 + ], + "credentials": { + "supabaseApi": { + "id": "azIAMHxdSaq5XhoW", + "name": "Supabase account" + } + } + }, + { + "parameters": { + "url": "https://[YOUR SUPABASE PROJECT URL]/auth/v1/user", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "apikey", + "value": "YOUR_SUPABASE_API_KEY" + }, + { + "name": "Authorization", + "value": "={{ $json.headers.authorization }}" + } + ] + }, + "options": {} + }, + "id": "bed3b947-0c39-47f1-9dd6-3032cc357624", + "name": "HTTP Request", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 340, + 500 + ] + }, + { + "parameters": { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict" + }, + "conditions": [ + { + "id": "2d5f1cb2-511d-48a3-952a-c7c5be7b3e61", + "leftValue": "={{ $json.email }}", + "rightValue": "", + "operator": { + "type": "string", + "operation": "notEmpty", + "singleValue": true + } + } + ], + "combinator": "and" + }, + "options": {} + }, + "id": "2dadff1f-6a4f-4f2b-8b02-a4b2a3a4c876", + "name": "If", + "type": "n8n-nodes-base.if", + "typeVersion": 2, + "position": [ + 540, + 500 + ] + }, + { + "parameters": { + "options": {} + }, + "id": "9af5a135-aa55-4d7d-8d92-22e4b5f3a8bb", + "name": "Respond with Error", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1.1, + "position": [ + 740, + 500 + ] + }, + { + "parameters": { + "httpMethod": "POST", + "path": "invoke-supabase-agent", + "responseMode": "responseNode", + "options": {} + }, + "id": "dcdeeade-bfd1-47bb-a94c-e75f0060b41a", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 2, + "position": [ + 120, + 500 + ], + "webhookId": "33512ab3-8838-49a7-aaa1-90252504db01" + } + ], + "pinData": {}, + "connections": { + "OpenAI Chat Model": { + "ai_languageModel": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_languageModel", + "index": 0 + } + ] + ] + }, + "OpenAI Chat Model1": { + "ai_languageModel": [ + [ + { + "node": "Retrieve Documents", + "type": "ai_languageModel", + "index": 0 + } + ] + ] + }, + "Retrieve Documents": { + "ai_tool": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_tool", + "index": 0 + } + ] + ] + }, + "Download File": { + "main": [ + [ + { + "node": "Extract Document Text", + "type": "main", + "index": 0 + } + ] + ] + }, + "File Created": { + "main": [ + [ + { + "node": "Set File ID", + "type": "main", + "index": 0 + } + ] + ] + }, + "Embeddings OpenAI": { + "ai_embedding": [ + [ + { + "node": "Supabase Vector Store", + "type": "ai_embedding", + "index": 0 + } + ] + ] + }, + "Extract Document Text": { + "main": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "main", + "index": 0 + } + ] + ] + }, + "Embeddings OpenAI1": { + "ai_embedding": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "ai_embedding", + "index": 0 + } + ] + ] + }, + "Default Data Loader": { + "ai_document": [ + [ + { + "node": "Insert into Supabase Vectorstore", + "type": "ai_document", + "index": 0 + } + ] + ] + }, + "Postgres Chat Memory": { + "ai_memory": [ + [ + { + "node": "RAG AI Agent", + "type": "ai_memory", + "index": 0 + } + ] + ] + }, + "Recursive Character Text Splitter": { + "ai_textSplitter": [ + [ + { + "node": "Default Data Loader", + "type": "ai_textSplitter", + "index": 0 + } + ] + ] + }, + "Delete Old Doc Rows": { + "main": [ + [ + { + "node": "Download File", + "type": "main", + "index": 0 + } + ] + ] + }, + "Set File ID": { + "main": [ + [ + { + "node": "Delete Old Doc Rows", + "type": "main", + "index": 0 + } + ] + ] + }, + "File Updated": { + "main": [ + [ + { + "node": "Set File ID", + "type": "main", + "index": 0 + } + ] + ] + }, + "Supabase Vector Store": { + "ai_vectorStore": [ + [ + { + "node": "Retrieve Documents", + "type": "ai_vectorStore", + "index": 0 + } + ] + ] + }, + "When chat message received": { + "main": [ + [ + { + "node": "Edit Fields", + "type": "main", + "index": 0 + } + ] + ] + }, + "Edit Fields": { + "main": [ + [ + { + "node": "RAG AI Agent", + "type": "main", + "index": 0 + } + ] + ] + }, + "RAG AI Agent": { + "main": [ + [ + { + "node": "Respond to Webhook", + "type": "main", + "index": 0 + } + ] + ] + }, + "HTTP Request": { + "main": [ + [ + { + "node": "If", + "type": "main", + "index": 0 + } + ] + ] + }, + "If": { + "main": [ + [ + { + "node": "Edit Fields", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Respond with Error", + "type": "main", + "index": 0 + } + ] + ] + }, + "Webhook": { + "main": [ + [ + { + "node": "HTTP Request", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "versionId": "b6084362-7eaa-41a2-b29b-5fb3ac58f7b2", + "meta": { + "templateCredsSetupCompleted": true, + "instanceId": "620f0d7e3114cb344761d7d45a21ef2a32096f91d8696e7057756042e1999e2c" + }, + "id": "jfppAfyQOMf1B4Wd", + "tags": [] +} \ No newline at end of file diff --git a/n8n-streamlit-agent/n8n-streamlit-agent-basic-auth.py b/n8n-streamlit-agent/n8n-streamlit-agent-basic-auth.py new file mode 100644 index 0000000..d339aff --- /dev/null +++ b/n8n-streamlit-agent/n8n-streamlit-agent-basic-auth.py @@ -0,0 +1,59 @@ +import streamlit as st +import requests +import uuid + +# Constants +WEBHOOK_URL = "YOUR_N8N_WEBHOOK_URL_HERE" +BEARER_TOKEN = "YOUR_BEARER_TOKEN_HERE" + +def generate_session_id(): + return str(uuid.uuid4()) + +def send_message_to_llm(session_id, message): + headers = { + "Authorization": f"Bearer {BEARER_TOKEN}", + "Content-Type": "application/json" + } + payload = { + "sessionId": session_id, + "chatInput": message + } + response = requests.post(WEBHOOK_URL, json=payload, headers=headers) + if response.status_code == 200: + return response.json()["output"] + else: + return f"Error: {response.status_code} - {response.text}" + +def main(): + st.title("Chat with LLM") + + # Initialize session state + if "messages" not in st.session_state: + st.session_state.messages = [] + if "session_id" not in st.session_state: + st.session_state.session_id = generate_session_id() + + # Display chat messages + for message in st.session_state.messages: + with st.chat_message(message["role"]): + st.write(message["content"]) + + # User input + user_input = st.chat_input("Type your message here...") + + if user_input: + # Add user message to chat history + st.session_state.messages.append({"role": "user", "content": user_input}) + with st.chat_message("user"): + st.write(user_input) + + # Get LLM response + llm_response = send_message_to_llm(st.session_state.session_id, user_input) + + # Add LLM response to chat history + st.session_state.messages.append({"role": "assistant", "content": llm_response}) + with st.chat_message("assistant"): + st.write(llm_response) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/n8n-streamlit-agent/n8n-streamlit-agent.py b/n8n-streamlit-agent/n8n-streamlit-agent.py new file mode 100644 index 0000000..b7ee24e --- /dev/null +++ b/n8n-streamlit-agent/n8n-streamlit-agent.py @@ -0,0 +1,118 @@ +import streamlit as st +import requests +import uuid +from supabase import create_client, Client + +# Supabase setup +SUPABASE_URL = "YOUR_SUPABASE_PROJECT_URL_HERE" +SUPABASE_KEY = "YOUR_SUPABASE_ANONYMOUS_API_KEY_HERE" +supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) + +# Webhook URL (replace with your n8n webhook URL) +WEBHOOK_URL = "YOUR_N8N_WEBHOOK_URL_HERE" + +def login(email: str, password: str): + try: + res = supabase.auth.sign_in_with_password({"email": email, "password": password}) + return res + except Exception as e: + st.error(f"Login failed: {str(e)}") + return None + +def signup(email: str, password: str): + try: + res = supabase.auth.sign_up({"email": email, "password": password}) + return res + except Exception as e: + st.error(f"Signup failed: {str(e)}") + return None + +def generate_session_id(): + return str(uuid.uuid4()) + +def init_session_state(): + if "auth" not in st.session_state: + st.session_state.auth = None + if "session_id" not in st.session_state: + st.session_state.session_id = None + if "messages" not in st.session_state: + st.session_state.messages = [] + +def display_chat(): + for message in st.session_state.messages: + with st.chat_message(message["role"]): + st.markdown(message["content"]) + +def handle_logout(): + st.session_state.auth = None + st.session_state.session_id = None + st.session_state.messages = [] + st.rerun() + +def auth_ui(): + tab1, tab2 = st.tabs(["Login", "Sign Up"]) + + with tab1: + email = st.text_input("Email", key="login_email") + password = st.text_input("Password", type="password", key="login_password") + if st.button("Login"): + auth = login(email, password) + if auth: + st.session_state.auth = auth + st.session_state.session_id = generate_session_id() + st.rerun() + + with tab2: + email = st.text_input("Email", key="signup_email") + password = st.text_input("Password", type="password", key="signup_password") + if st.button("Sign Up"): + auth = signup(email, password) + if auth: + st.success("Sign up successful! Please log in.") + +def main(): + st.title("AI Chat Interface") + init_session_state() + + if st.session_state.auth is None: + auth_ui() + else: + st.sidebar.success(f"Logged in as {st.session_state.auth.user.email}") + st.sidebar.info(f"Session ID: {st.session_state.session_id}") + + if st.sidebar.button("Logout"): + handle_logout() + + display_chat() + + if prompt := st.chat_input("What is your message?"): + st.session_state.messages.append({"role": "user", "content": prompt}) + with st.chat_message("user"): + st.markdown(prompt) + + # Prepare the payload + payload = { + "chatInput": prompt, + "sessionId": st.session_state.session_id + } + + # Get the access token from the session + access_token = st.session_state.auth.session.access_token + + # Send request to webhook + headers = { + "Authorization": f"Bearer {access_token}" + } + with st.spinner("AI is thinking..."): + response = requests.post(WEBHOOK_URL, json=payload, headers=headers) + + if response.status_code == 200: + ai_message = response.json().get("output", "Sorry, I couldn't generate a response.") + st.session_state.messages.append({"role": "assistant", "content": ai_message}) + with st.chat_message("assistant"): + st.markdown(ai_message) + else: + st.error(f"Error: {response.status_code} - {response.text}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/n8n-streamlit-agent/prompts.txt b/n8n-streamlit-agent/prompts.txt new file mode 100644 index 0000000..c703325 --- /dev/null +++ b/n8n-streamlit-agent/prompts.txt @@ -0,0 +1,19 @@ +Basic Streamlit + n8n Agent App without Authentication: + +``` +Create a basic Streamlit application with a chat interface to talk to an LLM. When a user enters a message, it is sent through a webhook with a hard coded bearer token to an n8n workflow that handles the user input and gives a response from the LLM. + +The payload for the POST request includes the sessionId for a randomly generated session ID you need to create, and chatInput which contains the user message. The response JSON has just a single key, output, which is the response from the LLM to display back to the user. +``` + +Streamlit App with Supabase Authentication: + +``` +Now update this Streamlit app to use Supabase for authentication. Have a tab for logging in and a tab for signing up when a user first enters the app. + +Use the user's Supabase token when authenticated as the bearer token for the webhook request to the n8n workflow. + +Have a left-side panel to display the user email and session ID. + +Do NOT include experimental Streamlit features to do things like refresh the page. +``` \ No newline at end of file diff --git a/n8n-streamlit-agent/requirements.txt b/n8n-streamlit-agent/requirements.txt new file mode 100644 index 0000000..c421437 --- /dev/null +++ b/n8n-streamlit-agent/requirements.txt @@ -0,0 +1,70 @@ +aiohappyeyeballs==2.4.3 +aiohttp==3.10.8 +aiosignal==1.3.1 +altair==5.4.1 +annotated-types==0.7.0 +anyio==4.6.0 +async-timeout==4.0.3 +attrs==24.2.0 +blinker==1.8.2 +cachetools==5.5.0 +certifi==2024.8.30 +charset-normalizer==3.3.2 +click==8.1.7 +colorama==0.4.6 +deprecation==2.1.0 +exceptiongroup==1.2.2 +frozenlist==1.4.1 +gitdb==4.0.11 +GitPython==3.1.43 +gotrue==2.9.1 +h11==0.14.0 +h2==4.1.0 +hpack==4.0.0 +httpcore==1.0.5 +httpx==0.27.2 +hyperframe==6.0.1 +idna==3.10 +Jinja2==3.1.4 +jsonschema==4.23.0 +jsonschema-specifications==2023.12.1 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +multidict==6.1.0 +narwhals==1.9.0 +numpy==2.1.1 +packaging==24.1 +pandas==2.2.3 +pillow==10.4.0 +postgrest==0.17.0 +protobuf==5.28.2 +pyarrow==17.0.0 +pydantic==2.9.2 +pydantic_core==2.23.4 +pydeck==0.9.1 +Pygments==2.18.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +realtime==2.0.5 +referencing==0.35.1 +requests==2.32.3 +rich==13.9.1 +rpds-py==0.20.0 +six==1.16.0 +smmap==5.0.1 +sniffio==1.3.1 +storage3==0.8.0 +streamlit==1.38.0 +StrEnum==0.4.15 +supabase==2.8.1 +supafunc==0.6.0 +tenacity==8.5.0 +toml==0.10.2 +tornado==6.4.1 +typing_extensions==4.12.2 +tzdata==2024.2 +urllib3==2.2.3 +watchdog==4.0.2 +websockets==13.1 +yarl==1.13.1