8
n8n 中文网amn8n.com

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)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量27
分类2
节点类型10
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
外部链接
在 n8n.io 查看

分享此工作流