{
  "name": "CSV Data Cleaner with AI",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "csv-cleaner",
        "responseMode": "responseNode",
        "options": {
          "rawBody": true
        }
      },
      "id": "a1b2c3d4-1111-4000-8000-000000000001",
      "name": "Webhook - CSV Upload",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const csvText = $input.first().json.body;\nconst lines = csvText.split('\\n');\nconst headers = lines[0].split(',').map(h => h.trim());\nconst rows = [];\nfor (let i = 1; i < lines.length; i++) {\n  if (lines[i].trim() === '') continue;\n  const values = lines[i].split(',').map(v => v.trim());\n  const row = {};\n  headers.forEach((h, idx) => {\n    row[h] = values[idx] || '';\n  });\n  rows.push(row);\n}\nreturn [{ json: { headers, rows, rowCount: rows.length, rawCsv: csvText } }];"
      },
      "id": "a1b2c3d4-1111-4000-8000-000000000002",
      "name": "Code - Parse CSV",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        300
      ]
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4o",
        "messages": {
          "values": [
            {
              "content": "=You are a data cleaning specialist. Given the following CSV data, perform these operations:\n1. Standardize date formats to ISO 8601 (YYYY-MM-DD)\n2. Fix common typos and inconsistencies in text fields\n3. Normalize phone numbers to E.164 format\n4. Remove duplicate rows\n5. Fill obvious missing values where possible\n6. Standardize capitalization (Title Case for names, lowercase for emails)\n\nReturn ONLY the cleaned CSV data with headers, no explanations.\n\nHeaders: {{ $json.headers.join(', ') }}\n\nData ({{ $json.rowCount }} rows):\n{{ $json.rawCsv }}"
            }
          ]
        },
        "options": {
          "temperature": 0.1,
          "maxTokens": 4096
        }
      },
      "id": "a1b2c3d4-1111-4000-8000-000000000003",
      "name": "OpenAI - Clean & Standardize",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.4,
      "position": [
        720,
        300
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const cleanedCsv = $input.first().json.message.content;\nconst lines = cleanedCsv.split('\\n').filter(l => l.trim() !== '');\nconst headers = lines[0].split(',').map(h => h.trim());\nconst cleanedRows = [];\nfor (let i = 1; i < lines.length; i++) {\n  const values = lines[i].split(',').map(v => v.trim());\n  const row = {};\n  headers.forEach((h, idx) => {\n    row[h] = values[idx] || '';\n  });\n  cleanedRows.push(row);\n}\nreturn [{ json: { cleanedCsv, cleanedRows, rowCount: cleanedRows.length, headers } }];"
      },
      "id": "a1b2c3d4-1111-4000-8000-000000000004",
      "name": "Code - Format Output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: true, cleanedCsv: $json.cleanedCsv, rowCount: $json.rowCount, headers: $json.headers }) }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "id": "a1b2c3d4-1111-4000-8000-000000000005",
      "name": "Respond with Cleaned Data",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1200,
        300
      ]
    }
  ],
  "connections": {
    "Webhook - CSV Upload": {
      "main": [
        [
          {
            "node": "Code - Parse CSV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Parse CSV": {
      "main": [
        [
          {
            "node": "OpenAI - Clean & Standardize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Clean & Standardize": {
      "main": [
        [
          {
            "node": "Code - Format Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Format Output": {
      "main": [
        [
          {
            "node": "Respond with Cleaned Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    {
      "name": "ai-data"
    }
  ]
}