提取法律合同数据并使用VLM Run、Google Workspace和Slack发送提醒
中级
这是一个自动化工作流,包含 14 个节点。主要使用 Set, Code, Slack, Webhook, GoogleDrive 等节点。 提取法律合同数据并使用VLM Run、Google Workspace和Slack发送提醒
前置要求
- •Slack Bot Token 或 Webhook URL
- •HTTP Webhook 端点(n8n 会自动生成)
- •Google Drive API 凭证
- •Google Sheets API 凭证
使用的节点 (14)
分类
-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "bdfebade-893c-411c-80c6-0dace07f7dc9",
"name": "📁 输入处理文档",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 7,
"width": 400,
"height": 680,
"content": "## 📁 输入处理"
},
"typeVersion": 1
},
{
"id": "2fca40fa-ac4a-4515-a1e0-295cdcbfc595",
"name": "监控合同上传",
"type": "n8n-nodes-base.googleDriveTrigger",
"notes": "Monitors Google Drive folder for new receipt uploads and triggers processing automatically.",
"position": [
48,
480
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1S6baavqJn98MjUlbB6KtmARCWuWEekIZ",
"cachedResultUrl": "https://drive.google.com/drive/folders/1S6baavqJn98MjUlbB6KtmARCWuWEekIZ",
"cachedResultName": "test_data"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "zYyIOFMdGz258avn",
"name": "Google Drive account 6"
}
},
"typeVersion": 1
},
{
"id": "95acb226-9205-4a21-9a2d-c9792bc81de4",
"name": "下载合同文件",
"type": "n8n-nodes-base.googleDrive",
"notes": "Downloads receipt files from Google Drive for AI processing.",
"position": [
256,
480
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {
"binaryPropertyName": "data"
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "zYyIOFMdGz258avn",
"name": "Google Drive account 6"
}
},
"typeVersion": 3
},
{
"id": "61fa2c83-72cd-44b0-a5cd-5fbaeef5dfb1",
"name": "🤖 AI 提取文档",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
0
],
"parameters": {
"width": 416,
"height": 680,
"content": "## 🤖 VLM Run 合同提取"
},
"typeVersion": 1
},
{
"id": "84d28c8a-b33c-4bc3-9489-846c3b412d4a",
"name": "VLM Run 合同解析器",
"type": "@vlm-run/n8n-nodes-vlmrun.vlmRun",
"position": [
560,
480
],
"parameters": {
"operation": "executeAgent",
"agentPrompt": "extract data from the invoice or contract, Extract the key details from this lease contract. I am expecting the output to be in JSON format, with tags, using parameters : contract_id, title, parties (with role), property_address, effective_date, termination_date, rent_amount, security_deposit, payment_terms, governing_law . All the parameters should get values from the pdf of data file from the download contract file. \nNormalize dates to YYYY-MM-DD and amounts as numbers with currency. \nIf a field is missing, return null.",
"agentCallbackUrl": "https://playground.attensys.ai/webhook/b905e71d-8ea5-4fc2-a773-b0f92e5398e4"
},
"credentials": {
"vlmRunApi": {
"id": "B7ZYM8AfBgjnOEOl",
"name": "VLM Run account 5"
}
},
"typeVersion": 1
},
{
"id": "17996d92-afea-484c-88d3-9b2b673b1f4c",
"name": "📊 存储文档",
"type": "n8n-nodes-base.stickyNote",
"position": [
1056,
0
],
"parameters": {
"color": 7,
"width": 420,
"height": 680,
"content": "## 📊 数据存储"
},
"typeVersion": 1
},
{
"id": "70c2c9c5-d950-495f-9e91-5a0b402ef739",
"name": "保存到支出数据库",
"type": "n8n-nodes-base.googleSheets",
"notes": "Automatically saves extracted receipt data to Google Sheets for expense tracking.",
"position": [
1344,
480
],
"parameters": {
"columns": {
"value": {
"Title": "={{$node[\"Format Contract Data\"].json[\"Title\"]}}",
"Parties": "={{$node[\"Format Contract Data\"].json[\"Parties\"]}}",
"Contract ID": "={{$node[\"Format Contract Data\"].json[\"Contract ID\"]}}",
"Effective Date": "={{$node[\"Format Contract Data\"].json[\"Effective Date\"]}}",
"Termination Date": "={{$node[\"Format Contract Data\"].json[\"Termination Date\"]}}"
},
"schema": [
{
"id": "Contract ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Contract ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Parties",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Parties",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Effective Date",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Effective Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Termination Date",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Termination Date",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Customer"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/11_VjMdhv_JN2eSRZiw_t0dIN-yShkn2jlCDwiG8eb14/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1lg0aJKvd7E2pbhumHNjcgxUfEQKvlBs9h1zZbhSeqas",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1lg0aJKvd7E2pbhumHNjcgxUfEQKvlBs9h1zZbhSeqas/edit?usp=drivesdk",
"cachedResultName": "test"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "sdLQgQJjowDNfXMU",
"name": "Google Sheets account 7"
}
},
"typeVersion": 4.6
},
{
"id": "f752ffb1-d4eb-4d69-919d-2f4d72fb753e",
"name": "格式化合同数据",
"type": "n8n-nodes-base.set",
"notes": "Transforms AI-extracted receipt data into clean, structured format for spreadsheet storage.",
"position": [
1136,
480
],
"parameters": {
"values": {
"string": [
{
"name": "Contract ID",
"value": "={{ $json.body.response.contract_id }}"
},
{
"name": "Title",
"value": "={{ $json.body.response.title }}"
},
{
"name": "Parties",
"value": "={{ $json.body.parties && $json.body.parties.length ? $json.body.parties.map(p => p.name + \" (\"+ p.role + \")\").join(\"; \") : \"\" }}"
},
{
"name": "Effective Date",
"value": "={{ $json.body.response.effective_date }}"
},
{
"name": "Termination Date",
"value": "={{ $json.body.response.termination_date }}"
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 1
},
{
"id": "d04b627c-1b80-4692-91a3-2df61bec0b4d",
"name": "发送消息",
"type": "n8n-nodes-base.slack",
"position": [
1712,
512
],
"webhookId": "6b8dcfb9-51a9-418b-8469-4bf5b5894f2a",
"parameters": {
"text": "=*New Contract Processed* 📄\n• Contract ID: {{$node[\"Format Contract Data\"].json[\"Contract ID\"] || \"N/A\"}}\n• Title: {{$node[\"Format Contract Data\"].json[\"Title\"] || \"N/A\"}}\n• Parties: {{$node[\"Format Contract Data\"].json[\"Parties\"] || \"N/A\"}}\n• Effective: {{$node[\"Format Contract Data\"].json[\"Effective Date\"] || \"N/A\"}}\n• Termination: {{$node[\"Format Contract Data\"].json[\"Termination Date\"] || \"N/A\"}}\n🔗 {{$node[\"Format Contract Data\"].json[\"Drive Link\"] || $node[\"Save to Expense Database\"].json[\"driveLink\"] || \"No drive link available\"}}\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C081Z0KL546",
"cachedResultName": "test"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "M00QrTNTmnr6yiTS",
"name": "Slack account 11"
}
},
"typeVersion": 2.3
},
{
"id": "955768a3-5fac-4296-a5a3-d307a98b471c",
"name": "准备日历事件",
"type": "n8n-nodes-base.code",
"position": [
1616,
336
],
"parameters": {
"jsCode": "// n8n Function node code\n// Reads from Format Contract Data node and returns 1..3 items, each has .json with summary, description, start, end (YYYY-MM-DD)\n\nconst fmt = $node[\"Format Contract Data\"].json;\nconst title = fmt[\"Title\"] || \"Untitled Contract\";\nconst cid = fmt[\"Contract ID\"] || \"\";\nconst parties = fmt[\"Parties\"] || \"\";\nconst drive = fmt[\"Drive Link\"] || \"\";\n\nfunction isoDate(d) {\n // return YYYY-MM-DD\n return d.toISOString().split('T')[0];\n}\n\nfunction makeAllDayDates(dateStr) {\n // Accepts YYYY-MM-DD (or other parseable), returns start and end for all-day event.\n if(!dateStr) return null;\n const d = new Date(dateStr + \"T00:00:00\");\n const start = isoDate(d);\n const endD = new Date(d);\n endD.setDate(endD.getDate() + 1); // exclusive end for all-day events\n const end = isoDate(endD);\n return { start, end };\n}\n\nconst items = [];\n\n// Effective Date event\nconst eff = makeAllDayDates(fmt[\"Effective Date\"]);\nif (eff) {\n items.push({\n json: {\n summary: `${title} — Effective Date`,\n description: `Contract ID: ${cid}\\nParties: ${parties}\\nDrive: ${drive}`,\n start: eff.start,\n end: eff.end,\n allDay: true,\n metaType: \"effective\"\n }\n });\n}\n\n// Termination Date event\nconst term = makeAllDayDates(fmt[\"Termination Date\"]);\nif (term) {\n items.push({\n json: {\n summary: `${title} — Termination Date`,\n description: `Contract ID: ${cid}\\nParties: ${parties}\\nDrive: ${drive}`,\n start: term.start,\n end: term.end,\n allDay: true,\n metaType: \"termination\"\n }\n });\n\n // Renewal review reminder 60 days before termination\n const termDate = new Date(fmt[\"Termination Date\"] + \"T00:00:00\");\n const reminderDate = new Date(termDate);\n reminderDate.setDate(reminderDate.getDate() - 60); // change 60 to your preferred days\n const remStart = isoDate(reminderDate);\n const remEndD = new Date(reminderDate);\n remEndD.setDate(remEndD.getDate() + 1);\n const remEnd = isoDate(remEndD);\n\n items.push({\n json: {\n summary: `${title} — Renewal Review (Reminder)`,\n description: `Contract ID: ${cid}\\nTermination Date: ${fmt[\"Termination Date\"]}\\nAction: Review & decide renewal.`,\n start: remStart,\n end: remEnd,\n allDay: true,\n metaType: \"renewal_reminder\"\n }\n });\n}\n\nreturn items;\n"
},
"typeVersion": 2
},
{
"id": "f3301d1a-5773-4598-ba4e-71019a4966bd",
"name": "创建事件",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1808,
336
],
"parameters": {
"end": "={{$json[\"end\"]}}",
"start": "={{$json[\"start\"]}}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "sayonaraistata@gmail.com",
"cachedResultName": "sayonaraistata@gmail.com"
},
"additionalFields": {
"allday": "yes",
"summary": "={{$json[\"summary\"]}}",
"description": "={{$json[\"description\"]}}"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "9TLut5ZDt3hcaQEo",
"name": "Google Calendar account 3"
}
},
"typeVersion": 1.3
},
{
"id": "dd656271-d2a3-4f8a-9df8-1da0596b2734",
"name": "📊 存储文档1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1552,
0
],
"parameters": {
"color": 7,
"width": 420,
"height": 680,
"content": "## 🔔 已添加通知:"
},
"typeVersion": 1
},
{
"id": "99fdd61d-c6a9-4e74-989a-e56b47caf2e9",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
368,
704
],
"parameters": {
"color": 5,
"width": 704,
"height": 144,
"content": "## 📝 设置回调 URL"
},
"typeVersion": 1
},
{
"id": "6d26e945-a724-4e3b-a8ff-c91dd8500f5f",
"name": "接收合同",
"type": "n8n-nodes-base.webhook",
"position": [
784,
480
],
"webhookId": "b905e71d-8ea5-4fc2-a773-b0f92e5398e4",
"parameters": {
"path": "b905e71d-8ea5-4fc2-a773-b0f92e5398e4",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
}
],
"pinData": {},
"connections": {
"Receive Contract": {
"main": [
[
{
"node": "Format Contract Data",
"type": "main",
"index": 0
}
]
]
},
"Format Contract Data": {
"main": [
[
{
"node": "Save to Expense Database",
"type": "main",
"index": 0
}
]
]
},
"Download Contract File": {
"main": [
[
{
"node": "VLM Run ContractParser",
"type": "main",
"index": 0
}
]
]
},
"Prepare Calendar Events": {
"main": [
[
{
"node": "Create an event",
"type": "main",
"index": 0
}
]
]
},
"Monitor Contract Uploads": {
"main": [
[
{
"node": "Download Contract File",
"type": "main",
"index": 0
}
]
]
},
"Save to Expense Database": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
},
{
"node": "Prepare Calendar Events",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用VLM Run提取收据数据
利用VLM Run和Google提取并整理收据数据用于费用跟踪
Set
Google Drive
Google Sheets
+3
9 节点Shahrear
财务
AI简历处理与GitHub分析(VLM运行)
AI简历处理与GitHub分析(VLM运行)
If
Code
Gmail
+7
18 节点Shahrear
人工智能
使用Google Drive、VLM Run和Airtable自动化收据处理用于费用跟踪
通过Google Drive、VLM Run和Airtable实现费用跟踪收据处理的自动化
Set
Airtable
Google Drive
+3
9 节点Shahrear
杂项
建筑蓝图至Google Sheets自动化
使用VLM Run和Google Drive实现建筑蓝图至Google Sheets自动化
Google Drive
Google Sheets
Vlm Run
+2
8 节点Shahrear
AI 摘要总结
使用VLM Run AI和Gmail提醒从Google Drive图片提取考勤数据到Sheets
使用VLM Run AI和Gmail提醒从Google Drive图片提取考勤数据到Sheets
Gmail
Webhook
Google Drive
+4
11 节点Shahrear
Google Drive文档内嵌图片提取
使用VLM Run Agent从Google Drive文档中提取内嵌图片
Webhook
Split Out
Google Drive
+4
11 节点Shahrear
工作流信息
难度等级
中级
节点数量14
分类-
节点类型10
作者
Shahrear
@shahrearI’m Shahrear, a Software Engineer with over 5 years of experience in full-stack development and workflow automation. I specialize in building intelligent automations using n8n, helping teams streamline operations and boost productivity. I’m also an expert in developing custom n8n nodes, with published work on npm - including the @vlm-run/n8n-nodes-vlmrun package. Linkedin - https://www.linkedin.com/in/shahrear-amin/ Email - shahrearbinamin33@gmail.com
外部链接
在 n8n.io 查看 →
分享此工作流