VLM Run과 마이크로소프트 오피스 패키지를 사용하여 건축 블루프린트 데이터 추출
이것은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": "Sticky Note",
"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": "Sticky Note2",
"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": "Sticky Note1",
"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": "Sticky Note3",
"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
이 워크플로우 공유