建筑蓝图至Google Sheets自动化
这是一个AI Summarization, Multimodal AI领域的自动化工作流,包含 8 个节点。主要使用 GoogleDrive, GoogleSheets, VlmRun, GoogleDriveTrigger 等节点。 使用VLM Run和Google Drive实现建筑蓝图至Google Sheets自动化
- •Google Drive API 凭证
- •Google Sheets API 凭证
{
"meta": {
"instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c"
},
"nodes": [
{
"id": "437ad354-32ef-4400-afa4-7cc37a819d5b",
"name": "VLM 运行",
"type": "@vlm-run/n8n-nodes-vlmrun.vlmRun",
"position": [
1744,
480
],
"parameters": {
"domain": "construction.blueprint"
},
"typeVersion": 1
},
{
"id": "6aa5ea64-0da0-4296-b57d-a002b9ca7b28",
"name": "在表格中追加行",
"type": "n8n-nodes-base.googleSheets",
"position": [
2256,
480
],
"parameters": {
"columns": {
"value": {
"SCALE": "={{ $json.response.title_block.scale }}",
"ADDRESS": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.title_block?.address) }}\n",
"DRAWN BY": "={{ $json.response.title_block.drawn_by }}",
"JOB NAME": "={{ $json.response.title_block.job_name }}",
"REVISION": "={{ $json.response.title_block.revision }}",
"CHECKED BY": "={{ $json.response.title_block.checked_by }}",
"ISSUE DATE": "={{ $json.response.document_metadata.issue_date }}",
"AGENCY NAME": "={{ $json.response.title_block.agency_name }}",
"DRAWING TYPE": "={{ $json.response.drawing_type }}",
"AUTHOR'S NAME": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.document_metadata?.author) }}\n",
"DOCUMENT TYPE": "={{ $json.response.document_metadata.document_type }}",
"DOCUMENT TITLE": "={{ $json.response.title_block.document_title }}",
"DRAWING NUMBER": "={{ $json.response.title_block.drawing_number }}",
"OTHER METADATA": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.title_block?.other_metadata) }}\n",
"SCALE LEEGENDS": "={{ $json.response.drawings_blueprints.scale_legends }}",
"PROJECT DETAILS": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.project_details) }}\n",
"DOCUMENT NUMBER ": "={{ $json.response.document_metadata.document_number }}",
"LEGAL COMPLIANCE": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x)\n return S(v)\n})($json.response?.compliance_legal) }}\n",
"REVISION HISTORY": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.drawings_blueprints?.revision_history) }}\n",
"SCALE INFORMATION": "={{ $json.response.scale_information }}",
"ANNOTATIONS MARKUPS": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.drawings_blueprints?.annotations_markups) }}\n",
"DRAWING TITLE NUMBERS": "={{ (v => {\n const S = x =>\n x == null ? '' :\n Array.isArray(x)\n ? x.map(S).map(s => String(s).trim()).filter(Boolean).join(',\\n')\n : typeof x === 'object'\n ? Object.entries(x)\n .filter(([_, val]) => {\n if (val == null) return false\n if (typeof val === 'string') return val.trim() !== ''\n if (Array.isArray(val)) return val.map(S).some(s => String(s).trim() !== '')\n if (typeof val === 'object') return Object.keys(val).length > 0\n return true\n })\n .map(([k, val]) => {\n const sv = S(val)\n return sv ? `${k}: ${sv}` : ''\n })\n .filter(Boolean)\n .join(',\\n')\n : String(x).trim()\n return S(v)\n})($json.response?.drawings_blueprints?.drawing_titles_numbers) }}\n"
},
"schema": [
{
"id": "PROJECT DETAILS",
"type": "string",
"display": true,
"required": false,
"displayName": "PROJECT DETAILS",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DOCUMENT TYPE",
"type": "string",
"display": true,
"required": false,
"displayName": "DOCUMENT TYPE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DOCUMENT NUMBER ",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "DOCUMENT NUMBER ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ISSUE DATE",
"type": "string",
"display": true,
"required": false,
"displayName": "ISSUE DATE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "AUTHOR'S NAME",
"type": "string",
"display": true,
"required": false,
"displayName": "AUTHOR'S NAME",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DRAWING TITLE NUMBERS",
"type": "string",
"display": true,
"required": false,
"displayName": "DRAWING TITLE NUMBERS",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCALE LEEGENDS",
"type": "string",
"display": true,
"required": false,
"displayName": "SCALE LEEGENDS",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "REVISION HISTORY",
"type": "string",
"display": true,
"required": false,
"displayName": "REVISION HISTORY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ANNOTATIONS MARKUPS",
"type": "string",
"display": true,
"required": false,
"displayName": "ANNOTATIONS MARKUPS",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "JOB NAME",
"type": "string",
"display": true,
"required": false,
"displayName": "JOB NAME",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ADDRESS",
"type": "string",
"display": true,
"required": false,
"displayName": "ADDRESS",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DRAWING NUMBER",
"type": "string",
"display": true,
"required": false,
"displayName": "DRAWING NUMBER",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "REVISION",
"type": "string",
"display": true,
"required": false,
"displayName": "REVISION",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DRAWN BY",
"type": "string",
"display": true,
"required": false,
"displayName": "DRAWN BY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "CHECKED BY",
"type": "string",
"display": true,
"required": false,
"displayName": "CHECKED BY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCALE",
"type": "string",
"display": true,
"required": false,
"displayName": "SCALE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "AGENCY NAME",
"type": "string",
"display": true,
"required": false,
"displayName": "AGENCY NAME",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DOCUMENT TITLE",
"type": "string",
"display": true,
"required": false,
"displayName": "DOCUMENT TITLE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "OTHER METADATA",
"type": "string",
"display": true,
"required": false,
"displayName": "OTHER METADATA",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DRAWING TYPE",
"type": "string",
"display": true,
"required": false,
"displayName": "DRAWING TYPE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LEGAL COMPLIANCE",
"type": "string",
"display": true,
"required": false,
"displayName": "LEGAL COMPLIANCE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCALE INFORMATION",
"type": "string",
"display": true,
"required": false,
"displayName": "SCALE INFORMATION",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"useAppend": true
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0/edit?usp=drivesdk",
"cachedResultName": "Construction Blue print"
}
},
"typeVersion": 4.7
},
{
"id": "42f825ee-f0dd-44c0-91f1-6088fcf29f0d",
"name": "下载文件",
"type": "n8n-nodes-base.googleDrive",
"position": [
1328,
480
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "download"
},
"typeVersion": 3
},
{
"id": "72f102a6-e223-437f-bf19-861818ff9b09",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
0
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 使用 VLM 运行处理建筑蓝图"
},
"typeVersion": 1
},
{
"id": "145286ec-906c-430d-8448-447eac2bd266",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2048,
0
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 在表格中追加行"
},
"typeVersion": 1
},
{
"id": "09952464-9148-44c9-a6c0-ab09b285be87",
"name": "Google Drive 触发器",
"type": "n8n-nodes-base.googleDriveTrigger",
"position": [
1088,
480
],
"parameters": {
"event": "fileCreated",
"options": {
"fileType": "all"
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1E8rvLEWKguorMT36yCD1jY78G0u8g6g7",
"cachedResultUrl": "https://drive.google.com/drive/folders/1E8rvLEWKguorMT36yCD1jY78G0u8g6g7",
"cachedResultName": "test_data"
}
},
"typeVersion": 1
},
{
"id": "6b368cd5-0ce9-453f-9e02-28440878aa72",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
0
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 📁 输入处理"
},
"typeVersion": 1
},
{
"id": "84b00cb6-ac37-4ea9-ab09-118c40160767",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
0
],
"parameters": {
"width": 480,
"height": 768,
"content": "# VLM 运行(文档)"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"VLM Run": {
"main": [
[
{
"node": "Append row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Download file": {
"main": [
[
{
"node": "VLM Run",
"type": "main",
"index": 0
}
]
]
},
"Google Drive Trigger": {
"main": [
[
{
"node": "Download file",
"type": "main",
"index": 0
}
]
]
}
}
}如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - AI 摘要总结, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
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
分享此工作流