8
n8n 中文网amn8n.com

集成语音识别与消息批处理的 Telegram 聊天机器人(OpenAI)

高级

这是一个Miscellaneous, AI Chatbot, Multimodal AI领域的自动化工作流,包含 31 个节点。主要使用 If, Set, Code, Wait, Merge 等节点。 使用 OpenAI 实现语音识别与消息批处理的 Telegram 聊天机器人

前置要求
  • Telegram Bot Token
  • Google Sheets API 凭证
  • OpenAI API Key
  • Supabase URL 和 API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "09e6c54fb78c9d77ec167a0ec95b912fee9c603713c00be212b364544c5a48e0",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "ca80efbc-515a-42d3-917c-07d32700c55b",
      "name": "传递文本消息",
      "type": "n8n-nodes-base.set",
      "position": [
        16,
        384
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "beaca9bb-d352-4ee2-8c27-f90eb6a38362",
              "name": "processedMessage",
              "type": "string",
              "value": "={{ $json.message.text }}"
            },
            {
              "id": "f37a2a8b-e149-485a-bed1-c14d9510f554",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $json.message.chat.id }}"
            },
            {
              "id": "5009366a-70ea-46c9-abc6-d56bae0e5ac0",
              "name": "name",
              "type": "string",
              "value": "={{ $json.message.from.first_name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8c98384b-9b27-4f39-aa26-bd66a58ddd99",
      "name": "链接过滤器",
      "type": "n8n-nodes-base.if",
      "position": [
        -656,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "792fd1b3-3782-4cf5-9362-e60f415bfb46",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.voice.file_id }}",
              "rightValue": "=https://lookaside.fbsbx.com"
            },
            {
              "id": "3f908dda-0030-4bae-92e7-6d8831ac1f86",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.chat.id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a4170c19-0c40-4660-9db7-d2f212c5e57f",
      "name": "合并",
      "type": "n8n-nodes-base.merge",
      "position": [
        240,
        176
      ],
      "parameters": {
        "numberInputs": 3
      },
      "typeVersion": 3.1,
      "alwaysOutputData": true
    },
    {
      "id": "7fcec4b0-7715-47f8-a0d1-5fae4e3ff88f",
      "name": "编辑字段",
      "type": "n8n-nodes-base.set",
      "position": [
        464,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "4cd71c48-f1bf-4237-935b-071549fb9335",
              "name": "processedMessage",
              "type": "string",
              "value": "={{ $json.processedMessage || $json.error || '' }} "
            },
            {
              "id": "55c5a9e9-24a0-4a99-9792-b4fbdd1c75d1",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $('Telegram Message').item.json.message.from.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4,
      "alwaysOutputData": true
    },
    {
      "id": "4cbfb8d6-f269-4b22-9f0d-7801d43d2e1c",
      "name": "转录错误输出",
      "type": "n8n-nodes-base.set",
      "position": [
        16,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "380af7d7-3a3b-44da-9b2c-d138c1099925",
              "name": "error",
              "type": "string",
              "value": "={{ $json.error }}"
            },
            {
              "id": "5c2d1746-8a82-4391-8616-9df73d646810",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $('Telegram Message').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "85d8125a-8874-4a07-ae40-edf4747ae48a",
      "name": "转录结果",
      "type": "n8n-nodes-base.set",
      "position": [
        16,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cf189008-5ea4-493d-972d-190f3a785607",
              "name": "processedMessage",
              "type": "string",
              "value": "={{ $json.text }}"
            },
            {
              "id": "bc4c4384-a717-41c7-9b33-8937300525cd",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $('Telegram Message').item.json.message.chat.id }}"
            },
            {
              "id": "2c1eaa75-9eca-467e-9977-02023283ef95",
              "name": "name",
              "type": "string",
              "value": "={{ $('Telegram Message').item.json.message.from.first_name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "948c4933-6453-4cc8-afa6-bb61b18cb8cd",
      "name": "获取音频文件",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -432,
        96
      ],
      "webhookId": "fc05c0e8-bdf1-4887-9b84-b100a5ce65de",
      "parameters": {
        "fileId": "={{ $('Telegram Message').item.json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "u2BfWijDAq8IoWsR",
          "name": "ATEM MM Bot"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f521f015-2d23-4e04-a144-ad26c7b19d66",
      "name": "转录录音",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "onError": "continueErrorOutput",
      "position": [
        -208,
        96
      ],
      "parameters": {
        "options": {},
        "resource": "audio",
        "operation": "transcribe"
      },
      "credentials": {
        "openAiApi": {
          "id": "fgQFHZytDBcQ9EE5",
          "name": "OpenAi account"
        }
      },
      "retryOnFail": false,
      "typeVersion": 1.8
    },
    {
      "id": "d8dd439a-d7be-4954-a524-48631c5cbd97",
      "name": "在表格中追加行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        688,
        192
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $now }}",
            "message": "={{ $json.processedMessage }}",
            "user_id": "={{ $json.sessionId }}"
          },
          "schema": [
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "user_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "message",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1245350096,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
          "cachedResultName": "Msg Retention"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2fe418a4-dae4-4f8c-9adf-4e70af68e8d4",
      "name": "获取表中的行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2032,
        96
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('No Rows').item.json.user_id }}",
              "lookupColumn": "user_id"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1245350096,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
          "cachedResultName": "Msg Retention"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "db232946-eecb-42c3-b4c4-513beff920d0",
      "name": "OpenAI 嵌入1",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        3088,
        448
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "fgQFHZytDBcQ9EE5",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "418345bd-a996-4654-9237-c9e8fe4ff7a0",
      "name": "OpenAI 聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2768,
        288
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "gpt-5-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "fgQFHZytDBcQ9EE5",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "62c2632d-31db-42d2-9a10-77bcabeed278",
      "name": "AI 代理",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2928,
        32
      ],
      "parameters": {
        "text": "={{ $('Batch Messages').item.json.message }} ",
        "options": {
          "systemMessage": "ADD YOUR PROMPT HERE"
        },
        "promptType": "define"
      },
      "retryOnFail": false,
      "typeVersion": 1.7,
      "alwaysOutputData": false
    },
    {
      "id": "232c7722-2598-45ff-8c10-9f00ac16a977",
      "name": "获取 sheet1 中的行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        912,
        192
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Telegram Message').item.json.message.from.id }}",
              "lookupColumn": "user_id"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1701618791,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
          "cachedResultName": "Msg Waiting"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "048186f4-e41a-4948-b020-8c5c6e6b1a6a",
      "name": "要做什么",
      "type": "n8n-nodes-base.if",
      "position": [
        1360,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "8a83a137-2989-4b42-8e32-39557ef5182e",
              "operator": {
                "type": "dateTime",
                "operation": "before"
              },
              "leftValue": "={{ $json.last_updated }}",
              "rightValue": "={{ new Date(Date.now() - 30000).toISOString() }} "
            },
            {
              "id": "f6925d24-5bc5-4cf6-a4d2-e212eb11ec04",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              },
              "leftValue": "={{ $json.is_waiting }}",
              "rightValue": "=false"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "84f200f5-b4e2-4658-9236-80067ef01be7",
      "name": "在表格中更新行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1584,
        96
      ],
      "parameters": {
        "columns": {
          "value": {
            "user_id": "={{ $('Edit Fields').item.json.sessionId }}",
            "is_waiting": "true",
            "last_updated": "={{ $now }}"
          },
          "schema": [
            {
              "id": "user_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "user_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "is_waiting",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "is_waiting",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_updated",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_updated",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "user_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1701618791,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
          "cachedResultName": "Msg Waiting"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "4ba1454e-1ffa-49c5-8213-45fc16f4fafc",
      "name": "等待",
      "type": "n8n-nodes-base.wait",
      "position": [
        1808,
        96
      ],
      "webhookId": "92875d75-a126-4470-aa1b-ca0457cf2d06",
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "9026922d-b27a-4c81-8743-007543caa21e",
      "name": "从 sheet1 删除行或列",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2480,
        96
      ],
      "parameters": {
        "operation": "delete",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1245350096,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
          "cachedResultName": "Msg Retention"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        },
        "startIndex": "={{ $('Batch Messages').item.json.start_row_number }}",
        "numberToDelete": "={{ $('Batch Messages').item.json.row_count }}"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "8354d413-1d5e-4138-959d-c934a542666d",
      "name": "在 sheet1 中更新行",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1584,
        288
      ],
      "parameters": {
        "columns": {
          "value": {
            "user_id": "={{ $('Append row in sheet').item.json.user_id }}",
            "is_waiting": "true",
            "last_updated": "={{ $now }}"
          },
          "schema": [
            {
              "id": "user_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "user_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "is_waiting",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "is_waiting",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_updated",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_updated",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1701618791,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
          "cachedResultName": "Msg Waiting"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "62d9dcb5-80fc-45b4-afbd-87192125569f",
      "name": "无行",
      "type": "n8n-nodes-base.code",
      "position": [
        1136,
        192
      ],
      "parameters": {
        "jsCode": "// Normalize Msg Waiting result so the IF node always has something real to check\n\n// 1) Always get sessionId from the earlier node (not from this node's $json)\nconst sessionId = $('Edit Fields').item.json.sessionId;\n\n// 2) Detect \"no rows\": either zero items OR one empty item\nconst noRows =\n  items.length === 0 ||\n  (items.length === 1 && (!items[0].json || Object.keys(items[0].json).length === 0));\n\nif (noRows) {\n  // First-ever message for this user → pretend we have a row that says \"not waiting yet\"\n  return [{ json: { user_id: sessionId, is_waiting: false, last_updated: null } }];\n}\n\n// 3) Rows exist → pass them through (and ensure required keys exist)\nreturn items.map(it => ({\n  json: {\n    user_id: it.json.user_id ?? sessionId,\n    is_waiting: it.json.is_waiting ?? false,\n    last_updated: it.json.last_updated ?? null,\n  },\n}));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "237e36a5-eb9c-486a-9110-c4f5ae195978",
      "name": "批量消息",
      "type": "n8n-nodes-base.code",
      "position": [
        2256,
        96
      ],
      "parameters": {
        "jsCode": "// n8n Code node\n\nconst rowNumbers = items.map(item => item.json.row_number);\nconst sessionId = items[0].json.user_id; // Assuming all rows are from the same session/user\n\nconst merged = items\n  .map(item => item.json.message)\n  .filter(msg => msg && msg.trim() !== '')\n  .join(' '); // Or use '\\n' if line breaks are preferred\n\nreturn [\n  {\n    json: {\n      message: merged,\n      start_row_number: Math.min(...rowNumbers),\n      row_count: items.length,\n      session_id: sessionId,\n    },\n  },\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e84f5e5b-18b2-4a0e-a5d4-991888294d6b",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -304
      ],
      "parameters": {
        "color": 5,
        "width": 2224,
        "height": 816,
        "content": "# 消息批处理"
      },
      "typeVersion": 1
    },
    {
      "id": "b81ef537-6b0a-45ac-b6f6-9b36c5747b29",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        -96
      ],
      "parameters": {
        "color": 4,
        "width": 1120,
        "height": 928,
        "content": "# Transcription Pipeline\n\n## Add your Open AI API key to transcribe audio messages using Whisper\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### Voice messages → downloaded with Telegram, transcribed via Whisper, saved as processedMessage.\n\n### Text messages → passed straight through as processedMessage.\n\n### Files/media (documents, images, videos, etc.) → politely refused with a short reply to the user.\n\n### All outputs (voice → text, plain text, or refusal) are normalized so the rest of the workflow always sees a single field processedMessage with the user’s content or an error message.\n\n### This way, the workflow can differentiate voice, text, and files, and always behave consistently."
      },
      "typeVersion": 1
    },
    {
      "id": "a9943cf2-7c8c-40cb-afb2-18e9ee682395",
      "name": "简单记忆",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        2928,
        288
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "813d014f-92a7-46d9-99ac-c190e48a89dc",
      "name": "Supabase Vector Store",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        3072,
        288
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "options": {},
        "tableName": {
          "__rl": true,
          "mode": "id",
          "value": "{SUPABASE_TABLE_ID}"
        },
        "toolDescription": "Use this node to access your Knowledge Base"
      },
      "credentials": {
        "supabaseApi": {
          "id": "k2Faw9ihcov3jBf0",
          "name": "Supabase n8n UI Builder "
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "eab1c6d2-e953-4179-9537-029dfa9f3923",
      "name": "Send message Back to TG",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3392,
        32
      ],
      "webhookId": "6941d8f4-ac04-4d49-80cc-9c96bc450d31",
      "parameters": {
        "text": "={{ $json.output.text }}",
        "chatId": "={{ $('Batch Messages').item.json.session_id }}",
        "forceReply": {},
        "replyMarkup": "=",
        "additionalFields": {
          "appendAttribution": false
        },
        "replyKeyboardRemove": {},
        "replyKeyboardOptions": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "u2BfWijDAq8IoWsR",
          "name": "ATEM MM Bot"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2d4ad4ac-0df1-46d3-b894-81075b000b06",
      "name": "Telegram 触发器",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1088,
        192
      ],
      "webhookId": "a675e34f-74c2-469b-b9f4-9c66706b4663",
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "xMN2lfwnxVBsziXP",
          "name": "Uchilka"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e1a6e83a-f60c-4f9b-8d89-30677f829267",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1296,
        -864
      ],
      "parameters": {
        "color": 6,
        "width": 1664,
        "height": 752,
        "content": "# How to run this on Telegram\n\n**1) Create a bot + add creds**\n- @BotFather → `/newbot` → copy Bot Token.\n- In n8n: **Credentials → Telegram API** → paste token.\n- Add **Telegram Trigger** → select credential → **Execute Node** once to register webhook.\n\n**2) Enable updates**\n- In **Telegram Trigger**, enable **`message`** (add photo/document if needed).\n\n**3) Voice messages (optional)**\n- Pipeline: **Telegram Trigger → Telegram (Get File by `file_id`) → OpenAI Whisper (Transcribe) → Set**.\n\n**4) Google Sheets (two sheets)**\n- Share both sheets with the **service account email** from your n8n Google Sheets credential (Editor).\n- **Msg Retention** columns: `date | user_id | message`\n- **Message Checkup** columns: `user_id | is_waiting | last_updated`\n\n**5) Debounce / batching**\n- After **Append row in Msg Retention**:\n  - **Get row(s) in Msg Waiting** by `user_id` → **No Rows** code normalizes empty to `{ user_id, is_waiting:false, last_updated:null }`.\n  - **IF (OR)**:\n    - `last_updated` **before** `{{ new Date(Date.now() - 20000).toISOString() }}`\n    - `is_waiting` is **false**\n  - **TRUE** → **Update Message Checkup** (`is_waiting=true`, `last_updated=$now`) → **Wait (e.g., 30s)** → **Get rows from Msg Retention** → **Batch Messages** (merge) → **Delete those rows** → **AI Agent** → **Send to TG** → **Delete row in Message Checkup**.\n  - **FALSE** → only **Update Message Checkup** (`is_waiting=true`, fresh `last_updated`) — **no extra Wait**.\n\n**6) Copy-paste expressions**\n- “Older than 20s” right side (IF → date before):\n  `{{ new Date(Date.now() - 20000).toISOString() }}`\n- Keep IF → **Type Validation = loose** for `is_waiting` so `\"true\"`/`true` both work.\n\n**7) “No Rows” safety (Code node)**\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b47866b2-0838-4076-9a08-0eff0937d043",
      "name": "Delete Row from Message Checkup",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3568,
        32
      ],
      "parameters": {
        "operation": "delete",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1701618791,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
          "cachedResultName": "Msg Waiting"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
          "cachedResultName": "ATEM Chat Logs"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "u715DFeBTkQLR0Bs",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "15087422-c826-46ea-83df-daafea1d4cb7",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -688
      ],
      "parameters": {
        "width": 1104,
        "height": 352,
        "content": "# Common pitfalls (TG + Sheets)\n\n- **Webhook not set**: Open the **Telegram Trigger** and **Execute** once to register. Ensure your n8n URL is public + HTTPS.\n- **Sheets permissions**: Share the sheets with the **service account email** from the Google Sheets credential (Editor). Otherwise appends/reads silently fail.\n- **Date comparisons**: Use ISO (`{{ $now }}`) so “before” comparisons work across rows.\n- **Duplicate waits (race)**: Only the **TRUE** branch starts a Wait. The **FALSE** branch must *only* refresh `last_updated`. This prevents parallel timers for the same user.\n- **Cleanup order**:\n  1) Batch & **delete Msg Retention rows** after merging.\n  2) Send reply to TG.\n  3) **Delete Msg Waiting row** (or set `is_waiting=false`) last.\n- **Type mismatches**: If `is_waiting` is stored as text `\"true\"/\"false\"`, use IF’s **loose** validation or cast to boolean in a Code node.\n- **Voice transcripts**: Make sure your Link/IF lets either text **or** voice path feed into the merge."
      },
      "typeVersion": 1
    },
    {
      "id": "2592aa82-2ca1-41b1-8302-c49b85028ab4",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2720,
        -480
      ],
      "parameters": {
        "width": 608,
        "height": 1232,
        "content": "# AI Agent node (plug-and-play)\n\n**Goal:** take the batched user text and produce one reply. You can keep it simple, or attach memory + a vector database.\n\n## Minimal setup\n- **Agent node:** `AI Agent`\n- **System prompt:** *Add Yours*\n- **User text:** `{{ $('Batch Messages').item.json.message }}`\n"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No Rows": {
      "main": [
        [
          {
            "node": "What to do",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Send message Back to TG",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "What to do": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Link Filter": {
      "main": [
        [
          {
            "node": "Get Audio File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Pass text message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Batch Messages": {
      "main": [
        [
          {
            "node": "Delete rows or columns from sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Audio File": {
      "main": [
        [
          {
            "node": "Transcribe a recording",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Link Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Pass text message": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Transcript Result": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI1": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Batch Messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update row in sheet": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet1": {
      "main": [
        [
          {
            "node": "No Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe a recording": {
      "main": [
        [
          {
            "node": "Transcript Result",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Transcript Error Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send message Back to TG": {
      "main": [
        [
          {
            "node": "Delete Row from Message Checkup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcript Error Output": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Delete Row from Message Checkup": {
      "main": [
        []
      ]
    },
    "Delete rows or columns from sheet1": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 杂项, AI 聊天机器人, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量31
分类3
节点类型15
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

外部链接
在 n8n.io 查看

分享此工作流