251 lines
18 KiB
Markdown
251 lines
18 KiB
Markdown
# Earth 新闻源配置
|
||
|
||
Earth 态势新闻使用 `/api/v1/news/earth-feed` 输出给前端。新闻源配置存放在 `SystemSetting.category = "earth_news_sources"`;没有数据库配置时,后端使用内置默认源作为 fallback seed。
|
||
|
||
## 默认源
|
||
|
||
默认源包含四类:
|
||
|
||
- **新闻源**:BBC World、DW Top Stories、CNBC Business、BBC Business、Guardian Business、NPR Business、MarketWatch、TechCrunch、Retail Dive、PR Newswire Retail、36氪、亿邦动力、国家统计局数据发布。
|
||
- **行业洞察源**:McKinsey Retail、Deloitte Retail。
|
||
- **官方数据源**:国家统计局数据发布、US Census Retail / E-Commerce、商务数据中心、商务部电商动态、电商物流指数。
|
||
- **线索源**:BusinessWire Electronic Commerce;Google News 作为一个聚合 source,下面挂 global / americas / europe / middle-east-africa / asia-pacific 五个区域 Feed 子项。
|
||
|
||
配置型数据源默认保留在 Admin 配置中,但若不是稳定 RSS/Atom,则默认不参与自动抓取。管理员可以在 `Earth 内容 -> 新闻源` 中改成可抓取 RSS、启用或禁用。
|
||
|
||
| 来源 | 类型 | 默认状态 | 默认主类型 | 主要标签 | 用途 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| BBC World | RSS | 启用 | 政治 | `official_media`, `global` | 全球公共新闻基线 |
|
||
| DW Top Stories | RSS | 启用 | 政治 | `official_media`, `europe` | 欧洲与国际新闻基线 |
|
||
| CNBC Business | RSS | 启用 | 商业 | `business_news`, `us`, `global` | 国际商业新闻 |
|
||
| BBC Business / Guardian Business / NPR Business / MarketWatch | RSS | 启用 | 商业 / 金融 | `business_news`, `finance` | 英美商业与金融基线 |
|
||
| TechCrunch / Retail Dive / PR Newswire Retail | RSS | 启用 | 科技 / 商业 | `business_news`, `ecommerce`, `retail`, `press_release` | 科技、电商、零售和企业公告 |
|
||
| 36氪 | RSS | 启用 | 商业 | `business_news`, `ecommerce`, `china` | 国内商业、创投和快讯;主页是 `https://www.36kr.com/`,Feed 信息页是 `https://www.36kr.com/rss-center`,Feed 子项是综合资讯、文章资讯、最新快讯、动态内容 |
|
||
| 亿邦动力 | RSS | 启用 | 电商 | `ecommerce`, `business_news`, `china`, `retail` | 国内电商行业新闻;主页是 `https://www.ebrun.com/`,Feed 信息页是 `https://www.ebrun.com/rss/`,Feed 子项是 B2C、B2B、零售、O2O、服务、数据、政策 XML |
|
||
| 国家统计局数据发布 | RSS | 启用 | 电商 | `official_data`, `ecommerce`, `retail`, `china` | 官方数据发布 RSS;社零和网上零售条目由分类/重要度规则识别 |
|
||
| Google News | Aggregated | 启用 | 政治 | `aggregated`, `low_stability` | 一个聚合 source,Feed 子项为全球、美洲、欧洲、中东与非洲、亚太区域兜底 RSS;优先级低于真实 RSS |
|
||
| BusinessWire Electronic Commerce | Reference | 禁用 | 电商 | `press_release`, `ecommerce`, `low_stability` | 企业公告线索 |
|
||
| McKinsey Retail Insights | Reference | 禁用 | 商业 | `industry_insight`, `retail` | 零售行业洞察 |
|
||
| Deloitte Retail | Reference | 禁用 | 商业 | `industry_insight`, `retail` | 零售行业洞察 |
|
||
| US Census Retail / E-Commerce | Reference | 禁用 | 电商 | `official_data`, `ecommerce`, `retail`, `us` | 美国零售和电商官方数据 |
|
||
| 商务数据中心 | Reference | 禁用 | 商业 | `official_data`, `china` | 国内商务数据 |
|
||
| 商务部电商动态 | Reference | 禁用 | 电商 | `official_data`, `ecommerce`, `china` | 国内电商政策与动态 |
|
||
| 电商物流指数 | Reference | 禁用 | 电商 | `official_data`, `ecommerce`, `logistics`, `china` | 物流履约与电商景气度 |
|
||
|
||
`Reference` 源表示参考链接/未来采集器线索,只记录官网、报告页或数据页,不参与 RSS/Atom 抓取。这样可以把商业与官方数据源先纳入后台治理,同时避免不可抓取页面拖垮新闻 feed。
|
||
|
||
新闻源模型是两层结构:
|
||
|
||
- `source` 表示来源品牌或聚合器,例如 36氪、亿邦动力、Google News、BBC。
|
||
- `homepage_url` 表示来源官网、栏目页或报告页。
|
||
- `feed_directory_url` 表示 Feed 信息页,也就是 RSS 订阅中心或 Feed 聚合页,只用于人工查看,不参与抓取。
|
||
- `feeds` 表示该来源下真正抓取的 RSS、Atom 或 Aggregated 子项。每个 Feed 子项都有 `id / name / url / type / enabled / default_category / tags / priority`。
|
||
|
||
后端会遍历同一 source 下所有启用的 Feed 子项,逐个抓取、合并去重,并把单个子项的检测结果写入 `health.feed_results`。这不是“备用地址”逻辑;36氪的四个订阅地址、亿邦的多个分类 XML、Google News 的五个区域 RSS 都可以同时启用,并且每个 Feed 可以单独配置默认新闻类型和启用状态。HTML 订阅中心或聚合页只能放在 `feed_directory_url`,不能放进 Feed 地址。默认启用的可抓 Feed 已逐项连通性检测:RSS/Atom/Aggregated Feed 必须解析到条目,Reference 源只保留参考地址和后续采集器线索。
|
||
|
||
当前仍保留为 Reference 的项不是“坏源”,而是没有找到稳定、可直接消费的 RSS/Atom:
|
||
|
||
- BusinessWire 官方说明支持可定制 RSS/Atom,但公开页面未暴露稳定行业 feed URL;当前保留电子商务行业页作为公告线索。
|
||
- McKinsey / Deloitte 的零售洞察页是报告和文章集合,不是公开 RSS。
|
||
- US Census 的 press release RSS 可访问,但条目链接为空;Quarterly E-Commerce 页面保留为官方数据参考链接。
|
||
- 商务部数据、电商物流指数目前未找到稳定 RSS,后续应做专用 collector 或人工配置可抓 feed。
|
||
|
||
## 源属性标签与新闻类型
|
||
|
||
新闻源有 `source_tags`,在 Admin 中显示为“源属性标签”。它用于描述 source 的属性,不是媒体来源名,也不是新闻条目的内容类型。例如:
|
||
|
||
- `official_data`:官方数据
|
||
- `business_news`:商业新闻
|
||
- `ecommerce`:电商
|
||
- `finance`:金融
|
||
- `retail`:零售
|
||
- `logistics`:物流
|
||
- `industry_insight`:行业洞察
|
||
- `press_release`:企业公告
|
||
- `china`、`global`、`us`
|
||
- `aggregated`、`low_stability`
|
||
|
||
单条新闻有一个主类型 `category`,默认类型包括:政治、商业、电商、金融、体育、科技、军事、灾害、能源、社会、文化、其他。`item_tags` 是条目级补充标签,例如跨境电商、直播电商、零售数据、物流履约、平台治理、AI、半导体、选举、油价、足球、供应链。
|
||
|
||
主类型优先由规则引擎根据标题、摘要、来源名打分生成;规则未命中时优先使用 Feed 子项的默认类型,再回退 source 默认类型。AI enrichment 不阻塞新闻展示。
|
||
|
||
## 重要度
|
||
|
||
每条新闻输出:
|
||
|
||
- `importance_score`
|
||
- `importance_level`
|
||
- `importance_reasons`
|
||
- `market_impact`
|
||
|
||
官方数据源、电商指标、平台型公司、量化指标会提高重要度;企业公告基础权重较低,只有命中大平台、金额、并购、监管等信号时提升。
|
||
|
||
重要度等级固定为:`low` 0–34、`medium` 35–59、`high` 60–79、`critical` 80–100。分类、重要度和 Breaking 的计算集中在 `earth_news_classification.py`;分类 key 和标签仍可配置,重要度与 Breaking 协议状态使用统一枚举,数据库和 API 继续保存兼容的小写字符串。
|
||
|
||
## 配置与缓存
|
||
|
||
`GET /api/v1/earth/news-sources` 返回默认或已保存配置。`PUT /api/v1/earth/news-sources` 保存配置并递增 `cache_version`,同时清理进程内 region cache。`POST /api/v1/earth/news-sources/reset` 恢复默认源。`POST /api/v1/earth/news-sources/test` 只测试单个 RSS/Atom/Aggregated 源,不写入新闻表。
|
||
|
||
## 手动新闻内容
|
||
|
||
手动新闻是内容管理能力,不是 RSS 源配置。Admin 入口是 `智能星球内容 -> 新闻内容`,左栏按 RSS 来源和手动新闻组聚合;进入手动组详情后可以按条添加新闻或上传 JSON 数组批量导入。手动新闻写入 `earth_news_items`,并标记 `feed_type/source_type = manual`;前台展示文案是“手动添加”。它不参与 RSS 连通性测试,也不会进入 RSS 抓取流程。
|
||
|
||
手动新闻采用“先展示,再精修”的策略:
|
||
|
||
1. 保存后立即写入 `earth_news_items`。
|
||
2. 没有人工坐标时使用所选区域锚点,`verified=false`。
|
||
3. 有人工坐标时使用 `location_source=manual_location`,`verified=true`,后续 AI 精修不会覆盖该坐标。
|
||
4. 创建或重新处理后进入新闻增强队列,后台补清洗、翻译、分类、重要度、Breaking 和目标位置推断。
|
||
5. 精修完成后更新同一条新闻,并通过 Earth news reload / patch 让前端无感替换。
|
||
|
||
后台接口挂在 `/api/v1/earth/news-items`:
|
||
|
||
- `GET /earth/news-groups`:返回 RSS 虚拟来源组和手动新闻组。
|
||
- `POST /earth/news-groups`:新建手动新闻组。
|
||
- `PUT /earth/news-groups/{group_id}`:重命名手动新闻组,并同步组内新闻 meta。
|
||
- `GET /earth/news-items`:分页查询 RSS 与手动新闻,支持来源类型、区域、类型和状态过滤。
|
||
- `POST /earth/news-items`:新增一条手动新闻。
|
||
- `POST /earth/news-items/import`:上传 JSON 数组批量导入,`group_id` 指定当前手动新闻组。
|
||
- `PUT /earth/news-items/{id}`:编辑手动新闻;RSS 新闻只读。
|
||
- `DELETE /earth/news-items/{id}`:删除手动新闻,并触发 Earth 新闻重载。
|
||
- `POST /earth/news-items/{id}/reprocess`:重新进入清洗、翻译和定位队列。
|
||
|
||
JSON 导入首版只支持数组:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"title": "必填标题",
|
||
"summary": "可选摘要",
|
||
"content": "可选正文",
|
||
"url": "https://example.com/story",
|
||
"source": "手动添加",
|
||
"region": "global",
|
||
"published_at": "2026-05-15T03:00:00Z",
|
||
"category": "business",
|
||
"tags": ["manual", "analysis"],
|
||
"location": {
|
||
"label": "北京市, 中国",
|
||
"latitude": 39.9057,
|
||
"longitude": 116.3913
|
||
}
|
||
}
|
||
]
|
||
```
|
||
|
||
重复导入使用稳定 ID 去重,ID 由标题、发布时间、URL 和来源生成,格式为 `manual:{hash}`。同一条手动新闻再次导入会更新原记录,不会重复出现在 EarthFeed。
|
||
|
||
## Feed 查询与类型过滤
|
||
|
||
星球端和 UE 端统一使用 `GET /api/v1/news/earth-feed` 获取新闻。接口支持服务端过滤,不要求客户端拿全量列表后自行筛选。
|
||
|
||
- `lat` / `lon`:按当前视角推断区域,适合 Web 星球端。
|
||
- `region`:显式指定区域,适合 UE 端或服务端集成;可选值包括 `global`、`americas`、`europe`、`asia-pacific`、`middle-east-africa`。`global` 是全局聚合视图,会展示所有区域来源;其它区域只展示该区域和 `global` 来源。
|
||
- `categories`:逗号分隔的新闻类型 key,例如 `business,ecommerce`。全选时可以不传。
|
||
- `locale`:展示语言,支持 `zh-CN` 和 `en-US`,默认 `zh-CN`。中文 RSS 会以中文原文入库,并由后台补 `en-US`;英文 RSS 则由后台补 `zh-CN`。
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/news/earth-feed?region=europe&categories=business,ecommerce
|
||
GET /api/v1/news/earth-feed?lat=48&lon=10&categories=technology
|
||
GET /api/v1/news/earth-feed?region=global&categories=business,ecommerce&locale=zh-CN
|
||
```
|
||
|
||
非法新闻类型或语言会返回 `422`,响应中包含允许值。响应体会带 `filters`,用于确认后端实际应用的区域、类型和语言过滤。`items` 和 `cruise_items` 使用同一套类型过滤规则。
|
||
|
||
Web 星球端的新闻类型按钮只保存当前浏览器的显示偏好;偏好变化后会重新请求接口。UE 端应直接把类型选择拼到 `categories` 参数里,不需要再做主过滤。
|
||
|
||
未指定 `sources` 时,服务层会优先选择当前 `locale` 已有可展示标题和摘要的新闻,并从当前启用来源补齐候选后做来源轮转,避免一个来源的最新待处理条目占满默认 12 条。指定 `sources` 时保持精确来源过滤,不做跨来源补齐。数据库查询层只负责区域、类型、来源和排序条件,不包含语言展示策略。
|
||
|
||
源测试只证明当前 RSS/Atom/XML 能解析到条目,不等于这些条目已经入库展示。展示链路还会检查区域、类型过滤和数据库新鲜度。保存或重置新闻源会递增配置版本并清理缓存;如果当前启用的 Feed 子项在库里没有近期条目,下一次 `earth-feed` 请求会补抓,避免新启用的 36氪、亿邦被旧 Google News 缓存挡住。
|
||
|
||
## 区域均衡与异步精修
|
||
|
||
`earth_news_items` 是 EarthFeed 的当前状态表。接口在没有显式 `sources` 过滤时会先按 Breaking、区域、发布时间排序,再做区域轮转,避免亚太或任一高频来源把全球视图和巡航队列全部占满。默认区域顺序是美洲、欧洲、中东与非洲、亚太、全球;未知区域只在已知区域之后参与轮转。区域视图仍遵守“当前区域 + global”的规则,不会把其它区域混进区域面板。
|
||
|
||
`items` 和 `cruise_items` 都会进入目标位置与本地化精修队列,但前端不能等 AI 完成后再展示。标题或摘要没有目标语言翻译时,Web Earth 先显示原始 `title / summary`,避免卡片出现“新闻汉化中”而实际内容已经可读。后台完成翻译、分类、Breaking 或目标坐标后,会更新同一条 `earth_news_items` 并通过 Earth news reload / patch 刷新前端。
|
||
|
||
目标位置队列使用 Redis Streams 两级队列:
|
||
|
||
- `earth_news:target_location:priority`:当前可见 `items` 与 `cruise_items` 的优先精修任务,短 TTL 去重。
|
||
- `earth_news:target_location:jobs`:普通后台精修任务,长 TTL 去重。
|
||
|
||
Worker 总是先处理优先队列,再处理普通队列;pending 消息超过空闲阈值会被 reclaim,单条 AI 任务有超时保护,失败后进入重试或 dead letter。这样即使历史普通队列有大量 backlog,当前打开的欧洲、美洲等区域新闻也不会被长队列饿死。
|
||
|
||
## Breaking News 插队
|
||
|
||
新闻体系里有三套互不替代的判断:
|
||
|
||
- **分类**:新闻是什么,例如商业、军事、灾害。
|
||
- **重要度**:长期是否值得关注,写入 `importance_score / importance_level`。
|
||
- **Breaking**:短时间内是否必须插队,写入 `location_meta.news_meta.breaking_*`。
|
||
|
||
Breaking 不新增表字段,继续保存在 `location_meta.news_meta`:
|
||
|
||
- `breaking_level`:`none / watch / breaking / critical`。
|
||
- `breaking_scope`:`regional / global`。
|
||
- `breaking_reasons`:触发原因。
|
||
- `breaking_source`:`rules / ai / manual / multi_source`。
|
||
- `breaking_confidence`:0 到 1。
|
||
- `breaking_expires_at`:过期时间。
|
||
|
||
排序由服务端完成,客户端和 UE 不需要自己重排。未过期的 `critical`、`breaking`、`watch` 会依次排在普通新闻前面;过期后只回到普通排序,不删除新闻,也不改变长期重要度。
|
||
|
||
`breaking_scope = global` 的新闻会无视当前区域,进入所有区域的 feed;`regional` 只遵守当前区域加 `global` 的普通区域规则。接口响应的 `filters` 会返回 `has_breaking` 和 `highest_breaking_level`,星球端据此给新闻面板和卡片加克制的背景/边框状态。
|
||
|
||
## 连通性监测
|
||
|
||
`POST /api/v1/earth/news-sources/test` 会测试单个源并把结果写入 `earth_news_sources.health[source_id]`。实际 RSS/Atom 抓取也会更新同一份健康状态。
|
||
|
||
健康结果包含:
|
||
|
||
- `status`:`ok`、`empty`、`format_error`、`http_error`、`timeout`、`network_error`、`reference`。
|
||
- `status_code`、`content_type`、`item_count`、`latency_ms`、`error`、`fetched_at`。
|
||
- `feed_results`:多 Feed source 的逐 Feed 子项检测结果,包含 `feed_id`、`feed_name`、`feed_type`、`feed_url`、状态、条数和错误。
|
||
|
||
常见诊断:
|
||
|
||
- 返回 HTML 页面:说明配置 URL 不是 RSS/Atom feed,例如把网页中心页当成 feed。
|
||
- HTTP 403:通常是 CDN、反爬或源站拒绝抓取。
|
||
- Reference:参考链接,不参与抓取;需要改为 RSS、Atom 或 Aggregated 后才可测试抓取。
|
||
|
||
Admin 入口是 `Earth 内容 -> 新闻源`。界面不是整包 JSON 编辑,而是两层:
|
||
|
||
- **新闻源**:左侧逐个 source 列表,支持按启用、停用、参考链接、RSS/Atom/Aggregated、区域和源属性标签筛选;右侧编辑当前 source 字段和 Feed 子项列表。
|
||
- **策略规则**:保留源属性标签、新闻类型、条目标签规则、默认健康策略等全局规则。高级 JSON 只用于排障,不作为默认编辑路径。
|
||
|
||
单源表单分为“来源信息”和“Feed 子项”:
|
||
|
||
- 来源信息包括名称、ID、区域、主页 URL、Feed 信息页、源类型、启用开关、源属性标签、重要度权重、抓取间隔、超时、失败阈值和熔断开关。
|
||
- Feed 子项包括 Feed ID、名称、真实 Feed URL、类型、启用开关、默认新闻类型、优先级和 Feed 标签。Feed 子项底部的 `+` 只新增一个前端草稿;保存 source 后才写入配置,取消会销毁草稿。
|
||
|
||
单源“测试源”会测试当前 source 下全部启用 Feed;Feed 子项上的测试按钮只测试当前 Feed。测试请求仍发送到 `/api/v1/earth/news-sources/test`,但 payload 里只带当前 source 和选中的 Feed 子项。
|
||
|
||
参考链接会显示“只记录官网、报告页或未来采集器线索,不参与 RSS/Atom 抓取”。它可作为商业或官方数据线索保留在配置中,但启用抓取前必须改成 RSS、Atom 或 Aggregated,并提供可抓取的 Feed 地址。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Admin["Admin: Earth 内容 / 新闻源"] --> Source["Source 配置"]
|
||
ManualAdmin["Admin: Earth 内容 / 新闻内容"] --> ManualAPI["/api/v1/earth/news-items"]
|
||
Source --> Feed["Feed 子项"]
|
||
Feed --> ConfigAPI["/api/v1/earth/news-sources"]
|
||
ConfigAPI --> Config["SystemSetting: earth_news_sources"]
|
||
ManualAPI --> Store
|
||
|
||
Earth["Earth 新闻面板"] --> NewsAPI["/api/v1/news/earth-feed"]
|
||
NewsAPI --> Resolver["Source Resolver"]
|
||
Resolver --> Config
|
||
Resolver --> Cache["Region Feed Cache"]
|
||
Resolver --> Fetcher["RSS / Atom Fetcher"]
|
||
Fetcher --> Parser["Feed Parser"]
|
||
Parser --> Classifier["Classifier: category + item_tags + importance"]
|
||
Classifier --> Store["earth_news_items"]
|
||
Fetcher --> Health["source health"]
|
||
Health --> Config
|
||
Store --> EnrichQueue["Location / Localization Queue"]
|
||
EnrichQueue --> AI["AI Provider"]
|
||
Store --> NewsAPI
|
||
UE["UE Client"] --> NewsAPI
|
||
```
|