后端:
- 将 handlers.rs (1338行) 拆分为 helpers/papers/notes/sync 四模块
- 将 batch_sync.rs 拆分为 batch/{mod,meta,asset} 三模块
- 新增 POST /api/upload 多部件文件上传接口
- 新增 POST /api/no_resource 标记文献"无全文资源"
- 新增 GET/POST /api/active_bibcode 追踪活跃文献
- StandardPaper 结构体扩展 pdf_error / html_error 错误诊断字段
- download.rs 记录下载失败详情至数据库
- 新增 health_check 二进制工具,支持只读扫描与 --fix 自动修复
- 移除 scratch/ 目录、recovered_handlers.rs 及调试日志
前端:
- 新建 CustomSelect 可复用组件,替换全部原生 select
- LibraryPanel:同步按钮反馈动画、下载失败/无资源状态筛选与计数、
文献类型筛选、状态优先排序、搜索一键清空
- 详情弹窗:错误诊断展示、手动 PDF/HTML 上传区、无资源标记/恢复
- SearchPanel:扩展文献类型徽章、下载失败状态提示
- SyncPanel:同步启动乐观 UI 更新、日志容器内自动滚动
- Tab 状态 localStorage 持久化、弹窗 z-index 修复
308 lines
16 KiB
Markdown
308 lines
16 KiB
Markdown
# AstroResearch Architecture / 架构设计
|
||
|
||
AstroResearch 是一个集成了天文学文献检索、多通道下载(含防爬绕过与手动上传)、下载错误诊断、结构化解析、中英学术对比翻译、引文星系图谱以及馆藏健康度诊断的天文科研辅助系统。
|
||
|
||
## 1. 整体架构 (Overall Architecture)
|
||
|
||
AstroResearch 采用 **C/S (Client-Server)** 架构,由前端 React 单页应用和后端 Axum HTTP 服务构成,核心流程及层级如下:
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph Frontend ["React 前端 (Port 5173 / 8000)"]
|
||
UI[仪表盘 UI / ReaderPanel]
|
||
Canvas[引文 Canvas 拓扑图]
|
||
API_Client[Axum API 客户端]
|
||
CustomSelect[CustomSelect 可复用组件]
|
||
end
|
||
|
||
subgraph Backend ["Rust Axum 后端 (Port 8000)"]
|
||
Router[Axum 路由与中间件]
|
||
|
||
subgraph API ["API 层 (模块化)"]
|
||
Helpers[helpers.rs 格式转换与数据库工具]
|
||
Papers[papers.rs 文献检索/下载/上传/解析/翻译/引文/导出]
|
||
Notes[notes.rs 笔记 CRUD]
|
||
Sync[sync.rs 批量同步控制]
|
||
end
|
||
|
||
subgraph Services ["服务层"]
|
||
Batch[batch/ 批量同步引擎]
|
||
BatchMeta[batch/meta.rs 元数据采集]
|
||
BatchAsset[batch/asset.rs 资源处理]
|
||
Parser[parser.rs HTML/PDF 解析]
|
||
Downloader[download.rs 多通道下载器]
|
||
Translator[translation.rs LLM 翻译器]
|
||
Logging[logging.rs 日志系统]
|
||
end
|
||
|
||
DB[("SQLite / astro_research.db")]
|
||
end
|
||
|
||
subgraph External [外部第三方服务]
|
||
ADS[NASA ADS API]
|
||
arXiv[arXiv Atom XML API]
|
||
MinerU[MinerU PDF 解析服务]
|
||
QiniuCDN[七牛云对象存储 CDN]
|
||
LLM[LLM API]
|
||
end
|
||
|
||
UI -->|用户操作| API_Client
|
||
API_Client -->|RESTful APIs| Router
|
||
Router --> API
|
||
|
||
Papers -->|查询/保存元数据| DB
|
||
Papers -->|文献下载| Downloader
|
||
Papers -->|文件上传| Papers
|
||
Papers -->|正文解析| Parser
|
||
Papers -->|学术翻译| Translator
|
||
Sync -->|批量操作| Batch
|
||
|
||
BatchMeta -->|元数据同步| ADS
|
||
BatchMeta -->|元数据同步| arXiv
|
||
BatchAsset -->|批量文件下载| Downloader
|
||
BatchAsset -->|批量正文解析| Parser
|
||
BatchAsset -->|批量翻译| Translator
|
||
Batch -->|写库记录| DB
|
||
|
||
Downloader -->|代理请求| ADS
|
||
Downloader -->|直连或 ar5iv| arXiv
|
||
|
||
Parser -->|图文降级解析| MinerU
|
||
Parser -->|托管插图| QiniuCDN
|
||
|
||
Translator -->|天文术语翻译| LLM
|
||
|
||
Canvas -->|引文网络请求| Papers
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 核心工作流 (Core Workflows)
|
||
|
||
### 2.1 文献下载流程 (Download Flow)
|
||
|
||
本流程实现了文献的多通道流式下载,支持多级回退、错误诊断记录以及安全反爬防线绕过:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户 (React 前端)
|
||
participant H as 处理器 (papers.rs)
|
||
participant D as 下载器 (download.rs)
|
||
participant DB as 本地数据库 (SQLite)
|
||
|
||
U->>H: 1. 发起下载请求 (POST /api/download, 含 bibcode, force)
|
||
H->>DB: 2. 查询文献元数据 (获取 arxiv_id, doi 等)
|
||
alt force == true
|
||
H->>DB: 3. 重置本地下载路径字段为 NULL
|
||
end
|
||
|
||
H->>D: 4. 调度下载器执行物理拉取
|
||
alt 文献含有 arxiv_id (通道 A:arXiv 直连优先)
|
||
D->>D: 5a. 去除版本号 (strip_arxiv_version, v2 -> 无版本)
|
||
D->>D: 5b. 随机延时 (maybe_delay: 500-2000ms) 并伪装 UA
|
||
D->>D: 5c. 下载 PDF 并校验文件头 (%PDF + %%EOF)
|
||
D->>D: 5d. 优先请求官方 HTML (arxiv.org/html/)
|
||
note over D: 若官方 HTML 返回 404/错误
|
||
D->>D: 5e. 自动降级回退请求 ar5iv HTML (ar5iv.labs.arxiv.org)
|
||
D->>D: 5f. 校验 HTML 内容 (detect_anti_bot 检测反爬)
|
||
else 无 arxiv_id (通道 B:ADS 路由回退)
|
||
D->>D: 6a. 跟踪 ADS Link Gateway 重定向路由
|
||
note over D: 若遇到 validate.perfdrive.com 拦截
|
||
D->>D: 6b. 自动解析并解码 ssc 参数提取直链
|
||
note over D: 若指向 IOPscience / Springer
|
||
D->>D: 6c. IOP 专属策略:预热主页写入 Cookie,带 Referer 下载 PDF
|
||
D->>D: 6d. Springer 专属策略:使用 Chrome 头下载 HTML 页
|
||
note over D: 若网关均失败且存在 DOI
|
||
D->>D: 6e. CrossRef 兜底:请求 CrossRef API 获取 PDF URL 并直连下载
|
||
end
|
||
|
||
alt 下载成功
|
||
D-->>H: 7a. 返回下载好的本地物理 PDF & HTML 路径
|
||
H->>DB: 8a. 更新 pdf_path & html_path 记录
|
||
H-->>U: 9a. 返回最新文献状态 (is_downloaded: true)
|
||
else 下载失败
|
||
D-->>H: 7b. 返回失败原因
|
||
H->>DB: 8b. 以 error: 前缀记录诊断信息
|
||
H-->>U: 9b. 返回文献状态 (pdf_error / html_error 已填充)
|
||
end
|
||
```
|
||
|
||
#### 详细下载说明:
|
||
1. **指令接收与校验**:后端 `download_paper` 接口在 `force` 参数为 `true` 时,会强行擦除数据库中已下载的文件路径,启动无缓存的物理文件重新拉取。
|
||
2. **下载反爬伪装**:下载器 `Downloader` 请求时采用动态生成的 Firefox/Chrome 轮换 User-Agent,并在每次 HTTP 访问前强制加入随机休眠机制(500ms - 2000ms),模拟人类自然阅读行为。
|
||
3. **内容完整性校验**:
|
||
- 对 PDF 严格校验前四个字节(必须是 `%PDF`)以及尾部检索(必须包含 `%%EOF` 终止符),排查登录墙、错误页伪装成 PDF 导致下载坏文件的问题。
|
||
- 对 HTML 文本利用 `detect_anti_bot` 流水线过滤 "cloudflare"、"captcha"、"robot check" 等拦截特征。
|
||
4. **错误诊断记录**:下载失败时,系统会将具体的失败原因(如 "Cloudflare 拦截"、"404 Not Found" 等)以 `error:` 前缀存入数据库的 `pdf_path` / `html_path` 字段。前端通过 `pdf_error` / `html_error` 字段读取并向用户展示。
|
||
|
||
---
|
||
|
||
### 2.2 手动上传流程 (Upload Flow)
|
||
|
||
当自动下载受防爬或人机验证阻碍时,用户可手动上传文献文件:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户 (React 前端 / 浏览器书签)
|
||
participant H as 处理器 (papers.rs)
|
||
participant DB as 本地数据库 (SQLite)
|
||
participant FS as 本地文件系统
|
||
|
||
U->>H: 1. 上传文件 (POST /api/upload, Multipart: bibcode + type + file)
|
||
H->>H: 2. 解析 Multipart 字段
|
||
alt bibcode 未直接匹配数据库
|
||
H->>DB: 3a. 尝试通过 DOI 匹配
|
||
H->>DB: 3b. 尝试通过 arXiv ID 匹配(自动去除版本号)
|
||
end
|
||
H->>H: 4. 校验文件格式 (PDF 校验 %PDF 文件头)
|
||
H->>FS: 5. 写入物理文件 (library/PDF/ 或 library/HTML/)
|
||
H->>DB: 6. 更新 pdf_path / html_path,清除 error: 诊断记录
|
||
H-->>U: 7. 返回更新后的文献元数据 (is_downloaded: true)
|
||
```
|
||
|
||
---
|
||
|
||
### 2.3 文献解析流程 (Parse Flow)
|
||
|
||
本流程负责将本地下载的 HTML 或 PDF 转换为高保真的 Markdown:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户 (React 前端)
|
||
participant H as 处理器 (papers.rs)
|
||
participant P as 解析器 (parser.rs)
|
||
participant M as MinerU (PDF解析服务)
|
||
participant Q as 七牛云 (对象存储)
|
||
participant DB as 本地数据库 (SQLite)
|
||
|
||
U->>H: 1. 发起解析请求 (POST /api/parse, 含 bibcode, force)
|
||
H->>DB: 2. 查询文献物理路径 (pdf_path, html_path, markdown_path)
|
||
alt force == false 且本地已存在 Markdown 物理缓存
|
||
H->>H: 3. 读取本地 Markdown 物理文件
|
||
H-->>U: 4. 直接返回缓存 Markdown,流程结束
|
||
end
|
||
|
||
H->>P: 5. 触发结构化文献解析
|
||
alt 本地存在 HTML 文件
|
||
P->>P: 6a. 剥离广告/导航栏与尾页页脚噪声
|
||
P->>P: 6b. 公式保护:利用占位符隔离 MathJax/LaTeX 公式段
|
||
P->>P: 6c. 标签规范:还原 LaTeXML 特定 span 为标准 table/tr/td,修正上下标
|
||
P->>P: 6d. 插图处理:把相对图像路径替换为绝对 CDN 外链地址
|
||
P->>P: 6e. 转换 GFM Markdown 并恢复 LaTeX 公式
|
||
P->>P: 6f. 后处理:清除冗余的 margin 空白与前导缩进
|
||
else 仅有 PDF 文件 (PDF 降级解析)
|
||
P->>M: 7a. 获取批量预签名上传 URL (POST /file-urls/batch/)
|
||
M-->>P: 7b. 返回预签名上传 URL 与 Batch ID
|
||
P->>M: 7c. 上传 PDF 二进制字节流 (PUT 至预签名 URL)
|
||
loop 轮询任务状态 (每 10s 一次,最多 45 次)
|
||
P->>M: 7d. 查询提取进度与结果 (GET /extract-results/batch/{id})
|
||
M-->>P: 7e. 返回处理状态 ("done"/"error"等)
|
||
end
|
||
P->>P: 7f. 下载解析结果的 ZIP 压缩包并解压提取
|
||
loop 遍历每一个提取的插图
|
||
P->>Q: 7g. 上传插图文件并获取七牛云 CDN 域名外链
|
||
end
|
||
P->>P: 7h. 在 Markdown 中重写插图链接为七牛云 CDN 绝对路径
|
||
end
|
||
|
||
P-->>H: 8. 返回清洗转换出的标准英文 Markdown 文本
|
||
H->>P: 9. 写入本地物理缓存 Markdown/ 目录
|
||
H->>DB: 10. 更新数据库 markdown_path 记录
|
||
H-->>U: 11. 返回标准 Markdown 内容渲染展示
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 智能对照翻译流程 (Translation Flow)
|
||
|
||
本流程实现了基于天文学专属词汇表的 LLM 专业对比翻译:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户 (React 前端)
|
||
participant H as 处理器 (papers.rs)
|
||
participant T as 翻译器 (translation.rs)
|
||
participant D as 天文词典 (Trie 树)
|
||
participant L as 大模型 (LLM API)
|
||
participant DB as 本地数据库 (SQLite)
|
||
|
||
U->>H: 1. 请求文献对比翻译 (POST /api/translate, 含 bibcode, force)
|
||
H->>DB: 2. 查询文献路径及状态
|
||
alt force == false 且本地已存在翻译缓存文件
|
||
H->>H: 3. 读取本地 Translation/{bibcode}_zh.md 物理文件
|
||
H-->>U: 4. 直接返回缓存译文,流程结束
|
||
end
|
||
|
||
H->>H: 5. 读取对应的英文解析 Markdown 物理文件
|
||
H->>T: 6. 调度翻译器执行翻译工作流
|
||
|
||
T->>D: 7. 加载本地 dictionary.txt 并初始化 Trie 树结构
|
||
T->>D: 8. 执行英文 Markdown 文本分词匹配
|
||
D->>D: 9a. 进行前缀匹配检索
|
||
D->>D: 9b. 遵循"最长匹配优先"原则,过滤子词去重
|
||
D-->>T: 10. 返回该篇文献提取出的天文学名词对照 (Glossary)
|
||
|
||
loop 针对英文 Markdown 进行段落分块 (Token 长度控制)
|
||
T->>L: 11. 携带 Glossary + 英文原文段落发送 Prompt 请求
|
||
note over L: LLM 遵循系统 Prompt 约束:<br>1. 专业词汇严格对应 Glossary 译出<br>2. 严禁改变 LaTeX 公式及 Markdown 标签<br>3. 保持中英段落高度对齐
|
||
L-->>T: 12. 返回学术级双语对照翻译段落
|
||
end
|
||
|
||
T->>T: 13. 拼接所有段落,生成完整的对照 Markdown
|
||
T->>H: 14. 写入本地物理缓存 Translation/ 目录
|
||
H->>DB: 15. 更新数据库中的 translation_path 字段
|
||
H-->>U: 16. 返回翻译后 Markdown 渲染展示
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 核心模块说明
|
||
|
||
### 3.1 API 层 (`src/api/`)
|
||
|
||
| 模块文件 | 职责 |
|
||
|:---|:---|
|
||
| **[mod.rs](../src/api/mod.rs)** | 定义全局共享状态 `AppState`(含 `active_bibcode` 追踪)和统一文献格式 `StandardPaper`(含 `pdf_error` / `html_error` 诊断字段),通过 `pub mod handlers` 保持向后兼容命名空间。 |
|
||
| **[helpers.rs](../src/api/helpers.rs)** | 共享工具函数:`convert_ads_doc_to_standard`、`convert_arxiv_to_standard`、`save_paper_to_db`、`get_paper_from_db`、`check_paper_paths_in_db`。负责数据库 CRUD 和 `error:` 前缀诊断信息的读取与解析。 |
|
||
| **[papers.rs](../src/api/papers.rs)** | 文献相关核心处理器:统一检索 (`search_papers`)、下载 (`download_paper`)、**手动上传 (`upload_paper_file`)**、**无资源标记 (`mark_no_resource`)**、解析 (`parse_paper`)、翻译 (`translate_paper`)、引文拓扑 (`get_citation_network`)、文献详情 (`get_paper_detail`)、馆藏列表 (`get_library`)、BibTeX 导出 (`export_citations`)、**活跃文献追踪 (`get/set_active_bibcode`)**。 |
|
||
| **[notes.rs](../src/api/notes.rs)** | 笔记 CRUD 处理器:创建 (`create_note`)、查询 (`get_notes`)、删除 (`delete_note`)。 |
|
||
| **[sync.rs](../src/api/sync.rs)** | 批量同步控制处理器:元数据同步启动/状态/计数、资源同步启动/停止/状态、检索条件管理。 |
|
||
|
||
### 3.2 服务层 (`src/services/`)
|
||
|
||
| 模块文件 | 职责 |
|
||
|:---|:---|
|
||
| **[batch/mod.rs](../src/services/batch/mod.rs)** | 批量同步引擎公共导出模块。 |
|
||
| **[batch/meta.rs](../src/services/batch/meta.rs)** | 元数据大批量采集引擎 (`MetaSync`):分页检索 ADS/arXiv 并增量入库。 |
|
||
| **[batch/asset.rs](../src/services/batch/asset.rs)** | 物理资源批量处理引擎 (`AssetSync`):后台异步执行下载/解析/翻译流水线,记录 `download_failed` / `parse_failed` 计数,保留最新 100 条日志。 |
|
||
| **[download.rs](../src/services/download.rs)** | 多通道下载器:浏览器头伪装与请求延迟控制、ADS Link Gateway 重定向追踪与 `validate.perfdrive.com` 防护解码绕过、官方 `arxiv.org/html` 优先及 `ar5iv` 兜底、**下载失败时以 `error:` 前缀记录诊断信息至数据库**。 |
|
||
| **[parser.rs](../src/services/parser.rs)** | HTML 语法树向 GFM Markdown 逆向转换,使用占位符保护 LaTeX 公式;统一图表链接;集成 MinerU PDF 解析。 |
|
||
| **[translation.rs](../src/services/translation.rs)** | 基于本地天文双语词典的 Trie 树最长匹配分词,注入 Glossary 系统提示词让 LLM 实现学术级精细翻译。 |
|
||
| **[query_parser.rs](../src/services/query_parser.rs)** | 高级检索语法解析器,将前端组合条件(AND/OR/NOT + 字段限定)转换为 ADS API 查询语法。 |
|
||
| **[logging.rs](../src/services/logging.rs)** | 全局日志记录系统,基于 `tracing-subscriber` 实现控制台美化日志输出与基于时间的每日滚动日志文件写出,使用上海时区 (+08:00) 格式化时间。 |
|
||
|
||
### 3.3 客户端层 (`src/clients/`)
|
||
|
||
| 模块文件 | 职责 |
|
||
|:---|:---|
|
||
| **[ads.rs](../src/clients/ads.rs)** | NASA ADS API 客户端:文献检索、元数据获取、BibTeX 导出。 |
|
||
| **[arxiv.rs](../src/clients/arxiv.rs)** | arXiv Atom XML API 客户端:解析 XML Feed 提取文献元数据。 |
|
||
| **[qiniu.rs](../src/clients/qiniu.rs)** | 七牛云对象存储客户端:PDF 插图上传与 CDN 外链生成。 |
|
||
|
||
### 3.4 独立工具 (`src/bin/`)
|
||
|
||
| 文件 | 职责 |
|
||
|:---|:---|
|
||
| **[health_check.rs](../src/bin/health_check.rs)** | 馆藏健康度诊断与修复工具:检测损坏文件、丢失文件、`error:` 报错记录和孤立 Markdown;`--fix` 模式自动清理并重置数据库状态。 |
|
||
|
||
### 3.5 前端核心组件 (`dashboard/src/`)
|
||
|
||
| 组件文件 | 职责 |
|
||
|:---|:---|
|
||
| **[App.tsx](../dashboard/src/App.tsx)** | 全局状态管理:Tab 持久化、手动上传处理、无资源标记、活跃文献追踪、详情弹窗(含错误诊断和上传区)。 |
|
||
| **[components/CustomSelect.tsx](../dashboard/src/components/CustomSelect.tsx)** | 可复用下拉选择组件:统一视觉风格、点击外部关闭、选中高亮。 |
|
||
| **[components/CitationGalaxyCanvas.tsx](../dashboard/src/components/CitationGalaxyCanvas.tsx)** | 基于 HTML5 Canvas 的自研力导向引文星系图谱引擎:节点排斥力、中心引力、拖拽阻尼、双击多层级衍生。 |
|
||
| **[features/library/LibraryPanel.tsx](../dashboard/src/features/library/LibraryPanel.tsx)** | 馆藏管理面板:同步反馈、下载失败/无资源状态筛选、文献类型筛选(13 种)、状态优先排序。 |
|
||
| **[features/search/SearchPanel.tsx](../dashboard/src/features/search/SearchPanel.tsx)** | 跨源检索面板:高级组合条件、排序分页、下载失败状态提示、文献类型徽章(16 种)。 |
|
||
| **[features/sync/SyncPanel.tsx](../dashboard/src/features/sync/SyncPanel.tsx)** | 批量同步控制台:乐观 UI 更新、容器内日志自动滚动。 |
|