使用VLM Run和Microsoft Office套件提取建筑蓝图数据
这是一个Document Extraction, AI Summarization, Multimodal AI领域的自动化工作流,包含 8 个节点。主要使用 MicrosoftExcel, VlmRun, MicrosoftOneDrive, MicrosoftOneDriveTrigger 等节点。 使用VLM Run和Microsoft Office套件提取建筑蓝图数据
- •无特殊前置要求,导入即可使用
{
"meta": {
"instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "53f75ca8-6a2a-46b2-b4f7-b4786170d8ce",
"name": "VLM Run 解析",
"type": "@vlm-run/n8n-nodes-vlmrun.vlmRun",
"position": [
1728,
288
],
"parameters": {
"domain": "construction.blueprint"
},
"credentials": {
"vlmRunApi": {
"id": "7JF2kdNzjhKZsHGg",
"name": "VLM Run account 2"
}
},
"typeVersion": 1
},
{
"id": "fcf3a39e-e959-4c1b-8b9e-21e2553bd7dc",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 使用 VLM Run 进行施工蓝图处理"
},
"typeVersion": 1
},
{
"id": "d4229b1b-5209-46f7-b2de-1ad7cbb096ef",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2048,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 在 Excel 表格中追加行"
},
"typeVersion": 1
},
{
"id": "a4ced382-369a-4694-9da8-2cbc4b15c690",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 📁 输入处理"
},
"typeVersion": 1
},
{
"id": "1956b501-857a-411e-a151-c67a487a1e54",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
-208
],
"parameters": {
"width": 480,
"height": 768,
"content": "# VLM Run (文档)"
},
"typeVersion": 1
},
{
"id": "90bb7989-ea88-4ae4-95c2-ccf9a3040b33",
"name": "Microsoft OneDrive 触发器",
"type": "n8n-nodes-base.microsoftOneDriveTrigger",
"position": [
1104,
288
],
"parameters": {
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "AE5A9F7C8F06E9ED!se2bce082634d472487eaa7baa7be36b1"
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"watchFolder": true
},
"credentials": {
"microsoftOneDriveOAuth2Api": {
"id": "yem1XL6RzYx55n22",
"name": "Microsoft Drive account"
}
},
"typeVersion": 1
},
{
"id": "579975f5-effe-4cb8-8358-f877ba99d414",
"name": "下载文件",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
1312,
288
],
"parameters": {
"fileId": "={{ $json.id }}",
"operation": "download"
},
"credentials": {
"microsoftOneDriveOAuth2Api": {
"id": "yem1XL6RzYx55n22",
"name": "Microsoft Drive account"
}
},
"typeVersion": 1
},
{
"id": "dad380a9-0be1-465c-99d5-f326e608100a",
"name": "将数据追加到表格",
"type": "n8n-nodes-base.microsoftExcel",
"position": [
2224,
288
],
"parameters": {
"options": {},
"fieldsUi": {
"values": [
{
"column": "PROJECT DETAILS",
"fieldValue": "={{ (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"
},
{
"column": "DOCUMENT TYPE",
"fieldValue": "={{ $json.response.document_metadata.document_type }}"
},
{
"column": "DOCUMENT NUMBER",
"fieldValue": "={{ $json.response.document_metadata.document_number }}"
},
{
"column": "ISSUE DATE",
"fieldValue": "={{ $json.response.document_metadata.issue_date }}"
},
{
"column": "AUTHOR'S NAME",
"fieldValue": "={{ (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"
},
{
"column": "DRAWING TITLE NUMBERS",
"fieldValue": "={{ (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"
},
{
"column": "SCALE LEGENDS",
"fieldValue": "={{ $json.response.drawings_blueprints.scale_legends }}"
},
{
"column": "REVISION HISTORY",
"fieldValue": "={{ (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"
},
{
"column": "ANNOTATIONS MARKUPS",
"fieldValue": "={{ (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"
},
{
"column": "JOB NAME",
"fieldValue": "={{ $json.response.title_block.job_name }}"
},
{
"column": "ADDRESS",
"fieldValue": "={{ (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"
},
{
"column": "DRAWING NUMBER",
"fieldValue": "={{ $json.response.title_block.drawing_number }}"
},
{
"column": "REVISION",
"fieldValue": "={{ $json.response.title_block.revision }}"
},
{
"column": "DRAWN BY",
"fieldValue": "={{ $json.response.title_block.drawn_by }}"
},
{
"column": "CHECKED BY",
"fieldValue": "={{ $json.response.title_block.checked_by }}"
},
{
"column": "SCALE",
"fieldValue": "={{ $json.response.title_block.scale }}"
},
{
"column": "AGENCY NAME",
"fieldValue": "={{ $json.response.title_block.agency_name }}"
},
{
"column": "DOCUMENT TITLE",
"fieldValue": "={{ $json.response.title_block.document_title }}"
},
{
"column": "OTHER METADATA",
"fieldValue": "={{ (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"
},
{
"column": "DRAWING TYPE",
"fieldValue": "={{ $json.response.drawing_type }}"
},
{
"column": "LEGAL COMPLIANCE",
"fieldValue": "={{ (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"
},
{
"column": "SCALE INFORMATION",
"fieldValue": "={{ $json.response.scale_information }}"
}
]
},
"resource": "worksheet",
"workbook": {
"__rl": true,
"mode": "list",
"value": "AE5A9F7C8F06E9ED!sc46f0642e32643ada075b983e522bdc7",
"cachedResultUrl": "https://onedrive.live.com/personal/ae5a9f7c8f06e9ed/_layouts/15/doc.aspx?resid=c46f0642-e326-43ad-a075-b983e522bdc7&cid=ae5a9f7c8f06e9ed",
"cachedResultName": "Construction Blueprint"
},
"operation": "append",
"worksheet": {
"__rl": true,
"mode": "list",
"value": "{00000000-0001-0000-0000-000000000000}",
"cachedResultUrl": "https://onedrive.live.com/personal/ae5a9f7c8f06e9ed/_layouts/15/doc.aspx?resid=c46f0642-e326-43ad-a075-b983e522bdc7&cid=ae5a9f7c8f06e9ed&activeCell=Sheet1!A1",
"cachedResultName": "Sheet1"
}
},
"credentials": {
"microsoftExcelOAuth2Api": {
"id": "YspXACjq4yHdKOIF",
"name": "Microsoft Excel account"
}
},
"typeVersion": 2.1
}
],
"pinData": {},
"connections": {
"Download a file": {
"main": [
[
{
"node": "VLM Run Parsing",
"type": "main",
"index": 0
}
]
]
},
"VLM Run Parsing": {
"main": [
[
{
"node": "Append data to sheet",
"type": "main",
"index": 0
}
]
]
},
"Microsoft OneDrive Trigger": {
"main": [
[
{
"node": "Download a 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
分享此工作流