使用 Telegram 和 Google Sheets 通过 OCR.space 从收据照片跟踪支出
中级
这是一个Invoice Processing, AI Chatbot领域的自动化工作流,包含 14 个节点。主要使用 If, Function, HttpRequest, TelegramBot, GoogleSheets 等节点。 使用 Telegram 和 Google Sheets 通过 OCR.space 从收据照片跟踪支出
前置要求
- •可能需要目标 API 的认证凭证
- •Telegram Bot Token
- •Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
无法加载工作流预览
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"nodes": [
{
"name": "Telegram Bot (Webhook)",
"type": "n8n-nodes-base.telegramBot",
"position": [
250,
200
],
"parameters": {
"webhookUrl": "=https://api.telegram.org/bot{{$env.YOUR_TELEGRAM_BOT_TOKEN}}/getUpdates",
"pollInterval": 5,
"allowedUpdates": [
"message"
],
"onlyNewUpdates": true
},
"typeVersion": 1
},
{
"name": "检查'收入'",
"type": "n8n-nodes-base.if",
"position": [
450,
100
],
"parameters": {
"conditions": [
{
"value1": "={{$json.message.text}}",
"value2": "income",
"operation": "contains"
}
]
},
"typeVersion": 1
},
{
"name": "检查'支出'(文本)",
"type": "n8n-nodes-base.if",
"position": [
450,
300
],
"parameters": {
"conditions": [
{
"value1": "={{$json.message.text}}",
"value2": "expense",
"operation": "contains"
}
]
},
"typeVersion": 1
},
{
"name": "添加收入到 Google Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
700,
100
],
"parameters": {
"operation": "appendRow",
"sheetName": "Income",
"columnValues": {
"mapping": {
"Date": "={{$today}}",
"Type": "Income",
"Amount": "={{$json.message.text.split(' ')[2]}}",
"Source": "Manual",
"Description": "={{$json.message.text.split(' ')[1]}}"
}
},
"spreadsheetId": "={{$env.YOUR_GOOGLE_SHEET_ID}}",
"authentication": "oAuth2",
"valueInputOption": "USER_ENTERED"
},
"typeVersion": 1
},
{
"name": "添加支出到 Google Sheet (文本)",
"type": "n8n-nodes-base.googleSheets",
"position": [
700,
300
],
"parameters": {
"operation": "appendRow",
"sheetName": "Expenses",
"columnValues": {
"mapping": {
"Date": "={{$today}}",
"Type": "Expense",
"Amount": "={{$json.message.text.split(' ')[2]}}",
"Source": "Manual",
"Category": "={{$json.message.text.split(' ')[3]}}",
"Description": "={{$json.message.text.split(' ')[1]}}"
}
},
"spreadsheetId": "={{$env.YOUR_GOOGLE_SHEET_ID}}",
"authentication": "oAuth2",
"valueInputOption": "USER_ENTERED"
},
"typeVersion": 1
},
{
"name": "发送收入确认",
"type": "n8n-nodes-base.telegramBot",
"position": [
950,
100
],
"parameters": {
"text": "Income \"{{$json.message.text.split(' ')[1]}}\" of ${{parseFloat($json.message.text.split(' ')[2]).toLocaleString('en-US')}} successfully recorded!",
"chatId": "={{$json.message.chat.id}}",
"parseMode": "HTML"
},
"typeVersion": 1
},
{
"name": "发送支出确认 (文本)",
"type": "n8n-nodes-base.telegramBot",
"position": [
950,
300
],
"parameters": {
"text": "Expense \"{{$json.message.text.split(' ')[1]}}\" of ${{parseFloat($json.message.text.split(' ')[2]).toLocaleString('en-US')}} for category \"{{$json.message.text.split(' ')[3]}}\" successfully recorded!",
"chatId": "={{$json.message.chat.id}}",
"parseMode": "HTML"
},
"typeVersion": 1
},
{
"name": "发送错误消息 (文本)",
"type": "n8n-nodes-base.telegramBot",
"position": [
700,
700
],
"parameters": {
"text": "Sorry, message format not recognized. Use format:\n*income [description] [amount]*\nor\n*expense [description] [amount] [category]*\nAlternatively, send a photo of your receipt for automatic tracking!",
"chatId": "={{$json.message.chat.id}}",
"parseMode": "HTML"
},
"typeVersion": 1
},
{
"name": "检查'照片'",
"type": "n8n-nodes-base.if",
"position": [
450,
500
],
"parameters": {
"conditions": [
{
"value1": "={{$json.message.photo}}",
"value2": "true",
"operation": "isNotEmpty"
}
]
},
"typeVersion": 1
},
{
"name": "获取 Telegram 照片",
"type": "n8n-nodes-base.telegramBot",
"position": [
700,
500
],
"parameters": {
"chatId": "={{$json.message.chat.id}}",
"fileId": "={{$json.message.photo[{$json.message.photo.length - 1}].file_id}}",
"operation": "getFile"
},
"typeVersion": 1
},
{
"name": "OCR.space 请求",
"type": "n8n-nodes-base.httpRequest",
"position": [
950,
500
],
"parameters": {
"url": "https://api.ocr.space/parse/image",
"method": "POST",
"options": {
"query": [
{
"name": "apikey",
"value": "={{$env.YOUR_OCR_SPACE_API_KEY}}"
},
{
"name": "language",
"value": "eng"
},
{
"name": "isOverlayRequired",
"value": "true"
}
],
"bodyParameters": [
{
"name": "file",
"value": "={{$binary.data}}"
}
],
"bodyContentType": "formData"
}
},
"typeVersion": 1
},
{
"name": "解析 OCR 数据",
"type": "n8n-nodes-base.function",
"position": [
1200,
500
],
"parameters": {
"function": "const ocrData = $json.ParsedResults[0].ParsedText;\n\n// Basic regex to find common patterns for amount ($) and dates (MM/DD/YYYY, YYYY-MM-DD, DD/MM/YYYY)\nconst amountRegex = /(?:[USD|SGD|MYR|\\$])?\\s*(\\d{1,3}(?:[.,]\\d{3})*(?:[.,]\\d{2})?)/i;\nconst dateRegex = /(\\d{1,2}[-/.]\\d{1,2}[-/.]\\d{2,4})/;\n\nlet description = 'OCR Expense';\nlet amount = 0;\nlet date = new Date().toISOString().slice(0, 10); // Default to today\nlet category = 'Uncategorized';\n\nconst amountMatch = ocrData.match(amountRegex);\nif (amountMatch && amountMatch[1]) {\n amount = parseFloat(amountMatch[1].replace(/[,.]/g, m => m === ',' ? '.' : ',')).toFixed(2); // Handle both comma and dot decimals\n}\n\nconst dateMatch = ocrData.match(dateRegex);\nif (dateMatch && dateMatch[1]) {\n // Attempt to parse date, try common formats\n const dateStr = dateMatch[1];\n let parsedDate = null;\n\n // Try YYYY-MM-DD\n if (dateStr.match(/^\\d{4}[-/.]\\d{1,2}[-/.]\\d{1,2}$/)) {\n parsedDate = new Date(dateStr);\n }\n // Try MM/DD/YYYY or DD/MM/YYYY (be careful with ambiguity)\n else if (dateStr.match(/^\\d{1,2}[-/.]\\d{1,2}[-/.]\\d{2,4}$/)) {\n // Assuming MM/DD/YYYY for simplicity, adjust if DD/MM/YYYY is more common for you\n const parts = dateStr.split(/[-/.]/);\n if (parts.length === 3) {\n parsedDate = new Date(`${parts[2]}-${parts[0]}-${parts[1]}`); // YYYY-MM-DD format for constructor\n }\n }\n\n if (parsedDate && !isNaN(parsedDate.getTime())) {\n date = parsedDate.toISOString().slice(0, 10);\n }\n}\n\n// Simple keyword-based categorization (you'd make this more robust)\nif (ocrData.toLowerCase().includes('food') || ocrData.toLowerCase().includes('restaurant') || ocrData.toLowerCase().includes('cafe')) {\n category = 'Food & Drinks';\n} else if (ocrData.toLowerCase().includes('transport') || ocrData.toLowerCase().includes('uber') || ocrData.toLowerCase().includes('taxi')) {\n category = 'Transportation';\n} else if (ocrData.toLowerCase().includes('shopping') || ocrData.toLowerCase().includes('store')) {\n category = 'Shopping';\n} else if (ocrData.toLowerCase().includes('utility') || ocrData.toLowerCase().includes('electric') || ocrData.toLowerCase().includes('water')) {\n category = 'Utilities';\n}\n\n// Try to get a simple description from the text (e.g., first few words of the text)\nconst lines = ocrData.split('\\n').filter(line => line.trim() !== '');\nif (lines.length > 0) {\n description = lines[0].substring(0, Math.min(lines[0].length, 50)); // Take first 50 chars of the first non-empty line\n}\n\nreturn [\n {\n json: {\n description: description,\n amount: amount,\n date: date,\n category: category\n }\n }\n];"
},
"typeVersion": 1
},
{
"name": "添加支出到 Google Sheet (OCR)",
"type": "n8n-nodes-base.googleSheets",
"position": [
1450,
500
],
"parameters": {
"operation": "appendRow",
"sheetName": "Expenses",
"columnValues": {
"mapping": {
"Date": "={{$json.date}}",
"Type": "Expense",
"Amount": "={{$json.amount}}",
"Source": "OCR",
"Category": "={{$json.category}}",
"Description": "={{$json.description}}"
}
},
"spreadsheetId": "={{$env.YOUR_GOOGLE_SHEET_ID}}",
"authentication": "oAuth2",
"valueInputOption": "USER_ENTERED"
},
"typeVersion": 1
},
{
"name": "发送支出确认 (OCR)",
"type": "n8n-nodes-base.telegramBot",
"position": [
1700,
500
],
"parameters": {
"text": "Expense from receipt successfully recorded:\nDescription: *{{$json.description}}*\nAmount: *${{parseFloat($json.amount).toLocaleString('en-US')}}*\nCategory: *{{$json.category}}*",
"chatId": "={{$json.message.chat.id}}",
"parseMode": "HTML"
},
"typeVersion": 1
}
],
"connections": {
"Check 'Photo'": {
"output": [
{
"node": "Get Telegram Photo",
"type": "main",
"index": 0
},
{
"node": "Send Error Message (Text)",
"type": "main",
"index": 1
}
]
},
"Check 'Income'": {
"output": [
{
"node": "Add Income to Google Sheet",
"type": "main",
"index": 0
},
{
"node": "Send Error Message (Text)",
"type": "main",
"index": 1
}
]
},
"Parse OCR Data": {
"output": [
{
"node": "Add Expense to Google Sheet (OCR)",
"type": "main",
"index": 0
}
]
},
"OCR.space Request": {
"output": [
{
"node": "Parse OCR Data",
"type": "main",
"index": 0
}
]
},
"Get Telegram Photo": {
"output": [
{
"node": "OCR.space Request",
"type": "main",
"index": 0
}
]
},
"Check 'Expense' (Text)": {
"output": [
{
"node": "Add Expense to Google Sheet (Text)",
"type": "main",
"index": 0
},
{
"node": "Send Error Message (Text)",
"type": "main",
"index": 1
}
]
},
"Telegram Bot (Webhook)": {
"output": [
{
"node": "Check 'Income'",
"type": "main",
"index": 0
},
{
"node": "Check 'Expense' (Text)",
"type": "main",
"index": 0
},
{
"node": "Check 'Photo'",
"type": "main",
"index": 0
}
]
},
"Add Income to Google Sheet": {
"output": [
{
"node": "Send Income Confirmation",
"type": "main",
"index": 0
}
]
},
"Add Expense to Google Sheet (OCR)": {
"output": [
{
"node": "Send Expense Confirmation (OCR)",
"type": "main",
"index": 0
}
]
},
"Add Expense to Google Sheet (Text)": {
"output": [
{
"node": "Send Expense Confirmation (Text)",
"type": "main",
"index": 0
}
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 发票处理, AI 聊天机器人
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
高级SEO、核心网页指标和聊天机器人自动化套件
使用GPT-4顾问、PageSpeed Insights和Slack提醒审核和监控SEO性能
If
Set
Cron
+12
22 节点Candra Reza
市场调研
使用GPT-4o和Google Sheets的自动公司研究和线索丰富
使用GPT-4o和Google Sheets的自动公司研究和线索丰富
Set
Merge
Google Sheets
+9
22 节点Candra Reza
潜在客户开发
构建用于Slack候选人评估的AI驱动聊天机器人
AI简历分析与候选人评估:Slack和Google表格集成
If
Code
Slack
+12
29 节点Trung Tran
AI 聊天机器人
AI驱动的食品订单处理系统,集成Facebook Messenger、Google表格和日历
AI驱动的食品订单处理系统,集成Facebook Messenger、Google表格和日历
If
Code
Webhook
+8
26 节点Hans Wilhelm Radam
客户培育
使用Google Maps、GPT-4和WhatsApp自动化商业合作伙伴拓展
使用Google Maps、GPT-4和WhatsApp自动化商业合作伙伴拓展
If
Set
Code
+23
64 节点Khairul Muhtadin
AI 聊天机器人
新开发人员入职自动化
使用 GPT-4o 实现员工入职自动化:Jira、Notion 和 Gmail 集成
If
Set
Code
+9
21 节点Rahul Joshi
人力资源