Intelligenter Telegram-Assistent

Experte

Dies ist ein AI Chatbot, Multimodal AI-Bereich Automatisierungsworkflow mit 36 Nodes. Hauptsächlich werden Set, Code, Switch, Postgres, Telegram und andere Nodes verwendet. Intelligenten Telegram-Assistenten mit Gemini AI, PostgreSQL-Speicher und dynamischer Routing bauen

Voraussetzungen
  • PostgreSQL-Datenbankverbindungsdaten
  • Telegram Bot Token
  • Google Gemini API Key
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
  "meta": {
    "instanceId": "50be75eaab016244f302e16f06394e6613d664bfc61e8cd41452474a0de6a3ee",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa",
      "name": "Modellauswahl",
      "type": "@n8n/n8n-nodes-langchain.modelSelector",
      "position": [
        800,
        1536
      ],
      "parameters": {
        "rules": {
          "rule": [
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "976d83bb-7e9e-4aab-9722-25a9e238164f",
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.output.difficulty }}",
                    "rightValue": 1
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "1e68688d-73fe-47c1-9b35-a1e226220bcd",
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.output.difficulty }}",
                    "rightValue": 2
                  }
                ]
              },
              "modelIndex": 2
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "61d58197-db59-4cd7-bc41-bbeaf5e7b069",
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.output.difficulty }}",
                    "rightValue": 3
                  }
                ]
              },
              "modelIndex": 3
            }
          ]
        },
        "numberInputs": 3
      },
      "typeVersion": 1
    },
    {
      "id": "cf5b2ea0-78c5-47bf-a3c1-4c59c9a32f76",
      "name": "Strukturierter Ausgabeparser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        336,
        1504
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"difficulty\": {\n      \"type\": \"integer\",\n      \"enum\": [1, 2, 3]\n    },\n    \"context\": {\n      \"type\": \"string\"\n    }\n  },\n  \"required\": [\"difficulty\", \"context\"]\n}\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "3a60caa7-eb1a-4bbd-88fc-55d7a3ffae29",
      "name": "Gemini 2.5 Flash Lite",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        720,
        1728
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-2.5-flash-lite"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "to92mdfNe3L6sBae",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "412d35ed-cd49-4d20-b425-2f556ef175b1",
      "name": "Gemini 2.5 Flash",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        880,
        1728
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "to92mdfNe3L6sBae",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2cc40e2c-a2be-435e-8540-9235efc41e08",
      "name": "Gemini 2.5 Pro",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1024,
        1728
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-2.5-pro"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "to92mdfNe3L6sBae",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "35f56404-6998-4952-a7f3-8716712bf96a",
      "name": "Chat-Gedächtnis abrufen",
      "type": "n8n-nodes-base.postgres",
      "onError": "continueRegularOutput",
      "position": [
        -256,
        1328
      ],
      "parameters": {
        "limit": 25,
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "chat_memory",
          "cachedResultName": "chat_memory"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "options": {},
        "operation": "select"
      },
      "credentials": {
        "postgres": {
          "id": "eQR2NFRag48wov9g",
          "name": "Postgres account"
        }
      },
      "typeVersion": 2.6,
      "alwaysOutputData": true
    },
    {
      "id": "5e6058bc-a3b8-4827-954e-85e3a000a986",
      "name": "MarkdownV2",
      "type": "n8n-nodes-base.code",
      "position": [
        1136,
        1264
      ],
      "parameters": {
        "jsCode": "/**\n * MarkdownV2-safe formatter + auto-chunker for Telegram (n8n Code node)\n * --------------------------------------------------------------------\n * - Allows: *bold*, _italic_, ||spoiler||, [label](url)\n * - Escapes everything else for Telegram MarkdownV2\n * - Validates/normalizes URLs\n * - Converts \"# Heading\" lines to bold titles\n * - Splits long messages into <= 4096-char chunks (uses a 4000-char budget)\n * - Outputs one item per chunk so the Telegram node sends all parts\n *\n * Recommended: Run this node in \"Run Once for All Items\".\n */\n\nconst MAX_TELEGRAM = 4096;\nconst SAFE_BUDGET = 4000; // small margin to avoid edge overflows\n\n// ============ MarkdownV2 helpers ============\nfunction escapeMarkdownV2(text) {\n  if (!text) return '';\n  return String(text).replace(/([\\\\_*[\\]()~`>#+\\-=|{}.!])/g, '\\\\$1');\n}\n\nfunction escapeForUrl(url) {\n  return String(url).replace(/[)\\\\]/g, '\\\\$&');\n}\n\nfunction normalizeAndValidateUrl(url) {\n  let raw = String(url || '').trim();\n  try {\n    const u = new URL(raw);\n    return u.toString();\n  } catch {}\n  // Try https:// for bare domains\n  const domainLike = /^[a-z0-9.-]+\\.[a-z]{2,}([/:?#].*)?$/i.test(raw);\n  if (domainLike) {\n    try {\n      const u2 = new URL('https://' + raw);\n      return u2.toString();\n    } catch {}\n  }\n  return null;\n}\n\nfunction normalizeHeadings(text) {\n  // Turn \"# Title\" → \"*Title*\"\n  return text.replace(/^(#{1,6})\\s+(.*)$/gm, (m, hashes, title) => `*${title.trim()}*`);\n}\n\nfunction normalizeCommonMd(text) {\n  return String(text)\n    .replace(/\\*\\*([\\s\\S]*?)\\*\\*/g, '*$1*') // **bold** → *bold*\n    .replace(/__([\\s\\S]*?)__/g, '_$1_');    // __italic__ → _italic_\n}\n\n/**\n * Convert incoming text to Telegram-safe MarkdownV2.\n */\nfunction processMarkdownV2Safe(inputText) {\n  if (!inputText) return '';\n\n  let text = normalizeCommonMd(String(inputText));\n  text = normalizeHeadings(text);\n\n  const placeholders = { links: [], bolds: [], italics: [], spoilers: [] };\n\n  // Links: keep safe via placeholders during escaping\n  text = text.replace(/\\[([^\\]\\n]+)\\]\\(([^)]+)\\)/g, (m, label, url) => {\n    const normalizedUrl = normalizeAndValidateUrl(url);\n    if (!normalizedUrl) return escapeMarkdownV2(label);\n    const idx = placeholders.links.length;\n    const ph = `⟬L${idx}⟭`;\n    const safeLabel = escapeMarkdownV2(label);\n    const safeUrl = escapeForUrl(normalizedUrl);\n    placeholders.links.push(`[${safeLabel}](${safeUrl})`);\n    return ph;\n  });\n\n  // Bold\n  text = text.replace(/\\*([\\s\\S]+?)\\*/g, (m, inner) => {\n    const idx = placeholders.bolds.length;\n    const ph = `⟬B${idx}⟭`;\n    placeholders.bolds.push(`*${escapeMarkdownV2(inner)}*`);\n    return ph;\n  });\n\n  // Italic\n  text = text.replace(/_([\\s\\S]+?)_/g, (m, inner) => {\n    const idx = placeholders.italics.length;\n    const ph = `⟬I${idx}⟭`;\n    placeholders.italics.push(`_${escapeMarkdownV2(inner)}_`);\n    return ph;\n  });\n\n  // Spoilers\n  text = text.replace(/\\|\\|([\\s\\S]+?)\\|\\|/g, (m, inner) => {\n    const idx = placeholders.spoilers.length;\n    const ph = `⟬S${idx}⟭`;\n    placeholders.spoilers.push(`||${escapeMarkdownV2(inner)}||`);\n    return ph;\n  });\n\n  // Escape everything else\n  text = escapeMarkdownV2(text);\n\n  // Restore placeholders\n  placeholders.links.forEach((md, i) => { text = text.replace(`⟬L${i}⟭`, md); });\n  placeholders.bolds.forEach((md, i) => { text = text.replace(`⟬B${i}⟭`, md); });\n  placeholders.italics.forEach((md, i) => { text = text.replace(`⟬I${i}⟭`, md); });\n  placeholders.spoilers.forEach((md, i) => { text = text.replace(`⟬S${i}⟭`, md); });\n\n  return text;\n}\n\n// ============ Chunking helpers ============\n/**\n * Split text into Telegram-safe chunks <= maxLen.\n * Prefers paragraph boundaries, then sentence boundaries, then words.\n * Falls back to hard cuts only when unavoidable (e.g., extremely long URL).\n */\nfunction chunkForTelegram(text, maxLen = SAFE_BUDGET) {\n  if (!text || text.length <= maxLen) return [text || ''];\n\n  const parts = [];\n  let buffer = '';\n\n  const flush = () => {\n    if (buffer) {\n      parts.push(buffer);\n      buffer = '';\n    }\n  };\n\n  // 1) Paragraph-level packing\n  const paragraphs = text.split(/\\n{2,}/);\n  for (const pRaw of paragraphs) {\n    const p = pRaw; // keep paragraph as-is\n    const candidate = buffer ? buffer + '\\n\\n' + p : p;\n    if (candidate.length <= maxLen) {\n      buffer = candidate;\n      continue;\n    }\n    if (p.length <= maxLen) {\n      flush();\n      buffer = p;\n      continue;\n    }\n\n    // 2) Sentence-level packing (paragraph is still too big)\n    flush();\n    const sentences = p.split(/(?<=[.!?…])\\s+(?=[^\\s])/u);\n    let sBuf = '';\n    for (const s of sentences) {\n      const sCandidate = sBuf ? sBuf + ' ' + s : s;\n      if (sCandidate.length <= maxLen) {\n        sBuf = sCandidate;\n        continue;\n      }\n      if (s.length <= maxLen) {\n        if (sBuf) parts.push(sBuf);\n        sBuf = s;\n        continue;\n      }\n\n      // 3) Word-level packing (sentence is still too big)\n      if (sBuf) { parts.push(sBuf); sBuf = ''; }\n      let wBuf = '';\n      const words = s.split(/\\s+/);\n      for (const w of words) {\n        const wCandidate = wBuf ? wBuf + ' ' + w : w;\n        if (wCandidate.length <= maxLen) {\n          wBuf = wCandidate;\n          continue;\n        }\n        if (w.length <= maxLen) {\n          if (wBuf) parts.push(wBuf);\n          wBuf = w;\n          continue;\n        }\n        // 4) Hard split (extremely long token, e.g., massive URL)\n        if (wBuf) { parts.push(wBuf); wBuf = ''; }\n        const re = new RegExp(`.{1,${maxLen}}`, 'g');\n        const hardPieces = w.match(re) || [];\n        parts.push(...hardPieces);\n      }\n      if (wBuf) parts.push(wBuf);\n    }\n    if (sBuf) parts.push(sBuf);\n  }\n  if (buffer) parts.push(buffer);\n\n  // Final safety pass: trim chunks that might still exceed MAX_TELEGRAM\n  return parts.flatMap(part => {\n    if (part.length <= MAX_TELEGRAM) return [part];\n    const re = new RegExp(`.{1,${SAFE_BUDGET}}`, 'g');\n    return part.match(re) || [];\n  });\n}\n\n// ============ Main ============\nconst inputItems = $input.all();\nconst out = [];\n\nfor (const item of inputItems) {\n  const j = item.json || {};\n  const raw =\n    j.message ?? j.output ?? j.text ?? j.content ?? '';\n\n  const formatted = processMarkdownV2Safe(raw);\n  const chunks = chunkForTelegram(formatted, SAFE_BUDGET);\n\n  chunks.forEach((chunk, idx) => {\n    out.push({\n      json: {\n        ...j,\n        message: chunk,\n        message_part_index: idx + 1,\n        message_parts_total: chunks.length,\n      },\n      binary: item.binary,\n    });\n  });\n}\n\nreturn out;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6ce0f61c-03d1-4bef-827f-ac3c80f48939",
      "name": "Textnachricht senden",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1312,
        1264
      ],
      "webhookId": "1ad49e91-7894-4fb1-ba93-73ba3ec4e666",
      "parameters": {
        "text": "={{ $json.message }}",
        "chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
        "additionalFields": {
          "parse_mode": "MarkdownV2",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "rzhkYoexl5hHvqnv",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "662e6beb-7498-42c2-ba0c-6530c100bf97",
      "name": "MIME korrigieren",
      "type": "n8n-nodes-base.code",
      "position": [
        -1184,
        1328
      ],
      "parameters": {
        "jsCode": "// --- Mapa Extendido de Tipos MIME ---\n// Una lista completa para cubrir la mayoría de los formatos de archivo comunes.\nconst mimeMap = {\n  // --- Formatos de Documentos ---\n  'pdf': 'application/pdf',\n  'txt': 'text/plain',\n  'rtf': 'application/rtf',\n  'csv': 'text/csv',\n  'html': 'text/html',\n  'htm': 'text/html',\n  'json': 'application/json',\n  'xml': 'application/xml', // 'text/xml' también es válido pero 'application/xml' es más común\n  'yaml': 'application/x-yaml',\n  'yml': 'application/x-yaml',\n\n  // --- Formatos de Microsoft Office ---\n  'doc': 'application/msword',\n  'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n  'xls': 'application/vnd.ms-excel',\n  'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n  'ppt': 'application/vnd.ms-powerpoint',\n  'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n  'pub': 'application/vnd.ms-publisher',\n\n  // --- Formatos de OpenOffice / LibreOffice ---\n  'odt': 'application/vnd.oasis.opendocument.text',\n  'ods': 'application/vnd.oasis.opendocument.spreadsheet',\n  'odp': 'application/vnd.oasis.opendocument.presentation',\n  'odg': 'application/vnd.oasis.opendocument.graphics',\n\n  // --- Formatos de Apple iWork ---\n  'pages': 'application/vnd.apple.pages',\n  'numbers': 'application/vnd.apple.numbers',\n  'key': 'application/vnd.apple.keynote',\n\n  // --- Formatos de Imagen ---\n  'png': 'image/png',\n  'jpg': 'image/jpeg',\n  'jpeg': 'image/jpeg',\n  'gif': 'image/gif',\n  'webp': 'image/webp',\n  'svg': 'image/svg+xml',\n  'bmp': 'image/bmp',\n  'ico': 'image/vnd.microsoft.icon',\n  'tif': 'image/tiff',\n  'tiff': 'image/tiff',\n  'heic': 'image/heic',\n  'heif': 'image/heif',\n\n  // --- Formatos de Audio ---\n  'mp3': 'audio/mpeg',\n  'wav': 'audio/wav',\n  'oga': 'audio/ogg',\n  'ogg': 'audio/ogg',\n  'flac': 'audio/flac',\n  'm4a': 'audio/mp4',\n  'aac': 'audio/aac',\n  'opus': 'audio/opus',\n  'wma': 'audio/x-ms-wma',\n  'mid': 'audio/midi',\n  'midi': 'audio/midi',\n\n  // --- Formatos de Video ---\n  'mp4': 'video/mp4',\n  'mov': 'video/quicktime',\n  'webm': 'video/webm',\n  'mpeg': 'video/mpeg',\n  'mpg': 'video/mpeg',\n  'avi': 'video/x-msvideo',\n  'wmv': 'video/x-ms-wmv',\n  'flv': 'video/x-flv',\n  'mkv': 'video/x-matroska',\n\n  // --- Formatos de Archivos y Compresión ---\n  'zip': 'application/zip',\n  'rar': 'application/vnd.rar',\n  '7z': 'application/x-7z-compressed',\n  'tar': 'application/x-tar',\n  'gz': 'application/gzip',\n  'bz2': 'application/x-bzip2',\n\n  // --- Otros Formatos ---\n  'epub': 'application/epub+zip',\n  'ics': 'text/calendar',\n  'vcf': 'text/vcard',\n  'js': 'text/javascript',\n  'css': 'text/css',\n  'sh': 'application/x-sh',\n  'py': 'text/x-python',\n};\n\n// --- Lógica de Procesamiento (sin cambios) ---\n\n// Obtenemos todos los items que llegan al nodo\nconst items = $input.all();\n\n// Iteramos sobre cada item para procesarlo\nfor (const item of items) {\n  // Verificamos que el item tenga datos binarios para procesar\n  if (item.binary && item.binary['data']) {\n    // Obtenemos el nombre del archivo de forma segura\n    const fileName = item.binary['data'].fileName || '';\n    if (!fileName) {\n      continue; // Si no hay nombre de archivo, pasamos al siguiente item\n    }\n\n    // Extraemos la extensión del archivo de forma robusta\n    const extension = fileName.slice((fileName.lastIndexOf(\".\") - 1 >>> 0) + 2).toLowerCase();\n\n    // Buscamos la extensión en nuestro mapa\n    const newMimeType = mimeMap[extension];\n\n    // Si encontramos una coincidencia en el mapa, actualizamos el mimeType\n    if (newMimeType) {\n      if(item.binary['data'].mimeType !== newMimeType) {\n        console.log(`Cambiando mimeType para '${fileName}' de '${item.binary['data'].mimeType}' a '${newMimeType}'.`);\n        item.binary['data'].mimeType = newMimeType;\n      }\n    }\n  }\n}\n\n// Devolvemos todos los items, modificados o no\nreturn items;"
      },
      "typeVersion": 2
    },
    {
      "id": "07281d83-6c94-4952-819e-288a4435da24",
      "name": "Wird getippt…",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -1744,
        1184
      ],
      "webhookId": "b768e407-5f22-4b80-a8a9-2d255b9bf815",
      "parameters": {
        "chatId": "={{ $json.message.chat.id }}",
        "operation": "sendChatAction"
      },
      "credentials": {
        "telegramApi": {
          "id": "rzhkYoexl5hHvqnv",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e211d4af-9ebd-4524-84ef-934349b6b155",
      "name": "Nachricht abrufen (Audio/Video)",
      "type": "n8n-nodes-base.set",
      "position": [
        -848,
        1328
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d8935452-fe20-469d-a68d-1aad056cb8dd",
              "name": "message",
              "type": "string",
              "value": "=Voice message description:{{ $json.candidates?.[0]?.content?.parts?.[0]?.text || $json.content?.parts?.[0]?.text }}"
            },
            {
              "id": "93f1bba1-1180-404a-93ca-c34cf1d1b7ac",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9c28c37b-1d37-4f23-90a3-872f5e3870a7",
      "name": "Sprachnachricht analysieren",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        -1024,
        1328
      ],
      "parameters": {
        "text": "What's in this audio message from telegram user?",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-pro",
          "cachedResultName": "models/gemini-2.5-pro"
        },
        "options": {},
        "resource": "audio",
        "inputType": "binary",
        "operation": "analyze"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "to92mdfNe3L6sBae",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ea646e8c-e6d0-47ea-8743-45eade4c1c4d",
      "name": "Nachricht abrufen (Text)",
      "type": "n8n-nodes-base.set",
      "position": [
        -1184,
        1152
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "801ec600-22ad-4a94-a2b4-ae72eb271df0",
              "name": "message",
              "type": "string",
              "value": "={{ $('Telegram Trigger').item.json.message.text }}"
            },
            {
              "id": "263071fb-bcdf-42b0-bb46-71b75fa0bf2a",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "1ca88076-5c56-4561-bb8a-fdf1db080d2a",
      "name": "Eingabe-Nachrichtenrouter1",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1600,
        1312
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Text",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "fcb767ee-565e-4b56-a54e-6f97f739fc24",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Voice Message",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c1016c40-f8f2-4e08-8ec8-5cdb88f5c87a",
                    "operator": {
                      "type": "object",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.voice }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "ignoreCase": false,
          "fallbackOutput": "extra",
          "allMatchingOutputs": true
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "298fa06c-d3fc-4d20-a2d4-fe879a01527c",
      "name": "Sprachnachricht herunterladen",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -1360,
        1328
      ],
      "webhookId": "d28e2f59-d662-4e75-8bac-11fdc3fbb295",
      "parameters": {
        "fileId": "={{ $('Telegram Trigger').item.json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "rzhkYoexl5hHvqnv",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5a1dc986-6bfe-4400-bdbf-d4f5817e0f7e",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1888,
        1328
      ],
      "webhookId": "1aecee74-ba0f-4fe2-a302-578312187154",
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "rzhkYoexl5hHvqnv",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0188bc12-4fc1-4149-8c80-edf8e80009ec",
      "name": "Eingabe normalisieren",
      "type": "n8n-nodes-base.set",
      "position": [
        -464,
        1328
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3c2fa4f9-079c-4729-9737-66ce8f42029f",
              "name": "message",
              "type": "string",
              "value": "={{ $json.message }}"
            },
            {
              "id": "b6e57068-8ece-4725-b07d-1b00069943b0",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $json.chat_id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4db66ea5-0817-4326-9991-ab6a905ec0ee",
      "name": "Aggregieren",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        -48,
        1328
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "message"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a4ce42c2-d1cc-4233-9ee7-2aac9a5f0c45",
      "name": "Google Gemini 2.5 Flash Lite",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        192,
        1504
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-2.5-flash-lite"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "to92mdfNe3L6sBae",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5c2cd387-3b15-4869-87da-6873437a0d33",
      "name": "Fehlermeldung abrufen",
      "type": "n8n-nodes-base.set",
      "position": [
        -1184,
        1504
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d8935452-fe20-469d-a68d-1aad056cb8dd",
              "name": "message",
              "type": "string",
              "value": "=It was not possible to process the file.File type not supported."
            },
            {
              "id": "38ba2498-2141-4a04-a22a-64563fe2ee6f",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d31898fc-4d10-43ea-bc5d-402ac29f3f4b",
      "name": "Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        800,
        1328
      ],
      "parameters": {
        "text": "=Context: {{ $json.output.context }}\nUser request: {{ $('Normalize input').item.json.message }}",
        "options": {
          "returnIntermediateSteps": true
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "ee146b55-17b6-414c-be6b-f8416ece7075",
      "name": "Notizzettel",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1984,
        1104
      ],
      "parameters": {
        "color": 5,
        "width": 1312,
        "height": 624,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "e677f7d7-2cfc-476d-bdc0-08b4cf17cb4d",
      "name": "Notizzettel1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -576,
        1248
      ],
      "parameters": {
        "color": 3,
        "width": 1216,
        "height": 400,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "d36b2018-ca63-4c1f-a40e-46d1452753e2",
      "name": "Bei Klick auf ‚Workflow ausführen‘",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1888,
        880
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "451eb06f-5b47-44c5-86fa-20587cf89870",
      "name": "Chat-Gedächtnistabelle erstellen",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -1696,
        880
      ],
      "parameters": {
        "query": "CREATE TABLE IF NOT EXISTS public.chat_memory (\n  id SERIAL PRIMARY KEY,\n  session_id VARCHAR(255) NOT NULL,\n  message TEXT DEFAULT 'Could not get data'\n) TABLESPACE pg_default;\n\nCREATE INDEX IF NOT EXISTS chat_memory_session_id_idx \nON public.chat_memory USING btree (session_id) \nTABLESPACE pg_default;\n",
        "options": {},
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "id": "eQR2NFRag48wov9g",
          "name": "Postgres account"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "fb4c1415-dd98-4944-8c12-e69f8d445be7",
      "name": "Notizzettel2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1984,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 208,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "50ac5adc-ce42-4f35-84ac-cf8e2bea5d38",
      "name": "Notizzettel3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        1248
      ],
      "parameters": {
        "color": 6,
        "width": 880,
        "height": 624,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "97859eb8-951f-4abf-8b89-63299b456304",
      "name": "Chat-Gedächtnis aktualisieren (Benutzer und Agent)",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1136,
        1424
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "chat_memory",
          "cachedResultName": "chat_memory"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "message": "=User:  {{ $('Normalize input').item.json.message }}\nAgent:  {{ $json.output }}\n",
            "session_id": "={{ $('Normalize input').item.json.chat_id }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "session_id",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "session_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "id": "eQR2NFRag48wov9g",
          "name": "Postgres account"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde",
      "name": "Zusammenfassen & Kategorisieren",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        192,
        1328
      ],
      "parameters": {
        "text": "=Chat Memory: {{ $('Aggregate').item.json.message.join('\\n') }}\n\nUser Request: {{ $('Normalize input').item.json.message }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are a system that analyzes a user request and its chat history.\n\n## Your goals:\n1. Summarize the chat history into only the relevant context for the current user request.\n2. Determine the difficulty of the request:\n   - 1: Very simple (short answers, reminders, basic actions).\n   - 2: Medium (some reasoning, structured outputs, combining info).\n   - 3: Complex (multi-step reasoning, ambiguous queries, coding-level reasoning).\n\n## Output Format:\nYou must return JSON strictly following this schema:\n\n{\n  \"difficulty\": 1 | 2 | 3,\n  \"context\": \"string - summary of the relevant history\"\n}\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "8979f56c-2809-426d-acda-9d455df8836e",
      "name": "Notizzettel4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1984,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 256,
        "content": "## ⚙️ Database Initialization (Chat Memory Table)\n\n**Purpose:**  \nThis section is responsible for creating and preparing the `chat_memory` table in PostgreSQL. It ensures that chat interactions are stored persistently for later use in context management, summarization, and categorization.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cf047f39-85cd-41a6-8d2a-76ecec83b6f2",
      "name": "Notizzettel5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1392,
        432
      ],
      "parameters": {
        "color": 5,
        "width": 704,
        "height": 640,
        "content": "## 🔵 Input Handling (Telegram Trigger & Preprocessing)\n\n### Purpose:\nThis section receives and processes incoming messages from Telegram. It detects whether the input is text, voice, or unsupported media.\n\n### Key Steps:\n\n*   **Telegram Trigger** – Listens for new updates (messages from users).\n*   **Input Message Router** – Classifies whether the input is:\n    *   Text message\n    *   Voice message\n    *   Unsupported media → redirects to an error handler\n*   **Voice Handling** – If it’s a voice message:\n    *   Downloads the file\n    *   Normalizes MIME type\n    *   Sends it to speech-to-text analysis\n    *   Extracts the text message from audio\n*   **Error Handling** – If the input is not supported, an error message is returned.\n\n### Optional Extension:\nFor multimodal and media group support (multiple files, images, videos), you can extend this section with the following template: https://n8n.io/workflows/7455-process-multiple-media-files-in-telegram-with-gemini-ai-and-postgresql-database/"
      },
      "typeVersion": 1
    },
    {
      "id": "3557d1c3-c155-430a-a11b-5bc901111d46",
      "name": "Notizzettel6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -352,
        496
      ],
      "parameters": {
        "color": 3,
        "width": 784,
        "height": 720,
        "content": "## 🔴 Chat Memory Retrieval & Context Optimization\n\n### Purpose:\nThis section retrieves past interactions from the database, aggregates them into a single string, and summarizes them before passing them to the agent.\n\n### Key Steps:\n\n*   **Normalize Input** – Standardizes the message before processing.\n*   **Get Chat Memory** – Queries PostgreSQL for previous messages linked to the `session_id`.\n*   **Aggregate** – Combines past interactions into one text block.\n*   **Summarize & Categorize** – Uses Google Gemini 2.5 Flash Lite (low-cost, low-latency) to:\n    *   Summarize the chat history.\n    *   Extract relevant context.\n    *   Categorize the difficulty level of the task.\n\n### Why Summarization First?\n\n*   Only relevant and important context is passed to the agent.\n*   Reduces token usage, speeding up responses and lowering costs.\n*   Prevents irrelevant history from cluttering the model’s attention.\n\n### Advantages:\n\n*   Saves processing time and cost by using a lightweight summarization model.\n*   Produces more accurate and focused responses.\n*   Optimizes memory queries by reducing data size passed downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "42fdc20f-2c28-4826-8704-20ffb8792bd7",
      "name": "Notizzettel7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        704,
        384
      ],
      "parameters": {
        "color": 6,
        "width": 784,
        "height": 832,
        "content": "## 🟣 Agent Processing & Response Delivery\n\n### Purpose:\nThis section routes the request to the appropriate Gemini model depending on task difficulty, generates the final response, and sends it back to Telegram. It also updates the chat memory.\n\n### Key Steps:\n\n*   **Agent Node** – Receives:\n    *   User request\n    *   Relevant summarized context\n    *   Difficulty level\n*   **Model Selector** – Dynamically chooses the model:\n    *   **Difficulty 1** → Gemini 2.5 Flash Lite (fastest & cheapest)\n    *   **Difficulty 2** → Gemini 2.5 Flash\n    *   **Difficulty 3** → Gemini 2.5 Pro (advanced reasoning)\n*   **Markdown Formatting** – Converts model output into Telegram-compatible Markdown V2.\n*   **Send Message** – Sends the response back to Telegram.\n*   **Update Chat Memory** – Inserts a single row containing both the user and agent message.\n\n### Why single-row storage for user & agent?\n\n*   Since the message is sent to Telegram first and then the memory is updated, this saves an average of 0.3 seconds in response time.\n*   Reduces the number of queries (`Get Chat Memory` fetches fewer rows).\n*   Updates are faster since both messages are stored at once.\n*   Optimizes resource usage while maintaining full conversational context.\n\n### Advantages:\n\n*   Cost-optimized model usage (only advanced models used when strictly necessary).\n*   Faster response times by minimizing context size and database operations.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1c29f5cf-c95e-40fc-9dc0-362dcda71574",
      "name": "Notizzettel8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2560,
        1104
      ],
      "parameters": {
        "color": 4,
        "width": 544,
        "height": 592,
        "content": "## ✅ Key Benefits of This Architecture\n\n### Cost Efficiency\n\n*   Uses cheaper LLMs for summarization and simple queries.\n*   Reserves expensive models only for complex tasks.\n\n### Performance Optimization\n\n*   Reduced token consumption through summarization.\n*   Faster memory queries due to single-row storage.\n\n### Flexibility & Scalability\n\n*   Easy integration of multimodal inputs (images, audio, video).\n*   Modular structure allows replacing/upgrading models or database logic.\n\n### User Experience\n\n*   Quick Telegram responses.\n*   Consistent memory of past interactions without overwhelming the LLM."
      },
      "typeVersion": 1
    },
    {
      "id": "84019987-a071-44d0-8e4b-d80c838007dc",
      "name": "Notizzettel9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2496,
        848
      ],
      "parameters": {
        "color": 2,
        "width": 368,
        "height": 192,
        "content": "## Acknowledgment\n\nA special thank you to Davide for the inspiration behind this template.  \nHis work on the [**AI Orchestrator that dynamically selects models based on input type**](https://n8n.io/workflows/7004-ai-orchestrator-dynamically-selects-models-based-on-input-type/) served as a foundational guide for this architecture.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0c425ab2-41d3-43c9-86bb-9c7cbfe968a4",
      "name": "Notizzettel10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        1648
      ],
      "parameters": {
        "color": 2,
        "width": 368,
        "height": 192,
        "content": "## 💡 Need Assistance?\n\nIf you’d like help customizing or extending this workflow, feel free to reach out:  \n\n📧 Email: [johnsilva11031@gmail.com](mailto:johnsilva11031@gmail.com)  \n🔗 LinkedIn: [John Alejandro Silva Rodríguez](https://www.linkedin.com/in/john-alejandro-silva-rodriguez-48093526b/)\n"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "d31898fc-4d10-43ea-bc5d-402ac29f3f4b": {
      "main": [
        [
          {
            "node": "5e6058bc-a3b8-4827-954e-85e3a000a986",
            "type": "main",
            "index": 0
          },
          {
            "node": "97859eb8-951f-4abf-8b89-63299b456304",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "662e6beb-7498-42c2-ba0c-6530c100bf97": {
      "main": [
        [
          {
            "node": "9c28c37b-1d37-4f23-90a3-872f5e3870a7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4db66ea5-0817-4326-9991-ab6a905ec0ee": {
      "main": [
        [
          {
            "node": "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5e6058bc-a3b8-4827-954e-85e3a000a986": {
      "main": [
        [
          {
            "node": "6ce0f61c-03d1-4bef-827f-ac3c80f48939",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2cc40e2c-a2be-435e-8540-9235efc41e08": {
      "ai_languageModel": [
        [
          {
            "node": "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa",
            "type": "ai_languageModel",
            "index": 2
          }
        ]
      ]
    },
    "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa": {
      "ai_languageModel": [
        [
          {
            "node": "d31898fc-4d10-43ea-bc5d-402ac29f3f4b",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "35f56404-6998-4952-a7f3-8716712bf96a": {
      "main": [
        [
          {
            "node": "4db66ea5-0817-4326-9991-ab6a905ec0ee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "0188bc12-4fc1-4149-8c80-edf8e80009ec": {
      "main": [
        [
          {
            "node": "35f56404-6998-4952-a7f3-8716712bf96a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "412d35ed-cd49-4d20-b425-2f556ef175b1": {
      "ai_languageModel": [
        [
          {
            "node": "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "5a1dc986-6bfe-4400-bdbf-d4f5817e0f7e": {
      "main": [
        [
          {
            "node": "1ca88076-5c56-4561-bb8a-fdf1db080d2a",
            "type": "main",
            "index": 0
          },
          {
            "node": "07281d83-6c94-4952-819e-288a4435da24",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5c2cd387-3b15-4869-87da-6873437a0d33": {
      "main": [
        [
          {
            "node": "0188bc12-4fc1-4149-8c80-edf8e80009ec",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ea646e8c-e6d0-47ea-8743-45eade4c1c4d": {
      "main": [
        [
          {
            "node": "0188bc12-4fc1-4149-8c80-edf8e80009ec",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9c28c37b-1d37-4f23-90a3-872f5e3870a7": {
      "main": [
        [
          {
            "node": "e211d4af-9ebd-4524-84ef-934349b6b155",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3a60caa7-eb1a-4bbd-88fc-55d7a3ffae29": {
      "ai_languageModel": [
        [
          {
            "node": "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "1ca88076-5c56-4561-bb8a-fdf1db080d2a": {
      "main": [
        [
          {
            "node": "ea646e8c-e6d0-47ea-8743-45eade4c1c4d",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "298fa06c-d3fc-4d20-a2d4-fe879a01527c",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "5c2cd387-3b15-4869-87da-6873437a0d33",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "298fa06c-d3fc-4d20-a2d4-fe879a01527c": {
      "main": [
        [
          {
            "node": "662e6beb-7498-42c2-ba0c-6530c100bf97",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde": {
      "main": [
        [
          {
            "node": "d31898fc-4d10-43ea-bc5d-402ac29f3f4b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "cf5b2ea0-78c5-47bf-a3c1-4c59c9a32f76": {
      "ai_outputParser": [
        [
          {
            "node": "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "a4ce42c2-d1cc-4233-9ee7-2aac9a5f0c45": {
      "ai_languageModel": [
        [
          {
            "node": "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "e211d4af-9ebd-4524-84ef-934349b6b155": {
      "main": [
        [
          {
            "node": "0188bc12-4fc1-4149-8c80-edf8e80009ec",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "97859eb8-951f-4abf-8b89-63299b456304": {
      "main": [
        []
      ]
    },
    "d36b2018-ca63-4c1f-a40e-46d1452753e2": {
      "main": [
        [
          {
            "node": "451eb06f-5b47-44c5-86fa-20587cf89870",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Häufig gestellte Fragen

Wie verwende ich diesen Workflow?

Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.

Für welche Szenarien ist dieser Workflow geeignet?

Experte - KI-Chatbot, Multimodales KI

Ist es kostenpflichtig?

Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.

Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes36
Kategorie2
Node-Typen15
Schwierigkeitsbeschreibung

Für fortgeschrittene Benutzer, komplexe Workflows mit 16+ Nodes

Autor
John Alejandro SIlva

John Alejandro SIlva

@alejandro-silva

Detail-oriented professional with a dual degree in Systems Engineering and Business Administration and international experience in technology and process improvement. I specialize in workflow automation with n8n, API integration, programming, and data analysis. Known for strong analytical skills and clear technical documentation.

Externe Links
Auf n8n.io ansehen

Diesen Workflow teilen

Kategorien

Kategorien: 34