eiler2005/reddit-compass

GitHub: eiler2005/reddit-compass

一个 AI 驱动的多源趋势监测雷达,自动收集 21 个信息源的内容并通过 Qwen LLM 提取趋势情报,以 REST API 和仪表板提供服务。

Stars: 0 | Forks: 0

# 🧭 reddit-compass [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Python 3.12](https://img.shields.io/badge/Python-3.12-green.svg)](https://www.python.org/) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/eiler2005/reddit-compass/actions) [![Docker](https://static.pigsec.cn/wp-content/uploads/repos/cas/fe/fefca86bf4776b6db9e2a57c7ed9357a6027d1c95ae8ccea29596796f1e9a62e.svg)](https://github.com/eiler2005/reddit-compass/actions) **你的广域趋势探测雷达。12 个稳定领域,多源证据,一个指南针。** 你正在写一本关于 AI 如何改变工作的书。或者在运营一个专栏。又或者正在开发一款产品,需要知道市场*真正*的想法——而不是新闻稿里说的那些。 所以你查看 Reddit。接着是 Hacker News。然后是 NYT。接着是 Wired。然后是 FT。接着是 TechCrunch。然后是 Medium。再是 ProductHunt。每。一。天。早。晨。 这是喝第一杯咖啡前长达 45 分钟的切换标签页时间。而且你*仍然*会错过凌晨 2 点爆火的帖子——那个有 400 名被裁工程师准确描述了你的产品正在解决的痛点的帖子。 **reddit-compass 为你完成这些。每天晚上。广域雷达(Broad Radar)监控全球动态;AI 原生透镜(AI-native Lens)** 让书籍/RBC 的研究专注于 AI、工作、机构和市场。** ## reddit-compass 能为你做什么 ### 每天晚上,自动运行 在 Qwen 折扣窗口运行(**17:00–03:00 莫斯科时间 = 14:00–00:00 UTC**),因此 LLM 分析使用更便宜的非高峰费率。 | 时间 (UTC / MSK) | 发生了什么 | 你为何需要关注 | |---|---|---| | 14:00 / 17:00 | 来自 BBC、Guardian、Reuters、TechCrunch、Verge、Ars 的 227 篇文章 (RSS) | 主流叙事——大众明天会听到什么 | | 14:10 / 17:10 | 来自 Hacker News 的 197 个故事 (Algolia API,过去 7 天) | 开发者正在构建什么以及在争论什么 | | 14:20 / 17:20 | 来自 NYT、WaPo、FT、Wired、Medium 及其他 7 家的 183 篇文章 (Ladder 付费墙代理) | 付费墙背后的*真正*分析 | | 14:30 / 17:30 | 来自 ProductHunt 的 30 款产品 (GraphQL) | 现在正在发布什么 | | 独立运行 | Collector 在 `compass.db` 中敲定原始事实 | 收集状态不依赖于 LLM | | 手动/影子模式 | 带版本控制的 Engine 运行 facets → stories → trends | 无需重新收集即可重复分析 | 你醒来时看到的报告会这样显示: ### 当你向它提问时 ``` reddit-compass collect --profile broad --sources reddit,hn,rss,ladder,ph reddit-compass engine release create --run RUN_ID reddit-compass engine facets --release RELEASE_ID --profile broad reddit-compass engine stories propose --facet-release FACET_ID --limit 50 reddit-compass engine trends propose --story-release STORY_ID --window 30d reddit-compass fetch --stealth # Reddit: 40 subreddits, stealth mode reddit-compass hn # Hacker News: AI stories reddit-compass rss # RSS: 6 free sources reddit-compass ladder # Paywall: 12 sources via Ladder reddit-compass ph # ProductHunt: top products reddit-compass signals # LLM analysis (Qwen API, all sources) reddit-compass serve # REST API + UI on :8900 reddit-compass db rebuild # Только legacy recovery, не Engine workflow reddit-compass db stats # SQLite history reddit-compass fetch --dry-run # Preview without network ``` ### 设计上它不会做的事 已写入 [`AGENTS.md`](AGENTS.md)。该服务在架构上拒绝: - 在 Reddit 上**发帖、投票或评论**。(只读。永远如此。) - **绕过账号封禁**或冒充用户。(代理仅用于速率限制。) - 使用收集的内容**训练 ML 模型**。(明确禁止。) - 在 git、日志或 API 响应中**泄露机密**。(detect-secrets 提交前门禁。) - **触碰 VPS 上的其他服务**。(隔离的网络 + 数据卷。) ## 架构 ``` 🌐 Reddit packs 💬 Hacker News 📰 RSS sections 🪜 Ladder optional 🚀 ProductHunt Playwright + JSON Algolia front/search aiohttp + XML fallback GraphQL API │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────────────────────┐ │ two independent runtimes in one repository │ │ │ │ Collector → compass.db ──read-only snapshot──► Trend Engine → publication → Radar/Today │ └─────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ JSONL snapshots compass.db trend_engine.db REST API :8900 (exchange format) (raw facts) (immutable versions) (FastAPI + OAuth2) ``` **数据源 → 5 个数据源集群 → 12 个宽泛领域 → stories/trends → Today + Radar** 收集和分析是独立的运行时。`collect` 将原始事实写入 `compass.db`; 带版本控制的 Engine 将它们冻结到 `trend_engine.db` 中。Radar 仅读取手动发布的 Story/Trend 组合,因此收集失败或实验性尝试无法抹除上一次 经过验证的 dashboard。 包含部署图的完整架构:[`ARCHITECTURE.md`](ARCHITECTURE.md) ## 数据源与领域 默认收集配置为 [`config/profiles/broad.json`](config/profiles/broad.json): AI/技术、劳动力/职业、商业/市场、社会/政治、世界/地缘政治、 文化/媒体、体育、科学/健康/教育、金融/消费、 气候/能源/基础设施、安全/隐私,以及 `other`。 | 集群 | 数据源 | 访问方式 | |---|---|---| | **Mainstream** | BBC, Guardian, NYT/WaPo/USA Today via RSS/Google News;可选 Ladder | RSS + Ladder 降级方案 | | **Business** | Reuters, FT, Fox Business, American Banker | RSS + Ladder 降级方案 | | **Tech/Culture** | TechCrunch, Verge, Ars Technica, Wired, New Yorker, Vanity Fair | RSS + Ladder 降级方案 | | **Voices** | Reddit 宽泛包,Medium | 公开的 JSON/RSS + Ladder 降级方案 | | **Developers / Pulse** | Hacker News, ProductHunt | Algolia + GraphQL/feed | 实现说明:[`docs/RADAR_TRENDWATCHING_IMPLEMENTATION.md`](docs/RADAR_TRENDWATCHING_IMPLEMENTATION.md)。 Prompt 契约:[`docs/RADAR_PROMPTS.md`](docs/RADAR_PROMPTS.md)。 完整数据源映射:[`docs/MULTI_SOURCE_PLAN.md`](docs/MULTI_SOURCE_PLAN.md) ## 快速开始 ### 前置条件 - Python 3.12+,[`uv`](https://docs.astral.sh/uv/) - Playwright:`uv run playwright install chromium` - (可选)用于 VPS 部署的 Docker ### 安装 ``` git clone https://github.com/eiler2005/reddit-compass.git cd reddit-compass uv sync ``` ### 首次运行 ``` # 预览将要收集的内容(无网络): uv run reddit-compass fetch --dry-run # 收集 Reddit 帖子: uv run reddit-compass fetch # 收集所有内容(Reddit + HN + RSS): uv run reddit-compass all # 启动 API: uv run reddit-compass serve # → http://localhost:8900/docs (Swagger UI) ``` ### 可选的 Reddit 住宅代理 在 `.env.secrets` 中将 `REDDIT_COMPASS_PROXIES` 设置为提供商分配的 HTTP 代理 URL(占位符格式请参见 `.env.example`)。Reddit 的引导请求 和公开的 `.json` 列表/评论请求随后将使用该代理;如果 HTTP 客户端 收到 HTML 或 HTTP 403,Playwright 降级方案将通过 同样配置的代理启动 Chromium。请求间隔保持在 4 秒,最多进行两次 429 重试,间隔为 10 秒。代理仅用于缓解速率限制 — 绝不用于账号封禁、登录、发帖、投票或评论。 对于轮换住宅 IP 池(例如 IPRoyal),请设置 `REDDIT_COMPASS_ENGINE=playwright`: Reddit 会向完整的浏览器流量提供 `.json` 数据,但经常以 403 拒绝来自 IP 池的纯 HTTP 请求(已于 2026-07-27 验证)。如果提供商提供 粘性会话 endpoint(约 20 分钟内使用相同的出口 IP),请优先使用它 — 每次连接都 进行 IP 轮换会导致短暂的 `Failed to fetch` 错误(浏览器引擎会 自动重试)。 凭据只能保存在 `.env.secrets`(已 gitignored)中;切勿提交或记录它们。 用于其他已批准的公开只读数据源的可选本地代理,仅记录在 gitignored 的运维笔记和机密文件中;切勿将其移动到受版本控制的 配置或 `REDDIT_COMPASS_PROXIES` 中。 ### 夜间自动化 **VPS**(RSS, HN, Ladder, PH, LLM, radar)— 在 Qwen 折扣窗口内使用主机 cron (14:00–15:30 UTC = 17:00–18:30 MSK)。详见 [`deploy/hostkey/README.md`](deploy/hostkey/README.md)。 **Reddit**(住宅 IP)— 从 Mac 上收集(Reddit 会封锁数据中心 IP), 然后同步到 VPS。夜间的 `scripts/fetch-and-sync.sh`(由 launchd 运行,03:17)会交替 路由以避免耗尽家庭 IP:偶数天 — 直接使用家庭 IP,奇数天 — 使用 带有 `REDDIT_COMPASS_ENGINE=playwright` 的 IPRoyal 住宅代理(代理来自 gitignored 的 `deploy/hostkey/.env.secrets`)。使用 `RC_PROXY_MODE=on|off` 强制指定路由: ``` ./scripts/fetch-and-sync.sh # fetch + sync (route chosen automatically) RC_PROXY_MODE=on ./scripts/fetch-and-sync.sh --fetch # force proxy route # 手动替代方案: uv run reddit-compass fetch --stealth # collect on Mac (~11 min) scp data/snapshots/$(date +%F)/posts.jsonl deploy@VPS:/tmp/ ssh deploy@VPS "docker cp /tmp/posts.jsonl rc-api:/data/snapshots/$(date +%F)/" ``` ### VPS 部署 ``` ./deploy/hostkey/deploy.sh # 部署:API (FastAPI) + Caddy (reverse proxy) + 批量收集器 # → http://VPS_IP:8900/health ``` ## API OAuth2 客户端凭据 → JWT。针对外部使用者配置了 CORS。 ``` # 获取 token: curl -X POST http://localhost:8900/oauth/token \ -H "Content-Type: application/json" \ -d '{"client_id":"practicum","client_secret":""}' # 查询帖子: curl -H "Authorization: Bearer " \ "http://localhost:8900/api/v1/posts?date=2026-07-22&subreddit=artificial&limit=10" ``` | Endpoint | 认证 | 描述 | |---|---|---| | `GET /health` | — | 存活探针 | | `GET /dashboard` | — | HTML 仪表板(编辑风格) | | `GET /docs` | — | Swagger UI | | `POST /oauth/token` | — | 客户端凭据 → JWT | | `GET /api/v1/snapshots` | Bearer | 列出快照日期 | | `GET /api/v1/posts` | Bearer | 带有过滤和分页的帖子 | | `GET /api/v1/signals` | Bearer | LLM 提取的信号 | | `GET /api/v1/stats` | Bearer | 聚合统计信息 | ## LLM 分析 (Qwen API) 不仅仅是收集——而是**情报**。分析**所有可用数据源** (Reddit, HN, RSS, Ladder, ProductHunt)——即使没有 Reddit 数据也能工作。 ``` export QWEN_TOKEN_PLAN_KEY=sk-... # QwenCloud: https://home.qwencloud.com/api-keys uv run reddit-compass signals ``` 对于每个帖子,LLM 会提取: - **痛点** — 人们描述了什么问题 - **购买意向** — 是否有人正在寻找购买 AI 产品的机会? - **业务相关性** (1–10) — 与企业级 AI 的相关程度 - **书籍相关性** (1–10) — 与叙事内容的相关程度 - **主题** — 关键话题(每个帖子 1–3 个) 然后进行综合:**前 5 大深度主题**(含解释)、**3 个专栏想法**、 **叙事转变**、**按书籍相关性排名前 10**、**所有痛点**。 ### 模型金字塔(价格 / 质量) | 任务 | 模型 | 原因 | |---|---|---| | **综合**(主题、专栏想法、叙事转变) | `qwen3.8-max-preview` | 复杂任务,调用次数少,可享 17:00–03:00 MSK 的非高峰折扣 | | **分类**(每个帖子的痛点、相关性) | `qwen3.7-plus` | 量大,价格/质量均衡 | | **简单任务**(过滤、总结) | `qwen3.6-flash` | 最便宜 | ## Dashboard 与趋势雷达 三种模式,三种场景: | 视图 | URL | 目的 | |---|---|---| | **Today** | `/today` | 晨间简报:3–5 项变动,阅读推荐,工作进展 | | **News** | `/news` | 已发布 Data Release 的原始收件箱:材料、数据源、板块、相关 story | | **Stories** | `/stories` | 带有 evidence items 的具体事件;非原始新闻也非趋势 | | **Trends** | `/trends` | 基于多个 stories 的重复性模式 | | **Pulse** | `/pulse` | Reddit 原生社区信号:sub 内的百分位、速度、讨论深度、缺口 | | **Radar** | `/radar` → `/runs/{date}/radar` | 完整的分析工作区:landscape、shelves、coverage、项目面板 | | **Project Lens** | `/projects/rbc`, `/projects/book` | 基于已发布 stories/trends 的书籍/RBC/商业视角 | | **Explore** | `/explore` | 兼容旧版 projection 的遗留搜索 | | **Story 详情** | `/stories/{id}` | 已发布的 Engine story evidence;如有需要会降级到遗留详情页 | | **Trend 详情** | `/trends/{id}` | 已发布的 trend pattern、成员 stories 和 evidence | | **Runs** | `/runs` | 包含真实数量的运行历史 | 遗留版本(仅一个过渡版本):`/legacy/dashboard`, `/legacy/runs/{date}/radar` ### 带版本控制的 Story/Trend Engine 为了实现无需 full rebuild 的迭代,使用了 `trend_engine.db`:完整的 frozen Data Releases, 独立的 Facet/Story/Trend 尝试,Golden Set,仅针对灰度地带的 Qwen-review 以及原子化的 发布指针。 已发布的分析被明确拆分为 `News → Stories → Trends → Project Lens`。 参见 [`docs/NEWS_STORIES_TRENDS.md`](docs/NEWS_STORIES_TRENDS.md)。端到端的收集和 分析血缘记录在 [`docs/COLLECTOR_TO_TRENDS_FLOW.md`](docs/COLLECTOR_TO_TRENDS_FLOW.md)。 已发布的 Radar 包含一个链接这些层的驾驶舱(cockpit)部分。 ``` reddit-compass engine release create --run 2026-07-29:broad reddit-compass engine facets --release RELEASE_ID --profile broad reddit-compass engine embeddings --release RELEASE_ID --model lexical-hash-v1 reddit-compass engine stories propose \ --facet-release FACET_ID \ --limit 50 \ --embedding-model lexical-hash-v1 \ --dense-top-k 24 \ --dense-threshold 0.55 reddit-compass engine stories inspect --story-release STORY_ID reddit-compass engine reddit-pulse propose \ --release RELEASE_ID \ --date 2026-07-29 \ --profile broad \ --story-release STORY_ID reddit-compass engine experiments compare --facet-release FACET_ID --limit 300 reddit-compass engine trends propose --story-release STORY_ID reddit-compass engine publish --story-release STORY_ID --trend-release TREND_ID --channel shadow ``` `broad` 的发布受到质量门禁的限制;实验性版本仅在 `shadow` 中发布。`compass.db` 以只读模式打开;Radar 仅已发布的版本。旧的 `lab` 作为一个兼容别名保留一个版本。完整契约: [`docs/TREND_ENGINE.md`](docs/TREND_ENGINE.md). ### 设计 动感优先,暗黑科技美学(根据 Awwwards 的描述:icreon-digital-velocity)。 两种主题:暗色(默认)+ 亮色切换。排版:Space Grotesk / Inter / JetBrains Mono。 Scroll-reveal,hover lift + glow,count-up KPI,环境背景。 ### 故事卡片 Title → 直接跳转至最重要的数据源(主要证据)。 排名:content_scope(full > excerpt > abstract > headline)× 集群权重。 旁边的 📋 → 带有时间线和 evidence matrix 的完整故事。 集群:🗣 Voices,💻 Developers,📰 Mainstream,💰 Business,Tech/Culture,🚀 Products。 ``` http://127.0.0.1:8900/today # утренний бриф http://127.0.0.1:8900/radar # полный Radar http://127.0.0.1:8900/explore # поиск + фильтры http://127.0.0.1:8900/explore?date=2026-07-28&profile=broad&pain=security+breach http://127.0.0.1:8900/legacy/dashboard # legacy ``` 认证:Basic Auth(凭据位于 `.env.secrets`),Let's Encrypt TLS。 ## 安全模型 | 层级 | 机制 | |---|---| | **机密** | `.env.secrets` (gitignored) + `detect-secrets` 提交前检查 | | **API 认证** | OAuth2 客户端凭据 → JWT (1小时过期) | | **网络** | 仅限 Loopback,Caddy 反向代理 | | **容器** | `read_only`, `no-new-privileges`, `cap_drop: ALL` | | **Reddit** | 只读,速率受限,仅限公开数据 | | **Git** | 每次提交进行机密扫描,禁止 `--no-verify` | 完整规则:[`AGENTS.md`](AGENTS.md) ## 文档 | 文档 | 主题 | |---|---| | [`ARCHITECTURE.md`](ARCHITECTURE.md) | 包含图表的完整系统架构 | | [`ROADMAP.md`](ROADMAP.md) | 阶段 2–6,状态 | | [`docs/MULTI_SOURCE_PLAN.md`](docs/MULTI_SOURCE_PLAN.md) | 21 个数据源,5 个集群 | | [`docs/COLLECTOR_TO_TRENDS_FLOW.md`](docs/COLLECTOR_TO_TRENDS_FLOW.md) | 从数据源收集到 News、Stories、Trends 和 Radar 的文本图表 | | [`docs/DATA_FLOW_DIAGRAMS.md`](docs/DATA_FLOW_DIAGRAMS.md) | Mermaid 图表:Reddit → stories → trends → Reddit Pulse → 发布 | | [`docs/ENGINE_REVIEW_V3.md`](docs/ENGINE_REVIEW_V3.md) | Engine v3 审查 + 阶段 1–8 计划及实施状态 | | [`docs/TREND_ENGINE.md`](docs/TREND_ENGINE.md) | 规范的不可变 Engine 工作流、门禁和回滚 | | [`docs/CLUSTER_LAB.md`](docs/CLUSTER_LAB.md) | 已弃用的 Cluster Lab 兼容指南 | | [`docs/STORY_TREND_CLUSTERING_RESEARCH.md`](docs/STORY_TREND_CLUSTERING_RESEARCH.md) | 基于研究的 story/trend 聚类路线图 | | [`docs/COMPETITIVE_ANALYSIS.md`](docs/COMPETITIVE_ANALYSIS.md) | GitHub 全景,Ladder | | [`docs/IMPROVEMENTS.md`](docs/IMPROVEMENTS.md) | 排名后的改进计划 | | [`CHANGELOG.md`](CHANGELOG.md) | 保持更新日志 | | [`AGENTS.md`](AGENTS.md) | LLM 代理契约 | ## 技术栈 | 层级 | 技术 | |---|---| | 语言 | Python 3.12,严格模式的 mypy | | 收集 | Playwright, aiohttp, Ladder 代理 | | 存储 | JSONL + SQLite | | LLM | Qwen API — 金字塔结构:qwen3.8-max-preview / qwen3.7-plus / qwen3.6-flash | | API | FastAPI + uvicorn + JWT | | 部署 | Docker + Caddy + host-cron | | 质量 | ruff, 严格模式的 mypy, pytest (84%), detect-secrets | | CI/CD | GitHub Actions → GHCR | ## 许可证 [MIT](LICENSE) © 2026 Denis Ermilov
标签:AI, API, LLM, Python, Unmanaged PE, 无后门, 特征检测, 自动化代码审查, 请求拦截, 资讯聚合, 趋势分析