{
  "nodes": [
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "a4144d15-29fe-4870-ad02-9553ccd3f5ee",
              "leftValue": "={{ $json.query[\"hub.mode\"] }}",
              "rightValue": "subscribe",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            },
            {
              "id": "e5f35eb3-ab21-4fe2-9b51-aefed012fc98",
              "leftValue": "={{ $json.query[\"hub.verify_token\"] }}",
              "rightValue": "=123456",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        40,
        480
      ],
      "id": "7e4ce80d-6a57-4faf-a6a8-07a9af8e2ab4",
      "name": "If"
    },
    {
      "parameters": {
        "content": "## Xác thực facebook app webhook",
        "height": 380,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        320
      ],
      "typeVersion": 1,
      "id": "95a9a2a1-539a-489c-99e9-2527d18df22a",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('MergeMessage').first().json.text.join('\\n') }}",
        "options": {
          "systemMessage": "={{ $('PromptSheet').item.json.prompt }}"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        1020,
        2240
      ],
      "id": "cdeeb2ac-7d98-4fb2-b65f-fea292f3431c",
      "name": "AI Agent",
      "executeOnce": false,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        900,
        2460
      ],
      "id": "ed53af93-7968-4cd7-9fc7-ba64ac01078e",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "id": "npnMtU7kA3sNSLyr",
          "name": "OpenAi Chatbot"
        }
      }
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('MergeMessage').item.json.page_id }}_{{ $('MergeMessage').item.json.sender_id }}"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        1040,
        2460
      ],
      "id": "cd2c0be3-0c75-4a1d-a80b-869c7bcde32c",
      "name": "Postgres Chat Memory",
      "credentials": {
        "postgres": {
          "id": "GLfIWU3rbAidDMPe",
          "name": "Postgres account"
        }
      }
    },
    {
      "parameters": {
        "content": "## Map dữ liệu và Lấy page access token\n- Ta sẽ cấu trúc lại dữ liệu sau đó kiểm tra và lấy ra đúng token của page mà chúng ta đang thao tác (Mục đích là sẽ có nhiều page) ",
        "height": 340,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        1400
      ],
      "typeVersion": 1,
      "id": "fe8aaa54-a514-4c23-902b-86b1efca18aa",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Check trùng và lưu lại tin nhắn vào database\n- Facebook có cơ chế bắn lại tin nhắn nếu request bị false và đôi khi cũng bắn nhầm bắn thừa\n- Vậy nên ta phải check trùng để tránh bị nhận tin nhắn và trả lời 2 lần.\n- Nếu không có tin nhắn nào trùng - false -> ta sẽ ghi lại message và tiếp tục",
        "height": 340,
        "width": 700
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        1400
      ],
      "typeVersion": 1,
      "id": "08387036-6586-45c4-83ae-ec6f7ff6883e",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "## Response ngay sau khi nhận được dữ liệu\n- Tại sao phải res ngay sau khi nhận?\n- Facebook sẽ cho rằng false nếu sau 20s mà chưa trả về 200\n- Facebook sẽ bắn lại tin nhắn nếu bị coi là false",
        "height": 300,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        720
      ],
      "typeVersion": 1,
      "id": "e6a1c86a-5f30-4eee-85e2-50c86dd58370",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "multipleMethods": true,
        "path": "fbmessager",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -380,
        740
      ],
      "id": "9849c0c3-d762-4ec3-9c2c-9437c6d89028",
      "name": "Webhook",
      "webhookId": "84b7cec3-c047-4f9a-aff2-ca16706d2e66"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.query[\"hub.challenge\"] }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        480,
        400
      ],
      "id": "9c85963a-d63c-4f2a-b7b9-5ca1bd7fe608",
      "name": "Verify success"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"error\": true\n}",
        "options": {
          "responseCode": 403
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        480,
        560
      ],
      "id": "7ae42476-ddfd-423b-b3f2-84fca5ab9c6c",
      "name": "Verify fail"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "EVENT_RECEIVED",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        40,
        880
      ],
      "id": "c3c75217-9be4-4d2f-9cd8-f3fa23cc3b7c",
      "name": "RECEIVED",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "={{ $('PageAccessToken').first().json.data_sheet }}",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "data",
          "mode": "name"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.6,
      "position": [
        1160,
        2460
      ],
      "id": "ba597064-3d88-4e70-9f93-d9bfa000e39c",
      "name": "data",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "AxWVGvJ75f8LaApa",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "tableId": "fb_chats",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "page_id",
              "fieldValue": "={{ $('StructureData').item.json.page_id }}"
            },
            {
              "fieldId": "sender_id",
              "fieldValue": "={{ $('StructureData').item.json.sender_id }}"
            },
            {
              "fieldId": "recipient_id",
              "fieldValue": "={{ $('StructureData').item.json.recipient_id }}"
            },
            {
              "fieldId": "timestamp",
              "fieldValue": "={{ $('StructureData').item.json.timestamp }}"
            },
            {
              "fieldId": "message_id",
              "fieldValue": "={{ $('StructureData').item.json.message_id }}"
            },
            {
              "fieldId": "text",
              "fieldValue": "={{ $('StructureData').item.json.text }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1260,
        1580
      ],
      "id": "d609c65b-0466-4ea0-be3f-4af9f4555113",
      "name": "SaveToChats",
      "credentials": {
        "supabaseApi": {
          "id": "XnneQjbtAW4FyfV2",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "fb_chats",
        "filters": {
          "conditions": [
            {
              "keyName": "message_id",
              "keyValue": "={{ $('StructureData').first().json.message_id }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        780,
        1580
      ],
      "id": "fc683aca-755c-4cb3-85e5-7418d7bdd5b7",
      "name": "ExistsMessage",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "id": "XnneQjbtAW4FyfV2",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "content": "## Kiểm tra danh sách chát với người thật\n- Truy vấn xem có phải người dùng này có trong danh sách chát với người thật không",
        "height": 280,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        1760
      ],
      "typeVersion": 1,
      "id": "fba1e340-848b-4eab-8cb9-d07584b6d1a2",
      "name": "Sticky Note5"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        480,
        1860
      ],
      "id": "c25a25f4-3e5f-4fbe-bf8f-a7c2685b2ced",
      "name": "Chủ Page đâu, Ra đây trả lời nhanh lên"
    },
    {
      "parameters": {
        "operation": "upsert",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "fb_included_users",
          "mode": "list",
          "cachedResultName": "fb_included_users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "page_id": "={{ $('MergeMessage').item.json.page_id }}",
            "sender_id": "={{ $('MergeMessage').item.json.sender_id }}",
            "key": "={{ $('MergeMessage').item.json.page_id }}_{{ $('MergeMessage').item.json.sender_id }}"
          },
          "matchingColumns": [
            "key"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "page_id",
              "displayName": "page_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "sender_id",
              "displayName": "sender_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": false,
              "removed": true
            },
            {
              "id": "key",
              "displayName": "key",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgresTool",
      "typeVersion": 2.6,
      "position": [
        1300,
        2460
      ],
      "id": "2a774f2f-d6b2-4dc5-aef8-5e368dfffafe",
      "name": "toolAddToExcludeList",
      "credentials": {
        "postgres": {
          "id": "GLfIWU3rbAidDMPe",
          "name": "Postgres account"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "fb_included_users",
        "filters": {
          "conditions": [
            {
              "keyName": "key",
              "keyValue": "={{ $json.page_id }}_{{ $json.sender_id }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        40,
        1860
      ],
      "id": "fa39eec6-0acb-4254-a9bf-d6d9e3999058",
      "name": "GetUserIncluded",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "id": "XnneQjbtAW4FyfV2",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "return [\n  {\n    page_id: 'id của page fb',\n    data_sheet: 'https://docs.google.com/spreadsheets/d/1vtHZyKchfc3GWoB9lHf2xVCDi2vNZu5UpcdvMVf1i_M/edit?gid=0#gid=0',\n    page_access_token: 'paste_access_token của facebook vào đây'\n  },\n  {\n    page_id: 'id của page fb',\n    data_sheet: 'https://docs.google.com/spreadsheets/d/1jQa7BSD2oAisG7okVJkvxPyAnZ5SWHZomav5h4gD5aw/edit?gid=0#gid=0',\n    page_access_token: 'paste_access_token của facebook vào đây'\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        1580
      ],
      "id": "96332248-cfac-4c63-af2b-3566713a71f6",
      "name": "ListPageAccessToken"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "650b7794-71e3-46a7-9b1e-da5311b41a60",
              "leftValue": "={{ $json.page_id }}",
              "rightValue": "={{ $('StructureData').last().json.page_id }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        480,
        1580
      ],
      "id": "5b457a58-f1b6-4938-ba76-a2b861035591",
      "name": "PageAccessToken"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v22.0/{{ $('StructureTextOutput').item.json.page_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('PageAccessToken').last().json.page_access_token }}"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"recipient\": {\n    \"id\": \"{{ $('StructureTextOutput').item.json.sender_id }}\"\n  },\n  \"message\": {\n    \"text\": {{ $('StructureTextOutput').item.json.output }}\n  }\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1260,
        2780
      ],
      "id": "164d1f6a-6557-4388-902e-bb15e67150bf",
      "name": "SendMessage"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v22.0/{{ $json.page_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('PageAccessToken').last().json.page_access_token }}"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"recipient\": {\n    \"id\": {{ $json.sender_id }}\n  },\n  \"sender_action\":\"typing_on\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        780,
        2780
      ],
      "id": "e96794f4-15ba-4c94-bfb6-3176ff871772",
      "name": "SendTypingOn",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "02d72cf3-bcee-4e2a-866d-91a3ff41edaa",
              "leftValue": "={{ $json.id }}",
              "rightValue": "",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1020,
        1580
      ],
      "id": "8333efa6-cc0f-456c-871f-d2acda4598d9",
      "name": "NotFoundMessage",
      "alwaysOutputData": false
    },
    {
      "parameters": {
        "fieldToSplitOut": "body.entry",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        760,
        880
      ],
      "id": "f2000c6e-af4c-437d-91da-69c1b1834ad7",
      "name": "Split Out"
    },
    {
      "parameters": {
        "content": "## Tiến hành phân tách dữ liệu từ entry và gửi\n- Tại sao phải phân tách? Hãy xem dữ liệu mà fb trả về ta có gì? Ta thấy rằng có 1 entry với kiểu dữ liệu là 1 mảng, mảng này có id page và 1 mảng messaging.\n- Điều này nghĩa là gì? Nghĩa là fb có thế bắn 1 hook có nhiều entry cho chúng ta. mà 1 entry có thể là 1 page khác nhau.\n- Nên ta phải tách nó ra để không bị nhầm page hoặc bị bỏ sót tin nhắn",
        "height": 300,
        "width": 700
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        720
      ],
      "typeVersion": 1,
      "id": "0c585d22-bfcd-4158-a7ea-a24599bb723a",
      "name": "Sticky Note8"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "8c5196db-15df-470a-8fab-ac384b45b480",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -380,
        1580
      ],
      "id": "601bb937-cb43-4221-b07b-5241ebdb6acb",
      "name": "OnMessage",
      "webhookId": "8c5196db-15df-470a-8fab-ac384b45b480"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "2cedc0a7-8b32-4b46-ab19-6c157e21268b",
              "name": "page_id",
              "value": "={{ $json.body.page_id }}",
              "type": "string"
            },
            {
              "id": "c9b6c3ed-40d0-4c27-b3f4-84661a6c8cee",
              "name": "sender_id",
              "value": "={{ $json.body.sender_id }}",
              "type": "string"
            },
            {
              "id": "d985d779-d0b0-4a56-bdef-15019e8d68ef",
              "name": "recipient_id",
              "value": "={{ $json.body.recipient_id }}",
              "type": "string"
            },
            {
              "id": "29d991a0-5395-4d62-aff3-e5739b0ddf83",
              "name": "timestamp",
              "value": "={{ $json.body.timestamp }}",
              "type": "string"
            },
            {
              "id": "4b38a917-b656-4e5a-be18-a2077557f2cf",
              "name": "message_id",
              "value": "={{ $json.body.message_id }}",
              "type": "string"
            },
            {
              "id": "6c438dce-30b3-479e-a56a-1048c0ec39c9",
              "name": "text",
              "value": "={{ $json.body.text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        40,
        1580
      ],
      "id": "8ec55873-5590-4425-a228-6e79af403ad2",
      "name": "StructureData"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        -160,
        1580
      ],
      "id": "896e9602-64c8-471d-886a-d0fbce0fb432",
      "name": "RespondOnMessage"
    },
    {
      "parameters": {
        "content": "## AI Agent\n- Lấy nội dung trả lời cho người dùng.\n- Nếu không thấy nội dung thì hỏi xem có muốn nhắn với chủ page không",
        "height": 500,
        "width": 700
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        2100
      ],
      "typeVersion": 1,
      "id": "ef2bdbfb-cc36-4215-b00f-f98707c6a5d2",
      "name": "Sticky Note10"
    },
    {
      "parameters": {
        "content": "## Structure Lại dữ liệu trước khi gửi trả lời người dùng\n- Node này cấu trúc lại dữ liệu và fix lỗi khi khi gửi bị lỗi JSON error",
        "height": 300,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        2660
      ],
      "typeVersion": 1,
      "id": "001f717d-2cd7-4b71-a642-2820a63973a4",
      "name": "Sticky Note11"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "d65dbf39-714b-450d-8a30-384483b5e8aa",
              "name": "output",
              "value": "={{ JSON.stringify($json.output) }}",
              "type": "string"
            },
            {
              "id": "aea834b4-09af-4312-b8a3-7ae64c38e5e7",
              "name": "page_id",
              "value": "={{ $('MergeMessage').first().json.page_id }}",
              "type": "string"
            },
            {
              "id": "df7d9604-23bb-43d6-930f-b562622401e9",
              "name": "sender_id",
              "value": "={{ $('MergeMessage').first().json.sender_id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        40,
        2780
      ],
      "id": "00777dee-cff8-4c94-9709-3b1a576034bc",
      "name": "StructureTextOutput"
    },
    {
      "parameters": {
        "content": "## Typing And Send Message\n- Typing là gì? Chính là tạo dấu ... tạo cảm giác đang trả lời trên fb\n- Để wait 1 giây (Cái này tùy chỉnh) sau đó sẽ trả lời",
        "height": 300,
        "width": 700
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        2660
      ],
      "typeVersion": 1,
      "id": "d973e3a6-381b-4282-bccd-721ebc6d22a2",
      "name": "Sticky Note12"
    },
    {
      "parameters": {
        "amount": 1
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1020,
        2780
      ],
      "id": "9144cca3-2487-4477-ad76-2412b158bf5f",
      "name": "Wait",
      "webhookId": "378864f4-a530-4017-8285-683a16451d7b"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "={{ $('PageAccessToken').first().json.data_sheet }}",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "prompt",
          "mode": "name"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.6,
      "position": [
        780,
        2240
      ],
      "id": "0d31d0ce-58e2-4422-bccf-8bee0dd26014",
      "name": "PromptSheet",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "AxWVGvJ75f8LaApa",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "6c20825f-4cae-4d4b-9558-4c4a10045d99",
              "leftValue": "={{ $('GetAllMessage').first().json.id }}",
              "rightValue": "",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        160,
        2440
      ],
      "id": "3b37b314-3006-4230-a7ed-d127714d833a",
      "name": "IFExistsMessage"
    },
    {
      "parameters": {
        "jsCode": "return [\n  {\n    ... $('GetAllMessage').last().json,\n    text: $('GetAllMessage').all().map(m => m.json.text)\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        2240
      ],
      "id": "70a8cb2a-56c6-4aaa-8ba2-121b855241da",
      "name": "MergeMessage"
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "fb_chats",
        "filterType": "string",
        "filterString": "=id=in.({{ $('GetAllMessage').all().map(item => item.json.id) }})",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "status",
              "fieldValue": "done"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        280,
        2240
      ],
      "id": "23e4e096-6dd7-424d-9bc2-b1534e3e536e",
      "name": "UpdateDoneMessage",
      "executeOnce": true,
      "credentials": {
        "supabaseApi": {
          "id": "XnneQjbtAW4FyfV2",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "fb_chats",
        "filters": {
          "conditions": [
            {
              "keyName": "page_id",
              "keyValue": "={{ $('SaveToChats').item.json.page_id }}"
            },
            {
              "keyName": "sender_id",
              "keyValue": "={{ $('SaveToChats').item.json.sender_id }}"
            },
            {
              "keyName": "status",
              "keyValue": "pending"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        40,
        2240
      ],
      "id": "f7e95935-a8ef-4c72-bbe4-abb71fed6f12",
      "name": "GetAllMessage",
      "credentials": {
        "supabaseApi": {
          "id": "XnneQjbtAW4FyfV2",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "content": "## Gộp tin và chuẩn hóa đầu vào\n- Ta sẽ dùng cơ chế debounce chờ thời gian x giây để gộp tin nhắn ngắt quãng sau đó chuẩn hóa đầu vào và gộp các tin nhắn lại thành 1 tin để gửi cho AI",
        "height": 500,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        2100
      ],
      "typeVersion": 1,
      "id": "e5517779-4ddd-48d8-8612-2a5914171a65",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "table": "fb_n8n_debounce",
        "key": "={{ $('StructureData').first().json.page_id }}_{{ $('StructureData').first().json.sender_id }}",
        "waitTime": 10
      },
      "type": "n8n-nodes-debounce.debouncePostgres",
      "typeVersion": 1,
      "position": [
        -200,
        2240
      ],
      "id": "401824c8-7582-42dc-801e-33221f3f2fe6",
      "name": "Debounce Postgres",
      "credentials": {
        "postgres": {
          "id": "GLfIWU3rbAidDMPe",
          "name": "Postgres account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "f279a143-a74d-4cbb-b815-c8443c8626ef",
              "leftValue": "={{ $json.id }}",
              "rightValue": "",
              "operator": {
                "type": "number",
                "operation": "notExists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        280,
        1860
      ],
      "id": "e3e4fa6c-4234-4e37-a4d4-ea379da615ac",
      "name": "IfDoesNotExist",
      "alwaysOutputData": false
    },
    {
      "parameters": {
        "fieldToSplitOut": "messaging",
        "include": "allOtherFields",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        40,
        1180
      ],
      "id": "1f006f55-d4d3-4ad0-99f5-7ee82a5776a7",
      "name": "Split Message"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "2cedc0a7-8b32-4b46-ab19-6c157e21268b",
              "name": "page_id",
              "value": "={{ $json.id }}",
              "type": "string"
            },
            {
              "id": "c9b6c3ed-40d0-4c27-b3f4-84661a6c8cee",
              "name": "sender_id",
              "value": "={{ $json.messaging.sender.id }}",
              "type": "string"
            },
            {
              "id": "d985d779-d0b0-4a56-bdef-15019e8d68ef",
              "name": "recipient_id",
              "value": "={{ $json.messaging.recipient.id }}",
              "type": "string"
            },
            {
              "id": "29d991a0-5395-4d62-aff3-e5739b0ddf83",
              "name": "timestamp",
              "value": "={{ $json.messaging.timestamp }}",
              "type": "string"
            },
            {
              "id": "4b38a917-b656-4e5a-be18-a2077557f2cf",
              "name": "message_id",
              "value": "={{ $json.messaging.message.mid }}",
              "type": "string"
            },
            {
              "id": "6c438dce-30b3-479e-a56a-1048c0ec39c9",
              "name": "text",
              "value": "={{ $json.messaging.message.text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        280,
        1180
      ],
      "id": "6db707ce-07bc-42c3-9df3-e49ea5196d5f",
      "name": "Map data"
    },
    {
      "parameters": {
        "content": "## Tiến hành phân tách dữ liệu từ messaging và gửi\n- Tại sao phải phân tách? Dữ liệu mà chúng ta nhận được lại cũng là 1 mảng messaging\n- Vậy nên có thể fb sẽ gửi tới nhiều message 1 lúc với 2 hoặc nhiều người dùng khác nhau\n- Cho nên ta phải tách nó ra để không gửi trả lời nhầm khách và không bị bỏ sót tin nhắn.",
        "height": 320,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        1060
      ],
      "typeVersion": 1,
      "id": "01d46120-3d65-471b-a7e7-b1fb3f8ca43e",
      "name": "Sticky Note13"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://dxunek.datadex.vn/webhook/8c5196db-15df-470a-8fab-ac384b45b480",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.toJsonString() }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        480,
        1180
      ],
      "id": "a0ee7338-28f7-4908-b730-e93e379c9a56",
      "name": "SendOnMessage1"
    },
    {
      "parameters": {
        "content": "## Tạo chatbot facebook\nTừng bước cấu hình trong các node, lưu ý bỏ ghim ở node google sheet khi chạy\n![Guide](https://datadex.vn/s/2025/05/3f0cc1a3-add6-4efb-910d-1bc267635cb0Cover.jpg)\n[🎥 Hướng dẫn tại đây](https://www.youtube.com/watch?v=w2zb47GC9-I)",
        "height": 700,
        "width": 700
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        0
      ],
      "typeVersion": 1,
      "id": "7537ba7d-0940-4963-93b9-712e1457e641",
      "name": "Sticky Note6"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        120,
        140
      ],
      "id": "56da5822-2dc1-4fff-b077-69f682e748b9",
      "name": "When clicking ‘Test workflow’"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "create table public.fb_chats (\n  id bigint generated by default as identity not null,\n  page_id text null,\n  sender_id text null,\n  recipient_id text null,\n  message_id text null,\n  text text null,\n  timestamp bigint null,\n  status character varying null default 'pending'::character varying,\n  created_at timestamp with time zone null default now(),\n  constraint fb_chats_pkey primary key (id),\n  constraint fb_chats_message_id_key unique (message_id)\n) TABLESPACE pg_default;\ncreate table public.fb_included_users (\n  id bigint generated by default as identity not null,\n  page_id text not null,\n  sender_id text null,\n  created_at timestamp with time zone not null default now(),\n  key text not null,\n  constraint fb_included_users_pkey primary key (id),\n  constraint fb_included_users_key_key unique (key),\n  constraint fb_included_users_key_key1 unique (key)\n) TABLESPACE pg_default;\ncreate table public.fb_n8n_debounce (\n  id bigint generated by default as identity not null,\n  key text not null,\n  incr bigint null default '0'::bigint,\n  constraint n8n_debounce_pkey primary key (id),\n  constraint n8n_debounce_key_key unique (key)\n) TABLESPACE pg_default;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        340,
        140
      ],
      "id": "528b4171-7772-40c9-bbd3-d56d4e7d609a",
      "name": "Postgres",
      "credentials": {
        "postgres": {
          "id": "GLfIWU3rbAidDMPe",
          "name": "Postgres account"
        }
      }
    },
    {
      "parameters": {
        "content": "## Chạy lệnh tạo cơ sở dữ liệu\nXác thực với Postgress ở trên supabase rồi chạy lệnh này để auto tạo sẵn các bảng",
        "height": 300,
        "width": 680
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "typeVersion": 1,
      "id": "2251aeef-7b35-4908-86ac-3ebd2e38ab0f",
      "name": "Sticky Note7"
    }
  ],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Verify success",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Verify fail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "StructureTextOutput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "RECEIVED",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RECEIVED": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "data": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "SaveToChats": {
      "main": [
        [
          {
            "node": "GetUserIncluded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ExistsMessage": {
      "main": [
        [
          {
            "node": "NotFoundMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "toolAddToExcludeList": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "GetUserIncluded": {
      "main": [
        [
          {
            "node": "IfDoesNotExist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ListPageAccessToken": {
      "main": [
        [
          {
            "node": "PageAccessToken",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PageAccessToken": {
      "main": [
        [
          {
            "node": "ExistsMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SendTypingOn": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "NotFoundMessage": {
      "main": [
        [],
        [
          {
            "node": "SaveToChats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Split Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OnMessage": {
      "main": [
        [
          {
            "node": "RespondOnMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StructureData": {
      "main": [
        [
          {
            "node": "ListPageAccessToken",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RespondOnMessage": {
      "main": [
        [
          {
            "node": "StructureData",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StructureTextOutput": {
      "main": [
        [
          {
            "node": "SendTypingOn",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "SendMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PromptSheet": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IFExistsMessage": {
      "main": [
        [
          {
            "node": "UpdateDoneMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MergeMessage": {
      "main": [
        [
          {
            "node": "PromptSheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "UpdateDoneMessage": {
      "main": [
        [
          {
            "node": "MergeMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetAllMessage": {
      "main": [
        [
          {
            "node": "IFExistsMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Debounce Postgres": {
      "main": [
        [
          {
            "node": "GetAllMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IfDoesNotExist": {
      "main": [
        [
          {
            "node": "Debounce Postgres",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Chủ Page đâu, Ra đây trả lời nhanh lên",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Message": {
      "main": [
        [
          {
            "node": "Map data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map data": {
      "main": [
        [
          {
            "node": "SendOnMessage1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "Postgres",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {
    "Webhook": []
  },
  "meta": {
    "instanceId": "588a021bb54b760204dc9fed657516230744845e005fe72c0f4b0664fd815974"
  }
}