{
  "name": "Reddit 行业痛点自动监测与分析",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 7
            }
          ]
        }
      },
      "id": "23ef6a47-689a-43ae-9a14-83a6a874e632",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [-496, 544],
      "typeVersion": 1.2
    },
    {
      "parameters": {
        "numberInputs": 3
      },
      "id": "e328abe4-0025-417d-b9d1-ce11f2a42bfb",
      "name": "Merge Reddit Sources",
      "type": "n8n-nodes-base.merge",
      "position": [-48, 432],
      "typeVersion": 3.1
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Analyze the following Reddit post:\n\nTitle: {{ $json.title }}\nSubreddit: {{ $json.subreddit }}\nContent: {{ $json.text }}\nLink: {{ $json.permalink }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "You are a Senior Product Research Analyst for a DTC e-commerce brand. Your job is to transform raw Reddit discussions into structured market intelligence.\n\n### ANALYSIS RULES\n1. **Context**: Focus on the product category configured in the workflow (default: men's hair replacement systems / hair systems).\n2. **Pain Point Classification (Strictly follow this logic)**:\n   - **Type A (Adhesion)**: Lifting edges, glue melting, difficult cleanup, bond failure.\n   - **Type B (Sensory)**: Itching, scalp rash, heat/sweating, uncomfortable fit.\n   - **Type C (Quality)**: Shedding, oxidation/discoloration, dry or straw-like texture.\n   - **Type D (Social)**: Fear of being detected, wind anxiety, dating insecurity, unnatural appearance.\n   - **Type E (Service)**: Shipping delays, customs fees, return disputes, poor customer support.\n3. **Marketing Angle**: Propose a content title (Guide/Video) that directly solves the specific problem found.\n4. **Brand Detection**: Look for explicit mentions of competitor brands in the post. If none, output \"None\".\n\n### IRRELEVANT DATA HANDLING\nIf the post content is empty, deleted, or completely unrelated to the target product category (e.g., gaming, PC building), set \"pain_category\" to \"General\" and \"summary\" to \"Irrelevant/Spam\".\n\nOUTPUT FORMAT RESTRICTIONS\nCRITICAL: Return ONLY the raw JSON object. - DO NOT use Markdown code blocks (no ```json wrappers). - DO NOT add any introductory text. - Ensure all fields ('pain_category', 'marketing_angle', etc.) are present."
        }
      },
      "id": "a5e3ebc4-34e3-40ac-923e-ffb45fb6d737",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [848, 544],
      "typeVersion": 2.2,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"summary\": {\n      \"type\": \"string\",\n      \"description\": \"Neutral summary of the post, max 20 words.\"\n    },\n    \"pain_category\": {\n      \"type\": \"string\",\n      \"enum\": [\"Type A (Adhesion)\", \"Type B (Sensory)\", \"Type C (Quality)\", \"Type D (Social)\", \"Type E (Service)\", \"General\", \"Positive Review\"],\n      \"description\": \"Classify based on the product category pain point rules.\"\n    },\n    \"core_pain_point\": {\n      \"type\": \"string\",\n      \"description\": \"Specific problem described. Max 15 words.\"\n    },\n    \"marketing_angle\": {\n      \"type\": \"string\",\n      \"description\": \"A blog post title or video topic that solves this pain point.\"\n    },\n    \"brand_mentioned\": {\n      \"type\": \"string\",\n      \"description\": \"Competitor brand explicitly mentioned, or None if none.\"\n    },\n    \"sentiment\": {\n      \"type\": \"string\",\n      \"enum\": [\"Positive\", \"Neutral\", \"Negative\"],\n      \"description\": \"Sentiment towards the mentioned brand or the product experience.\"\n    },\n    \"urgency_flag\": {\n      \"type\": \"boolean\",\n      \"description\": \"True if the post mentions severe allergic reactions or scam accusations.\"\n    }\n  },\n  \"required\": [\"summary\", \"pain_category\", \"core_pain_point\", \"marketing_angle\", \"brand_mentioned\", \"sentiment\"]\n}",
        "autoFix": true,
        "customizeRetryPrompt": true
      },
      "id": "6bfa92d3-78e0-4253-9c64-85fa29bce1fe",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [928, 768],
      "typeVersion": 1.3
    },
    {
      "parameters": {
        "content": "# 工作流程设置指南\n\n## 1. 选择定时触发器时间\n\n在 Schedule Trigger 节点设置每天执行的时间，建议选团队上班前（如 07:00）。\n\n## 2. 连接 Reddit 并配置监听范围\n\n将 Reddit OAuth 凭证接入 n8n，在各 Reddit 节点填写 subreddit 和关键词。\n\n- 可复制 Reddit 节点扩展更多来源，接入 Merge 节点\n- 关键词不要太宽也不要太窄\n\n## 3. 接入大语言模型\n\n在 AI Agent 连接 LLM 凭证（OpenRouter / OpenAI / Anthropic 等）。\n\n按需修改 AI Agent 的 system prompt 里的品类描述和痛点分类规则。\n\n## 4. 复制 Google 表格模板并连接 Google Sheets 节点\n\n表格模板（含示例数据，请先创建副本）：\nhttps://docs.google.com/spreadsheets/d/1lRjSCTaPpkzs79YacCJdVwT-VjeVTWi4Qe3grhjwjOU/edit?usp=sharing\n\n操作步骤：\n1. 打开模板链接 → 文件 → 创建副本\n2. 在 Append row / Get Existing Links 两个 Google Sheets 节点选择你的副本\n3. 确认列名映射一致（日期、来源版块、痛点分类、核心痛点、提及品牌、营销切入点、情感倾向、摘要、链接）\n\n## 5. （可选）配置 Slack 负面预警\n\n在 Check Brand Negative 节点填写你的品牌名，连接 Slack 凭证。\n\n---\n\n## 工作流程概述\n\n本流程定时从 Reddit subreddit 抓取新帖子，经 AI 提取摘要、痛点分类和内容角度，写入 Google 表格。Gatekeeper 节点负责去重和噪声过滤。\n\n详细说明：https://sufob.com/blog/n8n-reddit-pain-point-monitor",
        "height": 960,
        "width": 768
      },
      "id": "beae8600-52a3-4b55-a405-c5b0b07a72c9",
      "name": "Setup Guide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [-1440, 32],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "## 配置 subreddit 和关键词\n\n默认示例：假发 / hair system 品类\n\n换品类时复制节点并修改",
        "height": 848,
        "width": 160
      },
      "id": "2f37f089-dd35-4bb6-9aed-8a23cc2df4cb",
      "name": "Note: Reddit Sources",
      "type": "n8n-nodes-base.stickyNote",
      "position": [-304, -48],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "## AI 分析：提取痛点和内容角度",
        "height": 352,
        "width": 272
      },
      "id": "0d26685f-fef5-4ff5-80cb-9f468c2b7b89",
      "name": "Note: AI Analysis",
      "type": "n8n-nodes-base.stickyNote",
      "position": [320, 352],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "## 写入 Google 表格选题库",
        "height": 352,
        "width": 192
      },
      "id": "1c6046b2-97eb-4bde-b30f-964573e269a0",
      "name": "Note: Google Sheets",
      "type": "n8n-nodes-base.stickyNote",
      "position": [848, 288],
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1lRjSCTaPpkzs79YacCJdVwT-VjeVTWi4Qe3grhjwjOU",
          "mode": "list",
          "cachedResultName": "hair system reddit 痛点收集-demo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1lRjSCTaPpkzs79YacCJdVwT-VjeVTWi4Qe3grhjwjOU/edit?usp=sharing"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "工作表1"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "链接": "={{ $('Gatekeeper').item.json.permalink }}",
            "来源版块": "={{ $('Gatekeeper').item.json.subreddit }}",
            "痛点分类": "={{ $json.output.pain_category }}",
            "核心痛点": "={{ $json.output.core_pain_point }}",
            "提及品牌": "={{ $json.output.brand_mentioned }}",
            "营销切入点": "={{ $json.output.marketing_angle }}",
            "情感倾向": "={{ $json.output.sentiment }}",
            "摘要": "={{ $json.output.summary }}",
            "日期": "={{ $now.format('yyyy-MM-dd') }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "日期",
              "displayName": "日期",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "来源版块",
              "displayName": "来源版块",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "痛点分类",
              "displayName": "痛点分类",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "核心痛点",
              "displayName": "核心痛点",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "提及品牌",
              "displayName": "提及品牌",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "营销切入点",
              "displayName": "营销切入点",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "情感倾向",
              "displayName": "情感倾向",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "摘要",
              "displayName": "摘要",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "链接",
              "displayName": "链接",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "useAppend": true
        }
      },
      "id": "e6c09f1a-c8ce-4c28-b389-fac3b32b45de",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [1296, 544],
      "typeVersion": 4.7
    },
    {
      "parameters": {
        "operation": "search",
        "subreddit": "HairSystem",
        "keyword": "hair system",
        "limit": 20,
        "additionalFields": {
          "sort": "new"
        }
      },
      "id": "d139312a-a190-4c2e-92d8-1efedd486a4f",
      "name": "r/HairSystem",
      "type": "n8n-nodes-base.reddit",
      "position": [-272, 256],
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "search",
        "subreddit": "tressless",
        "keyword": "considering system",
        "limit": 20,
        "additionalFields": {
          "sort": "new"
        }
      },
      "id": "2f1b56ea-c9b7-4c12-99cb-8934d0e9d03a",
      "name": "r/tressless",
      "type": "n8n-nodes-base.reddit",
      "position": [-272, 448],
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "search",
        "subreddit": "bald",
        "keyword": "hair system",
        "limit": 20,
        "additionalFields": {
          "sort": "new"
        }
      },
      "id": "bd351525-d94f-473a-8d2e-1b6e886474d7",
      "name": "r/bald",
      "type": "n8n-nodes-base.reddit",
      "position": [-272, 640],
      "typeVersion": 1
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "1lRjSCTaPpkzs79YacCJdVwT-VjeVTWi4Qe3grhjwjOU",
          "mode": "list",
          "cachedResultName": "hair system reddit 痛点收集-demo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1lRjSCTaPpkzs79YacCJdVwT-VjeVTWi4Qe3grhjwjOU/edit?usp=sharing"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "工作表1"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [-48, 784],
      "id": "ee978c45-4212-490f-8b9a-737073aa5b6a",
      "name": "Get Existing Links"
    },
    {
      "parameters": {
        "jsCode": "// ================= 配置区域 =================\nconst SHEET_LINK_COLUMN_NAME = '链接';\nconst BLACKLIST_KEYWORDS = [\n  'bios', 'gpu', 'cpu', 'motherboard', 'minisforum', 'ryzen',\n  'deadlift', 'squat', 'gym',\n  'itch.io', 'indie game', 'ps5', 'xbox'\n];\n\n// ================= 逻辑区域 =================\n\nconst allItems = items;\nconst existingLinks = new Set();\nconst redditPosts = [];\n\nfor (const item of allItems) {\n  const json = item.json;\n\n  if (json[SHEET_LINK_COLUMN_NAME]) {\n    const link = json[SHEET_LINK_COLUMN_NAME];\n    if (link) existingLinks.add(link.trim());\n  } else if (json.subreddit) {\n    redditPosts.push(item);\n  }\n}\n\nconst uniqueAndCleanPosts = [];\n\nfor (const item of redditPosts) {\n  const post = item.json;\n  const fullLink = post.url || `https://www.reddit.com${post.permalink}`;\n\n  if (existingLinks.has(fullLink)) {\n    continue;\n  }\n\n  const title = post.title || '';\n  const body = post.text || post.selftext || '';\n  const fullText = (title + ' ' + body).toLowerCase();\n\n  const isSpam = BLACKLIST_KEYWORDS.some(keyword => fullText.includes(keyword));\n  if (isSpam) {\n    continue;\n  }\n\n  uniqueAndCleanPosts.push({\n    json: {\n      title: title,\n      subreddit: post.subreddit,\n      text: body.length > 1500 ? body.substring(0, 1500) + '...' : body,\n      permalink: fullLink,\n      created_utc: post.created_utc\n    }\n  });\n}\n\nreturn uniqueAndCleanPosts;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [400, 544],
      "id": "b4b62060-aa48-407f-ade4-fafad275f7be",
      "name": "Gatekeeper"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [176, 544],
      "id": "b17d42d8-f643-4abe-8aad-be36344da054",
      "name": "Merge With History"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [624, 544],
      "id": "d77245c8-98a5-4dcb-9f20-3471baac1ea7",
      "name": "Loop Over Items"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [1968, 720],
      "id": "a2f07c4f-19e0-4273-990e-2717ef1d3006",
      "name": "Wait"
    },
    {
      "parameters": {
        "model": "meta-llama/llama-3.3-70b-instruct",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [928, 976],
      "id": "bfc6b0b1-fc5d-4fb2-b701-8eb4c1e32cc0",
      "name": "OpenRouter Chat Model"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "f1a4511f-0204-4d37-8715-8f5cb9c4ee5c",
              "leftValue": "={{ $json.output.brand_mentioned }}",
              "rightValue": "YOUR_BRAND_NAME",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            },
            {
              "id": "0ea7eb95-d9e1-4f93-a4ed-253f8e41224f",
              "leftValue": "={{ $json.output.sentiment }}",
              "rightValue": "Negative",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [1520, 544],
      "id": "fa9a63ec-af50-43f2-bcfe-ad44ba40462d",
      "name": "Check Brand Negative"
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "YOUR_SLACK_CHANNEL_ID",
          "mode": "id"
        },
        "text": "=🚨 **品牌负面/紧急情报预警** 🚨\n\n**核心痛点**: {{ $json.output.core_pain_point }}\n**摘要**: {{ $json.output.summary }}\n**来源**: {{ $('Gatekeeper').item.json.subreddit }}\n\n🔗 <{{ $('Gatekeeper').item.json.permalink }}|点击查看原帖>",
        "otherOptions": {}
      },
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [1744, 480],
      "id": "0d6b67d1-defc-46c3-8d7d-e4db9aeb248c",
      "name": "Send Slack Alert"
    }
  ],
  "connections": {
    "Merge Reddit Sources": {
      "main": [[{ "node": "Merge With History", "type": "main", "index": 0 }]]
    },
    "AI Agent": {
      "main": [[{ "node": "Append row in sheet", "type": "main", "index": 0 }]]
    },
    "Schedule Trigger": {
      "main": [
        [
          { "node": "r/tressless", "type": "main", "index": 0 },
          { "node": "r/HairSystem", "type": "main", "index": 0 },
          { "node": "r/bald", "type": "main", "index": 0 },
          { "node": "Get Existing Links", "type": "main", "index": 0 }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [[{ "node": "AI Agent", "type": "ai_outputParser", "index": 0 }]]
    },
    "r/tressless": {
      "main": [[{ "node": "Merge Reddit Sources", "type": "main", "index": 1 }]]
    },
    "r/bald": {
      "main": [[{ "node": "Merge Reddit Sources", "type": "main", "index": 2 }]]
    },
    "r/HairSystem": {
      "main": [[{ "node": "Merge Reddit Sources", "type": "main", "index": 0 }]]
    },
    "Get Existing Links": {
      "main": [[{ "node": "Merge With History", "type": "main", "index": 1 }]]
    },
    "Gatekeeper": {
      "main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
    },
    "Merge With History": {
      "main": [[{ "node": "Gatekeeper", "type": "main", "index": 0 }]]
    },
    "Loop Over Items": {
      "main": [
        [],
        [{ "node": "AI Agent", "type": "main", "index": 0 }]
      ]
    },
    "Append row in sheet": {
      "main": [[{ "node": "Check Brand Negative", "type": "main", "index": 0 }]]
    },
    "Wait": {
      "main": [[{ "node": "Loop Over Items", "type": "main", "index": 0 }]]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          { "node": "AI Agent", "type": "ai_languageModel", "index": 0 },
          { "node": "Structured Output Parser", "type": "ai_languageModel", "index": 0 }
        ]
      ]
    },
    "Check Brand Negative": {
      "main": [
        [{ "node": "Send Slack Alert", "type": "main", "index": 0 }],
        [{ "node": "Wait", "type": "main", "index": 0 }]
      ]
    },
    "Send Slack Alert": {
      "main": [[{ "node": "Wait", "type": "main", "index": 0 }]]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "public-v1",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
