Extraction de données de plans d'architecture via VLM Run et la suite Microsoft Office
Ceci est unDocument Extraction, AI Summarization, Multimodal AIworkflow d'automatisation du domainecontenant 8 nœuds.Utilise principalement des nœuds comme MicrosoftExcel, VlmRun, MicrosoftOneDrive, MicrosoftOneDriveTrigger. Extraire les données de plans architecturaux avec VLM Run et la suite Microsoft Office
- •Aucun prérequis spécial, prêt à l'emploi après importation
Nœuds utilisés (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": "Note adhésive",
"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": "Note adhésive2",
"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": "Note adhésive1",
"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": "Note adhésive3",
"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": "Déclencheur 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": "Télécharger un fichier",
"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": "Ajouter des données à une feuille",
"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
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - Extraction de documents, Résumé IA, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
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
Partager ce workflow