Extracción de datos de planos de construcción con VLM Run y la suite de Microsoft Office
Este es unDocument Extraction, AI Summarization, Multimodal AIflujo de automatización del dominio deautomatización que contiene 8 nodos.Utiliza principalmente nodos como MicrosoftExcel, VlmRun, MicrosoftOneDrive, MicrosoftOneDriveTrigger. Extraer datos de planos de construcción con VLM Run y la suite Microsoft Office
- •No hay requisitos previos especiales, puede importar y usarlo directamente
Nodos utilizados (8)
{
"meta": {
"instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "53f75ca8-6a2a-46b2-b4f7-b4786170d8ce",
"name": "VLM Run Parsing",
"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": "Nota adhesiva",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# Construction Blueprint Processing with VLM Run\n\nAutomatically extracts structured construction blueprint details from uploaded documents in OneDrive and saves them into an Excel Sheet for tracking, compliance, or reporting.\n\n## Workflow\n\n1. 📂 Detect file upload in OneDrive\n2. ⬇️ Download the uploaded document\n3. 🤖 Convert document to structured text using VLM Run (`construction.blueprint`)\n4. 📊 Append extracted order data to Excel Sheet\n\n## Perfect for\n\n* Construction blueprint processing\n* Architectural plan reviews\n* Engineering drawing requests\n* Permit and regulatory submission workflows\n* Automated compliance documentation\n\n## Requirements\n\n* VLM Run API access\n* OneDrive + Excel OAuth2\n* n8n server with active workflow"
},
"typeVersion": 1
},
{
"id": "d4229b1b-5209-46f7-b2de-1ad7cbb096ef",
"name": "Nota adhesiva2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2048,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# Append Row in Excel Sheet\n\n**Function:** Appends extracted structured data into an Excel Sheet.\n\n* Columns could be: Project Details, Document Type, Document Number, Issue Date, Author's Name, Drawing Title Numbers, Revision History, Annotations Markups, Job Name\n\n**Benefit:** Provides a structured, continuously updated database for tracking blueprints\n"
},
"typeVersion": 1
},
{
"id": "a4ced382-369a-4694-9da8-2cbc4b15c690",
"name": "Nota adhesiva1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
-208
],
"parameters": {
"color": 7,
"width": 480,
"height": 768,
"content": "# 📁 Input Processing\n\n**Monitors & downloads blueprint files from OneDrive.**\n\n**Process:**\n1. Watches designated Drive folder\n2. Auto-triggers on new uploads\n3. Downloads files for AI processing\n\n**Supported Formats:**\n- Images (JPG, PNG, WEBP)\n- PDF documents\n- Mobile camera uploads\n- Scanned receipts"
},
"typeVersion": 1
},
{
"id": "1956b501-857a-411e-a151-c67a487a1e54",
"name": "Nota adhesiva3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
-208
],
"parameters": {
"width": 480,
"height": 768,
"content": "# VLM Run (Document)\n\n**Function:** Sends the blueprint file to VLM Run under the category `construction.blueprint`.\n\n* Extracts structured details such as:\n\n * Project name, address, permit ID\n * Drawing elements (dimensions, materials, quantities, compliance flags)\n * Architect/engineer details (name, license number, approval date)\n\n**Benefit:** Turns complex construction blueprints into machine-readable JSON\n"
},
"typeVersion": 1
},
{
"id": "90bb7989-ea88-4ae4-95c2-ccf9a3040b33",
"name": "Microsoft OneDrive Trigger",
"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": "Descargar un archivo",
"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": "Agregar datos a la hoja",
"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": {
"579975f5-effe-4cb8-8358-f877ba99d414": {
"main": [
[
{
"node": "53f75ca8-6a2a-46b2-b4f7-b4786170d8ce",
"type": "main",
"index": 0
}
]
]
},
"53f75ca8-6a2a-46b2-b4f7-b4786170d8ce": {
"main": [
[
{
"node": "dad380a9-0be1-465c-99d5-f326e608100a",
"type": "main",
"index": 0
}
]
]
},
"90bb7989-ea88-4ae4-95c2-ccf9a3040b33": {
"main": [
[
{
"node": "579975f5-effe-4cb8-8358-f877ba99d414",
"type": "main",
"index": 0
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Intermedio - Extracción de documentos, Resumen de IA, IA Multimodal
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
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
Compartir este flujo de trabajo