{
  "id": "WkPttMonitor04",
  "name": "PTT \u8f3f\u60c5\u76e3\u6e2c (PTT Sentiment Monitor \u00b7 \u672c\u6a5f Ollama)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 * * *"
            }
          ]
        }
      },
      "id": "node-schedule",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        240,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const board = 'Tech_Job';\nconst keyword = 'AI';\nconst url = 'https://www.ptt.cc/bbs/' + board + '/search?q=' + encodeURIComponent(keyword);\nreturn [{ json: { board, keyword, url } }];"
      },
      "id": "node-input",
      "name": "Input (edit me)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        400
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $json.url }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Cookie",
              "value": "over18=1"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
            }
          ]
        },
        "options": {}
      },
      "id": "node-fetch",
      "name": "Fetch PTT",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        680,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const j = $input.first().json;\nconst html = j.data || j.body || '';\nconst re = /<div class=\\x22title\\x22>\\s*<a href=\\x22([^\\x22]+)\\x22>([^<]+)<\\/a>/g;\nconst items = []; let m;\nwhile ((m = re.exec(html)) !== null) {\n  const title = m[2].replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').trim();\n  items.push({ title, link: 'https://www.ptt.cc' + m[1] });\n  if (items.length >= 20) break;\n}\nconst meta = $('Input (edit me)').first().json;\nconst list = items.map((n, i) => (i + 1) + '. ' + n.title).join('\\n');\nconst prompt = '\u4ee5\u4e0b\u662f PTT\u300c' + meta.board + '\u300d\u7248\u641c\u5c0b\u300c' + meta.keyword + '\u300d\u7684\u6700\u65b0\u8a0e\u8ad6\u6a19\u984c\u3002\u8acb\u7528\u7e41\u9ad4\u4e2d\u6587\u6574\u7406\u6210\u8f3f\u60c5\u5831\u544a\uff1a\\n1) \u4e3b\u8981\u8a0e\u8ad6\u4ec0\u9ebc\uff082-4 \u500b\u91cd\u9ede\uff09\\n2) \u6574\u9ad4\u98a8\u5411\u8207\u60c5\u7dd2\uff08\u6b63\u9762/\u8ca0\u9762/\u4e2d\u7acb\uff0c\u4e26\u7c21\u8ff0\uff09\\n3) \u503c\u5f97\u54c1\u724c\u6ce8\u610f\u7684\u9ede\\n\\n\u6a19\u984c\u6e05\u55ae\uff1a\\n' + (list || '\uff08\u9019\u6b21\u6c92\u6293\u5230\u6a19\u984c\uff0c\u53ef\u80fd\u662f\u770b\u677f\u6216\u95dc\u9375\u5b57\u9700\u8abf\u6574\uff09');\nreturn [{ json: { count: items.length, prompt } }];"
      },
      "id": "node-parse",
      "name": "Parse PTT",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        400
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:11434/api/chat",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'qwen2.5:latest', messages: [ { role: 'system', content: '\u4f60\u662f\u53f0\u7063\u4eba\uff0c\u4e00\u5f8b\u4f7f\u7528\u53f0\u7063\u7e41\u9ad4\u4e2d\u6587\u8207\u53f0\u7063\u6163\u7528\u8a9e\u56de\u8986\uff0c\u7d55\u5c0d\u4e0d\u8981\u51fa\u73fe\u4efb\u4f55\u7c21\u9ad4\u5b57\u6216\u4e2d\u570b\u7528\u8a9e\u3002' }, { role: 'user', content: $json.prompt } ], stream: false }) }}",
        "options": {
          "timeout": 180000
        }
      },
      "id": "node-ollama",
      "name": "Summarize with Ollama",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1120,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nlet summary = '';\ntry { summary = (data.message && data.message.content) || (data.content && data.content[0] && data.content[0].text) || data.response || ''; } catch (e) {}\nif (!summary) summary = JSON.stringify(data);\nreturn [{ json: { summary } }];"
      },
      "id": "node-extract",
      "name": "Extract Result",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        400
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://discord.com/api/webhooks/REPLACE_WITH_YOUR_WEBHOOK_URL",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ content: ('\ud83d\udde3\ufe0f PTT \u8f3f\u60c5\u5831\u544a\\n\\n' + ($json.summary || '')).slice(0, 1900) }) }}",
        "options": {}
      },
      "id": "node-discord",
      "name": "Send to Discord",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1560,
        400
      ]
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Input (edit me)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input (edit me)": {
      "main": [
        [
          {
            "node": "Fetch PTT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch PTT": {
      "main": [
        [
          {
            "node": "Parse PTT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse PTT": {
      "main": [
        [
          {
            "node": "Summarize with Ollama",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize with Ollama": {
      "main": [
        [
          {
            "node": "Extract Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Result": {
      "main": [
        [
          {
            "node": "Send to Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}