From 5d4de50c8bc7493e4adbbb6f2c98b6761cea1c17 Mon Sep 17 00:00:00 2001 From: rain-bus Date: Sat, 6 Jun 2026 00:44:23 +0800 Subject: [PATCH] chore: update README and remove deprecated documentation --- README.md | 199 ++++++++++++++--------- REQUIREMENTS.md | 236 --------------------------- docs/api-and-ui.md | 224 -------------------------- docs/data-model.md | 394 --------------------------------------------- docs/services.md | 269 ------------------------------- 5 files changed, 119 insertions(+), 1203 deletions(-) delete mode 100644 REQUIREMENTS.md delete mode 100644 docs/api-and-ui.md delete mode 100644 docs/data-model.md delete mode 100644 docs/services.md diff --git a/README.md b/README.md index 1695573..6f54e57 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,42 @@ # HF Daily Papers — 中文论文导览站 -> 每日自动抓取 HuggingFace Daily Papers,调用 AI 生成中文结构化解读,提供本地 Web 应用用于浏览、搜索、收藏与管理。 - ---- - -## 文档导航 - -| 文档 | 说明 | -|------|------| -| [REQUIREMENTS.md](REQUIREMENTS.md) | 产品需求、技术选型、里程碑与验收标准 | -| [docs/services.md](docs/services.md) | 爬虫、AI 总结、搜索、清理、调度、安全等服务模块说明 | -| [docs/data-model.md](docs/data-model.md) | SQLite 表结构、`summary.json` schema、索引与校验策略 | -| [docs/api-and-ui.md](docs/api-and-ui.md) | 路由、页面、用户流程与验收标准 | +> 每日自动抓取 HuggingFace Daily Papers,调用 AI 生成结构化中文解读,提供本地 Web 应用用于浏览、搜索、收藏与管理。 --- ## 功能特性 - **每日抓取**:按日期拉取 HuggingFace Daily Papers,提取元数据并入库,自动去重与重试。 -- **AI 中文总结**:按需下载 PDF,调用 `pi` CLI 为每篇论文生成结构化中文解读,完成后清理临时文件。 +- **AI 中文总结**:下载 PDF,调用 `pi` CLI 为每篇论文生成结构化中文解读(动机、方法、结果、局限性等),完成后清理临时文件。 - **浏览与详情**:首页按日期导航、论文详情页展示元数据与总结,提供未总结论文的英文原文回退。 -- **搜索**:基于 SQLite FTS5 的关键词搜索,覆盖标题、摘要、作者、标签与中文总结正文。 +- **搜索**:基于 SQLite FTS5 的关键词搜索(BM25 排序、片段高亮),覆盖标题、摘要、作者、标签与总结正文。 +- **语义搜索**(可选):ChromaDB 向量数据库实现相似度搜索,优雅降级至 FTS5。 +- **论文对比**:并排对比最多 5 篇论文的 12 个结构化字段。 +- **趋势看板**:Chart.js 驱动的可视化统计(日论文量、Top 标签、投票分布、总结完成率)。 - **个人化**:收藏、阅读状态、个人笔记与阅读列表。 -- **管理后台**:基于 token 鉴权的手动抓取、总结、清扫、删除与日志查看接口。 -- **定时调度**:APScheduler 内嵌调度,默认每日 08:00 自动抓取与总结(单 worker 防重)。 +- **RSS 订阅**:最近 7 天论文的 RSS 2.0 输出,支持标签过滤。 +- **管理后台**:Token 鉴权的手动抓取、总结、清扫、删除与日志查看接口。 +- **定时调度**:APScheduler 内嵌调度,默认每日 08:00 自动抓取与总结(TaskLock 防重)。 +- **LaTeX 图片提取**:下载 arXiv 源码,扫描 `.tex` 文件提取论文图片用于详情页展示。 +- **HTMX 局部更新**:收藏切换等操作无需整页刷新。 +- **键盘快捷键**:`Ctrl+K` 或 `/` 聚焦搜索框。 --- ## 技术栈 -- **后端**:FastAPI + Uvicorn -- **模板**:Jinja2(服务端渲染) -- **前端**:HTMX + 原生 JS + 自定义 CSS -- **数据库**:SQLite + SQLAlchemy -- **全文搜索**:SQLite FTS5 -- **AI 总结**:`pi` CLI(每篇论文一次调用) -- **调度**:APScheduler(单进程内嵌) -- **语义搜索**(可选增强):ChromaDB +| 层级 | 技术 | +|------|------| +| 后端 | Python 3.12+ · FastAPI · Uvicorn | +| 模板 | Jinja2(服务端渲染) | +| 前端 | HTMX · 原生 JS · Chart.js · 自定义 CSS("kami" 纸质风格) | +| 数据库 | SQLite + SQLAlchemy · SQLite FTS5(全文搜索) | +| AI 总结 | `pi` CLI(外部工具) | +| 语义搜索 | ChromaDB(可选) | +| 调度 | APScheduler(内嵌单进程) | +| CLI | Typer | +| 测试 | pytest · pytest-asyncio | +| 构建 | Hatchling(PEP 517) | --- @@ -45,39 +45,71 @@ ``` paper/ ├── README.md -├── REQUIREMENTS.md -├── docs/ -│ ├── services.md -│ ├── data-model.md -│ └── api-and-ui.md ├── .env.example ├── pyproject.toml │ ├── app/ -│ ├── main.py # FastAPI 入口 -│ ├── config.py # 配置加载 -│ ├── database.py # SQLAlchemy 引擎与会话 -│ ├── models.py # ORM 模型 -│ ├── security.py # 管理接口 token 鉴权 -│ ├── cli.py # 命令行入口(手动抓取等) -│ ├── routes/ # 页面与 API 路由 -│ ├── services/ # 爬虫、总结、搜索、清理、调度等服务 -│ ├── templates/ # Jinja2 模板(含 partials) -│ └── static/ # CSS / JS +│ ├── main.py # FastAPI 入口(lifespan 管理) +│ ├── config.py # pydantic-settings 配置加载 +│ ├── database.py # SQLAlchemy 引擎、会话与 FTS5 +│ ├── models.py # 11 个 ORM 模型 +│ ├── utils.py # 共享工具函数 +│ ├── cli.py # Typer CLI(crawl / summarize / init-db) +│ │ +│ ├── routes/ # 页面与 API 路由 +│ │ ├── pages.py # 首页、日期页、论文详情 +│ │ ├── admin.py # Token 鉴权管理接口 +│ │ ├── search.py # 搜索、阅读列表、RSS +│ │ ├── user.py # 收藏、阅读状态、笔记 API +│ │ ├── trends.py # 趋势看板 +│ │ └── compare.py # 论文对比页 +│ │ +│ ├── services/ # 业务逻辑层 +│ │ ├── crawler.py # HuggingFace API 爬虫 +│ │ ├── summarizer.py # AI 总结编排 +│ │ ├── searcher.py # FTS5 + 语义搜索 +│ │ ├── schemas.py # Pydantic 总结校验 +│ │ ├── cleaner.py # 临时文件清理 + 日期范围删除 +│ │ ├── scheduler.py # APScheduler 每日管线 +│ │ ├── user_data.py # 收藏、阅读状态、笔记 +│ │ ├── embedder.py # ChromaDB 向量索引 +│ │ ├── trends.py # 趋势统计聚合 +│ │ ├── pdf_downloader.py # PDF + LaTeX 源码下载 +│ │ ├── pi_client.py # pi CLI 封装 + JSON 提取 +│ │ └── image_extractor.py # LaTeX 图片提取 +│ │ +│ ├── templates/ # Jinja2 模板 +│ │ ├── base.html +│ │ ├── index.html +│ │ ├── detail.html +│ │ ├── search.html +│ │ ├── reading_list.html +│ │ ├── compare.html +│ │ ├── trends.html +│ │ ├── admin_logs.html +│ │ └── partials/paper_card.html +│ │ +│ └── static/ +│ ├── css/style.css # 自定义 CSS(kami 风格) +│ └── js/app.js # 键盘快捷键 │ -├── data/ -│ ├── db/papers.db # SQLite 数据库 -│ ├── papers/{arxiv_id}/ # 长期保存的 meta.json / summary.json / raw_output.txt -│ ├── tmp/{arxiv_id}/ # 临时下载的 PDF / 源码(流程完成后清理) -│ └── chroma/ # 语义搜索向量库(可选) +├── data/ # 运行时数据(已 gitignore) +│ ├── db/papers.db # SQLite 数据库 +│ ├── papers/{arxiv_id}/ # 长期资产(meta.json / summary.json / 图片) +│ ├── tmp/{arxiv_id}/ # 临时下载(流程完成后清理) +│ └── chroma/ # ChromaDB 向量库(可选) │ -├── logs/ # 运行与抓取日志 -├── tests/ # 测试用例 -└── scripts/ # 初始化与手动工具脚本 +├── scripts/ +│ ├── init_db.py # 数据库初始化 +│ └── manual_crawl.py # 手动抓取脚本 +│ +├── tests/ # 10 个测试模块 +│ ├── conftest.py # 测试夹具(内存 DB、样本数据) +│ └── test_*.py # 各模块测试 +│ +└── logs/ # 运行日志 ``` -> `data/tmp/` 仅作为流程中转,不作为长期资产;`data/papers/` 中的 `meta.json`、`summary.json`、`raw_output.txt` 可长期保留。 - --- ## 快速开始 @@ -85,16 +117,13 @@ paper/ ### 1. 准备环境 - Python **3.12+** -- 可选:[pi](https://github.com/) CLI(用于 AI 总结,Phase 2 必需) +- 可选:[`pi`](https://github.com/) CLI(用于 AI 总结) ### 2. 安装依赖 ```bash -# 推荐使用虚拟环境 python -m venv .venv source .venv/bin/activate - -# 安装(含开发依赖) pip install -e ".[dev]" ``` @@ -107,20 +136,23 @@ cp .env.example .env 关键配置项: -| 变量 | 说明 | -|------|------| -| `APP_HOST` / `APP_PORT` | 服务监听地址,默认 `127.0.0.1:8000` | -| `ADMIN_TOKEN` | 管理接口 token,**必须修改** | -| `HF_API_BASE` | HuggingFace API 地址 | -| `TOP_N` | 每日抓取 Top N 论文 | -| `PI_BIN` / `SUMMARY_SKILL` | pi CLI 路径与使用的 skill | -| `SCHEDULER_ENABLED` | 是否启用每日定时任务 | -| `DATABASE_URL` | SQLite 数据库 URL | +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `APP_HOST` / `APP_PORT` | `127.0.0.1` / `8000` | 服务监听地址 | +| `ADMIN_TOKEN` | `change-me` | **必须修改** — 管理接口鉴权 | +| `TOP_N` | `20` | 每日抓取 Top N 论文 | +| `SCHEDULER_ENABLED` | `false` | 启用每日自动抓取 | +| `SCHEDULE_HOUR` / `SCHEDULE_MINUTE` | `8` / `0` | 定时任务时间(Asia/Shanghai) | +| `DATABASE_URL` | `sqlite:///data/db/papers.db` | 数据库路径 | +| `CHROMA_ENABLED` | `false` | 启用语义搜索 | +| `PI_BIN` | — | `pi` CLI 路径 | +| `SUMMARY_CONCURRENCY` | `3` | 最大并行总结数 | ### 4. 初始化数据库 ```bash python scripts/init_db.py +# 或:python -m app.cli init-db ``` ### 5. 启动服务 @@ -129,9 +161,9 @@ python scripts/init_db.py uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 1 ``` -> ⚠️ 调度器依赖单 worker:`--workers` 必须为 `1`,否则每日任务会被重复触发。 +> 调度器依赖单 worker:`--workers` 必须为 `1`,否则每日任务会被重复触发。 -打开浏览器访问 即可。 +打开浏览器访问 `http://127.0.0.1:8000` 即可。 --- @@ -141,13 +173,32 @@ uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 1 ```bash python scripts/manual_crawl.py --date 2025-01-15 -# 或通过 CLI 模块 -python -m app.cli crawl --date 2025-01-15 +# 或 +python -m app.cli crawl --date 2025-01-15 --top 20 ``` -### 触发单篇论文总结(管理接口) +### 手动触发总结 ```bash +# 单篇 +python -m app.cli summarize 2401.01234 + +# 批量(所有待总结论文) +python -m app.cli summarize +``` + +### 管理接口(Token 鉴权) + +```bash +# 抓取今日论文 +curl -X POST "http://127.0.0.1:8000/admin/crawl" \ + -H "Authorization: Bearer $ADMIN_TOKEN" + +# 批量总结 +curl -X POST "http://127.0.0.1:8000/admin/summarize" \ + -H "Authorization: Bearer $ADMIN_TOKEN" + +# 单篇总结 curl -X POST "http://127.0.0.1:8000/admin/summarize/2401.01234" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` @@ -160,23 +211,11 @@ pytest --- -## 里程碑 - -- **Phase 1 — MVP**:抓取、入库、首页 / 详情页浏览 -- **Phase 2 — AI 总结**:pi CLI 集成、临时文件清理、summary 校验 -- **Phase 3 — 搜索与个人化**:FTS5 搜索、收藏 / 阅读状态、阅读列表、RSS -- **Phase 4 — 管理与自动化**:APScheduler、管理后台、日志、删除与清理 -- **Phase 5 — 后续增强**:ChromaDB 语义搜索、相似推荐、趋势看板 - -详细任务列表与验收标准见 [REQUIREMENTS.md](REQUIREMENTS.md)。 - ---- - ## 安全提示 - `ADMIN_TOKEN` 是管理接口的唯一鉴权凭证,请使用强随机值并妥善保管。 - 默认仅监听 `127.0.0.1`,如需内网访问请配合反向代理与 HTTPS。 -- 项目面向本地 / 内网部署,**不包含** 多用户账号体系与公网防护。 +- 项目面向本地 / 内网部署,不包含多用户账号体系与公网防护。 --- diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md deleted file mode 100644 index e63f49e..0000000 --- a/REQUIREMENTS.md +++ /dev/null @@ -1,236 +0,0 @@ -# HF Daily Papers — 中文论文导览站 - -> 每日从 HuggingFace Daily Papers 获取热门论文,生成中文结构化解读,提供浏览、搜索、收藏和管理的本地 Web 应用。 - ---- - -## 文档索引 - -| 文档 | 内容 | -|------|------| -| [services.md](docs/services.md) | 服务模块:爬虫、AI 总结、搜索、清理、调度、安全等 | -| [data-model.md](docs/data-model.md) | SQLite 表结构、summary.json schema、索引和校验策略 | -| [api-and-ui.md](docs/api-and-ui.md) | 路由、页面、用户流程、验收标准 | - ---- - -## 1. 产品边界 - -### 当前目标 - -构建一个本地运行的论文导览站: - -1. 按日期抓取 HuggingFace Daily Papers。 -2. 提取必要元数据,写入 SQLite。 -3. 总结阶段按需下载 PDF,调用 pi CLI 为论文生成中文结构化总结,完成后清理下载文件。 -4. 展示首页、日期列表、论文详情、搜索结果、阅读列表。 -5. 支持收藏、阅读状态、个人笔记。 -6. 提供安全的管理接口,用于手动抓取、总结、清理和查看日志。 - -### 暂不做 - -- 不做 Docker / Docker Compose。 -- 不做自动归档。 -- 不保留下载文件作为长期资产:PDF/源码只用于解析和总结,流程完成后清理。 -- 不做 PDF 图片兜底提取。 -- 不做多用户账号体系。 -- 不做公网服务设计,默认本地或内网部署。 - ---- - -## 2. 技术选型 - -| 层 | 选型 | 说明 | -|----|------|------| -| 后端框架 | FastAPI | 页面路由、JSON API、管理接口 | -| 模板 | Jinja2 | 服务端渲染 HTML | -| 前端交互 | HTMX + 少量原生 JS | 收藏、状态、搜索、局部刷新 | -| 样式 | 自定义 CSS,参考 kami 风格 | kami 只作为视觉和排版参考,不调用 kami 构建管线 | -| 数据库 | SQLite + SQLAlchemy | 单文件、本地低运维 | -| 全文搜索 | SQLite FTS5 | 标题、摘要、总结、作者、标签关键词搜索 | -| 语义搜索 | ChromaDB(可选增强) | MVP 后接入,用在线嵌入服务生成向量 | -| AI 总结 | pi CLI | 一篇论文一次 pi 调用 | -| 调度 | APScheduler | 单进程内嵌调度,禁止多 worker 重复运行 | - ---- - -## 3. 项目结构 - -```text -paper/ -├── README.md -├── REQUIREMENTS.md -├── docs/ -│ ├── services.md -│ ├── data-model.md -│ └── api-and-ui.md -├── .env -├── .env.example -├── pyproject.toml -│ -├── app/ -│ ├── main.py -│ ├── config.py -│ ├── database.py -│ ├── models.py -│ ├── security.py -│ ├── cli.py -│ │ -│ ├── routes/ -│ │ ├── pages.py -│ │ ├── api.py -│ │ ├── search.py -│ │ ├── user.py -│ │ └── admin.py -│ │ -│ ├── services/ -│ │ ├── crawler.py -│ │ ├── summarizer.py -│ │ ├── searcher.py -│ │ ├── cleaner.py -│ │ ├── user_data.py -│ │ └── scheduler.py -│ │ -│ ├── templates/ -│ │ ├── base.html -│ │ ├── index.html -│ │ ├── detail.html -│ │ ├── search.html -│ │ ├── reading_list.html -│ │ ├── admin_logs.html -│ │ └── partials/ -│ │ ├── paper_card.html -│ │ ├── date_nav.html -│ │ └── search_bar.html -│ │ -│ └── static/ -│ ├── css/style.css -│ └── js/app.js -│ -├── data/ -│ ├── db/papers.db -│ ├── papers/{arxiv_id}/ -│ │ ├── meta.json -│ │ ├── summary.json -│ │ └── raw_output.txt -│ ├── tmp/{arxiv_id}/ -│ │ ├── paper.pdf -│ │ └── source/ -│ └── chroma/ -│ -├── logs/ -├── tests/ -└── scripts/ - ├── init_db.py - └── manual_crawl.py -``` - -`data/tmp/` 是临时文件目录。PDF、LaTeX 源码等下载文件只在总结阶段按需下载,解析和总结完成后删除;数据库、`meta.json`、`summary.json` 和 `raw_output.txt` 可长期保留。 - ---- - -## 4. 配置项 - -```bash -# 应用 -APP_HOST=127.0.0.1 -APP_PORT=8000 -APP_DEBUG=false -BASE_URL=http://127.0.0.1:8000 -APP_TIMEZONE=Asia/Shanghai - -# 安全 -ADMIN_TOKEN=change-me - -# HuggingFace / arXiv -HF_API_BASE=https://huggingface.co/api -HF_PROXY= -TOP_N=20 -HTTP_TIMEOUT_SECONDS=30 -HTTP_MAX_RETRIES=3 -HTTP_USER_AGENT=hf-daily-papers-local/0.1 - -# AI 总结 -PI_BIN=/home/rainbus/.local/share/mise/installs/pi/latest/pi -SUMMARY_SKILL=daily-paper-summary -SUMMARY_CONCURRENCY=3 -SUMMARY_TIMEOUT_SECONDS=300 -SUMMARY_MAX_RETRIES=1 - -# 调度 -SCHEDULER_ENABLED=true -SCHEDULE_HOUR=8 -SCHEDULE_MINUTE=0 -APP_WORKERS=1 - -# 数据库 -DATABASE_URL=sqlite:///data/db/papers.db - -# 语义搜索(后续增强,可为空) -CHROMA_ENABLED=false -CHROMA_DIR=data/chroma -EMBED_API_BASE= -EMBED_API_KEY= -EMBED_MODEL= -EMBED_DIMENSIONS= -``` - ---- - -## 5. 里程碑 - -### Phase 1 — MVP:抓取、入库、浏览 - -- [ ] FastAPI + SQLite + SQLAlchemy 项目骨架。 -- [ ] 数据表、FTS5 表、基础迁移或初始化脚本。 -- [ ] HF Daily Papers 抓取:支持日期、TOP_N、去重、重试、空日期。 -- [ ] 抓取阶段只入库元数据,不长期保存 PDF。 -- [ ] 首页 `/day/{date}` 和论文详情页 `/paper/{arxiv_id}`。 -- [ ] CLI:手动抓取指定日期。 - -### Phase 2 — AI 总结 - -- [ ] pi CLI 集成:一篇论文一次调用。 -- [ ] 总结阶段按需下载 PDF,成功或失败后清理临时文件。 -- [ ] summary.json schema 校验、降级展示、失败重试。 -- [ ] 总结状态追踪。 -- [ ] raw_output.txt 保存和管理后台复跑。 -- [ ] 总结完成后更新 `papers`、`paper_summaries`、FTS5。 - -### Phase 3 — 搜索和个人化 - -- [ ] FTS5 关键词搜索。 -- [ ] 收藏、阅读状态、个人笔记。 -- [ ] 阅读列表页。 -- [ ] RSS Feed。 - -### Phase 4 — 管理和自动化 - -- [ ] APScheduler 每日自动抓取和总结。 -- [ ] 管理接口 token 鉴权。 -- [ ] 管理后台日志。 -- [ ] 手动删除指定时间段内的数据。 -- [ ] 临时文件清理任务。 - -### Phase 5 — 后续增强 - -- [ ] ChromaDB 语义搜索。 -- [ ] 相似论文推荐。 -- [ ] 趋势看板。 -- [ ] 论文对比。 -- [ ] LaTeX 图片提取。 - ---- - -## 6. 核心验收标准 - -1. 重复抓取同一天不会重复入库。 -2. HuggingFace 或 arXiv 请求失败时有超时、重试和日志。 -3. 某篇论文总结失败不会阻塞其他论文。 -4. 首页能展示四种状态:未总结、总结中、总结失败、总结完成。 -5. 详情页在无总结时展示英文标题、摘要、作者、链接和手动总结入口。 -6. 搜索至少能匹配标题、摘要、作者、标签和中文总结正文。 -7. 管理接口没有 token 时不能触发抓取、总结、删除等写操作。 -8. PDF/源码临时文件在流程完成后被清理。 -9. 手动删除指定日期范围后,页面、搜索索引、用户数据和本地文件保持一致。 -10. 调度器在单 worker 下只触发一次每日任务。 diff --git a/docs/api-and-ui.md b/docs/api-and-ui.md deleted file mode 100644 index 4781821..0000000 --- a/docs/api-and-ui.md +++ /dev/null @@ -1,224 +0,0 @@ -# API 路由与页面设计 - -> 本文档定义页面路由、JSON API、管理接口、用户流程和验收标准。 - ---- - -## 1. 页面路由 - -| 方法 | 路径 | 说明 | -|------|------|------| -| GET | `/` | 重定向到 `/day/{today}` | -| GET | `/day/{date}` | 指定日期论文列表 | -| GET | `/paper/{arxiv_id}` | 论文详情 | -| GET | `/search` | 搜索页和搜索结果 | -| GET | `/reading-list` | 收藏和阅读列表 | -| GET | `/admin/logs` | 管理日志页,需要 token | -| GET | `/rss.xml` | RSS Feed | - -后续增强: - -- `/trends` -- `/compare?ids=id1,id2` -- `/similar/{arxiv_id}` - ---- - -## 2. 数据 API - -| 方法 | 路径 | 说明 | -|------|------|------| -| GET | `/api/papers?date=&tag=&q=` | 论文列表 | -| GET | `/api/paper/{arxiv_id}` | 单篇论文详情 | -| GET | `/api/dates` | 有数据的日期列表 | -| GET | `/api/tags` | 标签及计数 | -| GET | `/api/stats` | 统计信息 | -| GET | `/api/search?q=&tag=` | FTS5 搜索 | - ---- - -## 3. 用户数据 API - -| 方法 | 路径 | 说明 | -|------|------|------| -| POST | `/api/bookmark/{arxiv_id}` | 收藏/取消收藏 | -| POST | `/api/reading-status/{arxiv_id}` | 更新阅读状态 | -| GET | `/api/note/{arxiv_id}` | 获取笔记 | -| POST | `/api/note/{arxiv_id}` | 保存笔记 | - -请求和响应使用 JSON。无账号体系,数据写入本地 SQLite。 - -安全边界: - -- 默认 `APP_HOST=127.0.0.1` 时,用户数据 API 只服务本机访问。 -- 如果绑定到非本地地址,用户数据写接口需要启用 same-origin 检查或 token。 - ---- - -## 4. 管理接口 - -所有管理接口都需要: - -```text -Authorization: Bearer -``` - -| 方法 | 路径 | 说明 | -|------|------|------| -| POST | `/admin/crawl` | 手动抓取指定日期,默认今天 | -| POST | `/admin/summarize/{arxiv_id}` | 手动总结或重跑单篇 | -| POST | `/admin/summarize` | 批量总结 pending 论文 | -| POST | `/admin/cleanup` | 清理临时文件 | -| POST | `/admin/delete` | 删除指定日期范围内的数据 | -| GET | `/admin/logs` | 查看任务日志 | - -### `/admin/delete` 请求体 - -```json -{ - "date_start": "2026-06-01", - "date_end": "2026-06-05", - "include_notes": true, - "confirm": "DELETE" -} -``` - -`confirm` 必须为 `DELETE`,否则拒绝执行。 - ---- - -## 5. 页面状态 - -### 首页 / 日期页 - -每张论文卡片展示: - -- 中文标题;没有总结时展示英文标题。 -- 一句话摘要;没有总结时展示英文 abstract 截断。 -- 标签、作者、upvotes、难度。 -- 总结状态:未总结、总结中、失败、已完成。 -- 收藏按钮、阅读状态入口、详情链接。 - -### 详情页 - -详情页按状态降级: - -| 状态 | 展示 | -|------|------| -| 无总结 | 英文标题、作者、摘要、HF/arXiv 链接、手动总结按钮 | -| processing | 元数据 + “正在生成总结” | -| failed | 元数据 + 错误类型 + 手动重跑按钮 | -| done/normal | 完整中文结构化解读 | -| done/degraded | 展示已有内容,缺失模块标注不完整 | -| done/low | 顶部质量提示 + 已有内容 | - -详情模块: - -- 一句话摘要 -- 预置知识 -- 研究动机 -- 核心方法 -- 实验结果 -- 局限和改进方向 -- 原文链接 -- 收藏、阅读状态、个人笔记 - -### 搜索页 - -MVP 只提供关键词搜索: - -- 搜索框。 -- 标签筛选。 -- 结果按相关性和日期排序。 -- 命中片段高亮。 - -语义搜索作为后续增强,UI 上先不展示模式切换。 - -### 阅读列表 - -筛选项: - -- 全部收藏。 -- 未读。 -- 已读摘要。 -- 已读原文。 -- 有笔记。 -- 标签。 - ---- - -## 6. 用户流程 - -```text -访问 / - -> /day/{today} - -> 浏览论文卡片 - -> 点击论文进入 /paper/{arxiv_id} - -> 收藏 / 修改阅读状态 / 写笔记 - -> 搜索 /search?q=... - -> 阅读列表 /reading-list -``` - -管理员流程: - -```text -POST /admin/crawl - -> 抓取论文并入库 - -> POST /admin/summarize - -> 生成总结 - -> POST /admin/cleanup - -> 查看 /admin/logs -``` - -删除流程: - -```text -POST /admin/delete - -> 校验 token 和 confirm - -> 删除日期范围内论文、索引、用户数据、本地文件 - -> 写入删除记录和日志 -``` - ---- - -## 7. MVP 验收标准 - -### 抓取 - -- 指定日期能抓取 HF Daily Papers 前 N 篇。 -- 同一天重复抓取不会重复插入。 -- 空日期返回成功状态和 0 篇日志。 -- 网络失败有 timeout、重试和错误日志。 - -### 总结 - -- 单篇总结失败不会影响其他论文。 -- 必填字段缺失时自动重试一次。 -- 重试失败后标记 `permanent_failure`。 -- 总结成功后页面、FTS 索引和 summary.json 同步更新。 -- 成功或失败后都会清理 PDF/源码临时文件。 - -### 页面 - -- 首页能显示未总结、总结中、失败、完成状态。 -- 详情页无总结时仍可阅读英文元数据。 -- degraded/low 总结有清晰提示。 -- 移动端不出现主要内容横向溢出。 - -### 搜索 - -- 能搜索标题、摘要、作者、标签、中文总结。 -- 删除论文后搜索结果不再出现该论文。 - -### 管理 - -- 无 token 不能调用管理接口。 -- token 错误返回 401。 -- 删除接口没有 `confirm=DELETE` 时拒绝执行。 -- 删除指定日期范围后,页面、搜索索引、用户数据和本地文件保持一致。 - -### 调度 - -- 单 worker 下每日任务只执行一次。 -- 多 worker 或非本地 host 配置存在风险时,应用启动给出明确告警或拒绝启动。 -- `/` 的 today 和每日调度日期都按 `APP_TIMEZONE` 计算。 diff --git a/docs/data-model.md b/docs/data-model.md deleted file mode 100644 index 1ae3507..0000000 --- a/docs/data-model.md +++ /dev/null @@ -1,394 +0,0 @@ -# 数据模型 - -> 本文档定义 SQLite 表、summary.json schema、索引同步、校验和删除策略。 - ---- - -## 1. 设计原则 - -1. SQLite 是主存储,页面和 API 优先从 SQLite 读取。 -2. PDF、LaTeX 源码等下载文件是临时资产,解析和总结完成后清理。 -3. `meta.json`、`summary.json`、`raw_output.txt` 可作为可读备份保存在 `data/papers/{arxiv_id}/`。 -4. 作者和标签使用规范化表,避免 JSON 字符串聚合困难。 -5. FTS5 由独立索引表维护,写入/更新/删除论文时同步更新。 -6. ChromaDB 是后续增强,不能成为 MVP 页面渲染的必要依赖。 -7. 每个 SQLite 连接必须执行 `PRAGMA foreign_keys=ON`,确保级联删除生效。 - ---- - -## 2. 数据库表 - -### papers — 论文主表 - -```sql -CREATE TABLE papers ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - arxiv_id TEXT UNIQUE NOT NULL, - title_en TEXT NOT NULL, - title_zh TEXT, - abstract TEXT, - published_at DATE, - paper_date DATE NOT NULL, - crawled_at DATETIME NOT NULL, - upvotes INTEGER DEFAULT 0, - hf_url TEXT, - arxiv_url TEXT, - pdf_url TEXT, - source_url TEXT, - asset_status TEXT DEFAULT 'not_downloaded', -- not_downloaded / ready / failed / cleaned - asset_error TEXT, - meta_path TEXT, - summary_path TEXT, - raw_output_path TEXT, - summary_quality TEXT -- normal / degraded / low -); -``` - -手动删除采用物理删除。删除审计写入 `data_delete_jobs` 和 `crawl_logs`。 - -### paper_authors — 作者表 - -```sql -CREATE TABLE paper_authors ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - name TEXT NOT NULL, - position INTEGER DEFAULT 0, - UNIQUE(paper_id, name) -); -``` - -### paper_tags — 标签表 - -```sql -CREATE TABLE paper_tags ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - tag TEXT NOT NULL, - source TEXT DEFAULT 'hf', -- hf / ai / user - UNIQUE(paper_id, tag, source) -); -``` - -### paper_summaries — 结构化总结表 - -```sql -CREATE TABLE paper_summaries ( - paper_id INTEGER PRIMARY KEY REFERENCES papers(id) ON DELETE CASCADE, - one_line TEXT, - difficulty TEXT, - prerequisites_json TEXT, - motivation_problem TEXT, - motivation_goal TEXT, - motivation_gap TEXT, - method_overview TEXT, - method_key_idea TEXT, - method_steps_json TEXT, - method_novelty TEXT, - results_main_json TEXT, - results_benchmarks_json TEXT, - limitations_json TEXT, - weaknesses_json TEXT, - future_work_json TEXT, - reproducibility TEXT, - full_json TEXT NOT NULL, - updated_at DATETIME NOT NULL -); -``` - -结构化字段用于页面、对比、搜索和排序;`full_json` 保留完整原始结构。 - -### summary_status — 总结状态 - -```sql -CREATE TABLE summary_status ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - status TEXT NOT NULL, -- pending / processing / done / failed / permanent_failure - quality TEXT, -- normal / degraded / low - error_type TEXT, -- pdf_download_failed / timeout / process_error / json_not_found / json_invalid / field_missing / schema_error / unknown - error TEXT, - retry_count INTEGER DEFAULT 0, - raw_output_saved BOOLEAN DEFAULT FALSE, - started_at DATETIME, - completed_at DATETIME, - UNIQUE(paper_id) -); -``` - -### papers_fts — 全文搜索索引 - -```sql -CREATE VIRTUAL TABLE papers_fts USING fts5( - title_en, - title_zh, - abstract, - authors, - tags, - summary_text, - tokenize='unicode61' -); -``` - -使用普通 FTS5 表,由应用层显式维护。普通 FTS5 会复制一份索引文本,数据量可接受,换取简单可靠的更新和删除语义: - -- 新增论文:插入标题、摘要、作者、标签。 -- 总结完成:更新中文标题和 `summary_text`。 -- 收藏/笔记变更:不进入 FTS,避免个人笔记污染论文搜索。 -- 删除论文:同步删除对应 FTS row。 - -写入时必须使用 `papers.id` 作为 FTS rowid: - -```sql -INSERT INTO papers_fts(rowid, title_en, title_zh, abstract, authors, tags, summary_text) -VALUES (:paper_id, :title_en, :title_zh, :abstract, :authors, :tags, :summary_text); -``` - -更新时可使用普通 `UPDATE`,也可先按 rowid 删除再插入。删除论文时执行: - -```sql -DELETE FROM papers_fts WHERE rowid = :paper_id; -``` - -### crawl_logs — 任务日志 - -```sql -CREATE TABLE crawl_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task TEXT NOT NULL, -- crawl / summarize / cleanup / delete / scheduler - status TEXT NOT NULL, -- running / success / failed - date DATE, - papers_found INTEGER, - papers_new INTEGER, - error TEXT, - started_at DATETIME NOT NULL, - completed_at DATETIME -); -``` - -### task_locks — 任务锁 - -```sql -CREATE TABLE task_locks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task TEXT NOT NULL, - lock_key TEXT NOT NULL, -- 通常是日期,如 2026-06-05 - status TEXT NOT NULL, -- running / finished / failed - owner TEXT, - acquired_at DATETIME NOT NULL, - released_at DATETIME -); - -CREATE UNIQUE INDEX uq_task_locks_running -ON task_locks(task, lock_key) -WHERE status = 'running'; -``` - -防重入规则:启动任务前插入 `status='running'` 的锁;插入失败说明同一任务正在运行,直接跳过或返回 409。任务完成后更新为 `finished` 或 `failed`。 - -### user_bookmarks — 收藏 - -```sql -CREATE TABLE user_bookmarks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - note TEXT, - created_at DATETIME NOT NULL, - UNIQUE(paper_id) -); -``` - -### user_reading_status — 阅读状态 - -```sql -CREATE TABLE user_reading_status ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - status TEXT NOT NULL, -- unread / skimmed / read_summary / read_full - updated_at DATETIME NOT NULL, - UNIQUE(paper_id) -); -``` - -### user_notes — 个人笔记 - -```sql -CREATE TABLE user_notes ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_id INTEGER NOT NULL REFERENCES papers(id) ON DELETE CASCADE, - content TEXT NOT NULL, - created_at DATETIME NOT NULL, - updated_at DATETIME NOT NULL, - UNIQUE(paper_id) -); -``` - -### data_delete_jobs — 手动删除记录 - -```sql -CREATE TABLE data_delete_jobs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - date_start DATE NOT NULL, - date_end DATE NOT NULL, - include_notes BOOLEAN DEFAULT TRUE, - paper_count INTEGER DEFAULT 0, - status TEXT NOT NULL, -- running / success / failed - error TEXT, - started_at DATETIME NOT NULL, - completed_at DATETIME -); -``` - ---- - -## 3. summary.json Schema - -```python -from pydantic import BaseModel, Field, field_validator - - -class Prerequisites(BaseModel): - concepts: list[str] = Field(default_factory=list) - level: str = "" - - -class Motivation(BaseModel): - problem: str - goal: str = "" - gap: str = "" - - -class Method(BaseModel): - overview: str = "" - key_idea: str - steps: list[str] = Field(default_factory=list) - novelty: str = "" - - -class Results(BaseModel): - main_findings: list[str] = Field(default_factory=list) - benchmarks: list[dict] = Field(default_factory=list) - limitations: list[str] = Field(default_factory=list) - - -class Improvements(BaseModel): - weaknesses: list[str] = Field(default_factory=list) - future_work: list[str] = Field(default_factory=list) - reproducibility: str = "" - - -class SummarySchema(BaseModel): - title_zh: str - one_line: str - tags: list[str] - difficulty: str = "" - paper_date: str | None = None - prerequisites: Prerequisites = Field(default_factory=Prerequisites) - motivation: Motivation - method: Method - results: Results = Field(default_factory=Results) - improvements: Improvements = Field(default_factory=Improvements) - - @field_validator("title_zh", "one_line") - @classmethod - def non_empty_text(cls, value: str) -> str: - if not value or not value.strip(): - raise ValueError("field cannot be empty") - return value.strip() - - @field_validator("tags") - @classmethod - def non_empty_tags(cls, value: list[str]) -> list[str]: - tags = [tag.strip() for tag in value if tag and tag.strip()] - if not tags: - raise ValueError("tags cannot be empty") - return tags -``` - -实际实现时还要给 `Motivation.problem` 和 `Method.key_idea` 加同样的非空校验,空字符串视为 `field_missing`。 - -### 字段分级 - -| 级别 | 字段 | 处理 | -|------|------|------| -| 必填 | `title_zh`, `one_line`, `tags`, `motivation.problem`, `method.key_idea` | 缺失则失败并重试 | -| 重要 | `motivation.goal`, `motivation.gap`, `method.overview`, `results.main_findings` | 缺失可入库,标记 `degraded` | -| 可选 | `benchmarks`, `limitations`, `improvements`, `prerequisites` | 缺失用默认值 | - ---- - -## 4. 校验和错误处理 - -### 状态流转 - -```text -pending -> processing -> done - └-> failed -> pending retry -> processing - └-> permanent_failure -``` - -### 错误分级 - -| error_type | 场景 | 自动重试 | -|------------|------|----------| -| timeout | pi 超时 | 是 | -| pdf_download_failed | PDF 下载失败或文件不可读 | 是 | -| process_error | pi 进程非 0 退出 | 是 | -| json_not_found | 输出中找不到 JSON | 是 | -| json_invalid | JSON 解析失败 | 是 | -| field_missing | 必填字段缺失 | 是 | -| schema_error | 字段类型不合法 | 是 | -| unknown | 未分类异常 | 是 | - -最大自动重试次数为 1。重试后仍失败则标记 `permanent_failure`,管理后台可手动重跑。 - -### 质量分级 - -| quality | 条件 | 页面表现 | -|---------|------|----------| -| normal | 必填和重要字段完整 | 完整展示 | -| degraded | 必填完整,重要字段部分缺失 | 缺失模块显示“不完整” | -| low | 字段存在但内容明显空洞 | 顶部提示“AI 总结质量较低” | - ---- - -## 5. 删除和清理策略 - -### 临时文件清理 - -每篇论文处理完成后删除: - -- `data/tmp/{arxiv_id}/paper.pdf` -- `data/tmp/{arxiv_id}/source/` -- 其他下载中间文件 - -总结失败时也应清理下载文件,但保留 `raw_output.txt` 和错误日志。 - -### 手动删除指定日期范围 - -管理员可删除 `paper_date` 落在指定范围内的数据。删除流程: - -1. 查询目标论文。 -2. 删除用户收藏、阅读状态、笔记。 -3. 删除 summary/status/authors/tags。 -4. 删除 FTS5 索引。 -5. 删除 `data/papers/{arxiv_id}/` 和 `data/tmp/{arxiv_id}/`。 -6. 物理删除 `papers` 记录。 -7. 写入 `data_delete_jobs` 和 `crawl_logs`。 - -如后续需要可恢复删除,再引入 `deleted_at` 软删除字段;MVP 不实现。 - ---- - -## 6. ChromaDB 增强设计 - -ChromaDB 不进入 MVP。接入时只索引 `paper_summaries` 中的高信号字段: - -- 中文标题 -- 英文标题 -- 标签 -- 一句话摘要 -- `motivation_problem` -- `method_key_idea` - -向量维度必须和 `EMBED_MODEL` 匹配。写入前校验 embedding 长度,不匹配则跳过语义索引并记录日志,不影响普通页面和 FTS 搜索。 diff --git a/docs/services.md b/docs/services.md deleted file mode 100644 index 564faff..0000000 --- a/docs/services.md +++ /dev/null @@ -1,269 +0,0 @@ -# 服务模块详解 - -> 本文档描述各服务模块的职责、输入输出、失败处理和实现约束。 - ---- - -## 1. 爬虫服务 - -**职责**:从 HuggingFace Daily Papers 获取论文列表,写入元数据。PDF 不在抓取阶段长期保存。 - -### 数据源 - -- Daily Papers API:`GET https://huggingface.co/api/daily_papers?date=YYYY-MM-DD` -- PDF:`https://arxiv.org/pdf/{arxiv_id}.pdf`(总结阶段按需下载) -- 源码(后续增强):`https://arxiv.org/e-print/{arxiv_id}` - -HuggingFace 官方 Hub API 文档说明 `/api/daily_papers` 支持 `date` 查询参数。 - -### 规则 - -- `arxiv_id` 是唯一键。 -- 重复抓取同一天时,已有论文只更新 upvotes、标签等可变元数据,不重复插入。 -- 网络请求必须设置 timeout、User-Agent、重试次数。 -- API 返回空列表时记录成功日志,不视为失败。 -- 抓取阶段不下载 PDF;总结阶段 PDF 下载失败时更新 `asset_status=failed` 和 `summary_status.error_type=pdf_download_failed`。 - -### 接口 - -```python -async def fetch_daily(date: str, top_n: int) -> list[PaperMeta]: ... -async def upsert_papers(papers: list[PaperMeta]) -> list[Paper]: ... -``` - ---- - -## 2. AI 总结服务 - -**职责**:调用 pi CLI,把单篇论文转成结构化中文总结。 - -### 调用原则 - -- 一篇论文一次 pi 调用。 -- 并发数由 `SUMMARY_CONCURRENCY` 控制,默认 3。 -- 单篇超时由 `SUMMARY_TIMEOUT_SECONDS` 控制,默认 300 秒。 -- pi 路径通过 `PI_BIN` 配置,当前可以先使用宿主机路径;跑通后再抽象部署方式。 -- PDF 在总结开始前按需下载到 `data/tmp/{arxiv_id}/paper.pdf`,总结成功或失败后清理。 - -### 调用示例 - -```bash -pi -p --skill daily-paper-summary \ - "请深度解读以下论文,并按指定 JSON schema 输出: - @data/papers/2401.12345/meta.json - @data/tmp/2401.12345/paper.pdf" -``` - -### 流程 - -```text -取 pending 论文 - -> 下载 PDF 到 data/tmp/{arxiv_id}/paper.pdf - -> status=processing - -> 调 pi - -> 提取 JSON - -> Pydantic 校验 - -> 写 summary.json - -> 写 paper_summaries / paper_tags / papers_fts - -> status=done - -> 清理 PDF/源码临时文件 -``` - -失败时保存 raw output、更新 `summary_status`,并清理下载文件。 - -PDF 下载失败不调用 pi,直接记录 `pdf_download_failed` 并进入重试流程。 - ---- - -## 3. 搜索服务 - -**职责**:MVP 提供 FTS5 关键词搜索;后续接入 ChromaDB 语义搜索。 - -### FTS5 搜索 - -索引字段: - -- 英文标题 -- 中文标题 -- 英文摘要 -- 作者 -- 标签 -- 中文总结正文 - -应用层负责同步 FTS: - -```python -def build_fts_document(paper: Paper, summary: PaperSummary | None) -> FtsDocument: - summary_text = "" - if summary: - summary_text = " ".join([ - summary.one_line or "", - summary.motivation_problem or "", - summary.motivation_goal or "", - summary.method_overview or "", - summary.method_key_idea or "", - " ".join(summary.results_main or []), - ]) - return FtsDocument(...) -``` - -### ChromaDB 语义搜索(后续) - -接入时要求: - -- `CHROMA_ENABLED=true` 才初始化。 -- embedding API 失败不能影响总结入库。 -- embedding 维度和配置不匹配时记录日志并跳过。 -- 使用当前 ChromaDB 官方 API 重新确认查询和过滤语法后实现。 - ---- - -## 4. 页面渲染服务 - -**职责**:从 SQLite 读取数据并渲染 Jinja2 模板。 - -kami 只作为风格参考: - -- 参考纸张质感、留白、字体层级和墨蓝强调色。 -- 不调用 kami,不依赖 kami 生成页面。 -- CSS 放在 `app/static/css/style.css`,按本项目页面实际结构维护。 - -页面必须支持降级状态: - -- 无总结:显示英文元数据和“AI 总结尚未生成”。 -- 总结失败:显示错误类型和手动重跑入口。 -- degraded/low:显示提示,但仍展示已有内容。 - ---- - -## 5. 用户数据服务 - -**职责**:本地个人化数据,无账号体系。 - -功能: - -- 收藏/取消收藏。 -- 阅读状态:`unread`、`skimmed`、`read_summary`、`read_full`。 -- 个人 Markdown 笔记。 -- 阅读列表:按收藏、状态、标签、日期筛选。 - -所有用户数据跟随论文删除一起删除。 - ---- - -## 6. 清理和删除服务 - -**职责**:清理临时文件,并支持管理员手动删除指定日期范围内的数据。 - -### 临时文件清理 - -触发时机: - -- 单篇总结成功后。 -- 单篇总结失败后。 -- 每日任务结束后兜底扫描 `data/tmp/`。 - -### 手动删除 - -接口: - -```python -async def delete_papers_by_date_range( - date_start: date, - date_end: date, - include_notes: bool = True, -) -> DeleteResult: ... -``` - -要求: - -- 删除前统计目标论文数量。 -- 删除 DB 记录、FTS 索引、本地文件。 -- 删除失败时记录具体 arXiv ID 和错误。 -- 日期范围必须有限制,避免误删全部数据;管理接口需要二次确认参数。 - ---- - -## 7. 调度服务 - -**职责**:自动执行每日抓取和总结。 - -### 约束 - -- 应用以单 worker 运行。 -- `APP_WORKERS` 必须为 1,或 `SCHEDULER_ENABLED=false`。 -- 启动时检查运行中任务,避免重复执行。 -- 同一日期同一任务使用数据库锁或日志状态防重入。 -- 推荐使用 `task_locks` 表;抢锁失败时,自动任务跳过,管理接口返回 409。 - -### 每日流程 - -```text -08:00 - -> 按 APP_TIMEZONE 计算 today - -> crawl(date=today) - -> summarize pending papers - -> cleanup tmp files - -> write logs -``` - -手动触发方式: - -- CLI:`python -m app.cli crawl --date YYYY-MM-DD` -- API:`POST /admin/crawl` - ---- - -## 8. 管理和安全服务 - -**职责**:保护所有有副作用的管理操作。 - -### 鉴权 - -管理接口必须要求 `ADMIN_TOKEN`: - -```text -Authorization: Bearer -``` - -受保护接口: - -- `POST /admin/crawl` -- `POST /admin/summarize/{arxiv_id}` -- `POST /admin/summarize` -- `POST /admin/cleanup` -- `POST /admin/delete` -- `GET /admin/logs` - -如果 `ADMIN_TOKEN` 为空或为默认值 `change-me`,应用启动时应警告;如果 `APP_HOST` 不是 `127.0.0.1`,应拒绝启动或要求显式确认。 - -用户数据接口默认仅面向本地使用。如果 `APP_HOST=127.0.0.1`,收藏、阅读状态、笔记接口不额外要求 token;如果绑定到非本地地址,应启用 same-origin 检查或要求 `ADMIN_TOKEN`,避免内网其他人修改本地笔记。 - ---- - -## 9. RSS 服务 - -**职责**:输出最近论文的 RSS Feed。 - -MVP 只做 `/rss.xml`: - -- 默认最近 7 天。 -- 支持 `?tag=RAG`。 -- 有中文标题则用中文标题,否则用英文标题。 -- 详情链接指向本站 `/paper/{arxiv_id}`。 - -Atom 和 JSON Feed 作为后续增强。 - ---- - -## 10. 后续增强服务 - -这些能力暂不进入 MVP: - -- LaTeX 图片提取。 -- ChromaDB 语义搜索。 -- 相似论文推荐。 -- 趋势看板。 -- 论文对比页。 - -实现前需要重新评估数据量、API 成本、页面复杂度和验收标准。