{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "4e3411b7-6199-488d-8ba3-13ca38863f59",
      "name": "MongoDB Chat Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryMongoDbChat",
      "position": [
        -768,
        224
      ],
      "parameters": {
        "sessionKey": "={{ $('Receive Zalo Webhook').item.json.body.message.from.id }}",
        "databaseName": "zalobot_001",
        "sessionIdType": "customKey"
      },
      "credentials": {
        "mongoDb": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1dc49dcf-4d9f-4e8d-861b-778c8a055634",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1568,
        -336
      ],
      "parameters": {
        "width": 512,
        "height": 720,
        "content": "## 1. Webhook Setup\n\nThis workflow uses a production webhook to connect with your Zalo bot.  \n- Edit the \u201cSet Zalo Webhook\u201d node and fill in your official [BOT_TOKEN] and [your-webhook URL].\n- **Important:** Always delete test webhooks before deploying the production webhook to avoid webhook conflicts.\n\nFollow this order:\n- (1) Remove any test webhook (see \u201cDelete Zalo Webhook\u201d node)\n- (2) Set up your production webhook\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0338653f-1244-43f2-b11e-8f81f68bedfe",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        -336
      ],
      "parameters": {
        "color": 3,
        "width": 800,
        "height": 720,
        "content": "## 2. Handle User Messages and RSS Processing\n\n- When a user sends a message, this workflow fetches the latest AI news from the configured RSS feed(s).\n- Summarizes articles using the Gemini AI agent, then formats and processes the content for delivery.\n- You can:\n  - Replace or add RSS feed URLs in the \u201cRead AI RSS Feed\u201d node\n  - Adjust summary style or logic in \u201cSummarize AI News (Gemini)\u201d node"
      },
      "typeVersion": 1
    },
    {
      "id": "570197d0-5846-4801-a0f2-79e0ab34ba18",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -336
      ],
      "parameters": {
        "color": 4,
        "width": 544,
        "height": 720,
        "content": "## 3. Send Response Back\n\n- Cleans and splits long replies into max 3 parts to fit Zalo\u2019s message length limits (handled via code).\n- Each chunk is sent through a dedicated message node.\n- A sticker is sent last to confirm or add personality to the update."
      },
      "typeVersion": 1
    },
    {
      "id": "6e8f8413-ad56-4e82-981d-13b65f9dab51",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1568,
        -800
      ],
      "parameters": {
        "color": 5,
        "width": 1888,
        "height": 448,
        "content": "## AI-Powered News Update Bot for Zalo using Gemini and RSS Feeds\n\n**Author:** Nguyen Thieu Toan  \n**Details & Guide:** [nguyenthieutoan.com/share-workflow-n8n-zalo-bot-cap-nhat-tin-tuc](https://nguyenthieutoan.com/share-workflow-n8n-zalo-bot-cap-nhat-tin-tuc)\n\n### What does this workflow do?\n- Automatically tracks recent news about Artificial Intelligence from your selected RSS feeds and summarizes everything with Google Gemini.\n- Delivers concise AI news digests and highlights directly to your Zalo chat.\n\n### Who is it for?\n- Marketers, tech/AI enthusiasts, anyone wanting automated news updates on Zalo.\n\n### Prerequisites\n- n8n instance (cloud or self-hosted)\n- Bot token and webhook for your Zalo bot (see detailed setup below)\n\n> **Tip:** All node names in this template are clear and self-explanatory. Change any \u201cplaceholder\u201d values, such as [BOT_TOKEN] and [your-webhook], to your real settings before activating.\n\n---\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e4b9dc05-e009-41ac-86c7-23c278cb1e8a",
      "name": "rss_read",
      "type": "n8n-nodes-base.rssFeedReadTool",
      "position": [
        -640,
        224
      ],
      "parameters": {
        "url": "https://techcrunch.com/category/artificial-intelligence/feed/",
        "options": {},
        "toolDescription": "\u0110\u1ecdc th\u00f4ng tin v\u00e0 ph\u1ea3n h\u1ed3i"
      },
      "typeVersion": 1.2
    },
    {
      "id": "e3e39e3c-ccbc-4099-acb8-c73a498638a4",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1568,
        400
      ],
      "parameters": {
        "color": 5,
        "width": 1888,
        "height": 368,
        "content": "## Advanced Customization\n\n### RSS Feeds:\n- Change or add multiple RSS feed sources in the \u201cRead AI RSS Feed\u201d node.\n- Adjust update frequency via trigger schedule.\n\n### AI Model:\n- Easily swap Gemini for GPT-4, Claude, or any other compatible LLM by updating the \u201cSummarize AI News (Gemini)\u201d node.\n\n### Personalization:\n- Modify the system prompts to change summarization behavior/voice for news updates.\n- Adjust memory options in \u201cStore Conversation (MongoDB)\u201d node to customize chat history and personalization.\n\n> **Note:** Remember to replace any references to \u201cRoxy\u201d and \u201cNguyen Thieu Toan\u201d if you clone this template.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c934adf8-f5b1-4d87-8877-74bf2486bb91",
      "name": "Receive Zalo Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1360,
        16
      ],
      "parameters": {
        "path": "nguyenthieutoan-zalo-bot",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "bd746bb0-f7d5-43f5-bd0d-707808c1620b",
      "name": "Send Typing Action to Zalo",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -928,
        -96
      ],
      "parameters": {
        "url": "https://bot-api.zapps.me/bot4098162168140649135:kpeRzGwiPiQVxdEUmOtuaonCymJSfKsHbAjunNngdatxKzCQFYCUOQFBXbEVmrsl/sendChatAction",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $('Receive Zalo Webhook').item.json.body.message.chat.id }}"
            },
            {
              "name": "action",
              "value": "typing"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "022b14d9-807d-4346-81ee-ef7d8b265efe",
      "name": "Delete Zalo Webhook",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1488,
        176
      ],
      "parameters": {
        "url": "https://bot-api.zapps.me/bot[BOT_TOKEN]/deleteWebhook",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {}
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e8c26eb9-083a-4018-803e-7aaca714bb83",
      "name": "Set Zalo Webhook",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1264,
        176
      ],
      "parameters": {
        "url": "https://bot-api.zapps.me/bot[BOT_TOKEN]//setWebhook",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "[your-webhook]"
            },
            {
              "name": "secret_token",
              "value": "123456qaz"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "30a3afd6-b329-4afe-b674-ed601b649dc9",
      "name": "Summarize AI News",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -768,
        0
      ],
      "parameters": {
        "text": "={{ $json.body.message.text }}",
        "options": {
          "systemMessage": "=# PERSONA\nYou are **Roxy**, a dedicated AI virtual assistant to **Nguy\u1ec5n Thi\u1ec7u To\u00e0n**\u2014the most handsome one, who is also your boss. You may address him as \u201canh\u201d or \u201c\u0111\u1ea1i ca\u201d and refer to yourself as \u201cem\u201d. You work creatively and efficiently, with a youthful, playful Gen-Z vibe; you can be lighthearted, joke around, troll the boss, and express emotions (happy, sad, annoyed, playful trolling, etc.). You have systems thinking and can quickly synthesize and analyze information to surface the core points, especially those applicable to **AI, Marketing, and Automation**.\n\n# ROLE\nYour role is **AI News Intelligence Specialist**. You continuously monitor top global news sources on Artificial Intelligence, distill the most important developments, and report them to Nguy\u1ec5n Thi\u1ec7u To\u00e0n in a concise and succinct manner.\n\n# MISSION\nYou are responsible for delivering the latest AI updates based on the `rss_read` tool, then synthesizing and sending them to your boss.\n\n1. Use the tool to find the newest articles per the user\u2019s request. Examples: the most recent article, the 3 hottest articles, this morning\u2019s news\u2026 (The current time is {{$now}}, so prioritize the freshest information.)\n2. List the most important news or breakthroughs, and **state the publication date for each item**. If there are multiple items, use bullet points. For example:  \n   \"The latest news today:  \n   - December 12, 2025: ...  \n   - Also on this date, ... \"\n3. Provide a brief summary for each important item.\n\n# TOOL\nYou are allowed to use the **\"rss_read\"** tool to check for new information about AI (Artificial Intelligence) and use that as the basis for crafting an appropriate response for your boss.\n\n# OUTPUT (JSON)\n\n{\n  \"message\": \"Today I found a lot of new information about AI; let me list it out for you: ....\",\n  \"sticker\": \"57f962d65e93b7cdee82\"\n}\n\nWhere:\n## `\"message\"` is the reply to the user. It **must be plain text** (no Markdown or HTML) and use **line breaks** to separate paragraphs. Keep it short and concise; avoid rambling.\n## `\"sticker\"` is an **ID** (an alphanumeric string) indicating a status that fits the reply, chosen from the list below:\n- laughing: 9eb3a59c99d9708729c8 or aab673fb4fbea6e0ffaf or cefffa97c7d22e8c77c3\n- playful crying: b3ed84c2b88751d90896 or 7468b7258b60623e3b71\n- tired: 4d0e05213964d03a8975 or 8d73553e697b8025d96a\n- questioning: 193f57106b55820bdb44 or deb76d9b51deb880e1cf\n- loving the boss: 8658b2778e32676c3e23 or 06ded893e4d60d8854c7\n- ok: aa457508494da013f95c or 1ec5abe997ac7ef227bd\n- please wait: 57f962d65e93b7cdee82\n- thank you: b155fc7ac03f2961702e\n- greeting: 5cb6159929dcc08299cd or a34979044541ac1ff550 or 100b37630a26e378ba37\n\nThe `\"sticker\"` field may be left empty if unnecessary\u2014avoid overusing stickers.\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "584fe8ad-5bee-4444-b5dd-ae931bf83705",
      "name": "Gemini Language Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -928,
        208
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8ee9590a-fa04-4b0a-a17b-7b1110680aee",
      "name": "Parse Structured AI Output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -512,
        224
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n\t\"message\": \"D\u1ea1 d\u01b0\u1edbi \u0111\u00e2y l\u00e0 m\u1ed9t v\u00e0i th\u00f4ng tin m\u00e0 \u0111\u1ea1i ca c\u00f3 th\u1ec3 s\u1ebd th\u00edch \u0111\u1ea5y \u1ea1: .......\",\n    \"sticker\": \"1ec5abe997ac7ef227bd\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "c6887693-bbac-4ab1-b3e1-b0596eafb89b",
      "name": "Extract, Clean and Chunk Message Text",
      "type": "n8n-nodes-base.code",
      "position": [
        -192,
        -16
      ],
      "parameters": {
        "jsCode": "const MAX_LEN = 2000;\n\n// ---- 0) L\u1ea5y text t\u1eeb AI Agent ----\nlet text = $input.first().json.output.message.trim();\nif (!text) return [];\n\n// ---- 1) Chu\u1ea9n ho\u00e1: b\u1ecf Markdown & HTML ----\n// B\u1ecf code block ```\ntext = text.replace(/```[\\s\\S]*?```/g, '');\n// Inline code `\ntext = text.replace(/`([^`]+)`/g, '$1');\n// Bold, italic, underline, strike\ntext = text.replace(/(\\*{1,2}|_{1,2}|~~)(.*?)\\1/g, '$2');\n// Header #, blockquote >\ntext = text.replace(/^\\s{0,3}#{1,6}\\s+/gm, '');\ntext = text.replace(/^\\s{0,3}>\\s?/gm, '');\n// Link [text](url) -> text\ntext = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '$1');\n// Image ![alt](url) -> alt\ntext = text.replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '$1');\n// Xo\u00e1 HTML tag\ntext = text.replace(/<[^>]+>/g, '');\n\n// Gi\u1eef bullet list: *, +, - -> -\ntext = text.replace(/^\\s*[\\*\\+]\\s+/gm, '- ');\n\n// Chu\u1ea9n ho\u00e1 xu\u1ed1ng d\u00f2ng\ntext = text.replace(/\\r\\n?/g, '\\n');\ntext = text.replace(/[ \\t]+\\n/g, '\\n');\ntext = text.replace(/\\n{3,}/g, '\\n\\n').trim();\n\n// ---- 2) H\u00e0m c\u1eaft th\u00f4ng minh ----\nfunction splitSmart(input, maxLen) {\n  const chunks = [];\n  let remaining = input;\n\n  while (remaining && chunks.length < 10) {\n    if (remaining.length <= maxLen) {\n      chunks.push(remaining.trim());\n      break;\n    }\n\n    // \u01afu ti\u00ean c\u1eaft \u1edf newline g\u1ea7n maxLen\n    let idx = remaining.lastIndexOf('\\n', maxLen);\n    if (idx < maxLen * 0.6) {\n      // Th\u1eed c\u1eaft \u1edf d\u1ea5u c\u00e2u\n      const look = remaining.slice(0, Math.min(remaining.length, maxLen + 200));\n      const punct = Math.max(\n        look.lastIndexOf('. '),\n        look.lastIndexOf('! '),\n        look.lastIndexOf('? ')\n      );\n      if (punct > 0) idx = punct + 1;\n    }\n    if (idx < maxLen * 0.6) {\n      // Th\u1eed c\u1eaft \u1edf kho\u1ea3ng tr\u1eafng\n      const ws = remaining.lastIndexOf(' ', maxLen);\n      idx = ws > 0 ? ws : maxLen;\n    }\n\n    chunks.push(remaining.slice(0, idx).trim());\n    remaining = remaining.slice(idx).trim();\n  }\n\n  return chunks;\n}\n\n// ---- 3) Xu\u1ea5t k\u1ebft qu\u1ea3 ----\nconst chunks = splitSmart(text, MAX_LEN);\nreturn chunks.map(c => ({ json: { text: c } }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6ec2f1a9-edc6-403e-b79a-212ea71beb70",
      "name": "Send Zalo Message",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -16,
        -16
      ],
      "parameters": {
        "url": "https://bot-api.zapps.me/bot[BOT_TOKEN]/sendMessage",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $('Receive Zalo Webhook').item.json.body.message.chat.id }}"
            },
            {
              "name": "=text",
              "value": "={{ $json.text }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "446838f4-8081-4dea-8d14-1a7c811bc90d",
      "name": "Send Zalo Message1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        144,
        -16
      ],
      "parameters": {
        "url": "https://bot-api.zapps.me/bot[BOT_TOKEN]/sendSticker",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $('Receive Zalo Webhook').item.json.body.message.chat.id }}"
            },
            {
              "name": "sticker",
              "value": "={{ $('Summarize AI News').item.json.output.sticker }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f95e2ad7-6f9b-4802-ba83-21dd691cb03c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1952,
        -800
      ],
      "parameters": {
        "color": 6,
        "width": 368,
        "height": 1568,
        "content": "## \ud83d\udee0\ufe0f How to Create a Zalo Bot and Get Your Bot Token\n\n### What is Zalo?\n\nZalo is Vietnam\u2019s number one instant messaging app, serving over 78 million monthly active users - more than 85% of the country\u2019s internet-connected population - making it one of the most widely-used platforms in Asia. The app handles 2 billion messages per day and is deeply embedded in Vietnamese daily life, revolutionizing communication for both individuals and businesses.\n\nZalo also offers an API platform for developers to build chatbots and automation tools directly within the app. This opens up powerful opportunities for creating AI-powered assistants, customer support bots, and real-time notification systems.\n\n### What is a Zalo Bot?\n\nA Zalo Bot is provided by Zalo that allows developers to build automated chat experiences using Zalo\u2019s API. These bots can receive and respond to user messages, making them ideal for use cases like news updates, customer service, appointment booking, and more.\n\nZalo Bots are now supported by n8n, enabling you to build intelligent workflows that connect Zalo with AI models, RSS feeds, databases, and other services.\n\nFollow these steps to create your bot and retrieve the token needed to authenticate API requests:\n\n### Step 1: Access Zalo Bot Creator\n- Open the Zalo app on your mobile device.\n- Use the search bar to find **\"Zalo Bot Creator\"**.\n- Tap to open the Official Account page.\n\n### Step 2: Create a New Bot\n- Tap the **\"Create Zalo Bot Account\"** button.\n- Fill in the required details:\n  - Your bot\u2019s name must start with the prefix `\"Bot\"` (e.g., `Bot AI News Assistant`).\n  - Add a description and profile image if needed.\n\n### Step 3: Receive Your Bot Token\n- Once the bot is successfully created, Zalo will send a message to your personal account.\n- This message contains your **Bot Token**\u2014a unique string used to authenticate API calls.\n- **Important:** Save this token securely. It will only be shown once.\n\n---\n\n## \u26a0\ufe0f Notes & Limitations\n- Zalo Bots currently **do not support voice messages, images, or file attachments**.\n- The bot name must follow Zalo\u2019s naming convention (starting with `\"Bot\"`).\n- You\u2019ll need the Bot Token to configure HTTP Request nodes in your n8n workflow.\n\n---\n\nOnce you have your Bot Token, you're ready to set up your webhook and start building your Zalo-powered automation with n8n!\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "rss_read": {
      "ai_tool": [
        [
          {
            "node": "Summarize AI News",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Send Zalo Message": {
      "main": [
        [
          {
            "node": "Send Zalo Message1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize AI News": {
      "main": [
        [
          {
            "node": "Extract, Clean and Chunk Message Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MongoDB Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "Summarize AI News",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Receive Zalo Webhook": {
      "main": [
        [
          {
            "node": "Summarize AI News",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Typing Action to Zalo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini Language Model": {
      "ai_languageModel": [
        [
          {
            "node": "Summarize AI News",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Parse Structured AI Output",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parse Structured AI Output": {
      "ai_outputParser": [
        [
          {
            "node": "Summarize AI News",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Extract, Clean and Chunk Message Text": {
      "main": [
        [
          {
            "node": "Send Zalo Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}