8
n8n 中文网amn8n.com

提取法律合同数据并使用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 凭证

分类

-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 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)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量14
分类-
节点类型10
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

作者
Shahrear

Shahrear

@shahrear

I’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 查看

分享此工作流