release: bump version to 0.44.0

This commit is contained in:
linkong
2026-04-29 17:27:44 +08:00
parent 2da25376bd
commit 87594a95ff
54 changed files with 3665 additions and 2154 deletions

View File

@@ -24,6 +24,8 @@
- [earth-webgl-instancing-satellites-plan.md](/home/ray/dev/linkong/planet/docs/plans/earth-webgl-instancing-satellites-plan.md)
- [earth-real-terrain-plan.md](/home/ray/dev/linkong/planet/docs/plans/earth-real-terrain-plan.md)
- [earth-news-source-configuration-and-collector-plan.md](/home/ray/dev/linkong/planet/docs/plans/earth-news-source-configuration-and-collector-plan.md)
- [earth-news-cruise-summary-plan.md](/home/ray/dev/linkong/planet/docs/plans/earth-news-cruise-summary-plan.md)
- [earth-vessel-rendering-performance-plan.md](/home/ray/dev/linkong/planet/docs/plans/earth-vessel-rendering-performance-plan.md)
- [frontend-public-docs-site-plan.md](/home/ray/dev/linkong/planet/docs/plans/frontend-public-docs-site-plan.md)
- [frontend-ai-playground-development-plan.md](/home/ray/dev/linkong/planet/docs/plans/frontend-ai-playground-development-plan.md)
- [ue5-mvp-fused-plan.md](/home/ray/dev/linkong/planet/docs/plans/ue5-mvp-fused-plan.md)

View File

@@ -235,7 +235,9 @@ Settings 中保留统一外部集成配置:
DataSources 不直接管理全局 secret只引用 provider profile。
### Phase 2 — DataSources 自定义源向导
### Phase 2 — Settings 自定义源向导
自定义数据源配置入口应放在 `/settings` 的“采集器设置”或后续专门的自定义采集器设置区。`/datasources` 保持数据源目录和采集触发职责,不再承载编辑入口。
自定义数据源配置改成向导或右侧 drawer

View File

@@ -0,0 +1,366 @@
# Earth 新闻巡航摘要增强计划
## 背景
`Earth` 的新闻巡航模式目前直接消费 `/api/v1/news/earth-feed` 返回的 `items[].summary`。这个字段主要来自 RSS/Atom 的 `description``summary``content`,再经过 HTML 清理与长度截断。
这个实现足够轻量,但在巡航展示里有三个问题:
- 不是所有新闻源都会提供摘要,部分源只返回标题和链接。
- 聚合源的摘要质量不稳定,可能只是重复标题、来源署名或片段文本。
- 巡航模式需要更稳定的“态势说明”,否则新闻卡片的 `SUMMARY` 区域会显得空或信息密度不足。
目标不是把所有新闻都交给大模型,而是建立一个分层摘要管线:能用新闻源自带内容时零成本处理,需要增强时优先用本地模型,云端 LLM 只作为可控兜底。
## 当前相关实现
| 文件 | 作用 |
| --- | --- |
| `backend/app/services/earth_news.py` | 拉取 RSS/Atom 新闻源、解析标题/摘要、按区域聚合并返回 Earth 新闻 payload |
| `backend/app/api/v1/news.py` | 暴露 `/api/v1/news/earth-feed` |
| `frontend/public/earth/js/news.js` | 拉取新闻 payload 并渲染媒体面板新闻列表 |
| `frontend/public/earth/js/news-cruise-adapter.js` | 将新闻条目映射为巡航事件,并把 `summary` 传给信息卡 |
| `frontend/public/earth/js/info-card.js` | 展示新闻巡航卡片中的 `SUMMARY` |
当前摘要生成逻辑集中在 `earth_news.py`
```python
summary = _extract_item_text(node, "description", "content")
clean_summary = _truncate(_strip_html(summary), 180)
```
这意味着后端还没有区分“摘要来自哪里”“质量是否足够”“是否需要异步增强”。
## 总体方案
采用四级摘要来源:
| 优先级 | 来源 | 成本 | 适用情况 | 风险 |
| --- | --- | --- | --- | --- |
| 1 | 新闻源自带 summary / description | 低 | RSS/Atom 已提供可读摘要 | 字段可能为空或重复标题 |
| 2 | 本地规则提取 | 低 | 有正文片段但没有可靠摘要 | 只能抽取,不能真正概括 |
| 3 | 本地 Gemma/Ollama 摘要 | 中 | 巡航会展示且前两级质量不足 | 本地模型质量与机器性能相关 |
| 4 | 云端 LLM 兜底 | 高 | 用户手动增强、重点新闻、失败补偿 | 成本与网络依赖 |
推荐默认策略:
```text
provider summary -> extractive summary -> cached local model summary -> async local model summary -> optional cloud LLM
```
巡航 UI 永远先展示已有摘要,不等待模型调用。模型摘要在后台补齐,写入缓存后下一轮巡航或刷新时使用。
## 数据结构
后端应把原来的 `summary: str` 升级为可追踪的摘要元信息,同时为了兼容前端保留顶层 `summary` 字段。
建议新增结构:
```json
{
"summary": "短摘要文本",
"summary_meta": {
"source": "provider",
"quality": "good",
"generated_at": "2026-04-29T00:00:00Z",
"content_hash": "sha256:...",
"model": null,
"language": "zh-CN"
}
}
```
字段说明:
| 字段 | 可选值 | 说明 |
| --- | --- | --- |
| `source` | `provider` / `extractive` / `local_llm` / `cloud_llm` / `fallback` | 摘要来源 |
| `quality` | `good` / `partial` / `poor` | 后端对摘要可用性的判断 |
| `generated_at` | ISO 时间 | 模型或规则生成时间 |
| `content_hash` | SHA-256 | 用于缓存命中和判断内容变化 |
| `model` | 字符串或 `null` | 例如 `gemma3:4b` |
| `language` | 语言代码 | 默认 `zh-CN`,也可跟随新闻语言 |
前端第一阶段不需要显示 `summary_meta`,但可以用于后续调试面板或质量标记。
## 后端设计
### NewsSummaryService
新增 `backend/app/services/news_summary.py`,提供统一入口:
```python
async def resolve_news_summary(item: ParsedNewsItem, *, mode: str) -> NewsSummaryResult:
...
```
核心职责:
- 标准化新闻输入标题、URL、来源、发布时间、摘要片段、正文片段。
- 判断 provider summary 是否可用。
- 生成本地规则摘要。
- 查询模型摘要缓存。
- 在允许时调用本地 Ollama/Gemma。
- 在增强模式或手动触发时调用云端 LLM。
- 返回摘要文本与 `summary_meta`
### 摘要质量判断
第一版可以用轻量规则:
- 少于 30 个字符:`poor`
- 与标题高度重复:`partial`
- 包含明显来源署名或聚合噪声:`partial`
- 60-180 个字符且不重复标题:`good`
伪代码:
```python
def score_summary(title: str, summary: str) -> SummaryQuality:
if len(summary.strip()) < 30:
return "poor"
if normalized_overlap(title, summary) > 0.75:
return "partial"
if looks_like_source_attribution(summary):
return "partial"
return "good"
```
### 本地规则摘要
如果新闻源没有摘要,但有 `content``description``snippet` 或正文片段:
- 清理 HTML。
- 去掉标题重复内容。
- 去掉来源署名、发布时间、图片说明。
- 优先取前 1-2 个完整句子。
- 控制在 80-140 个中文字符或 40-80 个英文词。
### 本地 Gemma/Ollama Provider
不要在业务里写死 Gemma抽象为 `LocalLLMSummaryProvider`,默认可以指向 Ollama
```env
NEWS_SUMMARY_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
NEWS_SUMMARY_MODEL=gemma3:4b
NEWS_SUMMARY_TIMEOUT_SECONDS=20
NEWS_SUMMARY_MAX_INPUT_CHARS=5000
NEWS_SUMMARY_MAX_PER_HOUR=60
```
Ollama 请求示例:
```http
POST /api/generate
Content-Type: application/json
{
"model": "gemma3:4b",
"prompt": "...",
"stream": false,
"options": {
"temperature": 0.2,
"num_predict": 180
}
}
```
摘要 prompt 要强调“只基于原文”,避免模型补事实:
```text
你是新闻摘要器。只根据输入新闻内容生成摘要,不要添加原文没有的信息。
输出中文1-2 句话80-140 字。
如果原文信息不足,只概括已知事实,不要推测。
标题:{title}
来源:{source}
发布时间:{published_at}
正文或片段:
{content}
```
### 缓存
需要缓存模型摘要,避免重复花时间和费用。
缓存 key
```text
sha256(url + title + published_at + normalized_content)
```
建议新增表或复用系统设置缓存。若要可查询与清理,推荐独立表:
```text
news_summary_cache
- id
- cache_key
- url
- title
- content_hash
- summary
- source
- quality
- provider
- model
- generated_at
- expires_at
- failure_count
- last_error
```
缓存策略:
- 同一 `cache_key` 命中后直接返回。
- `provider` / `extractive` 可以短期缓存。
- `local_llm` / `cloud_llm` 可以长缓存,内容 hash 变化才重算。
- LLM 失败后记录 `failure_count`,短时间内不重复调用。
## 前端与巡航行为
前端第一阶段只需要继续使用 `item.summary`,不阻塞现有逻辑。
后续可选增强:
- `news.js` 在渲染新闻列表时,如果 `summary_meta.quality === "poor"`,可以用更紧凑的标题卡样式。
- `news-cruise-adapter.js` 选择巡航项时,可以优先选择 `summary_meta.quality !== "poor"` 的新闻。
- `info-card.js` 不显示“AI 生成中”这类文案,避免把系统内部状态暴露给用户。
如果后端异步生成完成,可以通过下一次 `/api/v1/news/earth-feed` 刷新自然更新。第一版不需要 WebSocket。
## 调用策略
默认使用“省钱模式”:
- 只处理本次 payload 中即将进入巡航队列的前 N 条。
- `provider``extractive` 达到 `good` 时不调用模型。
- 本地模型失败时不影响新闻 payload。
- 云端 LLM 默认关闭,只允许手动增强或后台配置开启。
推荐限制:
| 配置 | 默认值 | 说明 |
| --- | --- | --- |
| `NEWS_SUMMARY_MODE` | `economy` | `off` / `economy` / `enhanced` / `manual` |
| `NEWS_SUMMARY_CRUISE_PREFETCH_LIMIT` | `10` | 每次新闻 payload 预热多少条巡航摘要 |
| `NEWS_SUMMARY_MAX_PER_HOUR` | `60` | 本地模型每小时最多处理数量 |
| `NEWS_SUMMARY_CLOUD_MAX_PER_DAY` | `20` | 云端 LLM 每天最多处理数量 |
| `NEWS_SUMMARY_TIMEOUT_SECONDS` | `20` | 单条模型摘要超时 |
| `NEWS_SUMMARY_MAX_INPUT_CHARS` | `5000` | 输入截断上限 |
## Gemma 本地部署建议
Gemma 适合作为“本地省钱层”,但不应成为强绑定依赖。建议通过 Ollama 接入,未来可切换 Qwen、Llama 或其他本地模型。
开发环境:
```bash
ollama pull gemma3:4b
ollama serve
```
集成原则:
- 后端只依赖 Ollama HTTP API不直接依赖 Gemma SDK。
- 模型名称来自配置,不写死在代码里。
- 健康检查访问 `/api/tags` 或执行一条极短测试 prompt。
- 如果 Ollama 不可用,摘要管线自动退回 `provider` / `extractive`
中文新闻较多时,需要单独评估 Gemma 与 Qwen 系本地模型的中文摘要质量。不要只看单条效果,至少抽样 50 条新闻比较:
- 事实准确性
- 中文自然度
- 长度稳定性
- 延迟
- 是否会补充原文没有的信息
## 云端 LLM 兜底
云端 LLM 不作为默认路径,只用于:
- 用户点击“增强摘要”。
- 管理员开启增强模式。
- 本地模型连续失败且新闻进入重点巡航队列。
云端结果同样写入 `news_summary_cache`,并受每日限额控制。
## 分阶段实施
### 第一阶段:零成本摘要质量增强
-`earth_news.py` 中引入 `summary_meta`
- 增加 provider summary 质量判断。
- 增加本地规则摘要兜底。
- `/api/v1/news/earth-feed` 保持兼容,继续返回顶层 `summary`
- 前端无需大改。
验收标准:
- 没有摘要的新闻也能尽量得到短摘要。
- `summary_meta.source``summary_meta.quality` 可用于调试。
- 现有新闻面板和巡航模式不破坏。
### 第二阶段:本地 Gemma/Ollama 摘要
- 新增 `LocalLLMSummaryProvider`
- 接入 Ollama `/api/generate`
- 添加超时、输入截断、错误退避。
- 增加模型摘要缓存。
- 巡航 payload 后台预热前 N 条摘要。
验收标准:
- Ollama 可用时,低质量摘要能被本地模型增强。
- Ollama 不可用时,新闻接口仍然正常返回。
- 同一新闻不会重复调用模型。
### 第三阶段:设置与可观测性
- 在设置中增加新闻摘要模式:
- `关闭`
- `省钱模式`
- `增强模式`
- `仅手动`
- 增加本地模型连通性检查。
- 暴露缓存命中率、模型调用次数、失败次数。
- 日志记录摘要来源和失败原因。
验收标准:
- 用户可以不改环境变量就知道本地摘要服务是否可用。
- 管理员能看出成本和失败情况。
### 第四阶段:云端 LLM 兜底
- 接入现有 AI Provider 或新增 cloud summary provider。
- 增加每日限额与手动增强入口。
- 对云端生成结果落缓存。
验收标准:
- 云端调用可控、可关闭、可限流。
- 云端失败不影响巡航。
## 风险与防护
| 风险 | 防护 |
| --- | --- |
| 本地模型生成不存在的事实 | prompt 明确禁止扩写;摘要只作为原文概括;保留来源链接 |
| 本地模型慢导致新闻接口卡住 | 模型摘要异步化;接口先返回已有摘要 |
| 成本失控 | 默认不启用云端;按小时/天限流;缓存命中优先 |
| 摘要语言不一致 | 配置目标语言,默认 `zh-CN` |
| 新闻源正文不足 | 只概括标题和片段,不强行扩写 |
| 模型服务不可用 | 自动回退,不影响巡航主流程 |
## 推荐优先级
先做第一阶段和第二阶段的最小闭环:
1. `summary_meta` + 质量判断。
2. 本地规则摘要。
3. Ollama provider。
4. 缓存。
5. 巡航前 N 条异步预热。
云端 LLM 和设置页可以后置。这样能先验证“摘要缺失比例、本地模型质量、实际延迟”三个关键问题,再决定是否投入更重的 UI 与云端增强。

View File

@@ -96,3 +96,11 @@ GEO 轨道点数高,采样率需要按轨道类型分层。
2. 解锁后轨道立即清除
3. 不同轨道类型下点数可控
4. 页面切换回来不会闪出旧轨道残留
## Satellite Footprint Follow-Up Items
从技术文档迁出的 footprint 后续项,作为卫星覆盖能力的计划 backlog
1.`iridium-next` 新建独立 footprint adapter。
2. 在 UI 上补一个只读提示,让用户知道当前卫星是否支持 footprint。
3. 如果未来拿到 GEO beam contour / operator metadata再为 GEO 开 operator-specific footprint。

View File

@@ -25,6 +25,49 @@
- 状态和渲染更新散落在多个模块
- 后续再加新图层时容易复制旧逻辑
## Current High-Frequency Risks
### 1. Visual state and business state drift apart
Earth 里最常见的 bug 不是“没渲染”,而是状态没有一起收口:
- 图层关了tooltip 还在
- 锁定对象隐藏了info card 还在
- legend 没跟图层切换
- loading 已结束,但按钮还像没开
后续架构治理需要把这类同步责任从临时 UI patch 转为统一状态流。
### 2. HUD layout fixes skip structure analysis
Earth HUD 历史上反复出现:
- 面板只剩一条缝
- markdown 被裁掉
- tabs / iframe 被 `overflow: hidden` 吃掉
这类问题应纳入布局治理计划,而不是散落在单个功能改动里临时修。
### 3. Transitional paths keep accumulating
Earth 已经经历过多轮 HUD、toolbar、media panel 重构,容易留下:
- 旧 helper
- 旧 class
- 旧 fallback 逻辑
- 已废弃变体
架构分离阶段需要把 cleanup pass 作为计划项,而不是让技术上下文承担提醒职责。
### 4. Cruise logic and business events couple too deeply
巡航相关风险是通用巡航层继续混入业务事件细节,导致 BGP、新闻、卫星、海缆各自复制一套状态机。
架构目标应保持:
- 通用巡航层管理目标、队列、focus、停留、隐藏和切换
- 业务模块只提供队列、坐标、卡片内容和高亮副作用
## Target Architecture
Earth 对每类对象都尽量拆成三层:

View File

@@ -0,0 +1,217 @@
# Earth Vessel Rendering Performance Plan
## 背景
Earth 船只图层已经形成了一套较好的视觉语言:
- 航行船只使用三角形标记
- 标记按航向旋转
- 停泊或低速船只使用圆点
- 不同船型使用不同颜色
- hover / locked 状态有放大、透明度和聚焦反馈
- 标记带有轻微 glow / soft edge和 Earth HUD 的观感一致
当前性能问题不应通过降级成普通 `Points` 来解决。目标是在保留现有观赏性的前提下,把底层从“每艘船一个 Sprite 对象”优化为批量绘制和轻量交互。
## 当前问题判断
卫星图层能承载几万个对象,是因为它主要走 `THREE.Points` / `BufferGeometry` / instanced trail 路径。船只图层目前每艘船创建一个 `THREE.Sprite` 和独立 `SpriteMaterial`,这会带来:
- draw call 随船只数量增长
- 透明 sprite 排序和 overdraw 成本上升
- 每帧遍历所有船只更新 opacity / scale / visible
- pointer move 时对船只 sprite 做对象级 raycast
- hover reset 时全量遍历 marker
因此,即使免费 BarentsWatch AIS 只开放挪威周边数据,前端仍可能因为对象级 sprite、raycast 和每帧全量更新出现地球拖动卡顿。
## 目标
1. 保留当前船只标记的视觉质量。
2. 保留 hover tooltip、点击详情、lock、轨迹等交互。
3. 显著降低 draw call、每帧 JS 遍历和 pointer picking 成本。
4. 为后续全球 AIS 或更高船只数量预留扩展空间。
## 非目标
- 不把船只降级为普通无方向 `Points`
- 不取消船型颜色、航向三角和停泊圆点。
- 不为了短期性能直接删除 hover / click 交互。
## Phase 1交互路径止血
这一阶段不改视觉,只减少 pointer move 和 hover 状态开销。
### 1. 拖动和惯性期间跳过船只 picking
地球拖动时用户主要关注视角变化,不需要每个 pointer move 都命中船只。
处理方式:
- `isDragging === true` 时跳过船只 hover picking。
- 惯性旋转期间也跳过船只 hover picking。
- 拖动结束后再恢复 hover 检测。
### 2. vessel hover picking 节流
对船只 hover 命中增加节流,例如 `80ms ~ 120ms` 一次。鼠标高速移动时复用上一次 hover 状态,不在每个 pointer event 上都做 raycast。
### 3. hover reset 从全量遍历改为增量更新
当前 `resetTransientVesselStates()` 会遍历所有船只。改为记录:
- `hoveredVessel`
- `lockedObject`
当 hover 目标变化时,只更新旧 hover 和新 hover。
### 4. 点击路径只在 click 时做一次精确 picking
点击仍保留精确命中,但只在 click 事件里执行,不参与拖动和高频 pointer move。
## Phase 2每帧更新减负
这一阶段仍保留 `Sprite` 外观,但减少每帧对全部 marker 的写操作。
### 1. `updateVesselVisualState()` 增量化
当前每帧都会遍历船只并写:
- `marker.material.opacity`
- `marker.scale`
- `marker.visible`
优化方向:
- 图层关闭时直接 return。
- 没有船只时直接 return。
- 只有以下状态变化时才更新 marker
- show/hide 变化
- hover 变化
- locked 变化
- camera zoom / distance scale 变化超过阈值
- focus dim 状态变化
### 2. 缓存 distance scale
`getDistanceScale(camera)` 可以按 camera distance 或 zoom 阈值缓存。缩放没有明显变化时,不必每帧重设所有船只 scale。
### 3. 降低透明 overdraw
在不破坏视觉的前提下微调:
- marker 基础尺寸
- glow blur 半径
- 最大 size stabilization
目标是减少屏幕空间重叠面积,而不是改变符号设计。
## Phase 3保留视觉的批量渲染
正式方案是把每艘船的视觉从 `THREE.Sprite` 迁移为 instanced sprite batch。
### 1. 使用 instanced quad
每艘船仍然显示为带贴图/软边的 billboard但底层使用
- `THREE.InstancedBufferGeometry`
- 每类船只一个或少量 material
- per-instance attributes
可按形状和船型拆 batch
- moving cargo
- moving tanker
- moving passenger
- moving fishing
- moving military
- moving other
- anchored / slow dot
这样 draw call 从“每艘船一个”变为“每类船只一个”。
### 2. per-instance attributes
每个 instance 存:
- position
- color
- rotation
- scale
- opacity
- state
- mmsi / data index
hover、locked、dimmed 通过更新少量 instance attribute 实现,不再逐个修改 material。
### 3. 复刻当前视觉
视觉上继续使用当前 canvas texture 或等效 shader
- moving 使用三角形纹理
- anchored 使用圆点纹理
- 保留 soft glow
- 保留航向 rotation
- 保留 hover / locked 放大
因此用户看到的效果应与当前船只图层基本一致。
## Phase 4picking 改造
批量渲染后不再适合对所有 sprite object 做 `raycaster.intersectObjects()`
### 1. 屏幕空间 picking
参考卫星 picking
1. 过滤背面船只。
2. 将候选船只世界坐标投影到屏幕。
3. 用鼠标位置计算距离。
4. 取距离最近且小于半径阈值的船只。
### 2. 可选空间索引
如果后续船只数量明显上升,可增加轻量空间索引:
- 经纬度网格 bucket
- 屏幕空间 bucket
- viewport bbox 过滤
第一阶段不必引入复杂索引。
## Phase 5数据层和 LOD
当接入全球 AIS 或船只数量显著增加时,再做数据层优化。
### 1. 请求视口范围
前端请求 `/api/v1/visualization/geo/vessels` 时带上当前视口 `bbox`,减少无关船只。
### 2. 后端排序策略
从单纯 `received_at desc` 改为综合排序:
- 数据新鲜度
- 船型优先级
- 当前视口相关性
- 是否正在航行
### 3. 远景聚合
远景可显示聚合或 top N近景展开单船。
## 验收指标
1. 船只视觉效果保持当前质量三角、圆点、颜色、航向、hover、lock 都保留。
2. 开启船只图层后拖动地球不应明显掉帧。
3. pointer move 不应因为船只 hover 导致卡顿。
4. 船只数量达到 `1000` 级别时仍可顺畅旋转地球。
5. `renderer.info.render.calls` 相比 Sprite 版本显著下降。
6. hover / click 命中体验不低于当前版本。
## 建议落地顺序
1. 先做 Phase 1快速恢复地球拖动手感。
2. 再做 Phase 2减少每帧 JS 写操作。
3. 最后做 Phase 3 和 Phase 4把船只迁移到 instanced sprite batch。
4. Phase 5 等全球船只数据或数量压力出现后再推进。

View File

@@ -2,7 +2,7 @@
**状态**:规划中
**创建日期**2026-04-27
**优先数据源**BarentsWatch(免费)→ AISHub / MarineTrafficTODO付费
**优先数据源**BarentsWatch AIS免费但需要 OAuth client credentials)→ AISHub / MarineTrafficTODO付费
## 已确认决策
@@ -22,17 +22,17 @@
| 来源类型 | 典型服务 | 覆盖范围 | 成本 | 状态 |
|---------|---------|---------|------|------|
| **BarentsWatch Open API** | live.ais.barentswatch.no | 挪威海域实时 | 完全免费 | **当前使用** |
| **BarentsWatch AIS API** | live.ais.barentswatch.no | 挪威海域实时 | 免费,需要 AIS API client credentials | **当前使用** |
| **AISHub** | aishub.net | 全球实时 | 免费/小额 | TODO付费接入 |
| **MarineTraffic API** | marinetraffic.com | 全球实时 | $50$500/月 | TODO评估 tier |
| **VesselFinder API** | vesselfinder.com | 全球实时 | $50$300/月 | TODO备选 |
| **自建 SDR 接收** | RTL-SDR + AIS-catcher | 仅本地 3050km | 硬件 $30 | 不考虑 |
| **NOAA 历史数据** | Marine Cadastre | 美国近海历史 | 免费 | 可用于冷启动 |
### BarentsWatch API
### BarentsWatch AIS API
- 端点:`https://live.ais.barentswatch.no/v1/latest/combined`
- 无需注册,直接 GET返回挪威近海 20005000 艘船只 JSON
- 需要在 BarentsWatch developer portal 创建 `AIS - API` client通过 client credentials 获取 `scope=ais` 的 access token 后请求 AIS endpoint
- 字段mmsi, lat, lon, sog, cog, heading, nav_status, name, vessel_type, flag
- 刷新频率:数据约 3060s 更新一次,可随意轮询
@@ -49,7 +49,7 @@
### Phase 0 — 数据源验证与链路打通12 天)
- 接入 BarentsWatch Open API验证数据格式与字段
- 接入 BarentsWatch AIS API验证 OAuth token、数据格式与字段
- 构建全球 mock 数据生成器(用于前端渲染压测,补充 BarentsWatch 的地域限制)
- 确认前端可渲染船只点,整条链路走通