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 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": "付箋",
"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": "付箋2",
"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": "付箋1",
"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": "付箋3",
"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": "ファイルをダウンロード",
"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": {
"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
}
]
]
}
}
}このワークフローの使い方は?
上記の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
このワークフローを共有