{
  "name": "Auto expense tracker from LINE messages with GPT-4 and Google Sheets",
  "nodes": [
    {
      "id": "a9abe724-ec70-4aa9-9579-39968d9f624c",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -3000,
        40
      ]
    },
    {
      "id": "559432eb-1739-49e7-9fae-9337ef843239",
      "name": "message",
      "type": "n8n-nodes-base.set",
      "position": [
        -2540,
        20
      ]
    },
    {
      "id": "1161ff82-4ceb-435a-a4ed-c2ca4f618627",
      "name": "image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2540,
        200
      ]
    },
    {
      "id": "afb32020-22d2-420c-9567-b3b81fda1075",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -2200,
        20
      ]
    },
    {
      "id": "a4fe0a3b-40e0-4cf0-9d44-86abadca9fe4",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -2200,
        340
      ]
    },
    {
      "id": "516361f7-21a9-4d9a-9f44-2bab05b9bfcb",
      "name": "reply_to_line",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        0,
        60
      ]
    },
    {
      "id": "ab9fbffc-cd1e-4a2c-8f5e-23ee0f844c77",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1540,
        260
      ]
    },
    {
      "id": "88bd5d9f-bcaa-4191-bcb6-1e3a0b138879",
      "name": "Merge_all",
      "type": "n8n-nodes-base.merge",
      "position": [
        -700,
        40
      ]
    },
    {
      "id": "5d153710-d3a2-42dc-a090-c4faa3390210",
      "name": "reply_to_line_duplicated",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -200,
        280
      ]
    },
    {
      "id": "570de74c-b410-40ff-b7ac-781625c912a7",
      "name": "reply_to_line_no_spending",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -200,
        -120
      ]
    },
    {
      "id": "05789d97-3ebb-4e9f-951d-ecd54c4da404",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -2000,
        180
      ]
    },
    {
      "id": "cbadff1d-15f5-4282-a62f-b42c25b41661",
      "name": "append_to_sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -200,
        60
      ]
    },
    {
      "id": "aee3b5eb-ff29-4847-ab57-8cbb0cdba7a6",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        -940,
        260
      ]
    },
    {
      "id": "8da264bd-5b13-4912-ae8e-7ded8fc6af17",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2540,
        -640
      ],
      "parameters": {
        "width": 720,
        "height": 540,
        "content": "## Prompt en\nCheck relevance: If the text is not an expense record or invoice, immediately stop all processing. If it is bookkeeping-related, extract the six data fields below.\nExtract these six piece"
      }
    },
    {
      "id": "4f8f3594-5aa1-4279-b25e-502658e8bedc",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2100,
        440
      ],
      "parameters": {
        "width": 280,
        "height": 440,
        "content": "## Structured Output en\n{\n  \"Date\": \"...\",\n  \"Channel\": \"...\",\n  \"Channel Type\": \"...\",\n  \"Expense Description\": \"...\",\n  \"Amount\": \"...\",\n  \"Category\": \"...\"\n}\n\n## Structured Output zh\n{\n  \"日期\": \"..."
      }
    },
    {
      "id": "efb13bc2-bc7a-4f6a-8ec1-d783ac9c1d41",
      "name": "deduplication",
      "type": "n8n-nodes-base.set",
      "position": [
        -1700,
        20
      ]
    },
    {
      "id": "f6f35e3c-0424-4e7c-be0f-33e191dca2b4",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1700,
        -420
      ],
      "parameters": {
        "width": 320,
        "height": 300,
        "content": "## deduplication en\nfor_duplication = {{ $json.output.Date }}-{{ $json.output['Channel Type'] }}-{{ $json.output.Amount }}-{{ $json.output.Category }}\n\n## deduplication zh\n去重使用 = {{ $json.output['日期']"
      }
    },
    {
      "id": "296b9ff9-4819-49a8-b813-37dc507db57d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        440
      ],
      "parameters": {
        "width": 320,
        "height": 480,
        "content": "## Google Sheet Fields en\nSet up in advance\n1. Date\n2. Channel\n3. Channel Type\n4. Expense Description\n5. Amount\n6. Category\n7. for_duplication\n\n## Google Sheet Fields zh\n預先設置好\n1. 日期\n2. 通路\n3. 通路類型\n4. 花"
      }
    },
    {
      "id": "8ff07d6b-6aa1-4a43-ab5a-231a4f668ca3",
      "name": "for_deduplications",
      "type": "n8n-nodes-base.set",
      "position": [
        -1240,
        260
      ]
    },
    {
      "id": "e1af076e-37f4-4cdf-8a9c-ca5f3cd2e743",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1380,
        440
      ],
      "parameters": {
        "width": 320,
        "height": 240,
        "content": "## for_deduplications en\nManual Mapping\nfor_deduplication = {{ $json['for_duplication'] }}\n\n## for_deduplications zh\nManual Mapping\n去重使用 = {{ $json['去重使用'] }}"
      }
    },
    {
      "id": "f62cb77b-74e1-4b90-9937-95af55e76497",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -940,
        440
      ],
      "parameters": {
        "width": 220,
        "height": 260,
        "content": "## Aggregrate en\nindividual field\ninput for_deduplication\noutput dedupeList\n\n## Aggregrate zh\nindividual field\ninput 去重使用\noutput dedupeList"
      }
    },
    {
      "id": "e2f1f377-4d78-4853-8d4e-037c4db5a483",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        -640
      ],
      "parameters": {
        "width": 540,
        "height": 540,
        "content": "## Switch en\n### empty\n{{ $('Merge_all').item.json['for_duplication'] }} = DN-DN-DN-DN\n{{ $('Merge_all').item.json['for_duplication'] }} matches regrx ^.*-DN-DN-DN$\n{{ $('Merge_all').item.json['for_du"
      }
    },
    {
      "id": "c9ea87a2-0f69-47a7-b409-1ea4ada2a666",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3240,
        -400
      ],
      "parameters": {
        "width": 400,
        "height": 300,
        "content": "## Requirements en\n1. Set up GCP OAuth and enable the Google Sheets API\n2. Pre-configure the Google Sheet field names\n3. Obtain the LINE Developer Webhook URL\n4. OpenAI API Key\n\n## 需求 zh\n1. 設置 GCP OAu"
      }
    },
    {
      "id": "6a01a146-0b13-4ac5-8429-bf8452157587",
      "name": "Switch based on Expense Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        -2780,
        40
      ]
    },
    {
      "id": "12f21b25-8a50-4224-8f3d-cfcba20510b6",
      "name": "Response Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        -460,
        0
      ]
    }
  ],
  "connections": {
    "image": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Switch based on Expense Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "message": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "deduplication",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "Merge_all",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge_all": {
      "main": [
        [
          {
            "node": "Response Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "deduplication": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge_all",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Response Switch": {
      "main": [
        [
          {
            "node": "reply_to_line_no_spending",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "reply_to_line_no_spending",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "reply_to_line_no_spending",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "append_to_sheet1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "reply_to_line_duplicated",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "append_to_sheet1": {
      "main": [
        [
          {
            "node": "reply_to_line",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Structured Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "for_deduplications": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "for_deduplications",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Switch based on Expense Type": {
      "main": [
        [
          {
            "node": "message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}