Automatisation des plans d'architecture vers Google Sheets

Intermédiaire

Ceci est unAI Summarization, Multimodal AIworkflow d'automatisation du domainecontenant 8 nœuds.Utilise principalement des nœuds comme GoogleDrive, GoogleSheets, VlmRun, GoogleDriveTrigger. Automatiser la conversion de plans d'architecture vers Google Sheets avec VLM Run et Google Drive

Prérequis
  • Informations d'identification Google Drive API
  • Informations d'identification Google Sheets API
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "meta": {
    "instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c"
  },
  "nodes": [
    {
      "id": "437ad354-32ef-4400-afa4-7cc37a819d5b",
      "name": "VLM Run",
      "type": "@vlm-run/n8n-nodes-vlmrun.vlmRun",
      "position": [
        1744,
        480
      ],
      "parameters": {
        "domain": "construction.blueprint"
      },
      "typeVersion": 1
    },
    {
      "id": "6aa5ea64-0da0-4296-b57d-a002b9ca7b28",
      "name": "Ajouter une ligne dans la feuille",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2256,
        480
      ],
      "parameters": {
        "columns": {
          "value": {
            "SCALE": "={{ $json.response.title_block.scale }}",
            "ADDRESS": "={{ (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",
            "DRAWN BY": "={{ $json.response.title_block.drawn_by }}",
            "JOB NAME": "={{ $json.response.title_block.job_name }}",
            "REVISION": "={{ $json.response.title_block.revision }}",
            "CHECKED BY": "={{ $json.response.title_block.checked_by }}",
            "ISSUE DATE": "={{ $json.response.document_metadata.issue_date }}",
            "AGENCY NAME": "={{ $json.response.title_block.agency_name }}",
            "DRAWING TYPE": "={{ $json.response.drawing_type }}",
            "AUTHOR'S NAME": "={{ (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",
            "DOCUMENT TYPE": "={{ $json.response.document_metadata.document_type }}",
            "DOCUMENT TITLE": "={{ $json.response.title_block.document_title }}",
            "DRAWING NUMBER": "={{ $json.response.title_block.drawing_number }}",
            "OTHER METADATA": "={{ (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",
            "SCALE LEEGENDS": "={{ $json.response.drawings_blueprints.scale_legends }}",
            "PROJECT DETAILS": "={{ (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",
            "DOCUMENT NUMBER ": "={{ $json.response.document_metadata.document_number }}",
            "LEGAL COMPLIANCE": "={{ (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",
            "REVISION HISTORY": "={{ (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",
            "SCALE INFORMATION": "={{ $json.response.scale_information }}",
            "ANNOTATIONS MARKUPS": "={{ (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",
            "DRAWING TITLE NUMBERS": "={{ (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"
          },
          "schema": [
            {
              "id": "PROJECT DETAILS",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "PROJECT DETAILS",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DOCUMENT TYPE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DOCUMENT TYPE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DOCUMENT NUMBER ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "DOCUMENT NUMBER ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ISSUE DATE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ISSUE DATE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "AUTHOR'S NAME",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "AUTHOR'S NAME",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DRAWING TITLE NUMBERS",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DRAWING TITLE NUMBERS",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "SCALE LEEGENDS",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "SCALE LEEGENDS",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "REVISION HISTORY",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "REVISION HISTORY",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ANNOTATIONS MARKUPS",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ANNOTATIONS MARKUPS",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "JOB NAME",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "JOB NAME",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ADDRESS",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ADDRESS",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DRAWING NUMBER",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DRAWING NUMBER",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "REVISION",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "REVISION",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DRAWN BY",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DRAWN BY",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "CHECKED BY",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "CHECKED BY",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "SCALE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "SCALE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "AGENCY NAME",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "AGENCY NAME",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DOCUMENT TITLE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DOCUMENT TITLE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "OTHER METADATA",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "OTHER METADATA",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DRAWING TYPE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DRAWING TYPE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "LEGAL COMPLIANCE",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "LEGAL COMPLIANCE",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "SCALE INFORMATION",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "SCALE INFORMATION",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "useAppend": true
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1NyNXDvHHJwedBSXa8qENv_4nBlqyaU-l3wgtAK-9Om0/edit?usp=drivesdk",
          "cachedResultName": "Construction Blue print"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "42f825ee-f0dd-44c0-91f1-6088fcf29f0d",
      "name": "Télécharger le fichier",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1328,
        480
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "typeVersion": 3
    },
    {
      "id": "72f102a6-e223-437f-bf19-861818ff9b09",
      "name": "Note adhésive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        0
      ],
      "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 Google Drive and saves them into a Google Sheet for tracking, compliance, or reporting.\n\n## Workflow\n\n1. 📂 Detect file upload in Google Drive\n2. ⬇️ Download the uploaded document\n3. 🤖 Convert document to structured text using VLM Run (`construction.blueprint`)\n4. 📊 Append extracted order data to Google 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* Google Drive + Sheets OAuth2\n* n8n server with active workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "145286ec-906c-430d-8448-447eac2bd266",
      "name": "Note adhésive2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 768,
        "content": "# Append Row in Sheet\n\n**Function:** Appends extracted structured data into a Google 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": "09952464-9148-44c9-a6c0-ab09b285be87",
      "name": "Google Déclencheur Drive",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        1088,
        480
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {
          "fileType": "all"
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "1E8rvLEWKguorMT36yCD1jY78G0u8g6g7",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1E8rvLEWKguorMT36yCD1jY78G0u8g6g7",
          "cachedResultName": "test_data"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6b368cd5-0ce9-453f-9e02-28440878aa72",
      "name": "Note adhésive1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 768,
        "content": "# 📁 Input Processing\n\n**Monitors & downloads blueprint files from Google Drive.**\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": "84b00cb6-ac37-4ea9-ab09-118c40160767",
      "name": "Note adhésive3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        0
      ],
      "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
    }
  ],
  "pinData": {},
  "connections": {
    "437ad354-32ef-4400-afa4-7cc37a819d5b": {
      "main": [
        [
          {
            "node": "6aa5ea64-0da0-4296-b57d-a002b9ca7b28",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "42f825ee-f0dd-44c0-91f1-6088fcf29f0d": {
      "main": [
        [
          {
            "node": "437ad354-32ef-4400-afa4-7cc37a819d5b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "09952464-9148-44c9-a6c0-ab09b285be87": {
      "main": [
        [
          {
            "node": "42f825ee-f0dd-44c0-91f1-6088fcf29f0d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Foire aux questions

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 - 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

Informations sur le workflow
Niveau de difficulté
Intermédiaire
Nombre de nœuds8
Catégorie2
Types de nœuds5
Description de la difficulté

Adapté aux utilisateurs expérimentés, avec des workflows de complexité moyenne contenant 6-15 nœuds

Auteur
Shahrear

Shahrear

@shahrear

I’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

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34