8
n8n 中文网amn8n.com

多模态费用追踪:Telegram、Gemini AI 与 Google Sheets

高级

这是一个Personal Productivity, AI Chatbot领域的自动化工作流,包含 25 个节点。主要使用 If, Set, Switch, SplitOut, Telegram 等节点。 使用 Telegram、Gemini AI 和 Google Sheets 的多模态费用追踪系统

前置要求
  • Telegram Bot Token
  • Google Sheets API 凭证
  • Google Gemini API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "e4f10bef48753951b827b1628c136c25720855dd405c916d09e788211699198e",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "7be734f2-0de6-4763-81e5-346cb715bd66",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1664,
        624
      ],
      "parameters": {
        "width": 896,
        "height": 928,
        "content": "# 🚀 快速入门"
      },
      "typeVersion": 1
    },
    {
      "id": "dba88ead-1ca9-488d-9cb2-c1fdc4156dce",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        560
      ],
      "parameters": {
        "color": 2,
        "width": 672,
        "height": 992,
        "content": "## 1) 消息接收与路由"
      },
      "typeVersion": 1
    },
    {
      "id": "67cb65eb-65c3-4e83-a5db-8fc0a227513a",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        560
      ],
      "parameters": {
        "color": 3,
        "width": 688,
        "height": 992,
        "content": "## 2) 输入捕获与标准化"
      },
      "typeVersion": 1
    },
    {
      "id": "bbcaf572-fe02-49d9-bb73-9e0229c4e931",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        560
      ],
      "parameters": {
        "color": 5,
        "width": 432,
        "height": 992,
        "content": "## 3) 支出解析与验证"
      },
      "typeVersion": 1
    },
    {
      "id": "40c74ab6-4079-475d-89d1-c861ca778c94",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        560
      ],
      "parameters": {
        "color": 4,
        "width": 1056,
        "height": 992,
        "content": "## 4) 行生成、表格写入与确认"
      },
      "typeVersion": 1
    },
    {
      "id": "5ca4b51a-2d7e-46f9-82a5-081b0cb970fd",
      "name": "GSheet: Log Expense",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1824,
        1056
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "output",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "output",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "cellFormat": "RAW"
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 161899167,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1GRwglX459qYYAQm_gRZadyDwVR1dw8t6zuZU3T-T-Ak/edit#gid=161899167",
          "cachedResultName": "test"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1GRwglX459qYYAQm_gRZadyDwVR1dw8t6zuZU3T-T-Ak",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1GRwglX459qYYAQm_gRZadyDwVR1dw8t6zuZU3T-T-Ak/edit?usp=drivesdk",
          "cachedResultName": "记账"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "i2QQ5h70aiZ7H0s3",
          "name": "Google Sheets(owen)"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.7
    },
    {
      "id": "297ff453-2268-40ba-95c3-fa7a3e736467",
      "name": "LLM: Gemini Flash",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        768,
        1408
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "Kgz5ypv084tCLfvw",
          "name": "Gemini (wudi)"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9519104e-7bb0-4b48-aa2c-cd416266a9de",
      "name": "Gemini:转录语音",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        272,
        1072
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {},
        "resource": "audio",
        "inputType": "binary",
        "binaryPropertyName": "=data "
      },
      "credentials": {
        "googlePalmApi": {
          "id": "Kgz5ypv084tCLfvw",
          "name": "Gemini (wudi)"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "8bd5377e-39ef-4af7-846d-1d3a279151c2",
      "name": "Telegram: Send Confirmation",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2016,
        1056
      ],
      "webhookId": "94947e31-c3ff-4888-bdc6-946478134923",
      "parameters": {
        "text": "={{\n(() => {\n  const items = $input.all();\n\n  const arr = items\n    .map(i => i.json?.output ?? i.json)\n    .filter(Boolean);\n\n  const lines = arr.map(e => {\n    const item = (e?.Item ?? '').toString().trim() || '—';\n    const amount = (e?.Amount ?? '').toString().trim() || '—';\n    const date = e?.Date ? ` (${e.Date})` : '';\n    return `• ${item} — ${amount}${date}`;\n  });\n\n  const text =\n    '📒 Bookkeeping Complete\\n\\n' +\n    (lines.length ? lines.join('\\n') : '(No items found)');\n\n  // Telegram MarkdownV2 需要转义的字符:\n  // _ * [ ] ( ) ~ ` > # + - = | { } . ! \\\n  const escapeMdV2 = (s) =>\n    s.replace(/([_*[\\]()~`>#+\\-=|{}.!\\\\])/g, '\\\\$1');\n\n  return escapeMdV2(text);\n})()\n}}\n",
        "chatId": "<Your chat id>",
        "additionalFields": {
          "parse_mode": "MarkdownV2"
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 1.2,
      "waitBetweenTries": 3000
    },
    {
      "id": "ec454606-5cc7-45ff-a8fe-a8ecd39b7b13",
      "name": "Telegram: Get Voice File",
      "type": "n8n-nodes-base.telegram",
      "position": [
        64,
        1072
      ],
      "webhookId": "61b155dd-389b-4673-996a-2bce72c9a6f7",
      "parameters": {
        "fileId": "={{ $json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "ab30a0a4-0f88-437a-b75f-488eb11eb38b",
      "name": "Set: Text Input",
      "type": "n8n-nodes-base.set",
      "position": [
        384,
        912
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bed1c3bb-9ee7-4663-b89a-8a701df2c049",
              "name": "raw_text",
              "type": "string",
              "value": "={{ $json.message.text }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9850615f-f28d-4b68-8fe2-fbf704172667",
      "name": "Set: Voice Input (Text)",
      "type": "n8n-nodes-base.set",
      "position": [
        496,
        1072
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "82a0d6b4-f320-4b39-b05a-a2723f4d22fa",
              "name": "raw_text",
              "type": "string",
              "value": "={{ $json.content.parts.toJsonString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8cbe3328-cdd1-4773-90ad-4822859ddba1",
      "name": "AI: Extract Expenses",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        832,
        1040
      ],
      "parameters": {
        "text": "=information:{{ $json.raw_text }}",
        "options": {
          "systemMessage": "=You are a STRICT, deterministic expense parser. The user will provide free-form text or an ASR (voice) transcription that describes one or more bookkeeping entries.\n\nGOAL\nReturn a JSON ARRAY of 0..N objects. Each object has these EXACT keys:\n{\n  \"amount\": number | null,        // numeric value only; no currency symbol\n  \"item\": string | null,          // what was paid for / received\n  \"date\": date                 // ISO 8601 \"YYYY-MM-DD\"; \n\nCURRENT DATE CONTEXT (REQUIRED)\n- NOW_ISO = \"{{ new Date }}\" \n- Define CURRENT_DATE as the calendar date of NOW_ISO (YYYY-MM-DD) respecting its timezone info if present.\n\nHARD RULES (NO HALLUCINATIONS)\n- Work ONLY with the given input text; DO NOT invent, infer, or fetch anything external.\n- If a field cannot be reliably determined, set it to null (do NOT guess). Exception: \"date\" must never be null—if no explicit/relative date is found, use CURRENT_DATE.\n- Output MUST be raw JSON array only (no markdown, no comments, no extra text).\n- Each distinct purchase must yield its own object. Do NOT merge separate purchases. Do NOT compute totals from line items unless the text explicitly marks a “total”.\n- Amounts are positive numbers; do NOT add signs to indicate expense/income.\n\nMULTI-ENTRY DETECTION\nTreat as separate purchases when the text clearly presents distinct (amount, item) pairs or clearly separated entries by:\n- Newlines, bullet points, semicolons/commas that separate complete (amount + item) phrases, or connectors like “and/&, plus” when each part has its own amount or distinct item.\n- Examples of separate entries:\n  - \"Lunch 12; Grab 18; Netflix 55\" → three objects.\n  - \"RM8 coffee, RM5 bun\" → two objects.\nNOT separate (single entry):\n  - A list of items but ONE explicit \"total\" (e.g., \"apples 3, milk 5, total 8\") → output ONE object with amount=8 and item=apples & milk.\n  - Quantity/price math for the same item (e.g., \"2 x coffee RM5 each, total RM10\") → ONE object, amount=10, item=\"coffee\".\nIf multiple amounts exist but items are not clearly distinguishable, create multiple objects with item=null rather than guessing item names.\n\nAMOUNT PARSING\n- Normalize to a JSON number (strip currency symbols/codes/words): RM12.50 → 12.5, $1,299 → 1299, MYR 36 → 36.\n- Support magnitude suffixes: 1.2k/1.2K → 1200; 36k/36K → 36000.\n- Prefer an explicit total; if both unit price and total appear for the same purchase, choose the total.\n- Ignore percentages unless explicitly stated as the paid amount.\n- If multiple numeric candidates exist within one purchase with no clear total, choose the first well-formed currency-like amount; otherwise amount = null.\n\nITEM EXTRACTION\n- Concise description of what the payment is for (e.g., \"coffee\", \"Grab ride\", \"rental\", \"Netflix subscription\").\n- Remove ASR fillers (“uh”, “you know”), keep core item only.\n- If truly unknown, item = null.\n\nDATE RESOLUTION\n- Always output ISO \"YYYY-MM-DD\".\n- Recognize explicit dates in common formats and normalize (e.g., 22/10/2025, 2025-10-22, Oct 22, 2025). If month/day are given without a year and it is unambiguous, fill the year from CURRENT_DATE; otherwise treat missing parts as absent and use CURRENT_DATE.\n- Relative terms (multi-language; case-insensitive):\n  - \"today\", \"今天\", \"hari ini\" → CURRENT_DATE\n  - \"yesterday\", \"昨天\", \"semalam\" → CURRENT_DATE minus 1 day\n  - \"tomorrow\", \"明天\", \"esok\" → CURRENT_DATE plus 1 day\n  - \"the day before yesterday\" / \"前天\" → CURRENT_DATE minus 2 days\n- If a single relative date clearly applies to the whole input, apply it to all entries. If different parts contain different explicit/relative dates, resolve per entry. If no date cue for an entry, use CURRENT_DATE.\n\nNORMALIZATION & SANITY\n- Trim whitespace; tolerate ASR noise and mixed punctuation (including full-width).\n- Do not include currency symbols/codes anywhere in JSON.\n\nOUTPUT FORMAT\n- Return exactly one JSON array. Each array element is an object with keys in this order: amount, item, date.\n- Numbers must be valid JSON numbers (no quotes).\n\nEXAMPLES (assume NOW_ISO = \"2025-10-22T15:00:00+08:00\", so CURRENT_DATE = \"2025-10-22\")\n\nInput: \"Paid RM12.50 for latte at Starbucks today\"\nOutput:\n[{\"amount\":12.5,\"item\":\"latte at Starbucks\",\"date\":\"2025-10-22\"}]\n\nInput: \"Grab ride to Mid Valley, 18 ringgit, yesterday; Netflix monthly 55\"\nOutput:\n[\n  {\"amount\":18,\"item\":\"Grab ride to Mid Valley\",\"date\":\"2025-10-21\"},\n  {\"amount\":55,\"item\":\"Netflix monthly\",\"date\":\"2025-10-22\"}\n]\n\nInput: \"RM8 coffee, RM5 bun\"\nOutput:\n[\n  {\"amount\":8,\"item\":\"coffee\",\"date\":\"2025-10-22\"},\n  {\"amount\":5,\"item\":\"bun\",\"date\":\"2025-10-22\"}\n]\n\nInput: \"apples 3, milk 5, TOTAL 8\"\nOutput:\n[{\"amount\":8,\"item\":\"apples & milk\",\"date\":\"2025-10-22\"}]\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "retryOnFail": true,
      "typeVersion": 2.2
    },
    {
      "id": "cd20d803-47a3-496b-8160-0052c6b50ef4",
      "name": "Split: Entries to Rows",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1216,
        1040
      ],
      "parameters": {
        "include": "allOtherFields",
        "options": {},
        "fieldToSplitOut": "output"
      },
      "executeOnce": false,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "a1e5d645-da07-479c-84c7-5e6ad67d2f7c",
      "name": "Telegram: Send error message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -144,
        1392
      ],
      "webhookId": "94947e31-c3ff-4888-bdc6-946478134923",
      "parameters": {
        "text": "=🤖Sorry, I can only understand text, voice and image for bookkeeping. ",
        "chatId": "<Your chat id>",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "076077d4-a0c9-4800-aa1e-1f455255a8db",
      "name": "Gemini: Analyze an image",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        272,
        1264
      ],
      "parameters": {
        "text": "=Financial Image Text Extraction Prompt\n\nYour task is to analyze the provided image and **extract all text and numerical information related to financial or transactional data**.  \nThe image may contain receipts, invoices, transfer records, expense summaries, or digital payment screenshots (e.g., WeChat, Alipay, banking apps).\n\n#### Instructions:\n- Extract **all visible text and numbers**, including:\n  - Dates and times  \n  - Merchant or transaction party names  \n  - Notes, descriptions, or remarks  \n  - Amounts, currency symbols, and positive/negative signs  \n  - Summary information (e.g., total income, total expense)\n- **Preserve the original order and wording** as they appear in the image.  \n- Ensure numerical accuracy and retain all currency symbols.  \n- **Ignore decorative or non-informational elements**, such as logos, icons, watermarks, background graphics, or design borders.  \n- Do **not** interpret, categorize, or restructure the extracted data.  \n  The output should be **raw readable text** that captures all relevant words and numbers for bookkeeping analysis.\n\n#### Goal:\nProduce an **accurate, unmodified textual extraction** of the financial and accounting information visible in the image — ready for further processing by a bookkeeping or accounting system.\n",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {},
        "resource": "image",
        "inputType": "binary",
        "operation": "analyze"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "OBsJ1xTy5eLJvjhJ",
          "name": "Gemini(pixel)"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "fe77a802-f56e-4fae-ae7c-0c6dabf43d2c",
      "name": "Set: image Input (Text)",
      "type": "n8n-nodes-base.set",
      "position": [
        496,
        1264
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "82a0d6b4-f320-4b39-b05a-a2723f4d22fa",
              "name": "raw_text",
              "type": "string",
              "value": "={{ $json.content.parts.toJsonString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3c907845-b556-4a13-a93b-1319e953e001",
      "name": "Route: Text, Voice or Image?",
      "type": "n8n-nodes-base.switch",
      "position": [
        -384,
        1136
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Text",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "a3e1bf10-5e6d-4004-87f9-b0f6e8c421c8",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "leftValue": "={{ !!$json.message.text }}",
                    "rightValue": "text"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Voice",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "7de0d37c-e95d-4780-958b-25fe7a851243",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "leftValue": "={{ !!$json.message.voice }}",
                    "rightValue": "voice"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Image",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "f85ee560-74b1-47ab-ac61-06081de1a14f",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "leftValue": "={{ !!$json.message.photo }}",
                    "rightValue": "photo"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "allMatchingOutputs": false,
          "renameFallbackOutput": "else"
        }
      },
      "typeVersion": 3.3
    },
    {
      "id": "45416109-6e88-4b09-8327-bea0d9878b7e",
      "name": "Auto-Fix JSON",
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "position": [
        880,
        1248
      ],
      "parameters": {
        "options": {
          "prompt": "Instructions:\n--------------\n{instructions}\n--------------\nCompletion:\n--------------\n{completion}\n--------------\n\nAbove, the Completion did not satisfy the constraints given in the Instructions.\nError:\n--------------\n{error}\n--------------\n\nPlease try again. Please only respond with an answer that satisfies the constraints laid out in the Instructions:"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6c8d0ca0-9e88-41d7-9692-32b3751c70b0",
      "name": "AI Helper: Define Schema",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        992,
        1392
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n  \"amount\": \"number | null\",\n  \"item\": \"string | null\",         \n  \"date\": \"date\"\n  }\n]"
      },
      "typeVersion": 1.3
    },
    {
      "id": "95435178-b029-4319-a886-7a0aef028363",
      "name": "Telegram: Get Image File",
      "type": "n8n-nodes-base.telegram",
      "position": [
        64,
        1264
      ],
      "webhookId": "61b155dd-389b-4673-996a-2bce72c9a6f7",
      "parameters": {
        "fileId": "={{ $json.message.photo[0].file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "a0d74a66-0e2f-460a-ada8-c52c1a38535b",
      "name": "Start: On Telegram Message",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -608,
        1168
      ],
      "webhookId": "ae9666ea-0aaa-4b17-88ae-9049e0dd1213",
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "44724e36-7f53-4e42-b588-c7a808f57f70",
      "name": "Set: Extract Output",
      "type": "n8n-nodes-base.set",
      "position": [
        1632,
        1056
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "6b917f33-f6c0-4a49-b12c-6861238874b6",
              "name": "Amount",
              "type": "string",
              "value": "={{ $json.output.amount }}"
            },
            {
              "id": "f029fc1b-937a-432c-9832-fa1a0b7717ed",
              "name": "Item",
              "type": "string",
              "value": "={{ $json.output.item }}"
            },
            {
              "id": "e7908c7b-e1a5-4854-b6d2-7a57d90521b6",
              "name": "Date",
              "type": "string",
              "value": "={{ $json.output.date }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b2122f43-7eaf-4d09-ba73-b756fa8d2863",
      "name": "If null?",
      "type": "n8n-nodes-base.if",
      "position": [
        1424,
        1152
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "2afe62ea-0a1b-4836-a1d4-7863e35e7f39",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ !!$json.output }}",
              "rightValue": ""
            },
            {
              "id": "c8509d26-8c3c-4e43-8870-47691e631d8d",
              "operator": {
                "type": "array",
                "operation": "contains",
                "rightType": "any"
              },
              "leftValue": "={{ $json.output }}",
              "rightValue": "null"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b4d6dc9a-d623-455d-8fd5-a2f757229a07",
      "name": "Telegram: Send Null",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1616,
        1280
      ],
      "webhookId": "94947e31-c3ff-4888-bdc6-946478134923",
      "parameters": {
        "text": "=📒 Bookkeeping Complete\n\nnull",
        "chatId": "<Your chat id>",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "GqenigS1DQQpGb6b",
          "name": "Telegram (owenperosonal)"
        }
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 1.2
    }
  ],
  "pinData": {},
  "connections": {
    "If null?": {
      "main": [
        [
          {
            "node": "Set: Extract Output",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Telegram: Send Null",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Auto-Fix JSON": {
      "ai_outputParser": [
        [
          {
            "node": "AI: Extract Expenses",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Set: Text Input": {
      "main": [
        [
          {
            "node": "AI: Extract Expenses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM: Gemini Flash": {
      "ai_languageModel": [
        [
          {
            "node": "Auto-Fix JSON",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "AI: Extract Expenses",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "GSheet: Log Expense": {
      "main": [
        [
          {
            "node": "Telegram: Send Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: Extract Output": {
      "main": [
        [
          {
            "node": "GSheet: Log Expense",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI: Extract Expenses": {
      "main": [
        [
          {
            "node": "Split: Entries to Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split: Entries to Rows": {
      "main": [
        [
          {
            "node": "If null?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: Voice Input (Text)": {
      "main": [
        [
          {
            "node": "AI: Extract Expenses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: image Input (Text)": {
      "main": [
        [
          {
            "node": "AI: Extract Expenses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Helper: Define Schema": {
      "ai_outputParser": [
        [
          {
            "node": "Auto-Fix JSON",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Gemini: Analyze an image": {
      "main": [
        [
          {
            "node": "Set: image Input (Text)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini: Transcribe Voice": {
      "main": [
        [
          {
            "node": "Set: Voice Input (Text)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram: Get Image File": {
      "main": [
        [
          {
            "node": "Gemini: Analyze an image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram: Get Voice File": {
      "main": [
        [
          {
            "node": "Gemini: Transcribe Voice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start: On Telegram Message": {
      "main": [
        [
          {
            "node": "Route: Text, Voice or Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route: Text, Voice or Image?": {
      "main": [
        [
          {
            "node": "Set: Text Input",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Telegram: Get Voice File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Telegram: Get Image File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Telegram: Send error message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

高级 - 个人效率, AI 聊天机器人

需要付费吗?

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

工作流信息
难度等级
高级
节点数量25
分类2
节点类型13
难度说明

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

作者

A graduate student who is learning n8n. contact me: owenlzyxg@gmail.com

外部链接
在 n8n.io 查看

分享此工作流