Back to blog

La Casa de Aurelio / Resources

Video resources: Como crear un Agente de IA con n8n + Telegram + Supabase (10 min)

Resources for the Spanish tutorial: a Telegram bot connected to an LLM, deployed on Railway, and using Supabase as a vector base for document context.

Video resource10 minYouTube Video Resources

Welcome to La Casa de Aurelio.

This post includes the files from the tutorial for building a Telegram bot connected to an LLM, deployed on Railway, and backed by Supabase vector search.

System idea

  • Upload files or text.
  • The content is vectorized and stored in Supabase.
  • The agent uses that information as memory.
  • You message it through Telegram.
  • The bot answers using the context from your own documents.

Resources included

  • Workflow JSON to import into n8n.
  • SQL to create the Supabase table.
  • Base structure for connecting Telegram, LLM, Railway, and Supabase.

How to use it

  1. Open SQL Editor in Supabase.
  2. Paste the SQL below and run it.
  3. Import the workflow JSON in n8n.
  4. Connect your credentials: Telegram, Supabase, LLM/API, and Railway.
  5. Test with a small document before loading more information.

Important

Do not share API keys, Telegram tokens, or service role keys publicly. The downloadable workflow is sanitized: it does not include credentials or webhook IDs from the original environment.

Supabase SQL

Download
-- Extension
CREATE EXTENSION IF NOT EXISTS vector;

-- Tabla
CREATE TABLE documentos_negocio (
  id BIGSERIAL PRIMARY KEY,
  content TEXT,
  metadata JSONB,
  embedding VECTOR(1536)
);

-- Funcion con el nombre que espera n8n
CREATE OR REPLACE FUNCTION match_documents(
  query_embedding VECTOR(1536),
  match_count INT DEFAULT 5,
  filter JSONB DEFAULT '{}'
)
RETURNS TABLE (
  id BIGINT,
  content TEXT,
  metadata JSONB,
  similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN QUERY
  SELECT
    documentos_negocio.id,
    documentos_negocio.content,
    documentos_negocio.metadata,
    1 - (documentos_negocio.embedding <=> query_embedding) AS similarity
  FROM documentos_negocio
  ORDER BY documentos_negocio.embedding <=> query_embedding
  LIMIT match_count;
END;
$$;

n8n workflow JSON

Import this JSON into n8n and reconnect every credential before activating the workflow.

Download
{
  "nodes": [
    {
      "parameters": {
        "formTitle": "Upload your data to test RAG",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Upload your file(s)",
              "fieldType": "file",
              "acceptFileTypes": ".pdf, .csv",
              "requiredField": true
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.2,
      "position": [
        3488,
        1520
      ],
      "id": "39ac0897-e878-4e87-a433-a89ef5e8c20c",
      "name": "Upload your file here"
    },
    {
      "parameters": {
        "mode": "insert",
        "tableName": {
          "__rl": true,
          "value": "documentos_negocio",
          "mode": "list",
          "cachedResultName": "documentos_negocio"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1.3,
      "position": [
        3664,
        1520
      ],
      "id": "8ec98120-fdcc-4a89-ba32-268c257238ca",
      "name": "Supabase Vector Store"
    },
    {
      "parameters": {
        "jsCode": "const raw = $json.output || $json.respuesta || \"\";\n\nlet clean;\ntry {\n  clean = raw\n    // 0. Limpiar pre-escapado que viene del agente\n    .replace(/\\\\\\\\/g, '\\\\')\n    .replace(/\\\\\"/g, '\"')\n    // 1. Viñetas a guiones\n    .replace(/^\\*\\s+/gm, '- ')\n    // 2. **negrita** → *negrita* (antes de escapar)\n    .replace(/\\*\\*(.*?)\\*\\*/g, '*$1*')\n    // 3. Escapar especiales para MarkdownV2 (excepto * que ya está formateado)\n    .replace(/([_[\\]()~`>#+\\-=|{}.!\\\\])/g, '\\\\$1');\n} catch (e) {\n  clean = \"Lo siento, hubo un error procesando la respuesta\\\\.\";\n}\n\nreturn [{ json: { output: clean } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3936,
        1152
      ],
      "id": "9e8cb775-d149-4ddd-8656-f0b0c4c85f6d",
      "name": "formateo"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.message.text }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "id": "864a8a1f-8ded-419e-8680-0fc8663930c1"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "texto"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "bd30d3c6-9f5e-43a1-b84a-a1ef0903b40d",
                    "leftValue": "={{$json.message.voice.file_id}}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "audio"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "994b4cac-7bbd-4652-94d5-88f63f1d4d9a",
                    "leftValue": "={{$json.message.photo[0].file_id}}",
                    "rightValue": "foto",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "foto"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "b107b71a-8d71-4f76-9f6f-4c185b3c40ca",
                    "leftValue": "={{$json.message.document.mime_type}}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "documento"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        2736,
        1280
      ],
      "id": "2b29a043-5b08-4e86-a5e1-55c056c50ec8",
      "name": "Switch"
    },
    {
      "parameters": {
        "chatId": "={{ $('trigger_aurelio').first().json.message.from.id }}",
        "text": "=Formato no soportado. Intente de nuevo 🐶",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        3040,
        1488
      ],
      "id": "7493e86c-4054-44e1-a999-6f1f4ce6fdd0",
      "name": "mensaje_formato_no_soportado"
    },
    {
      "parameters": {
        "chatId": "={{ $('data').first().json.contact_id }}",
        "text": "={{ $json.output }}",
        "additionalFields": {
          "appendAttribution": false,
          "parse_mode": "MarkdownV2"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        4112,
        1152
      ],
      "id": "6d2fbdd4-187a-49af-87f8-9f31d4aa9d36",
      "name": "respuesta",
      "retryOnFail": false,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "resource": "file",
        "fileId": "={{ $json.message.voice.file_id }}",
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        3040,
        1296
      ],
      "id": "3fa25ead-77d4-4248-a82d-51e9db34d7af",
      "name": "get_audio"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "75da8d7f-60f7-49a6-8cc6-dc935a3d2623",
              "name": "contact_id",
              "value": "={{ $('trigger_aurelio').first().json.message.from.id }}",
              "type": "string"
            },
            {
              "id": "c5b7e5fa-6480-42a2-91cf-32e5c9711672",
              "name": "primer_nombre",
              "value": "={{ $('trigger_aurelio').first().json.message.from.first_name }}",
              "type": "string"
            },
            {
              "id": "a98db422-e2b1-474e-816a-32bb22b23671",
              "name": "nombre_usuario",
              "value": "={{ $('trigger_aurelio').first().json.message.from.username }}",
              "type": "string"
            },
            {
              "id": "874b422a-c7ed-4fc3-84a6-3b6b20cebaae",
              "name": "mensaje",
              "value": "={{ $('trigger_aurelio').first().json.message.text?.replace(/'/g, \"''\") || $('audio_texto1').first().json.content.parts[0].text || '' }}",
              "type": "string"
            },
            {
              "id": "f9db8d83-a199-461c-a47e-c86535d7b7c4",
              "name": "fecha_mensaje",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        3456,
        1152
      ],
      "id": "abd2cebf-bbb9-4ac4-bc9f-a6ee7641edea",
      "name": "data"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        3840,
        1872
      ],
      "id": "1612b2dd-8b0a-47cc-97df-e88e0f5a104f",
      "name": "Embeddings OpenAI"
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.3,
      "position": [
        2544,
        1312
      ],
      "id": "02a1d80a-9a83-4c15-ae13-d925d678514e",
      "name": "trigger_aurelio"
    },
    {
      "parameters": {
        "resource": "audio",
        "operation": "transcribe",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.3,
      "position": [
        3264,
        1296
      ],
      "id": "3b50d2a4-4916-44f4-8681-cedd6d338363",
      "name": "audio_texto"
    },
    {
      "parameters": {
        "dataType": "binary",
        "loader": "pdfLoader",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1.1,
      "position": [
        3840,
        1696
      ],
      "id": "b0c40230-193a-41ab-853c-45534a6338d5",
      "name": "Default Data Loader"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('data').first().json.contact_id }}",
        "tableName": "n8n_chat_histories_aurelio"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.4,
      "position": [
        3728,
        1344
      ],
      "id": "f0d68f32-856e-4e8d-9495-3fa38d1e62d2",
      "name": "Postgres Chat Memory"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "gpt-4o-mini"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        3568,
        1344
      ],
      "id": "7897b761-7c7d-4dc5-ac23-ec6df89d465e",
      "name": "OpenAI Chat Model"
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "Usa esta herramienta para buscar información sobre Aurelio: \nprocesos internos, políticas, manual de la empresa, \nprocedimientos operativos y documentación institucional.",
        "tableName": {
          "__rl": true,
          "value": "rpc/match_documents",
          "mode": "list",
          "cachedResultName": "rpc/match_documents"
        },
        "topK": 10,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1.3,
      "position": [
        3984,
        1520
      ],
      "id": "a430db20-9d8f-4910-a25a-2b3b6dce15e0",
      "name": "knowledge_aurelio"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Nombre del Usuario: {{ $('data').first().json.primer_nombre }}\nMensaje del Usuario: {{ $('data').first().json.mensaje }}",
        "options": {
          "systemMessage": "=Eres el asistente interno de Aurelio Agency, una agencia especializada en inteligencia artificial y automatización de procesos.\n\nTu función es responder preguntas de los empleados sobre los procesos internos, servicios, cultura y operaciones de la agencia, basándote EXCLUSIVAMENTE en la información de la base de conocimiento que tenés disponible.\n\nREGLAS:\n- Solo respondés con información que esté en la base de conocimiento. Si no encontrás la respuesta, decís: \"No tengo información sobre eso en la base de conocimiento. Te recomiendo consultarlo con Lucien o Gustavo.\"\n- Respondés siempre en español, de forma clara y concisa.\n- No inventás información, precios, procesos ni nombres que no estén en la base.\n- Si la pregunta es ambigua, pedís clarificación antes de responder.\n- Tu tono es profesional pero cercano, como un compañero de equipo con experiencia.\n\nCONTEXTO:\nEres usado principalmente por empleados nuevos que necesitan orientarse rápidamente sin interrumpir a los fundadores."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        3632,
        1152
      ],
      "id": "7912da4c-1e94-4a34-a68c-4f0ea726db65",
      "name": "aurelio_wiki"
    }
  ],
  "connections": {
    "Upload your file here": {
      "main": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "formateo": {
      "main": [
        [
          {
            "node": "respuesta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "get_audio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "mensaje_formato_no_soportado",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "mensaje_formato_no_soportado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "respuesta": {
      "main": [
        [],
        []
      ]
    },
    "get_audio": {
      "main": [
        [
          {
            "node": "audio_texto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "data": {
      "main": [
        [
          {
            "node": "aurelio_wiki",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "knowledge_aurelio",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "trigger_aurelio": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "audio_texto": {
      "main": [
        [
          {
            "node": "data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Default Data Loader": {
      "ai_document": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "aurelio_wiki",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "aurelio_wiki",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "knowledge_aurelio": {
      "ai_tool": [
        [
          {
            "node": "aurelio_wiki",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "aurelio_wiki": {
      "main": [
        [
          {
            "node": "formateo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}