将 RSS 订阅自动整理为每日新闻简报。
读取 OPML 订阅文件 → 抓取当日文章 → (可选) LLM 逐篇提取事件、全局去重汇聚、按领域分类 → 输出 Markdown 日报,可选 HTML / PDF。
output/2026-03-21/ — 一份由关键词分类生成的日报样例(不含 LLM 摘要)。
git clone https://github.com/<your-username>/RSSAbout.git
cd RSSAboutconda env create -f environment.yaml
conda activate rssabout# 从示例文件创建本地配置
cp settings.example.yaml settings.yaml编辑 settings.yaml:
# 必填:OPML 文件路径(从你的 RSS 阅读器导出)
opml_path: "/Users/you/path/to/subscriptions.opml"
# 可选:LLM 摘要(使用环境变量传入 API Key)
llm:
enabled: true
provider: "openai"
api_base: "https://api.deepseek.com/v1" # 或其他兼容 API
api_key: "" # 留空,用环境变量
model: "deepseek-chat"
max_tokens: 4096# macOS / Linux — 写入 shell 配置,永久生效
echo 'export LLM_API_KEY=sk-your-key-here' >> ~/.zshrc
source ~/.zshrc
# 或仅当前终端临时使用
export LLM_API_KEY=sk-your-key-here永远不要把 API Key 写入 settings.yaml 并提交到 Git。 本项目通过环境变量 LLM_API_KEY(或 OPENAI_API_KEY)读取密钥。settings.yaml 已在 .gitignore 中排除。
python main.py # 默认今天
python main.py --date 2026-04-29 # 指定日期
python main.py --no-llm # 仅关键词分类,不用 LLM
python main.py --html --pdf # 同时生成 HTML 和 PDF启用 llm.enabled: true 后:
| 阶段 | 说明 |
|---|---|
| Phase 1 | 逐篇送入 LLM,提取每篇文章中的所有独立事件(一篇可能含多个事件)。每个事件含:日期、一句话摘要、各方评论/观点(附观点发表人)、项目/参考链接、信息来源 |
| Phase 2 | 汇总所有事件,LLM 进行全局去重(同一事件多报道合并)、汇聚(同事件多角度融合)、自定领域分类,输出领域→事件层级的 Markdown 日报 |
LLM 不可用时自动退回关键词分类模式,不会中断报告生成。
output/2026-04-30/
├── README.md # 日报(LLM 领域→事件 或 关键词列表)
├── README.html # HTML(--html)
├── README.pdf # PDF(--pdf)
└── articles/ # 按来源分组的单篇文章
└── 来源名/
└── uid-标题.md
所有兼容 OpenAI API 的服务,修改 api_base + model 即可:
| 服务 | api_base | model 示例 |
|---|---|---|
| DeepSeek | https://api.deepseek.com/v1 |
deepseek-chat |
| 通义千问 | https://dashscope.aliyuncs.com/compatible-mode/v1 |
qwen-plus |
| Moonshot | https://api.moonshot.cn/v1 |
moonshot-v1-8k |
| OpenAI | https://api.openai.com/v1 |
gpt-4o-mini |
| Anthropic | 原生支持,设 provider: "anthropic" |
claude-sonnet-4-6 |
如果你通过 GitHub Actions 定时运行,在仓库 Settings → Secrets and variables → Actions 中添加 LLM_API_KEY,workflow 中通过 ${{ secrets.LLM_API_KEY }} 引用,不会暴露在日志或代码中。
cat > ~/Library/LaunchAgents/com.rssabout.daily.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.rssabout.daily</string>
<key>EnvironmentVariables</key>
<dict>
<key>LLM_API_KEY</key>
<string>sk-your-key-here</string>
</dict>
<key>ProgramArguments</key>
<array>
<string>/path/to/RSSAbout/run.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>8</integer>
<key>Minute</key><integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/tmp/rssabout.log</string>
<key>StandardErrorPath</key>
<string>/tmp/rssabout.err</string>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.rssabout.daily.plist0 8 * * * LLM_API_KEY=sk-... /path/to/RSSAbout/run.shRSSAbout/
├── settings.example.yaml # 配置模板(可提交)
├── settings.yaml # 本地配置(gitignore,不提交)
├── environment.yaml # Conda 环境
├── main.py # 入口
├── run.sh # 便捷运行
├── src/
│ ├── config.py # 配置加载
│ ├── opml_parser.py # OPML 解析 (xml.etree)
│ ├── rss_fetcher.py # RSS 并发抓取
│ ├── classifier.py # 关键词分类(LLM fallback)
│ ├── llm_summarizer.py # LLM 两阶段流水线
│ ├── report_generator.py # 报告生成 (MD / HTML / PDF)
│ ├── converter.py # MD → HTML / PDF
│ └── interfaces.py # 预留扩展接口
├── output/ # 日报(gitignore)
└── data/ # 运行时元数据(gitignore)
MIT