GiggleGPTBot 模板
高级
这是一个AI Chatbot, Multimodal AI领域的自动化工作流,包含 27 个节点。主要使用 If, Code, Switch, Postgres, Telegram 等节点。 使用 OpenRouter 创建具有 AI 驱动幽默、调侃和统计功能的机智 Telegram 机器人
前置要求
- •PostgreSQL 数据库连接信息
- •Telegram Bot Token
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "TfKEOWRNsYI093kR",
"meta": {
"instanceId": "673dd365761c86615255caaaae908ad0f2b40ed6e6f64e1be5631254544e65ca"
},
"name": "GiggleGPTBot 模板",
"tags": [],
"nodes": [
{
"id": "c4dbddca-9165-401f-9a96-995a958a425a",
"name": "Webhook Telegram",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-1136,
64
],
"webhookId": "3cb5a3b8-5bae-4708-be95-172a7d50cb48",
"parameters": {
"updates": [
"*"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"id": "GNUE3W3kc9bGnXyL",
"name": "GiggleGPTBot"
}
},
"typeVersion": 1
},
{
"id": "5369e144-45cd-4a99-9fa6-284ae24ec585",
"name": "OpenRouter 命令",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-512,
736
],
"parameters": {
"model": "openai/gpt-oss-120b",
"options": {}
},
"credentials": {
"openRouterApi": {
"id": "ONSHmBroionT6JFr",
"name": "OpenRouter account"
}
},
"typeVersion": 1
},
{
"id": "5ee25a3f-a9c7-4994-a9a9-315b9eeec5af",
"name": "初始化数据库",
"type": "n8n-nodes-base.postgres",
"position": [
-1248,
-128
],
"parameters": {
"query": "CREATE TABLE IF NOT EXISTS user_messages (\n id SERIAL PRIMARY KEY,\n user_id BIGINT NOT NULL,\n username VARCHAR(255),\n first_name VARCHAR(255),\n chat_id BIGINT NOT NULL,\n message_text TEXT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS bot_responses (\n id SERIAL PRIMARY KEY,\n user_id BIGINT NOT NULL,\n chat_id BIGINT NOT NULL,\n user_message TEXT,\n bot_response TEXT,\n response_type VARCHAR(50),\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS bot_commands (\n id SERIAL PRIMARY KEY,\n user_id BIGINT NOT NULL,\n chat_id BIGINT NOT NULL,\n command VARCHAR(50) NOT NULL,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS message_reactions (\n id SERIAL PRIMARY KEY,\n message_id BIGINT NOT NULL,\n chat_id BIGINT NOT NULL,\n user_id BIGINT NOT NULL,\n emoji VARCHAR(10),\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE IF NOT EXISTS scheduled_posts (\n id SERIAL PRIMARY KEY,\n chat_id BIGINT NOT NULL,\n message_text TEXT,\n post_type VARCHAR(50),\n scheduled_time TIME,\n is_active BOOLEAN DEFAULT true,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE user_stats (\n user_id BIGINT NOT NULL,\n chat_id BIGINT NOT NULL,\n messages_count INT DEFAULT 0,\n commands_count INT DEFAULT 0,\n reactions_received INT DEFAULT 0,\n last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (user_id, chat_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_user_messages_chat_user ON user_messages(chat_id, user_id);\nCREATE INDEX IF NOT EXISTS idx_bot_responses_chat_user ON bot_responses(chat_id, user_id);\nCREATE INDEX IF NOT EXISTS idx_commands_user ON bot_commands(user_id, command);\nCREATE INDEX IF NOT EXISTS idx_reactions_message ON message_reactions(message_id);\nCREATE INDEX idx_user_stats_activity ON user_stats(last_activity DESC);\nCREATE INDEX idx_user_stats_messages ON user_stats(messages_count DESC);\n",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "2f7789fd-645c-436f-91ef-04cb2143aa7d",
"name": "记录消息 + 统计信息",
"type": "n8n-nodes-base.postgres",
"onError": "continueRegularOutput",
"position": [
-960,
-192
],
"parameters": {
"query": "INSERT INTO user_messages (user_id, username, first_name, chat_id, message_text) \nVALUES ({{ $('Webhook Telegram').item.json.message.from.id }}, \n '{{ ($('Webhook Telegram').item.json.message.from.username || '').replace(/'/g, \"''\") }}', \n '{{ ($('Webhook Telegram').item.json.message.from.first_name || '').replace(/'/g, \"''\") }}', \n {{ $('Webhook Telegram').item.json.message.chat.id }}, \n '{{ ($('Webhook Telegram').item.json.message.text || '').replace(/'/g, \"''\") }}');\n\nINSERT INTO user_stats (user_id, chat_id, messages_count, last_activity)\nVALUES ({{ $('Webhook Telegram').item.json.message.from.id }}, \n {{ $('Webhook Telegram').item.json.message.chat.id }}, \n 1, CURRENT_TIMESTAMP)\nON CONFLICT (user_id, chat_id) \nDO UPDATE SET \n messages_count = user_stats.messages_count + 1,\n last_activity = CURRENT_TIMESTAMP;",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "5676c8d7-a456-4f12-be6a-2cd5c2ec41e6",
"name": "添加日程安排",
"type": "n8n-nodes-base.postgres",
"position": [
-1120,
400
],
"parameters": {
"query": "INSERT INTO scheduled_posts (chat_id, post_type, scheduled_time) VALUES\n(-1002837353897, 'morning_joke', '06:00:00'),\n(-1002837353897, 'random_wisdom', '17:00:00'),\n(-1002837353897, 'daily_motivation', '09:00:00');",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "5b7c3300-fa5a-43f5-881f-db48314be81c",
"name": "日程安排",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-992,
544
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 * * * *"
}
]
}
},
"typeVersion": 1
},
{
"id": "756e467d-835a-4166-8972-4edf50b0007f",
"name": "获取预定帖子",
"type": "n8n-nodes-base.postgres",
"position": [
-800,
544
],
"parameters": {
"query": "SELECT chat_id, post_type \nFROM scheduled_posts \nWHERE is_active = true \nAND EXTRACT(HOUR FROM scheduled_time) = EXTRACT(HOUR FROM CURRENT_TIME);",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "84247455-9eed-424d-8ee4-84ece8f10d54",
"name": "聊天历史",
"type": "n8n-nodes-base.postgres",
"position": [
-768,
-96
],
"parameters": {
"query": "SELECT \n message_text,\n username,\n first_name,\n created_at,\n 'user' as message_type\nFROM user_messages \nWHERE chat_id = {{ $('Webhook Telegram').item.json.message.chat.id }}\n\nUNION ALL\n\nSELECT \n bot_response as message_text,\n 'GiggleGPTBot' as username,\n 'GiggleGPTBot' as first_name,\n created_at,\n 'bot' as message_type\nFROM bot_responses \nWHERE chat_id = {{ $('Webhook Telegram').item.json.message.chat.id }}\n\nORDER BY created_at DESC \nLIMIT 15;",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "86872198-4d19-4c3e-b5dd-14dda87a9139",
"name": "提及分析",
"type": "n8n-nodes-base.code",
"position": [
-592,
-96
],
"parameters": {
"jsCode": "const telegramData = $('Webhook Telegram').first().json;\nconst chatHistory = $('Chat history').all();\n\nconst userId = telegramData.message.from.id;\nconst userName = telegramData.message.from.first_name || telegramData.message.from.username || 'Anonymous';\nlet userMessage = telegramData.message.text;\nconst chatId = telegramData.message.chat.id;\n\nconst commandMatch = userMessage.match(/^\\/(\\w+)(?:@\\w+)?(?:\\s+(.*))?/);\nconst command = commandMatch ? commandMatch[1].toLowerCase() : '';\n\nconst originalMessage = userMessage;\nuserMessage = userMessage.replace(/@GiggleGPTBot/gi, '').trim();\nconst isEmptyAfterTag = !userMessage || userMessage.length === 0;\n\nconst recentMessages = chatHistory.map(item => {\n const msgText = item.json.message_text || '';\n const author = item.json.message_type === 'bot' ? 'GiggleGPTBot' : \n (item.json.first_name || item.json.username || 'Anonymous');\n return `${author}: ${msgText}`;\n}).slice(0, 15).join('\\n'); \n\nlet contentType = 'mixed';\nconst lowerMessage = userMessage.toLowerCase();\nif (lowerMessage.includes('joke') || lowerMessage.includes('funny')) {\n contentType = 'funny';\n} else if (lowerMessage.includes('motivat') || lowerMessage.includes('motivat')) {\n contentType = 'inspiring';\n}\n\nif (isEmptyAfterTag) {\n const types = ['funny', 'inspiring', 'mixed'];\n contentType = types[Math.floor(Math.random() * types.length)];\n}\n\nconst now = new Date();\nconst hour = now.getHours();\nlet timeContext = '';\nif (hour < 6) timeContext = 'night';\nelse if (hour < 12) timeContext = 'morning';\nelse if (hour < 18) timeContext = 'day';\nelse timeContext = 'evening';\n\nreturn [{\n json: {\n userId,\n userName,\n userMessage: isEmptyAfterTag ? 'Random phrase' : userMessage,\n originalMessage,\n chatId,\n contentType,\n command,\n timeContext,\n recentMessages,\n chatType: telegramData.message.chat.type,\n isRandomRequest: isEmptyAfterTag\n }\n}];"
},
"typeVersion": 2
},
{
"id": "60de834b-47c8-428a-9d28-87ade8fa8a43",
"name": "获取用户统计信息",
"type": "n8n-nodes-base.postgres",
"position": [
-768,
64
],
"parameters": {
"query": "SELECT \n us.user_id,\n us.messages_count,\n us.commands_count,\n 0 as reactions_received,\n us.last_activity,\n (SELECT COUNT(*) FROM bot_responses br WHERE br.user_id = us.user_id AND br.chat_id = us.chat_id) as responses_count\nFROM user_stats us\nWHERE us.chat_id = {{ $json.message.chat.id }}\n AND us.user_id = {{ $json.message.from.id }}\nLIMIT 1;",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "d57380bc-5dc5-4130-a767-463bbf81931c",
"name": "获取顶级用户",
"type": "n8n-nodes-base.postgres",
"position": [
-768,
224
],
"parameters": {
"query": "SELECT \n us.messages_count,\n us.commands_count,\n CONCAT(\n COALESCE((SELECT first_name FROM user_messages WHERE user_id = us.user_id LIMIT 1), 'User'),\n ' (@',\n COALESCE((SELECT username FROM user_messages WHERE user_id = us.user_id LIMIT 1), 'no_username'),\n ')'\n ) as user_name\nFROM user_stats us\nWHERE us.chat_id = {{ $json.message.from.id }}\n AND us.messages_count > 0\nORDER BY (us.messages_count + us.commands_count * 2) DESC\nLIMIT 10;",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "b12f28fc-6fb0-45ca-8348-202bf5a78332",
"name": "AI 对命令的响应",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 2,
"position": [
-240,
-80
],
"parameters": {
"text": "=Command: /{{ $json.command }}\nUser: {{ $json.userName }}\nChat context: {{ $json.recentMessages }}\nTime: {{ $json.timeContext }}\n\nGenerate {{ $json.command === 'joke' ? 'a witty joke' : $json.command === 'inspire' ? 'a motivating line' : $json.command === 'roast' ? 'a sharp roast with folksy sarcasm' : 'a random interesting line' }} in your signature style with subtle humor and playful teasing.\n",
"options": {
"systemMessage": "You are GiggleGPTBot — a witty bot with a big heart. Your job: deliver short humor and folksy wisdom with light irony.\n\nStyle:\n• Modern spin on proverbs and sayings.\n• Gentle irony and kind subtext.\n• Emojis: allowed but sparing (0–2 per reply).\n\nAvoid:\n• Crudeness, profanity, cliché \"Soviet-style\" advice.\n• Rambling, long, or confusing imagery.\n• Explaining the joke or meta-notes about the prompt.\n\nReply format:\n• Strictly 1–2 sentences (3 only in rare cases).\n• One clear idea or joke.\n• At most one simple metaphor.\n• Must be easily understood at first read.\n\nCommands:\n/joke — clever short joke with light irony.\n/inspire — gentle, smiley motivation (no pomp).\n/random — unexpected witty line in folksy wisdom style.\n/roast — sharp roast with sarcastic tone. Some edge allowed, mild profanity ok, but NO insults targeting gender, race, nationality, or other protected traits.\n\nExamples:\n/joke → My neighbor runs every morning. I run too… my eyes over the bus schedule 🚌.\n/inspire → Even a snail has a goal — and you’ve got legs that are faster 🐌➡️🏃♂️.\n/random → Sometimes the kettle boils longer than love… yet both return to warmth ☕❤️.\n/roast → “Your alarm screams like it’s got a mortgage. You? Just laziness and snoring — also on credit 😏”.\n\nSelf-check before sending:\n• Did I stay within 1–2 sentences?\n• Is there light irony or a clear joke/wisdom?\n• Is it instantly clear to a regular person?\n• No extra fluff, confusion, or weird imagery?\n\nIf not, shorten and rewrite to a simple, clear, witty reply."
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 2
},
{
"id": "e1345b2b-f824-40cb-b01d-48031d417b1b",
"name": "生成信息响应",
"type": "n8n-nodes-base.code",
"position": [
-576,
144
],
"parameters": {
"jsCode": "const messageText = $('Webhook Telegram').first().json.message.text\nconst commandMatch = messageText.match(/^\\/(\\w+)(?:@\\w+)?(?:\\s+(.*))?/);\nconst commandData = commandMatch ? commandMatch[1].toLowerCase() : '';\n\nconst safe = (v, d = '') => (v === null || v === undefined ? d : v);\n\nlet userStatsItem;\ntry {\n userStatsItem = $input.first();\n} catch (_) {\n userStatsItem = undefined;\n}\n\nlet topUsersItems = [];\ntry {\n const topNode = $('Get top users');\n if (topNode && typeof topNode.all === 'function') {\n const raw = topNode.all() || [];\n topUsersItems = raw\n .map(i => (i && i.json) ? i.json : null)\n .filter(Boolean);\n }\n} catch (error) {\n console.log('Top users unavailable:', error.message);\n}\n\nconst userId = safe($('Webhook Telegram').first().json.message.from.id);\nconst userName = safe($('Webhook Telegram').first().json.message.chat.first_name, 'User');\nconst chatId = safe($('Webhook Telegram').first().json.message.chat.id);\nconst command = safe(commandData, '');\n\nlet responseText = '';\n\nconst formatDateRu = (iso) => {\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return 'Unknown';\n return d.toLocaleString('en-US', { dateStyle: 'short', timeStyle: 'short' });\n } catch {\n return 'Unknown';\n }\n};\n\nconst calcActivity = (u) => {\n const msgs = Number(u.messages_count || 0);\n const cmds = Number(u.commands_count || 0);\n return msgs + cmds * 2;\n};\n\nswitch (command) {\n case 'stats': {\n if (userStatsItem && userStatsItem.json) {\n const s = userStatsItem.json;\n responseText =\n `📊 Statistics ${userName}:\\n` +\n `💬 Messages: ${Number(s.messages_count || 0)}\\n` +\n `⚡ Commands: ${Number(s.commands_count || 0)}\\n` +\n `📅 Last activity: ${s.last_activity ? formatDateRu(s.last_activity) : 'Unknown'}`;\n } else {\n responseText =\n `📊 Statistics ${userName}:\\n` +\n `There is no data yet. Keep chatting and the statistics will appear! 💬`;\n }\n break;\n }\n\n case 'top': {\n if (topUsersItems.length > 0) {\n const sorted = [...topUsersItems]\n .sort((a, b) => calcActivity(b) - calcActivity(a))\n .slice(0, 10);\n\n const lines = sorted.map((u, idx) => {\n const uname = u.user_name || 'User';\n const msgs = Number(u.messages_count || 0);\n const cmds = Number(u.commands_count || 0);\n const total = calcActivity(u);\n return `${idx + 1}. ${uname}\\n 💬 ${msgs} messages, ⚡ ${cmds} commands\\n 📊 Activity: ${total} points`;\n });\n\n responseText = '🏆 Top Active Users:\\n\\n' + lines.join('\\n\\n');\n } else {\n responseText =\n '🏆 Top Active Users:\\n\\n' +\n 'There are no active users in this chat yet. Be the first! 🚀';\n }\n break;\n }\n\n case 'help': {\n responseText =\n '🤖 GiggleGPTBot commands:\\n\\n' +\n '😄 /joke — funny joke\\n' +\n '💪 /inspire — motivation\\n' +\n '🎲 /random — random phrase\\n' +\n '🔥 /roast — harsh joke with sarcasm (without insults based on prohibited characteristics)\\n' +\n '📊 /stats — your statistics\\n' +\n '🏆 /top — top users\\n' +\n '❓ /help — this help\\n\\n' +\n 'You can also write @GiggleGPTBot + text — I will answer personally.';\n break;\n }\n\n case 'joke':\n case 'inspire':\n case 'random':\n case 'roast': {\n responseText =\n 'This command generates a content response and is processed by another node. ' +\n 'Try again - or use /help for a list of available info commands.';\n break;\n }\n\n default: {\n responseText = 'Unknown command 🤔 Use /help for a list of commands.';\n }\n}\n\nreturn [{\n json: {\n userId,\n userName,\n chatId,\n command,\n responseText,\n isInfoCommand: true\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "bf1fd22f-7df0-4891-82b0-6fd1ed3648dd",
"name": "响应类型",
"type": "n8n-nodes-base.if",
"position": [
80,
112
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "condition1",
"operator": {
"type": "boolean",
"operation": "equal",
"singleValue": true
},
"leftValue": "={{ $json.isInfoCommand }}",
"rightValue": true
},
{
"id": "78352c71-3779-4ba9-afb7-1e836a019a24",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.responseText }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "6698db5c-408d-43ac-b4b8-edbb7a3ac367",
"name": "发送信息回复",
"type": "n8n-nodes-base.telegram",
"position": [
272,
32
],
"webhookId": "20b4671b-ebf4-4562-b40b-c3eba533ab60",
"parameters": {
"text": "={{ $json.responseText }}",
"chatId": "={{ $json.chatId }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"credentials": {
"telegramApi": {
"id": "GNUE3W3kc9bGnXyL",
"name": "GiggleGPTBot"
}
},
"typeVersion": 1
},
{
"id": "a95f6638-4406-4aab-8088-5d86125eedbf",
"name": "发送 AI 响应",
"type": "n8n-nodes-base.telegram",
"position": [
272,
208
],
"webhookId": "0c3d1f52-87ed-48f4-a056-31beab8dcaf3",
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('If1').item.json.chatId }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"credentials": {
"telegramApi": {
"id": "GNUE3W3kc9bGnXyL",
"name": "GiggleGPTBot"
}
},
"typeVersion": 1
},
{
"id": "2fc342ba-3372-4e85-91ac-be6cea8b66ae",
"name": "AI 对提及的响应",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 2,
"position": [
-240,
-288
],
"parameters": {
"text": "=User: {{ $json.userName }}\n{{ $json.isRandomRequest ? 'Mentioned the bot without text' : 'Message: \"' + $json.userMessage + '\"' }}\n\nChat context:\n{{ $json.recentMessages }}\n\nTime: {{ $json.timeContext }} | Style: {{ $json.contentType }}\n\n{{ $json.isRandomRequest ? 'Make a witty remark about the chat situation.' : 'Reply to the message with subtle humor.' }}\n\nBe witty and tactful! 🎭\n",
"options": {
"systemMessage": "You are GiggleGPTBot — a witty bot with subtle humor and a big heart. Be concise and to the point.\n\nStyle:\n• Modern spin on proverbs and sayings.\n• References to classics and folksy wisdom.\n• Soft irony with kind subtext.\n• Emojis: allowed but sparing (0–2 per reply).\n\nAvoid:\n• Crudeness, profanity, tired clichés.\n• Long, tangled, or meaningless phrases.\n• Surreal poetry or explaining your own jokes.\n\nFormat:\n• Max 1–2 sentences (3 only in rare cases).\n• One clear idea or joke.\n• At most one simple metaphor.\n• Do not repeat the user’s text; no digressions.\n\nBehavior by situation:\n• Question — answer the gist in one sentence, add a light ironic note in the second.\n• Joy/success — brief congrats; “what’s characteristic” can be used for charm.\n• Complaint/anxiety — tactful support and gentle hope, no moralizing.\n• User tells a joke — reply with a friendly counter-joke.\n• If a name is mentioned — address them by name.\n\nSelf-check before sending:\n• Did I stay within 1–2 sentences?\n• Is there light irony or clear wisdom?\n• Is it clear at first read, no fluff?\n• ≤1 metaphor, ≤2 emojis, ≤2 signature words?\n\nIf not, shorten and rewrite to a simple, clear, witty reply."
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 2,
"alwaysOutputData": false
},
{
"id": "c343e37c-9fe6-47d5-bae3-b1524d766243",
"name": "回复提及",
"type": "n8n-nodes-base.telegram",
"position": [
80,
-288
],
"webhookId": "f77cfa99-a956-4c47-b4ff-41c3267b2505",
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('Mention Analysis').item.json.chatId }}",
"additionalFields": {
"parse_mode": "HTML",
"reply_to_message_id": "={{ $('Webhook Telegram').first().json.message.message_id }}"
}
},
"credentials": {
"telegramApi": {
"id": "GNUE3W3kc9bGnXyL",
"name": "GiggleGPTBot"
}
},
"typeVersion": 1
},
{
"id": "d581be16-af5f-48bf-bfe2-9a66cf96612f",
"name": "AI 帖子生成",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 2,
"position": [
-416,
528
],
"parameters": {
"text": "=Post type: {{ $json.post_type }}\n\nGenerate {{ $json.post_type === 'morning_joke' ? 'a morning joke' : $json.post_type === 'daily_motivation' ? 'daily motivation' : 'a piece of random wisdom' }} in your style with subtle humor.\n",
"options": {
"systemMessage": "IMPORTANT: Respond with PLAIN TEXT ONLY!\nDo NOT use asterisks, underscores, fancy quotes, or formatting symbols.\n\nYou are GiggleGPTBot — a witty storyteller creating short, warm posts.\n\nTopics:\nmorning_joke: morning jokes with kind subtext\ndaily_motivation: day-starter motivation with gentle irony\nrandom_wisdom: everyday observations in an “isn’t that true!” tone\n\nBehavior by topic:\nmorning_joke — one joke and a short warm finish\ndaily_motivation — one clear thesis and a gentle call to action\nrandom_wisdom — an observation and a simple takeaway\n\nStyle:\n• Concise like Chekhov: max 2–3 sentences (prefer 2)\n• Folksy wisdom in a modern spin\n• Intelligent humor with kind subtext\n• Emojis allowed sparingly: 0–2 per post\n• Max one simple metaphor\n\nAvoid:\n• Crudeness, profanity, cliché “Soviet-style” advice\n• Long, tangled, or surreal imagery\n• Hashtags, links, lists, or explaining your own jokes\n\nSelf-check before sending:\n• Within 2–3 sentences?\n• Light irony or clear joke/wisdom?\n• Clear at first read for a general audience?\n• No fluff or confusion?\n\nIf not, shorten and rewrite to a simple, clear, friendly post."
},
"promptType": "define"
},
"retryOnFail": true,
"typeVersion": 2
},
{
"id": "06b1468d-5af7-46e9-8e50-ec6a3c49d895",
"name": "提交预定帖子",
"type": "n8n-nodes-base.telegram",
"position": [
-112,
528
],
"webhookId": "d17bb041-f75d-427a-9529-d93f39a51723",
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('Get scheduled posts').item.json.chat_id }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"credentials": {
"telegramApi": {
"id": "GNUE3W3kc9bGnXyL",
"name": "GiggleGPTBot"
}
},
"typeVersion": 1
},
{
"id": "c538c3eb-0ce6-4f34-80fb-b6668a9fe549",
"name": "保存机器人响应",
"type": "n8n-nodes-base.postgres",
"position": [
80,
-112
],
"parameters": {
"query": "INSERT INTO bot_responses (user_id, chat_id, user_message, bot_response, response_type) \nVALUES ({{ $('Mention Analysis').item.json.userId }}, \n {{ $('Mention Analysis').item.json.chatId }}, \n '{{ $('Mention Analysis').item.json.originalMessage.replace(/'/g, \"''\") }}', \n '{{ $json.output.replace(/'/g, \"''\") }}', \n '{{ $('Mention Analysis').item.json.contentType }}');",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "f78d3e69-c2ba-4640-921a-e3bb52988416",
"name": "如果",
"type": "n8n-nodes-base.if",
"position": [
-624,
544
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e1310a96-8c67-467e-b50d-fee95851424c",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.chat_id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "8afe12f7-ef5b-4b89-8b08-623024c97b3c",
"name": "切换",
"type": "n8n-nodes-base.switch",
"position": [
-960,
-32
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "joke",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1b2506b4-5b0b-48cb-bb27-5684c9bcbd88",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/joke"
}
]
},
"renameOutput": true
},
{
"outputKey": "inspire",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "6362199a-67f8-47c2-a845-3088f33c3338",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/inspire"
}
]
},
"renameOutput": true
},
{
"outputKey": "random",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f883e421-2f6e-490b-ae2c-9952c5083d2c",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/random"
}
]
},
"renameOutput": true
},
{
"outputKey": "roast",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "3d6557c4-2eab-4545-af30-3b4848c424fb",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/roast"
}
]
},
"renameOutput": true
},
{
"outputKey": "GiggleGPTBot",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "69fbe825-df4d-44c5-85eb-5d69e0f17896",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "@GiggleGPTBot"
}
]
},
"renameOutput": true
},
{
"outputKey": "stats",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ac0a71e3-8793-4c32-a5f9-bec6055c04d7",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/stats"
}
]
},
"renameOutput": true
},
{
"outputKey": "help",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "062c9bd8-d63d-4c22-9097-8499b04ebc13",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/help"
}
]
},
"renameOutput": true
},
{
"outputKey": "top",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ceb18c82-23d7-411d-8a48-c212ea7add91",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message?.text }}",
"rightValue": "/top"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "76628b1a-4f38-4e8b-be27-adf5cf078b83",
"name": "记录命令",
"type": "n8n-nodes-base.postgres",
"position": [
-384,
64
],
"parameters": {
"query": "INSERT INTO bot_commands (user_id, chat_id, command) \nVALUES ({{ $json.userId }}, {{ $json.chatId }}, '{{ $json.userMessage.replace(/'/g, \"''\") }}');\n\nUPDATE user_stats \nSET commands_count = commands_count + 1 \nWHERE user_id = {{ $json.userId }} AND chat_id = {{ $json.chatId }};",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "197cb78b-ff9b-46d3-93ca-ff708d45d36d",
"name": "条件判断1",
"type": "n8n-nodes-base.if",
"position": [
-416,
-96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "39d5e005-69f7-4e27-ad73-e00b7a694a4e",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.originalMessage }}",
"rightValue": "@GiggleGPTBot"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "cd2ae05c-a673-4b30-82fd-9c003610799a",
"name": "保存机器人响应2",
"type": "n8n-nodes-base.postgres",
"position": [
-112,
352
],
"parameters": {
"query": "INSERT INTO bot_responses (user_id, chat_id, user_message, bot_response, response_type) \nVALUES (0,\n {{ $('Get scheduled posts').item.json.chat_id }}, \n 'Scheduled post', \n '{{ $json.output.replace(/'/g, \"''\") }}', \n '{{ $('Get scheduled posts').item.json.post_type }}');",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "Fd7RaI9MHHQBq9hE",
"name": "Supabase Postgres"
}
},
"typeVersion": 2
},
{
"id": "f66c1418-8664-416b-8e0b-08ed120bb64e",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2064,
-416
],
"parameters": {
"color": 5,
"width": 700,
"height": 2844,
"content": "# GiggleGPTBot — 诙谐的 Telegram 机器人(带 AI 和 Postgres)"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "7c0fe80e-b260-4241-b8fb-328a99300eb1",
"connections": {
"If": {
"main": [
[
{
"node": "AI post generation",
"type": "main",
"index": 0
}
]
]
},
"If1": {
"main": [
[
{
"node": "AI response to mention",
"type": "main",
"index": 0
}
],
[
{
"node": "AI response to command",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Chat history",
"type": "main",
"index": 0
}
],
[
{
"node": "Chat history",
"type": "main",
"index": 0
}
],
[
{
"node": "Chat history",
"type": "main",
"index": 0
}
],
[
{
"node": "Chat history",
"type": "main",
"index": 0
}
],
[
{
"node": "Chat history",
"type": "main",
"index": 0
}
],
[
{
"node": "Get user statistics",
"type": "main",
"index": 0
}
],
[
{
"node": "Generating an information response",
"type": "main",
"index": 0
}
],
[
{
"node": "Get top users",
"type": "main",
"index": 0
}
]
]
},
"Schedule": {
"main": [
[
{
"node": "Get scheduled posts",
"type": "main",
"index": 0
}
]
]
},
"Chat history": {
"main": [
[
{
"node": "Mention Analysis",
"type": "main",
"index": 0
}
]
]
},
"Get top users": {
"main": [
[
{
"node": "Generating an information response",
"type": "main",
"index": 0
}
]
]
},
"Response type": {
"main": [
[
{
"node": "Send info reply",
"type": "main",
"index": 0
}
],
[
{
"node": "Send AI response",
"type": "main",
"index": 0
}
]
]
},
"Mention Analysis": {
"main": [
[
{
"node": "If1",
"type": "main",
"index": 0
}
]
]
},
"Webhook Telegram": {
"main": [
[
{
"node": "Log message + statistics",
"type": "main",
"index": 0
},
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"AI post generation": {
"main": [
[
{
"node": "Submit scheduled post",
"type": "main",
"index": 0
},
{
"node": "Save Bot Response2",
"type": "main",
"index": 0
}
]
]
},
"Get scheduled posts": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Get user statistics": {
"main": [
[
{
"node": "Generating an information response",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Commands": {
"ai_languageModel": [
[
{
"node": "AI response to command",
"type": "ai_languageModel",
"index": 0
},
{
"node": "AI response to mention",
"type": "ai_languageModel",
"index": 0
},
{
"node": "AI post generation",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI response to command": {
"main": [
[
{
"node": "Response type",
"type": "main",
"index": 0
},
{
"node": "Save Bot Response",
"type": "main",
"index": 0
}
]
]
},
"AI response to mention": {
"main": [
[
{
"node": "Reply to Mention",
"type": "main",
"index": 0
},
{
"node": "Save Bot Response",
"type": "main",
"index": 0
}
]
]
},
"Generating an information response": {
"main": [
[
{
"node": "Log command",
"type": "main",
"index": 0
},
{
"node": "Response type",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - AI 聊天机器人, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
股票分析模板
结合技术分析、AI和Telegram发布生成股票市场洞察
If
Set
Code
+12
25 节点Sergey Skorobogatov
加密货币交易
Telegram论坛脉搏:使用Gemini和Groq AI模型的社区监控
Telegram论坛脉搏:使用Gemini和Groq AI模型的社区监控
If
Set
Code
+13
59 节点Nguyen Thieu Toan
杂项
GPT-4驱动的冷邮件工作流,包含完全定制的3封邮件跟进
使用GPT-4、Mailgun和Supabase自动化个性化冷邮件序列
If
Set
Code
+22
100 节点Paul
客户培育
完整的 B2B 销售流程:Apollo 潜在客户生成、Mailgun 外展和 AI 回复管理
完整的 B2B 销售流程:Apollo 潜在客户生成、Mailgun 外展和 AI 回复管理
If
Set
Code
+26
116 节点Paul
内容创作
宠物美容发布与预约自动化
使用AI、Facebook和Telegram机器人自动化宠物美容发布与预约
If
Set
Switch
+17
36 节点Christian Moises
AI 聊天机器人
智能Telegram助手
使用Gemini AI、PostgreSQL记忆和动态路由构建智能Telegram助手
Set
Code
Switch
+12
36 节点John Alejandro SIlva
AI 聊天机器人