# 📰 新闻智能跟踪系统(news-tracker) 一款面向 AI 领域的**自动采集 → 智能分析 → 邮件推送**的新闻跟踪系统。后台定时从数据源采集资讯,先规则打分、再 LLM 深度分析,把与你兴趣画像相关且重要的资讯**实时发邮件提醒**,并每天 10:00 发一份**AI 资讯日报**。带完整网页管理台,兴趣画像/数据源/通知参数全部可配。 > 当前版本 **v1.4.1**:修复系统错误邮件被退信(补 Date 头)+ 数据源一键启动/停用开关(状态列直接点击)。 --- ## 系统运转流程(一张图看懂) ``` ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ 数据源 │ │ 后台调度器 │ │ 智能分析引擎 │ │ 邮件通知 │ │ sources │───▶│ scheduler │───▶│ analysis.py │───▶│ notifier.py │ │ (7个默认) │ │ (后台线程) │ │ (规则+LLM两级分析) │ │ (实时+日报) │ └──────────┘ └──────────────┘ └──────────────────┘ └─────────────────┘ 真实URL→爬虫抓取 每30分钟采集一次 规则打分→候选 LLM完成→重要度判定 crawler.py (scan_interval_min) →后台LLM深度分析 →发实时邮件 正文清洗+全文入库 每天10:00日报 →实时/日报邮件 example.com→模拟 大模型可一键切换 ``` **完整链路:** 1. **采集**(每 `scan_interval_min` 分钟,默认 30):`scheduler.collect_once()` 调 `crawler.fetch_all()`—— - 真实 URL 源:用 `requests` 抓页面 → **清洗出干净可读正文**(readability 风格,去除导航/广告/脚本)→ 提取候选资讯链接(按文章相似度排序、过滤导航词)→ 对前 5 条抓全文,**连同页面可读正文一起入库**(`articles.full_text`,详情页可查看); - `example.com` 占位源:用 `simulate.items_for_source()` 仿真数据填充,保证链路不空; - 真实源抓取失败:跳过并标记该源 `status=error`(数据源页可见),**不塞模拟数据冒充**。 2. **规则打分**(立即):`analysis.analyze_article()` 对每条新资讯算**兴趣相关度**(关键词命中权重 + 领域匹配 + 关注公司命中)和**重要度启发式**(发布/融资/禁令等强信号词、金额量级、时效性、数据源权重、公司影响),得到**综合分 total_score (0-100)**。 3. **LLM 深度分析**(后台异步):规则分 ≥ `llm_threshold`(默认 60)的资讯进入 `llm_analyze()`,**使用网页激活的大模型接口**(默认 SiliconFlow,可一键切换;调用失败自动切换下一个可用接口),输出重要度 1-10、相关度、分类、一句话结论,并与规则分融合更新。 4. **实时通知**:扫描「重要 + 已分析完成 + 未通知」的资讯,综合分 ≥ `realtime_threshold`(默认 80)→ 发 **🔥 重要AI资讯实时提醒** 邮件,标记 `notified=1`。 5. **每日日报**(新闻机制,默认每天 10:00):汇总往前 `summary_window_hours`(默认 24h)内普通源综合分 ≥50 的资讯,按分排序取前 `max_summary_items`(默认 15)条发 **📰 AI资讯日报**,含领域分布统计。 6. **定制监控汇总**(定制机制,默认每天 18:00,独立时间单独配置):汇总窗口内定制源**命中推送标准**(is_important=1)的资讯发 **🎯 定制监控汇总** 邮件。 7. **历史采样**:每次采集(无论成功/失败)写入 `source_snapshots`,数据源页可查看,也可用 `/api/sources/history`、`/api/sources/articles` 提取给自动流程。 --- ## 功能特性 - 📥 **真实网页采集**:真实 URL 源自动抓取 → readability 风格清洗出干净可读正文 → **全文入库**(详情页可看),提取候选资讯链接按文章相似度排序;`example.com` 占位源走仿真数据;失败源标记 error 不造假 - 🌐 **web-capture-api 网页提取**:数据源真实网页**默认通过 web-capture-api 项目接口抓取**(反爬强、可滚动态/选 agent-browser|playwright 后端),接口地址在设置页可改;每个数据源可**单独选择获取方式**(自动 / 仅 web-capture-api / 直接抓取)并**编辑抓取参数**(抓取动作 html/text、等待时间、滚动次数、后端、高级 JSON) - 📋 **通知日志分页 + 筛选**:通知日志支持分页查看,可按**类型**(实时/新闻汇总/定制汇总/系统错误)、**状态**(成功/失败)、**关键词**搜索 - ⚠️ **系统错误邮件通知**:采集/分析/通知/汇总/系统异常自动记录并邮件通知,可设置**通知频率(冷却分钟)** 与 **静默时段**(多段/跨午夜,静默期不发、结束后自动补发) - 🧠 **两级智能分析**:规则打分秒级响应 + LLM 深度分析(重要度/相关度/分类/结论) - 🤖 **大模型接口可配置**:设置页可增删改/测试大模型接口,预置 SiliconFlow(默认)/ DeepSeek 官方 / Autodl / Local Qwen 四个,**一键切换即时生效**,激活接口失败自动切换下一个可用接口 - 🔥 **实时重要资讯邮件**:综合分达到阈值自动推送,单批最多 10 条 - 🎯 **定制监控数据源**:数据源可选「定制监控」方式——**不设权重**,填写「推送标准」后由大模型逐条判断是否达到标准,达到即实时邮件推送(页面可直接「🧪 测试推送标准」);命中推送的资讯在邮件/列表中带「🎯 定制监控命中」标识 - 🔀 **两套独立机制**:新闻监控与定制监控**完全分开**——各自的采集间隔、汇总时间/窗口/条数单独配置(设置页「定制监控机制」区块);定制源命中会单独发「🎯 定制监控汇总」邮件,不混入新闻日报 - ⏱ **每源独立采集周期**:全局有统一采集间隔(新闻30分/定制15分),每个数据源可用本源「采集周期」字段自定义覆盖(0=跟随全局) - 📜 **历史采样留档**:每次采集记录时间/条数/成功失败到 `source_snapshots`,数据源页「📜 历史采样」可查看每次快照及本源采集到的资讯;`/api/sources/history`、`/api/sources/articles` 供自动流程提取历史数据 - 📰 **每日 AI 资讯日报**:默认每天 10:00,按领域统计 + 重点资讯卡片 - 🎯 **兴趣画像管理**:关键词(带权重)、领域、关注公司,全部可在网页维护,改完一键「重新打分」 - 🔗 **数据源管理**:7 个内置数据源模板,**完整编辑**(模态框一次性改名称/类型/URL/权重/描述/监控方式/推送标准)、启停、删除;普通源带权重,定制监控源填「推送标准」 - 📊 **网页管理台**:仪表盘(总数/重要/待分析/趋势/领域分布)、资讯列表(筛选/搜索/分页)、详情页(含全文)、通知日志 - 📧 **邮件通知**:支持 plain / starttls / ssl 三种 SMTP 模式,可测试发送 - 🛠 **手动操作台**:一键采集 / 一键 LLM 分析 / 一键发日报 / 一键造数据 / 重新打分 / 测试邮件 --- ## 技术栈 - **后端**:Python 3 + Flask(threaded) - **网页采集**:优先 **web-capture-api**(agent-browser / Playwright 双后端,反爬强);直接抓取回退用 requests + BeautifulSoup/lxml(readability 风格正文清洗) - **数据库**:SQLite(原生 sqlite3,WAL 模式,无 ORM) - **大模型**:OpenAI 兼容接口,默认 SiliconFlow `deepseek-ai/DeepSeek-V4-Flash`(可一键切换,`response_format=json_object`) - **前端**:原生 HTML/CSS/JS + Jinja2 模板(无前端框架) --- ## 目录结构 ``` news-tracker/ ├── app.py # Flask 主应用:页面路由 + API(含 /api/llm 大模型接口管理) ├── config.py # 全局配置(端口/LLM/预置大模型接口/采集参数/自动化/画像/数据源模板) ├── db.py # SQLite 数据访问层(原生 sqlite3;含 llm_providers / full_text 迁移) ├── crawler.py # 真实网页采集:抓取 + readability 清洗 + 链接提取 + 全文入库 ├── scheduler.py # 后台调度器:定时采集 + 每日日报 + 实时通知扫描 ├── analysis.py # 智能分析引擎:规则打分 + LLM 深度分析(多接口自动切换) ├── simulate.py # 模拟数据源(example.com 占位源 / 真实源失败时回退) ├── notifier.py # 邮件通知(实时 / 日报 / 系统错误,含通知频率+静默时段控制) ├── start.sh # 启动/停止/状态脚本 ├── templates/ # Jinja2 页面模板 ├── static/ # 静态资源 ├── data/ # news_tracker.db(运行时生成) └── logs/ # 运行日志 + app.pid ``` --- ## 快速开始 ```bash cd works/news-tracker ./start.sh # 启动(默认端口 16100) ./start.sh status # 查看状态 ./start.sh stop # 停止 ./start.sh restart # 重启 ``` 访问:`http://<服务器IP>:16100/` > ⚠️ 端口 16100 属于外网安全组白名单区间(16001-16100),可直接公网访问。 > 首次启动自动初始化:写入默认数据源/兴趣画像/设置,并 `simulate.seed_all()` 造一批模拟资讯 + 后台跑一轮 LLM 分析。 --- ## 配置说明 所有默认值在 `config.py`,运行时可在网页「设置」页修改并持久化到数据库(网页优先级更高): ### 自动化参数(设置页) | 配置项 | 默认值 | 说明 | |--------|--------|------| | `auto_collect` | 1 | 是否自动定时采集 | | `scan_interval_min` | 30 | 采集扫描间隔(分钟) | | `realtime_threshold` | 80 | 综合分 ≥ 该值 → 实时邮件通知 | | `llm_threshold` | 60 | 规则分 ≥ 该值 → 进入 LLM 深度分析 | | `realtime_enabled` | 1 | 是否启用实时重要资讯邮件 | | `summary_enabled` | 1 | 是否启用每日汇总 | | `summary_time` | 10:00 | 每日汇总时间 | | `summary_window_hours` | 24 | 汇总窗口(往前 N 小时) | | `max_summary_items` | 15 | 汇总邮件最多条目数 | ### 邮件配置(设置页) `smtp_host` / `smtp_port` / `smtp_user` / `smtp_pass` / `smtp_mode`(plain|starttls|ssl) / `email_to` / `sender_name`。默认 `mail.tphai.com:587` plain,收件人 `wlq@tphai.com`。 ### 大模型接口(设置页,一键切换) 预置 4 个接口(`config.py` 的 `LLM_PROVIDERS_DEFAULT`,首启写入 `llm_providers` 表): | 名称 | Base URL | 模型 | |------|----------|------| | **SiliconFlow(默认激活)** | `https://api.siliconflow.cn/v1` | `deepseek-ai/DeepSeek-V4-Flash` | | DeepSeek 官方 | `https://api.deepseek.com` | `deepseek-v4-flash` | | Autodl(火山方舟中转) | `https://www.autodl.art/api/v1` | `qwen3.6-plus` | | Local Qwen(内网) | `http://121.40.164.32:18003/v1` | `unsloth/Qwen3.8-27B-Q6_K` | 设置页可**增删改/测试**任意接口,点「⚡ 切换为当前」一键切换即时生效;分析时当前接口失败会自动切换下一个可用接口。`config.py` 里的 `LLM_BASE_URL/KEY/MODEL` 仅作无激活记录时的回退。 ### 采集参数(config.py) `CRAWL_DEFAULTS`:`per_source_links`(每源最多采集条目,默认 8)、`full_fetch_links`(其中抓全文条数,默认 5)、`crawl_timeout`(单页超时,默认 20s)、`user_agent`。 ### web-capture-api(设置页) `WEBCAPTURE_DEFAULTS`:`enabled`(是否启用)、`api_url`(默认 `http://121.40.164.32:16025`,可改)、`timeout`(单次抓取超时秒)。数据源页可对每个源选**获取方式**(`auto`=优先 web-capture-api、失败回退直接抓取;`webcapture`=仅走网页提取服务;`direct`=直接抓取)并编辑**抓取参数**(`capture_params` JSON:`action` html|text、`wait_time` 等待加载 ms、`scroll_times` 滚动次数、`backend` auto|agent-browser|playwright,以及任意高级参数如 `scroll_delay`/`full_page`/`viewport`)。 ### 系统错误邮件通知(设置页) `ERRNOTIFY_DEFAULTS`:`enabled`(是否启用)、`mode`(`immediate` 立即 / `cooldown` 按冷却聚合 / `off` 关闭)、`cooldown_min`(**通知频率**:两次错误邮件最小间隔分钟,默认 60)、`quiet_enabled` + `quiet_periods`(**静默时段**,每段 `HH:MM-HH:MM`,支持多段/跨午夜,静默期不发、结束后自动补发)、`max_items`(单封最多错误条数)。错误记录在 `system_error_log` 表(同类合并计数),发送后写 `notification_log(type=error)`。 --- ## 网页页面 | 路由 | 说明 | |------|------| | `/dashboard` | 仪表盘:总资讯/重要资讯/待分析/已通知 + 近7天趋势 + 领域分布(重要资讯 TOP / 最新收录各显示最多 10 条,含「更多」链接) | | `/news` | 资讯列表:按领域/重要/关键词搜索,分页 | | `/news/` | 资讯详情:规则分/LLM分/实体/分析结论 + **页面可读全文** | | `/sources` | 数据源管理:**完整编辑**(模态框,含获取方式+抓取参数)/启停/删除,支持普通(权重)与定制监控(推送标准),每源独立采集周期,「📜 历史采样」可查看每次采样快照与本源资讯 | | `/profile` | 兴趣画像:关键词/领域/公司维护 | | `/logs` | 通知日志:**分页 + 类型/状态/关键词筛选**,支持测试邮件/测试错误通知 | | `/settings` | 设置:自动化参数(新闻机制)+ **定制监控机制(独立配置)** + **网页提取服务(web-capture-api)** + **系统错误邮件通知(频率/静默)** + 邮件配置 + **大模型接口管理(一键切换/测试)** | --- ## API | 接口 | 方法 | 说明 | |------|------|------| | `/api/stats` | GET | 统计数据(总数/重要/趋势/领域分布) | | `/api/sources` | POST | `action=add\|update\|delete\|toggle\|test_standard` 数据源管理(update 可改全部配置含采集周期;test_standard=用大模型试测推送标准) | | `/api/sources/history` | GET | `?source_id=&limit=` 数据源历史采样记录(每次采集时间/条数/状态/备注,自动流程提取用) | | `/api/sources/articles` | GET | `?source_id=&page=&page_size=&q=` 数据源历史采集到的资讯(分页/搜索,自动流程提取用) | | `/api/profile` | POST | `action=add\|delete`,`kind=keyword\|domain\|company` 画像维护 | | `/api/settings` | POST | 更新 `auto` / `mail` / `custom` / `webcapture` / `errnotify` 设置 | | `/api/llm` | POST | 大模型接口:`add\|update\|delete\|switch\|toggle\|test`(switch=一键切换) | | `/api/actions` | POST | `action=collect`(采集) `llm`(LLM分析) `summary`(发日报) `seed`(造数据) `reanalyze`(重新打分) `test_mail`(测试邮件) `test_error_mail`(测试错误通知) `test_webcapture`(测试网页提取服务) | | `/api/logs` | GET | 通知日志分页:`?page=&page_size=&type=&status=&q=` | | `/api/errors` | GET | 系统错误日志:`?limit=`(最近 N 条,含累计次数/首末次时间/通知状态) | 请求体为 JSON,如:`{"action": "collect"}`、`{"action": "llm", "limit": 10}`。 --- ## 数据模型 - **sources**:数据源(name/type/url/weight/**kind**/**monitor_standard**/**scan_interval_min**/**fetch_method**/**capture_params**/enabled/status/last_fetch/last_count;`kind`=normal 普通按权重打分 / custom 定制监控按推送标准 LLM 判断;`monitor_standard`=定制监控的推送标准说明;`scan_interval_min`=本源采集间隔分钟数,0=跟随所属机制全局值;`fetch_method`=auto 优先 web-capture-api 失败回退直接抓取 / webcapture 仅走网页提取服务 / direct 直接抓取;`capture_params`=web-capture-api 抓取参数 JSON;status 标记真实源采集 ok/error) - **source_snapshots**:历史采样记录(source_id/fetched_at/count/status/detail,每次采集留档) - **articles**:资讯(title/url/content/summary/**full_text(页面可读全文)**/domain/entities/importance/relevance/total_score/is_important/analysis/llm_status/notified/status/published_at/collected_at) - **keywords** / **domains** / **companies**:兴趣画像 - **llm_providers**:大模型接口(name/base_url/api_key/model/active/enabled;active=当前激活) - **notification_log**:邮件通知日志(type:realtime / summary / custom_summary / error) - **system_error_log**:系统错误日志(source/message/detail/count/pending/first_seen/last_seen/last_notified/notified_count,同类错误合并计数,pending=待通知) - **settings**:KV 配置(`auto` / `mail` / `custom` / `webcapture` / `errnotify` 为 JSON) `llm_status`:`pending`(待分析) → `done`(完成) / `skipped`(未达标跳过) / `error`(失败) **采集调度**:`scheduler.collect_once()` 按**每源独立周期**采集(本源 `scan_interval_min` > 0 用本源值,否则普通源用 `scan_interval_min`、定制源用 `custom_scan_interval_min`);调度循环 30s 轮询到期源。新闻源受 `auto_collect` 控制、定制源受 `custom_enabled` 控制,互不影响。手动「立即采集」忽略周期全量采集。 **定制监控(kind=custom)**:无权重(规则打分时权重项按 0 处理,仅作展示);采集后**无条件进入 LLM 分析**(不受 `llm_threshold` 限制),LLM 按该源的 `monitor_standard`(推送标准)判断 `meets_standard`,达到 → `is_important=1` → 实时邮件推送;未达到 → 不推送。命中推送的资讯也会纳入每日日报。 **综合分公式**:`total_score = 0.4 × 相关度 + 0.6 × 重要度`(LLM 分析后按 `0.6×规则分 + 0.4×LLM分量` 融合) --- ## 接入真实数据源 系统已内置真实网页采集(`crawler.py`),接入真实源**无需写代码**: 1. 在数据源页「编辑」已有源或「新增」源,填真实 URL(如媒体频道/官网新闻/RSS 页); 2. 保存后下次采集会自动通过 **web-capture-api** 抓取该页 → 清洗出可读正文 → 提取资讯链接 → 对前几条抓全文入库(每源可在「获取方式/抓取参数」里调:抓取动作、等待时间、滚动次数、后端等); 3. 抓取失败的源会在数据源页标记 **error** 状态(网络被拒/反爬),并触发**系统错误邮件通知**(受频率/静默控制); 4. `example.com` 开头的占位地址继续走模拟数据,方便调试。 > 提示:web-capture-api 接口地址在设置页「网页提取服务」可改、可「测试接口」;个别重 JS 渲染/强反爬站点可改 `action=text` 整页取正文,或换 `backend=playwright`。 --- ## 常见问题 - **收不到邮件?** 在设置页点「测试邮件」;确认 `smtp_mode` 与端口匹配(plain 一般不加密、starttls 用 587、ssl 用 465)。 - **LLM 分析失败?** 设置页大模型接口点「测试」;切一个更稳的接口(如 SiliconFlow);系统会自动切备用接口,仍失败则该条标 `error` 不阻塞。 - **真实源采集不到?** 数据源页看该源状态是否 **error**(网络被拒/反爬);可换成可达的站点或 RSS 地址。 - **想立即看效果?** 数据管理页(`/api/actions` 手动)点「立即采集 / LLM 分析 / 发送日报」。 - **改了兴趣画像想重新算分?** 点「重新打分」(reanalyze)即可全量重跑规则打分。 - **日志在哪?** `logs/app.log`(服务日志)+ 网页 `/logs`(通知日志,可分页筛选)。 - **系统出错没收到邮件?** 设置页「系统错误邮件通知」确认已启用、通知方式非「关闭」、冷却分钟不宜过大,且当前不在静默时段(静默时段不发送,结束后自动补发)。 --- ## Git - 仓库:`hz4th_coder/news-tracker` - 版本:`v1.0.0`(初版)→ `v1.0.1`(补 README)→ `v1.1.0`(真实网页采集+全文入库 / 大模型接口多预置一键切换 / 数据源可编辑)→ `v1.2.0`(数据源完整编辑模态框 / 定制监控类型:无权重+推送标准+LLM判断推送+测试按钮)→ **`v1.3.0`**(每源独立采集周期 / 定制监控与新闻监控分离独立配置+独立汇总 / 历史采样留档+查看+提取API)→ **`v1.4.0`**(通知日志分页+筛选 / 仪表盘 TOP10+更多链接 / 数据源走 web-capture-api 抓取+获取方式与参数可编辑 / 系统错误邮件通知:频率+静默时段)→ **`v1.4.1`**(修复邮件退信:发信补 `Date` 头,mail.tphai.com amavisd 强制要求否则 554 退信 / 数据源状态列新增一键启动/停用开关,点击即生效无需刷新)