From 7e50e88ef9ba985eace7b8c44d11de0e385e4243 Mon Sep 17 00:00:00 2001 From: xiaji Date: Sun, 14 Jun 2026 21:05:32 +0800 Subject: [PATCH] =?UTF-8?q?docs(readme):=20=E5=90=8C=E6=AD=A5=20commit=201?= =?UTF-8?q?-7=20=E7=9A=84=E5=8A=9F=E8=83=BD=E5=92=8C=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README 在 commit 3 时只加过 API Push 的"关键特性"和"API 概览"两段, 但漏了以下 5 处,本次统一补上: 1. 数据模型表: - sources.kind 加 api_push(commit 1 alembic 0008 + commit 3 worker 跳过) - articles 加 is_short_news / external_id / source_ref / content_hash(commit 1) - articles.translation_status 加 'n/a' 状态值 - api_tokens 加 purpose + source_id(commit 1 + commit 2) - ER 关系: sources 1:N api_tokens(ingest token 绑定 source) - 新增"短新闻(API Push)特性"子节,描述 content_hash 算法 和 url 合成策略 2. API 概览: - POST /admin/refresh/{source_id} 注明对 api_push 源无效 - POST /admin/translation/rerun 注明对短新闻/中文源返 400(commit 4) - 新增"端到端测试"小节,引用 scripts/smoke_ingest.py(commit 5) 3. 故障排查: - 新增 3 个 Q:API Push 相关 / 中文 RSS 详情页 / alembic 部署顺序 - 最后一个 Q 引用 agent memory "FastAPI + alembic 部署 SOP"(commit 部署) 4. 路线图: - 新增 Phase 1.6 (API Push 短新闻) ✅ 2026-06-14 - 新增 Phase 1.7 (中文源头 RSS 优化) ✅ 2026-06-14 无代码改动,纯文档同步。 --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b459020..4e45149 100644 --- a/README.md +++ b/README.md @@ -415,18 +415,28 @@ diary-news/ | 表 | 关键字段 | 说明 | |---|---|---| | **users** | role(enum: owner/member), password_hash | 用户 + 角色 | -| **sources** | slug(uniq), kind(rss/html_list/tg_channel), priority, fetch_interval_min, consecutive_failures | 采集源 | -| **articles** | url_hash(uniq), translation_status(pending/ok/partial/failed), category, commentary, body_zh_formatted, image_ai_url, *_status, category, entities(JSONB), sentiment, topic_id, bias | 文章 + 译文 + LLM 增强 | +| **sources** | slug(uniq), kind(rss/html_list/tg_channel/**api_push**), priority, fetch_interval_min, consecutive_failures, blocklist_tags | 采集源(`api_push` 是被动接收,不被 worker 调度) | +| **articles** | url_hash(uniq), translation_status(pending/ok/partial/failed/n/a), category, commentary, body_zh_formatted, image_ai_url, *_status, entities(JSONB), sentiment, topic_id, bias, **is_short_news**, **external_id**, **source_ref**, **content_hash(uniq)** | 文章 + 译文 + LLM 增强;短新闻 4 字段为 API Push 接入 | | **bookmarks** | (user_id, article_id) UNIQUE | 收藏 | | **subscriptions** | keyword, match_in(any/title/body), channel | 关键词订阅 | -| **api_tokens** | token_hash(sha256), expires_at, revoked_at | Android 预留 | +| **api_tokens** | token_hash(sha256), purpose(mobile/ingest), source_id(ingest 专用), expires_at, revoked_at | Android + API Push ingest 双用途 | | **llm_settings** | format_prompt, classify_prompt, commentary_prompt, image_prompt_template, image_size, chat_model, image_model, interval_sec, enabled | LLM 提示词(单行) | ER 关系: - `users` 1:N → `bookmarks` / `subscriptions` / `api_tokens` -- `sources` 1:N → `articles`(cascade delete) +- `sources` 1:N → `articles`(cascade delete), 1:N → `api_tokens`(purpose=ingest 时) - `articles` 1:N → `bookmarks`, self-ref `duplicate_of`(去重链) +### 短新闻(API Push)特性 + +- `articles.is_short_news=true` 标记(其余文章默认 false) +- `articles.content_hash` UNIQUE 索引 — 内容指纹,API Push 三层去重的核心 key + - external_id 存在时:`sha1("ext:" + external_id)` + - external_id 缺失时:`sha1(title + "|" + body[:500])` +- `articles.url` 对短新闻合成占位 `api-push://{source_slug}/{content_hash[:16]}` +- 入库后 `translation/format/image_ai_status='n/a'`,enrichment_loop 只跑 classify + 双 provider commentary +- 中文源头的长新闻(RSS 抓的中文源)在前端详情页不显示译文板块,translation_loop 跳过省 TMT 配额 + --- ## 快速开始 @@ -633,13 +643,23 @@ WHERE translation_status='ok'; - `POST /admin/sources/{source_id}/ingest-tokens` — 为 api_push 源生成 ingest token(raw_token 仅一次性返回) - `GET /admin/sources/{source_id}/ingest-tokens` — 列出某个 source 的 ingest token - `DELETE /admin/ingest-tokens/{token_id}` — 撤销 ingest token -- `POST /admin/refresh/{source_id}` — 立即触发抓取 -- `POST /admin/translation/rerun/{article_id}` — 重译 +- `POST /admin/refresh/{source_id}` — 立即触发抓取(对 api_push 源无效,返回 OK 但 worker 不调度) +- `POST /admin/translation/rerun/{article_id}` — 重译;**对短新闻/中文源文章返 400**(commit 4) - `GET /admin/health` — 源健康看板 - `POST /admin/translation/quota/reset` — 重置本月配额 - `GET /admin/llm/settings` / `PUT` / `POST /reset` / `POST /test` — LLM 设置 - `POST /admin/llm/enrich/{article_id}` — 手动触发某篇 enrich +### 端到端测试 + +```bash +python scripts/smoke_ingest.py --token +# 期望输出:ALL PASS (6/6) +``` + +详见 [`scripts/smoke_ingest.py`](./scripts/smoke_ingest.py) — 验证 /api/v1/ingest 的 +"创建/重复 external_id/内容去重/错误 token/body 超长"6 步链路。 + --- ## 开发-部署工作流 @@ -750,12 +770,31 @@ ssh hknews "cd /root/diary-news && git reset --hard " ### Q: 中文用户名乱码? PowerShell 默认 GBK,运行前先 `chcp 65001` 切 UTF-8。 +### Q: 短新闻 / API Push 相关? +- 短新闻入库后停在 enrich 阶段:看 worker 日志 `docker compose logs worker | grep enrichment` +- ingest 接口 401:`X-Ingest-Token` 无效/吊销/过期;回 `/admin/sources/{id}/ingest-tokens` 重新生成 +- ingest 接口 429:1 秒内推超 2 篇(默认 `INGEST_RATE_PER_SEC=2`);退避 1 秒重试 +- 短新闻 Feed 看不到:先 `SELECT * FROM articles WHERE is_short_news=true` 查是否入库 +- 想清理 smoke 测试残留:`DELETE FROM articles WHERE source_ref='smoke';` + +### Q: 中文 RSS 长新闻详情页仍显示"译文"板块? +- 确认 `articles.lang_src` 是 `'zh'` / `'zh-CN'` 等(前端判断标准) +- 详情页逻辑在 `ArticleDetail.vue` `isChineseSource` computed:`isShort || lang_src.startsWith('zh')` +- 详情页还会显示"原文"卡片代替"译文"卡(commit 6) + +### Q: 加了 alembic 迁移但容器看不到新文件? +- 永远先 `docker compose up -d --no-deps --force-recreate api worker` 再 `alembic upgrade head` +- 容器在 bind mount 之前用镜像层启动,旧镜像层会被覆盖但只有 recreate 才生效 +- 详细踩坑记录见 agent memory "FastAPI + alembic 部署 SOP" + --- ## 路线图 - [x] **Phase 1 (MVP)**:5 RSS 源 + 翻译 + 网页 + admin CRUD - [x] **Phase 1.5**:LLM 智能增强(排版/分类/插图/点评) ✅ 2026-06-08 +- [x] **Phase 1.6**:API Push 短新闻(`POST /api/v1/ingest` + 三层去重 + per-token 限速) ✅ 2026-06-14 +- [x] **Phase 1.7**:中文源头 RSS 优化(详情页隐藏译文 + 翻译循环跳过省配额) ✅ 2026-06-14 - [ ] **Phase 2**:PWA 离线缓存 / 关键词订阅推送(Telegram) - [ ] **Phase 3**:Android 客户端(API Token 已预留) - [ ] **Phase 4**:自动分类/点评/实体识别(目前是 LLM 一次性,无 ML pipeline)