{
  "id": "CWmsTi8fPlSw4tkc",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI-driven construction execution monitoring",
  "tags": [],
  "nodes": [
    {
      "id": "c8c31116-0066-4cc7-9c78-289bbcf2b999",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2192,
        736
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "4e2a0461-7789-4262-ac27-3bba8a352707",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        992,
        608
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "58b599ea-5488-4f97-9386-8e2247c45524",
              "name": "runTimestamp",
              "type": "string",
              "value": "={{ DateTime.now().setZone('America/Sao_Paulo').toFormat('dd/MM/yyyy HH:mm:ss') }}"
            },
            {
              "id": "e8a6ad4d-9a9e-4cc6-91e3-4e5b35225e5b",
              "name": "inputFolderId",
              "type": "string",
              "value": "REPLACE_WITH_INPUT_FOLDER_ID"
            },
            {
              "id": "827673b9-a1b4-49f7-9688-5bd67631f05a",
              "name": "reportLanguage",
              "type": "string",
              "value": "English"
            },
            {
              "id": "4fb07426-fb5e-4deb-8e9e-90504cf153ac",
              "name": "emailTo",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "d776a866-cdfa-4dff-b75d-fc4e886945b8",
              "name": "emailSubjectPrefix",
              "type": "string",
              "value": "Construction Photo Report"
            },
            {
              "id": "1e197cec-ba03-4665-91e1-d7c946b6de02",
              "name": "logSpreadsheetId",
              "type": "string",
              "value": "REPLACE_WITH_SPREADSHEET_ID"
            },
            {
              "id": "54b7a530-d408-488a-8bdf-d90661d0e436",
              "name": "logSheetName",
              "type": "string",
              "value": "P\u00e1gina1"
            },
            {
              "id": "664a46d1-511f-4772-b9f1-11f667dfcaca",
              "name": "processedFolderId",
              "type": "string",
              "value": "REPLACE_WITH_PROCESSED_FOLDER_ID"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "748efe1d-50ae-4f2c-85ca-54e295c93632",
      "name": "Drive: List files (Input folder)",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1216,
        608
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "id",
            "value": "={{ $json.inputFolderId }}"
          }
        },
        "options": {
          "fields": [
            "id",
            "name",
            "mimeType"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "26900de8-647c-4610-b815-06b8a655e9da",
      "name": "Filter: Keep images only",
      "type": "n8n-nodes-base.filter",
      "position": [
        1440,
        608
      ],
      "parameters": {
        "options": {
          "ignoreCase": true
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "06f1432f-7f45-4ce6-9639-ed4da39397d6",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              },
              "leftValue": "={{ $json.mimeType }}",
              "rightValue": "image/"
            }
          ]
        }
      },
      "typeVersion": 2.3,
      "alwaysOutputData": true
    },
    {
      "id": "5272b0ff-4ce5-4d41-a594-b82382f93677",
      "name": "Drive: Download image",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1888,
        512
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "a5341e24-d1f2-40e3-b118-6e69335f1de1",
      "name": "AI: Analyze image",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2112,
        512
      ],
      "parameters": {
        "text": "=PROMPT FOR CONSTRUCTION SITE PHOTO ANALYSIS \u2013 CIVIL ENGINEERING\n\nRole:\nYou are a Civil Engineer acting as the Technical Manager responsible for the construction project, with experience in residential, commercial, and industrial works, covering execution, inspection, and quality control.\n\nObjective:\nAnalyze photo(s) of a civil construction project with a technical, critical, and professional perspective, providing a clear and well-founded assessment that is also understandable to non-technical clients.\n\nAnalysis Instructions\n\nWhen analyzing the image(s), strictly follow the steps below, without assuming any information that is not visibly evident:\n\n1. Identification of the Construction Stage\n\nIndicate, based solely on what is visible, which stage the project appears to be in, for example:\n\nFoundations (excavation, footings, pile caps, raft slab, piles)\n\nStructure (formwork, reinforcement, concrete casting, columns, beams, slabs)\n\nMasonry (partition or structural masonry)\n\nInstallations (plumbing, electrical, gas, fire protection)\n\nFinishes and surface treatments\n\nConstruction site setup / preliminary services\n\nIf there is any uncertainty, explicitly state it.\n\n2. Assessment of Execution Quality\n\nAnalyze the quality of what is visible, observing, when applicable:\n\nAlignment, leveling, and verticality\n\nSurface finishing quality\n\nOrganization and cleanliness of the work area\n\nApparent compliance with engineering best practices\n\nClassify the overall perception as adequate, fair, or critical, always providing justification.\n\n3. Identification of Non-Conformities and Risks\n\nPoint out possible:\n\nConstruction defects\n\nTechnical non-conformities\n\nSigns of pathologies (cracks, segregation, exposed reinforcement, moisture, etc.)\n\nApparent structural risks\n\nIssues that may lead to rework, additional costs, or future risks\n\nIf something cannot be confirmed based solely on the image, clearly state this limitation.\n\n4. Occupational Safety and Best Practices\n\nVisually verify:\n\nUse of PPE (helmet, gloves, boots, safety harnesses, etc.)\n\nShoring, collective protection systems, and temporary stability\n\nConstruction site organization\n\nImmediate risks to workers or third parties\n\nComment in an objective and technical manner.\n\n5. Technical Recommendations\n\nWhen applicable:\n\nSuggest corrections, adjustments, or preventive measures\n\nIndicate the need for complementary verification (design documents, testing, inspection)\n\nHighlight points that require attention from the technical manager\n\nResponse Format\n\nTechnical language, yet clear and accessible\n\nObjective text, structured in topics\n\nNo speculation beyond what is visible in the image\n\nSuitable for presentation to clients, contractors, or property owners\n\nMandatory Notice\n\nBegin the analysis as soon as the photo(s) are provided.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "a8db3b1f-135d-4926-b861-03f99eddf6fb",
      "name": "Gmail: Send report",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2688,
        512
      ],
      "parameters": {
        "sendTo": "={{ $('Config').item.json.emailTo }}",
        "message": "={{ $json.imageAnalysis }}",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {
                "property": "binaryImage"
              }
            ]
          }
        },
        "subject": "={{ $('Config').item.json.emailSubjectPrefix }} - {{ $('Config').item.json.runTimestamp }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e7a1a9ba-c2e1-4222-8b88-f827fbbe25b8",
      "name": "Drive: Share image (anyone reader)",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2912,
        512
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Prepare: Image data').item.json.imageId }}"
        },
        "options": {},
        "operation": "share",
        "permissionsUi": {
          "permissionsValues": {
            "role": "reader",
            "type": "anyone"
          }
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "fb1f5029-a29d-4f2a-8698-d64856a38031",
      "name": "Sheets: Append log row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3136,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "Foto": "={{ $('Prepare: Image data').item.json.imageName }}",
            "Imagem": "==IMAGE(\"https://drive.google.com/uc?export=view&id={{ $('Prepare: Image data').item.json.imageId }}\")",
            "Relato": "={{ $('Prepare: Image data').item.json.imageAnalysis }}",
            "Data/hora": "={{ $('Config').item.json.runTimestamp }}"
          },
          "schema": [
            {
              "id": "Data/hora",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Data/hora",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Foto",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Foto",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Imagem",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Imagem",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Relato",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Relato",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Config').item.json.logSheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Config').item.json.logSpreadsheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "59c2e83b-6c62-4123-b5ba-a329b9f3163f",
      "name": "Drive: Move image (Processed folder)",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3360,
        512
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Prepare: Image data').item.json.imageId }}"
        },
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Config').item.json.processedFolderId }}"
        },
        "operation": "move"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "ad346610-58b2-4675-8f20-d07fbaf80f1c",
      "name": "End: No images found",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1888,
        704
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b6b5ea65-e954-4e58-a649-3ac349b1e493",
      "name": "Prepare: Image data",
      "type": "n8n-nodes-base.set",
      "position": [
        2464,
        512
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "600b2a91-a59e-4c71-93b6-9cddabd5ad05",
              "name": "imageId",
              "type": "string",
              "value": "={{ $('Drive: Download image').item.json.id }}"
            },
            {
              "id": "1a832bce-c9ba-43ca-ab36-89b633cc7eb9",
              "name": "imageName",
              "type": "string",
              "value": "={{ $('Drive: Download image').item.json.name }}"
            },
            {
              "id": "1e6dfe93-335f-4aa4-949f-bc822cc975aa",
              "name": "binaryImage",
              "type": "binary",
              "value": "={{ $('Drive: Download image').item.binary.data }}"
            },
            {
              "id": "366595ec-91e1-4a0d-9490-a139456fc12f",
              "name": "imageAnalysis",
              "type": "string",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "98140831-1217-419f-b9a0-68363fe1bea6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        352
      ],
      "parameters": {
        "width": 688,
        "height": 576,
        "content": "## AI-Driven construction execution monitoring\n\n### How it works\n\n1. A scheduled trigger checks the configured Google Drive input folder for new files.\n2. New files are filtered to keep images, downloaded, and sent to the AI model for a technical inspection (identify stage, execution quality, non-conformities, safety issues, and recommendations).\n3. The workflow builds a concise, structured report and emails it to the configured recipient with the photo attached.\n4. The image is shared via a public link, a log row with timestamp, analysis and image preview is appended to a Google Sheet, and the file is moved to the processed folder.\n\n---\n\n### Setup\n\n- [ ] Connect Google Drive account and set the input folder ID.\n- [ ] Connect Gmail account and authorize sending from the workflow.\n- [ ] Add OpenAI API key or connect the AI account used by the LangChain/OpenAI node.\n- [ ] Set the log spreadsheet ID and sheet name for append rows.\n- [ ] Set the processed folder ID where handled images will be moved.\n- [ ] Update recipient email and optional subject prefix in the Config node.\n- [ ] Configure the schedule interval to run as needed.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ddac7ad9-43e0-4625-881a-ea10d1a1be11",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 496,
        "content": "## 1. Retrieve and Filter Construction Images"
      },
      "typeVersion": 1
    },
    {
      "id": "12a94950-9738-4986-bb22-bcdfc3de7372",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2080,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 496,
        "content": "## 2. AI-Powered Construction Image Analysis"
      },
      "typeVersion": 1
    },
    {
      "id": "4999da26-f54b-4317-bbce-aa786cc5af40",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 1136,
        "height": 496,
        "content": "## 3. Distribute Report and Log Work Performance Data"
      },
      "typeVersion": 1
    },
    {
      "id": "b735654f-6734-480a-81b1-02a903bcf7df",
      "name": "Schedule Trigger (Configurable Interval)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        768,
        608
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "seconds"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.3
    },
    {
      "id": "84c21fc4-3702-4cf7-8f16-1d6a4ff99977",
      "name": "IF: Images Found?",
      "type": "n8n-nodes-base.if",
      "position": [
        1664,
        608
      ],
      "parameters": {
        "options": {
          "ignoreCase": true
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ed4c2210-e9ef-40ab-aa32-884fb9f750c6",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $items().some(item => Object.keys(item.json).length > 0) }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "07fd9d9b-d92c-401e-885c-a40bede5068c",
      "name": "End: Processing Complete",
      "type": "n8n-nodes-base.noOp",
      "position": [
        3568,
        512
      ],
      "parameters": {},
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "95e81fca-ef26-4706-9722-eb845aed3545",
  "connections": {
    "Config": {
      "main": [
        [
          {
            "node": "Drive: List files (Input folder)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI: Analyze image": {
      "main": [
        [
          {
            "node": "Prepare: Image data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Images Found?": {
      "main": [
        [
          {
            "node": "Drive: Download image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "End: No images found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI: Analyze image",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Gmail: Send report": {
      "main": [
        [
          {
            "node": "Drive: Share image (anyone reader)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare: Image data": {
      "main": [
        [
          {
            "node": "Gmail: Send report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Drive: Download image": {
      "main": [
        [
          {
            "node": "AI: Analyze image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets: Append log row": {
      "main": [
        [
          {
            "node": "Drive: Move image (Processed folder)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter: Keep images only": {
      "main": [
        [
          {
            "node": "IF: Images Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Drive: List files (Input folder)": {
      "main": [
        [
          {
            "node": "Filter: Keep images only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Drive: Share image (anyone reader)": {
      "main": [
        [
          {
            "node": "Sheets: Append log row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Drive: Move image (Processed folder)": {
      "main": [
        [
          {
            "node": "End: Processing Complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger (Configurable Interval)": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}