AutomationFlowsEmail & Gmail › Generate Text & Image Responses in Telegram Channels with Gpt-4 and Tgpt

Generate Text & Image Responses in Telegram Channels with Gpt-4 and Tgpt

ByVigh Sandor @vighsandor on n8n.io

This n8n workflow creates an automated Telegram channel bot that responds to messages with AI-generated text or images using TGPT. The bot monitors a specific Telegram channel and generates responses based on message prefixes. Automated text response generation using TGPT Image…

Cron / scheduled trigger★★★★☆ complexity22 nodesHTTP RequestExecute CommandTelegramRead Write File
Email & Gmail Trigger: Cron / scheduled Nodes: 22 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #9818 — we link there as the canonical source.

This workflow follows the Executecommand → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "NyILudHveZv2PCWA",
  "name": "Telegram AI Channel Bot - Text & Image Response Generator with TGPT",
  "tags": [],
  "nodes": [
    {
      "id": "b0b9e65b-b10b-4515-a0d1-7bddf468fe43",
      "name": "Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1568,
        256
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "seconds",
              "secondsInterval": 10
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1e9869bb-34b6-4446-acf7-7a7da358f842",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        -1344,
        256
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bot-token",
              "name": "bot_token",
              "type": "string",
              "value": "your_telegram_token"
            },
            {
              "id": "channel-id",
              "name": "channel_id",
              "type": "string",
              "value": "your_telegram_channel_id"
            },
            {
              "id": "last-offset",
              "name": "last_offset",
              "type": "number",
              "value": "={{ $getWorkflowStaticData('global').last_offset || 0 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "56f197e8-0e2e-43e6-ba3b-d87ddcf47673",
      "name": "Get Updates",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -1120,
        256
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{ $json.bot_token }}/getUpdates",
        "options": {
          "timeout": 30000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "allowed_updates",
              "value": "[\"channel_post\"]"
            },
            {
              "name": "timeout",
              "value": "3"
            },
            {
              "name": "offset",
              "value": "={{ $json.last_offset }}"
            },
            {
              "name": "limit",
              "value": "15"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d6884a27-1999-4cea-9c83-427cdb507892",
      "name": "Process Offset",
      "type": "n8n-nodes-base.code",
      "position": [
        -896,
        256
      ],
      "parameters": {
        "jsCode": "// Process Offset - Complete solution with time window and duplicate prevention\nconst results = items[0].json.result || [];\nconst staticData = $getWorkflowStaticData('global');\n\n// Initialize if needed\nif (!staticData.processed_ids) {\n  staticData.processed_ids = [];\n  staticData.last_offset = 0;\n}\n\n// Get previous offset\nconst previousOffset = staticData.last_offset || 0;\n\n// Current time (Unix timestamp)\nconst currentTime = Math.floor(Date.now() / 1000);\nconst timeWindowSeconds = 15; // Slightly larger window for delays\n\n// Debug info\nconsole.log('=== Process Offset Debug ===' );\nconsole.log('Previous offset:', previousOffset);\nconsole.log('Number of messages received:', results.length);\nconsole.log('Number of processed IDs:', staticData.processed_ids.length);\n\n// ALWAYS update offset if there are results\nif (results.length > 0) {\n  const maxUpdateId = Math.max(...results.map(r => r.update_id));\n  staticData.last_offset = maxUpdateId + 1;\n  console.log('Offset updated:', staticData.last_offset);\n}\n\n// Filter: only new messages + time window + not yet processed\nconst newMessages = results.filter(msg => {\n  // Check if already processed\n  if (staticData.processed_ids.includes(msg.update_id)) {\n    console.log(`Message ${msg.update_id} already processed, skipping`);\n    return false;\n  }\n  \n  // Check time window\n  const messageTime = msg.channel_post?.date || 0;\n  const timeDiff = currentTime - messageTime;\n  \n  if (timeDiff > timeWindowSeconds) {\n    console.log(`Message ${msg.update_id} too old (${timeDiff}s), skipping`);\n    return false;\n  }\n  \n  // Check if newer than previous offset\n  if (msg.update_id < previousOffset) {\n    console.log(`Message ${msg.update_id} older than offset ${previousOffset}, skipping`);\n    return false;\n  }\n  \n  console.log(`Message ${msg.update_id} will be processed (${timeDiff}s old)`);\n  return true;\n});\n\n// If there are new messages\nif (newMessages.length > 0) {\n  // Add processed IDs\n  newMessages.forEach(msg => {\n    staticData.processed_ids.push(msg.update_id);\n  });\n  \n  // Cleanup: keep only last 100 IDs\n  if (staticData.processed_ids.length > 100) {\n    staticData.processed_ids = staticData.processed_ids.slice(-100);\n  }\n  \n  console.log(`${newMessages.length} new messages to process`);\n  \n  // Return new messages WITH OFFSET\n  return newMessages.map(msg => ({\n    json: {\n      ...msg,\n      _current_offset: staticData.last_offset\n    }\n  }));\n} else {\n  console.log('No new messages within time window');\n  \n  // If no new messages, still return the offset\n  return [{\n    json: {\n      _no_new_message: true,\n      _current_offset: staticData.last_offset\n    }\n  }];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "b241edda-7c4c-439f-923f-866ad1f7784f",
      "name": "Split",
      "type": "n8n-nodes-base.splitOut",
      "onError": "continueRegularOutput",
      "position": [
        -672,
        256
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "channel_post.text"
      },
      "typeVersion": 1
    },
    {
      "id": "f194dc72-3089-4461-9424-437ccab2d019",
      "name": "Filter",
      "type": "n8n-nodes-base.if",
      "position": [
        -448,
        256
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "channel-check",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Process Offset').item.json.channel_post.chat.id.toString() }}",
              "rightValue": "={{ $('Config').item.json.channel_id.toString() }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "c266df6f-c97f-439f-86ce-77aa37b08c6b",
      "name": "Clean",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        0
      ],
      "parameters": {
        "jsCode": "const rawOutput = items[0].json.stdout || '';\n\nif (!rawOutput) {\n  console.log('Nincs kimenet az Execute node-t\u00f3l');\n  return [{\n    json: {\n      humanReadableText: 'Hiba t\u00f6rt\u00e9nt a v\u00e1lasz gener\u00e1l\u00e1sa sor\u00e1n.'\n    }\n  }];\n}\n\nlet cleaned = rawOutput\n\nreturn [\n  {\n    json: {\n      humanReadableText: cleaned\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "66e7c7ac-7859-4ec3-a5e4-5163ff118b4e",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        -192,
        256
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "am",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "7831171b-9c57-4791-85cf-858817111370",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $('Split').item.json['channel_post.text'] }}",
                    "rightValue": "am# "
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "ami",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e9588452-a020-43c9-b75b-c182b629e97d",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $('Split').item.json['channel_post.text'] }}",
                    "rightValue": "ami# "
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "6ea51b7d-e8e5-4030-aedd-fa5dbec50a1f",
      "name": "Execute - Text",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        0,
        0
      ],
      "parameters": {
        "command": "=addscriptifnotexists=$(apk add util-linux-misc)\naddcurlifnotexists=$(apk add curl)\n\nautomessage=\"{{ $('Split').item.json['channel_post.text'] }}\"\nprompt=$(echo \"$automessage\" | sed 's/am#//')\n\ngetpackagetgpt=$(curl -LO https://github.com/aandrew-me/tgpt/releases/download/v2.11.0/tgpt-linux-amd64)\nmv ./tgpt-linux-amd64 ./tgpt\nchmod +x ./tgpt\n\nrm -rf /tmp/response.txt\nscript -q -c \"./tgpt --model \\\"gtp-4\\\" --temperature \\\"0.3\\\" -q \\\"$prompt\\\" >> /tmp/response.txt\" /dev/null\n\ntput reset\ncat /tmp/response.txt | sed '/^\\r*@web_search/d'"
      },
      "typeVersion": 1,
      "continueOnFail": true
    },
    {
      "id": "8f038fc1-f7d7-45f0-8a54-76e423c3d05a",
      "name": "Execute - Image",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        0,
        528
      ],
      "parameters": {
        "command": "=apk add util-linux-misc\nautomessage=\"{{ $('Split').item.json['channel_post.text'] }}\"\nprompt=$(echo \"$automessage\" | sed 's/ami#//')\ncurl -LO https://github.com/aandrew-me/tgpt/releases/download/v2.11.0/tgpt-linux-amd64\nmv ./tgpt-linux-amd64 ./tgpt\nchmod +x ./tgpt\nrm -rf /tmp/genimg.jpg\necho \"$prompt\"\nscript -q -c \"./tgpt  -image --height=1080 --width=1920 --out=/tmp/genimg.jpg --model \\\"gtp-4\\\" --temperature \\\"0.7\\\" \\\"$prompt\\\"\" /dev/null"
      },
      "typeVersion": 1,
      "continueOnFail": true
    },
    {
      "id": "66f1dc6c-f36e-41ca-857d-bc1cd9609c28",
      "name": "Send Telegram Text Response",
      "type": "n8n-nodes-base.telegram",
      "position": [
        448,
        0
      ],
      "parameters": {
        "text": "={{ $json.humanReadableText }}",
        "chatId": "={{ $('Config').item.json.channel_id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "200f6f2b-5772-40a6-b6a5-4e7253cb6ebb",
      "name": "Send Telegram Image Response",
      "type": "n8n-nodes-base.telegram",
      "position": [
        448,
        528
      ],
      "parameters": {
        "chatId": "={{ $('Config').item.json.channel_id }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {},
        "binaryPropertyName": "=genimg"
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "8595bf68-1061-472c-9b65-f783fbc0ca8f",
      "name": "Read Generated Image",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        224,
        528
      ],
      "parameters": {
        "options": {
          "fileName": "genimg.jpg",
          "dataPropertyName": "genimg"
        },
        "fileSelector": "=/tmp/genimg.jpg"
      },
      "typeVersion": 1
    },
    {
      "id": "a2c3e370-36e7-4d46-8f1d-639726c0439c",
      "name": "Clear Update List",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -896,
        496
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{ $('Config').item.json.bot_token }}/getUpdates?offset={{ $json._current_offset }}",
        "options": {
          "timeout": 30000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "allowed_updates",
              "value": "[\"channel_post\"]"
            },
            {
              "name": "timeout",
              "value": "3"
            },
            {
              "name": "offset",
              "value": "={{ $json.last_offset }}"
            },
            {
              "name": "limit",
              "value": "15"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f1188129-6ad5-4c29-8fa8-b03b7e440ebb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        -16
      ],
      "parameters": {
        "width": 492,
        "height": 248,
        "content": "## Telegram AI Channel Bot\n\nAutomated bot that monitors a Telegram channel and generates AI responses using TGPT.\n\nSupports text and image generation with customizable prompts.\n\nPolls every 10 seconds with duplicate prevention and time-window filtering."
      },
      "typeVersion": 1
    },
    {
      "id": "ae0fe6cb-6c11-483c-9011-524f3c156e5e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        432
      ],
      "parameters": {
        "width": 320,
        "height": 276,
        "content": "## CONFIGURATION REQUIRED\n\n1. Replace your_telegram_token with your bot token from @BotFather\n2. Replace your_telegram_channel_id with your channel ID\n3. Bot must be admin in the target channel\n\nOffset is managed automatically to track processed messages."
      },
      "typeVersion": 1
    },
    {
      "id": "67494d2b-6e50-405f-a4be-9f2b3860b759",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1120,
        -64
      ],
      "parameters": {
        "width": 340,
        "height": 292,
        "content": "## Message Polling & Processing\n\nFetches new channel messages using Telegram API.\n\nProcesses offset to track read messages and applies 15-second time window to filter only recent messages.\n\nDuplicate prevention ensures each message is processed only once."
      },
      "typeVersion": 1
    },
    {
      "id": "0a3b2b8c-294d-4277-8232-743fcc47c68a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -448,
        432
      ],
      "parameters": {
        "width": 348,
        "height": 208,
        "content": "## Filtering & Message Routing\n\nFilter: Validates messages are from the configured channel\n\nSwitch: Routes messages based on prefix:\n- am# for text generation\n- ami# for image generation"
      },
      "typeVersion": 1
    },
    {
      "id": "75b560d9-9698-4e46-a09f-fed0f645223c",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        -208
      ],
      "parameters": {
        "width": 556,
        "height": 192,
        "content": "## Text Generation Pipeline\n\nAutomatically installs TGPT and dependencies.\n\nRemoves am# prefix and generates text response using GPT-4 with temperature 0.3 for focused responses.\n\nCleans output before sending to channel."
      },
      "typeVersion": 1
    },
    {
      "id": "06cad956-9231-4216-b675-0ca3e3d3d11e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        704
      ],
      "parameters": {
        "width": 556,
        "height": 192,
        "content": "## Image Generation Pipeline\n\nInstalls TGPT and generates image from prompt.\n\nRemoves ami# prefix and creates 1920x1080 image using temperature 0.7 for creative output.\n\nReads generated file from /tmp/ and sends to channel."
      },
      "typeVersion": 1
    },
    {
      "id": "1b710ffd-80e0-4026-9420-b07dcac1c995",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        192
      ],
      "parameters": {
        "width": 300,
        "height": 308,
        "content": "## TELEGRAM CREDENTIALS\n\nBoth Send nodes require Telegram API credentials.\n\n1. Create credential with bot token from @BotFather\n2. Apply same credential to both text and image nodes\n\nMessages are sent with HTML parse mode enabled."
      },
      "typeVersion": 1
    },
    {
      "id": "81df46e8-10a8-4385-8121-8b40c00c26b7",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        256
      ],
      "parameters": {
        "width": 340,
        "height": 224,
        "content": "## Usage Commands\n\nText: Send message starting with am# followed by prompt\nExample: am# Explain quantum physics\n\nImage: Send message starting with ami# followed by description\nExample: ami# Futuristic city at sunset"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5405a7b9-8287-4ac9-bfef-fc1b83956ea6",
  "connections": {
    "Clean": {
      "main": [
        [
          {
            "node": "Send Telegram Text Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Get Updates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Execute - Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Execute - Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Updates": {
      "main": [
        [
          {
            "node": "Process Offset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute - Text": {
      "main": [
        [
          {
            "node": "Clean",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Offset": {
      "main": [
        [
          {
            "node": "Split",
            "type": "main",
            "index": 0
          },
          {
            "node": "Clear Update List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute - Image": {
      "main": [
        [
          {
            "node": "Read Generated Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Generated Image": {
      "main": [
        [
          {
            "node": "Send Telegram Image Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This n8n workflow creates an automated Telegram channel bot that responds to messages with AI-generated text or images using TGPT. The bot monitors a specific Telegram channel and generates responses based on message prefixes. Automated text response generation using TGPT Image…

Source: https://n8n.io/workflows/9818/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

Template - SSL Expiry Alert System. Uses googleSheets, scheduleTrigger, httpRequest, stickyNote. Scheduled trigger; 21 nodes.

Google Sheets, HTTP Request, Gmail +2
Email & Gmail

[](https://www.youtube.com/watch?v=q4d404G_OxY)

Gmail, HTTP Request, Telegram
Email & Gmail

This workflow is ideal for administrators or IT professionals responsible for monitoring SSL certificates of multiple websites to ensure they do not expire unexpectedly.

Google Sheets, HTTP Request, Gmail +2
Email & Gmail

url-uptime-monitor. Uses scheduleTrigger, splitOut, googleSheets, summarize. Scheduled trigger; 18 nodes.

Google Sheets, Gmail, HTTP Request +1
Email & Gmail

MPE Kleinanzeigen Unified (Reminder + Poster). Uses gmail, httpRequest, telegram, googleSheets. Scheduled trigger; 15 nodes.

Gmail, HTTP Request, Telegram +1