{
  "name": "RSS → AI 摘要 → 每日摘要信",
  "nodes": [
    {
      "id": "a1",
      "name": "每天 07:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 7
            }
          ]
        }
      }
    },
    {
      "id": "a2",
      "name": "Feed 清單",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "jsCode": "// 在這裡改成你要追的 RSS\nconst feeds = [\n  \"https://www.ithome.com.tw/rss\",\n  \"https://blog.n8n.io/rss/\",\n  \"https://hnrss.org/frontpage\"\n];\nreturn feeds.map(url => ({ json: { url } }));"
      }
    },
    {
      "id": "a3",
      "name": "讀取 RSS",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.2,
      "position": [
        440,
        0
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {}
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "a4",
      "name": "篩選 24 小時內",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "parameters": {
        "jsCode": "// 只留最近 HOURS 小時內、去重、取最新 MAX_ITEMS 則，並組成一段給 AI 的文字\nconst HOURS = 26;\nconst MAX_ITEMS = 15;\nconst cutoff = Date.now() - HOURS * 3600 * 1000;\nconst seen = new Set();\nconst items = [];\nfor (const it of $input.all()) {\n  const j = it.json;\n  if (!j.link || seen.has(j.link)) continue;\n  const t = Date.parse(j.isoDate || j.pubDate || '');\n  if (!t || t < cutoff) continue;\n  seen.add(j.link);\n  const snippet = String(j.contentSnippet || j.content || '').replace(/\\s+/g, ' ').slice(0, 400);\n  items.push({ title: j.title || '(無標題)', link: j.link, time: t, snippet });\n}\nitems.sort((a, b) => b.time - a.time);\nconst top = items.slice(0, MAX_ITEMS);\nif (top.length === 0) return [];   // 沒新文章就停在這裡，不叫 AI、不寄信\nconst digestInput = top.map((x, i) => `[${i + 1}] ${x.title}\\n${x.snippet}\\n${x.link}`).join('\\n\\n');\nreturn [{ json: { count: top.length, items: top, digestInput } }];"
      }
    },
    {
      "id": "a5",
      "name": "AI 寫摘要",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        880,
        0
      ],
      "parameters": {
        "promptType": "define",
        "text": "=你是幫一人副業經營者整理資訊的助理。以下是過去一天的新文章（含編號、標題、摘要片段、連結）。\n請用台灣繁體中文：\n1. 先給 3 行「今天最值得看的事」。\n2. 再把文章分成 2～4 類，每則一句話重點，句尾標註原編號，例如 [3]。\n3. 不要編造原文沒有的資訊；看不出重點就寫「片段不足」。\n\n{{ $json.digestInput }}"
      }
    },
    {
      "id": "a6",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        880,
        220
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "gpt-6-luna"
        },
        "options": {
          "maxTokens": 1500,
          "temperature": 0.3
        }
      }
    },
    {
      "id": "a7",
      "name": "組信件 HTML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        0
      ],
      "parameters": {
        "jsCode": "// 把 AI 摘要和原始連結組成 HTML 信件\nconst esc = s => String(s).replace(/[&<>\"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]));\nconst summary = $json.text || '';\nconst src = $('篩選 24 小時內').first().json.items;\nconst today = new Date().toLocaleDateString('zh-TW', { timeZone: 'Asia/Taipei' });\nconst html = `<h2>每日摘要 ${today}</h2>`\n  + `<div style=\"white-space:pre-wrap;line-height:1.7\">${esc(summary)}</div>`\n  + `<h3>原文連結</h3><ol>` + src.map(x => `<li><a href=\"${esc(x.link)}\">${esc(x.title)}</a></li>`).join('') + `</ol>`;\nreturn [{ json: { subject: `每日摘要 ${today}（${src.length} 則）`, html } }];"
      }
    },
    {
      "id": "a8",
      "name": "寄出摘要信",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1320,
        0
      ],
      "parameters": {
        "fromEmail": "digest@example.com",
        "toEmail": "you@example.com",
        "subject": "={{ $json.subject }}",
        "emailFormat": "html",
        "html": "={{ $json.html }}",
        "options": {}
      },
      "webhookId": "00000000-0000-4000-8000-000000000008"
    }
  ],
  "connections": {
    "每天 07:00": {
      "main": [
        [
          {
            "node": "Feed 清單",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Feed 清單": {
      "main": [
        [
          {
            "node": "讀取 RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "讀取 RSS": {
      "main": [
        [
          {
            "node": "篩選 24 小時內",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "篩選 24 小時內": {
      "main": [
        [
          {
            "node": "AI 寫摘要",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI 寫摘要": {
      "main": [
        [
          {
            "node": "組信件 HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI 寫摘要",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "組信件 HTML": {
      "main": [
        [
          {
            "node": "寄出摘要信",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Asia/Taipei",
    "saveDataSuccessExecution": "none",
    "saveDataErrorExecution": "all"
  },
  "pinData": {},
  "meta": {
    "note": "一人代理實驗室 範例。匯入後需自行建立 OpenAI 與 SMTP 憑證，並修改收件人。"
  }
}