Files
Rain-Bus 90fe705e8f refactor: 迁移布局检测模型从 PicoDet 到 DocLayout-YOLO
- 核心变更:
  - app/services/layout_detector.py: 重写布局检测器,从 PicoDet-S_layout_3cls 迁移到 DocLayout-YOLO (DocStructBench, imgsz=1024)
  - 支持多设备推理 (CPU/CUDA/DirectML/OpenVINO 等),自动探测最优设备
  - 预处理改为 letterbox (保比例缩放+灰边 padding),坐标还原使用 (model_coord - padding) / ratio 公式
  - 后处理解析 YOLOv10 end-to-end 输出 [N,6]=[x1,y1,x2,y2,conf,cls]
  - 类别映射改为按 class name 动态匹配 (figure/figure_group→picture, table/table_group→table)

- 新增文件:
  - scripts/export_doclayout_yolo_onnx.py: DocLayout-YOLO ONNX 导出脚本 (独立 venv 运行)
  - tests/test_layout_detector.py: 布局检测器完整测试 (35 个用例)

- 配置更新:
  - .env.example: 更新布局检测配置 (新增 LAYOUT_IMGSZ, LAYOUT_DEVICE, LAYOUT_DEVICE_ID)
  - app/config.py: Settings 类对应字段
  - pyproject.toml: 新增 export 依赖组 (torch, doclayout-yolo, onnx 等)

- 删除旧文件:
  - scripts/export_picodet_onnx.py: 旧 PicoDet 导出脚本

- 文档更新:
  - README.md: 更新环境变量说明
  - 相关服务注释更新 (pdf_image_extractor.py, summary_persister.py, reextract_images.py)

此重构遵循项目初期开发阶段规范,大胆调整数据模型,无需向后兼容。
2026-06-14 10:41:44 +08:00

287 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HF Daily Papers — 中文论文导览站
> 每日自动抓取 HuggingFace Daily Papers,调用 AI 生成结构化中文解读,提供本地 Web 应用用于浏览、搜索、收藏与管理。
---
## 功能特性
- **每日抓取**:按日期拉取 HuggingFace Daily Papers,提取元数据并入库,自动去重与重试。
- **AI 中文总结**:下载 PDF,通过 `pi``claude` 后端为每篇论文生成结构化中文解读(动机、方法、结果、局限性等),完成后清理临时文件。
- **浏览与详情**:首页按日期导航、论文详情页展示元数据与总结,提供未总结论文的英文原文回退。
- **搜索**:基于 SQLite FTS5 的关键词搜索(BM25 排序、片段高亮),覆盖标题、摘要、作者、标签与总结正文。
- **语义搜索**(可选):ChromaDB 向量数据库实现相似度搜索,优雅降级至 FTS5。
- **论文对比**:并排对比最多 5 篇论文的 12 个结构化字段。
- **趋势看板**:Chart.js 驱动的可视化统计(日论文量、Top 标签、投票分布、总结完成率)。
- **个人化**:收藏、阅读状态、个人笔记与阅读列表。
- **RSS 订阅**:最近 7 天论文的 RSS 2.0 输出,支持标签过滤。
- **管理后台**Session 认证的 Web 管理界面(仪表盘、论文管理、日志查看、手动操作)。
- **定时调度**APScheduler 内嵌调度,默认每日自动抓取与总结(TaskLock 防重)。
- **LaTeX 图片提取**:下载 arXiv 源码,扫描 `.tex` 文件提取论文图片用于详情页展示。
- **布局检测**(可选):ONNX 模型识别 PDF 页面布局,提升图片提取精度。
- **HTMX 局部更新**:收藏切换等操作无需整页刷新。
- **键盘快捷键**`Ctrl+K``/` 聚焦搜索框。
---
## 技术栈
| 层级 | 技术 |
|------|------|
| 后端 | Python 3.12+ · FastAPI · Uvicorn |
| 模板 | Jinja2(服务端渲染) |
| 前端 | HTMX · 原生 JS · Chart.js · 自定义 CSS"kami" 纸质风格) |
| 数据库 | SQLite + SQLAlchemy · SQLite FTS5(全文搜索) |
| AI 总结 | `pi` CLI 或 `claude` CLI(可配置后端) |
| 语义搜索 | ChromaDB(可选) |
| 调度 | APScheduler(内嵌单进程) |
| CLI | Typer |
| 测试 | pytest · pytest-asyncio |
| 构建 | HatchlingPEP 517 |
---
## 项目结构
```
paper/
├── README.md
├── .env.example
├── pyproject.toml
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 入口(lifespan 管理)
│ ├── config.py # pydantic-settings 配置加载
│ ├── database.py # SQLAlchemy 引擎、会话与 FTS5
│ ├── models.py # 11 个 ORM 模型 + 1 枚举
│ ├── utils.py # 共享工具函数
│ ├── exceptions.py # 统一业务异常体系
│ ├── cli.py # Typer CLIcrawl / summarize / init-db
│ │
│ ├── routes/ # 页面与 API 路由
│ │ ├── pages.py # 首页、日期页、论文详情、相似推荐
│ │ ├── admin.py # Session 认证管理后台
│ │ ├── search.py # 搜索、阅读列表、RSS
│ │ ├── user.py # 收藏、阅读状态、笔记 API
│ │ ├── trends.py # 趋势看板
│ │ └── compare.py # 论文对比页
│ │
│ ├── services/ # 业务逻辑层
│ │ ├── crawler.py # HuggingFace API 爬虫
│ │ ├── summarizer.py # AI 总结编排(调度层)
│ │ ├── summary_generator.py # 总结生成与重试
│ │ ├── summary_persister.py # 总结持久化与文件管理
│ │ ├── summary_utils.py # 总结工具(prompt 构建、PDF 提取)
│ │ ├── pi_client.py # pi CLI 封装 + JSON 提取
│ │ ├── claude_backend.py # claude CLI 后端
│ │ ├── searcher.py # FTS5 + 语义搜索
│ │ ├── schemas.py # Pydantic 总结校验
│ │ ├── cleaner.py # 临时文件清理 + 日期范围删除
│ │ ├── scheduler.py # APScheduler 每日管线
│ │ ├── pipeline.py # 抓取 + 总结流水线编排
│ │ ├── admin.py # 管理后台查询与统计
│ │ ├── user_data.py # 收藏、阅读状态、笔记
│ │ ├── embedder.py # ChromaDB 向量索引
│ │ ├── trends.py # 趋势统计聚合
│ │ ├── pdf_downloader.py # PDF + LaTeX 源码下载
│ │ ├── pdf_image_extractor.py # LaTeX 图片提取 + 图表关联
│ │ └── layout_detector.py # ONNX 布局检测(可选)
│ │
│ ├── templates/ # Jinja2 模板
│ │ ├── base.html
│ │ ├── index.html
│ │ ├── detail.html
│ │ ├── search.html
│ │ ├── reading_list.html
│ │ ├── compare.html
│ │ ├── trends.html
│ │ ├── login.html
│ │ ├── admin_dashboard.html
│ │ ├── admin_papers.html
│ │ ├── admin_logs.html
│ │ └── partials/
│ │ ├── admin_subnav.html
│ │ ├── paper_card.html
│ │ └── summary_list.html
│ │
│ └── static/
│ ├── css/
│ │ ├── style.css # 自定义 CSSkami 风格)
│ │ └── admin.css # 管理后台样式
│ ├── js/
│ │ ├── app.js # 键盘快捷键
│ │ ├── date-picker.js # 日期导航
│ │ └── lightbox.js # 图片灯箱
│ └── favicon.svg
├── data/ # 运行时数据(已 gitignore
│ ├── db/papers.db # SQLite 数据库
│ ├── papers/{arxiv_id}/ # 长期资产(meta.json / summary.json / 图片)
│ ├── tmp/{arxiv_id}/ # 临时下载(流程完成后清理)
│ ├── chroma/ # ChromaDB 向量库(可选)
│ └── models/ # ONNX 模型(布局检测)
├── scripts/
│ ├── init_db.py # 数据库初始化
│ ├── manual_crawl.py # 手动抓取脚本
│ ├── export_doclayout_yolo_onnx.py # 导出布局检测 ONNX 模型
│ ├── reextract_images.py # 批量重新提取图片
│ └── validate_summary.py # 校验总结 JSON 结构
├── tests/ # 13 个测试模块
│ ├── conftest.py # 测试夹具(内存 DB、样本数据)
│ └── test_*.py # 各模块测试
└── logs/ # 运行日志
```
---
## 快速开始
### 1. 准备环境
- Python **3.12+**
- [uv](https://docs.astral.sh/uv/) 包管理器
- 可选:[`pi`](https://www.npmjs.com/package/@mariozechner/pi-coding-agent) CLI 或 [`claude`](https://claude.ai/code) CLI(用于 AI 总结)
### 2. 安装依赖
```bash
cp .env.example .env
uv sync
```
### 3. 配置环境变量
```bash
# 编辑 .env,至少修改以下三项
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_password
SECRET_KEY=your_random_secret_key
```
关键配置项:
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `APP_HOST` / `APP_PORT` | `127.0.0.1` / `8000` | 服务监听地址 |
| `APP_DEBUG` | `false` | 调试模式(开启 uvicorn reload |
| `BASE_URL` | `http://127.0.0.1:8000` | 站点根 URL(用于 RSS 生成) |
| `APP_TIMEZONE` | `Asia/Shanghai` | 时区 |
| `ADMIN_USERNAME` | `admin` | 管理后台用户名 |
| `ADMIN_PASSWORD` | — | 管理后台密码 |
| `SECRET_KEY` | `change-me` | Session 签名密钥 |
| `HF_API_BASE` | `https://huggingface.co/api` | HuggingFace API 地址 |
| `HF_PROXY` | — | HTTP 代理 |
| `TOP_N` | `20` | 每日抓取 Top N 论文 |
| `HTTP_TIMEOUT_SECONDS` | `30` | HTTP 请求超时 |
| `HTTP_MAX_RETRIES` | `3` | HTTP 最大重试次数 |
| `SUMMARY_BACKEND` | `pi` | 总结后端:`pi``claude` |
| `PI_BIN` | — | `pi` CLI 路径 |
| `CLAUDE_BIN` | `claude` | `claude` CLI 路径 |
| `SUMMARY_SKILL` | `daily-paper-summary` | pi 总结技能名 |
| `SUMMARY_CONCURRENCY` | `3` | 最大并行总结数 |
| `SUMMARY_TIMEOUT_SECONDS` | `1200` | 单篇总结超时 |
| `SUMMARY_MAX_RETRIES` | `2` | 总结最大重试次数 |
| `SUMMARY_PDF_MODE` | `auto` | PDF 传递方式:`auto` / `inject` / `search` |
| `UPVOTE_REFRESH_DAYS` | `7` | 自动刷新最近 N 天论文的 upvotes |
| `PDF_DOWNLOAD_TIMEOUT` | `120` | PDF 下载超时(秒) |
| `SCHEDULER_ENABLED` | `false` | 启用每日自动抓取 |
| `SCHEDULE_HOUR` / `SCHEDULE_MINUTE` | `4` / `0` | 定时任务时间(APP_TIMEZONE |
| `APP_WORKERS` | `1` | Uvicorn worker 数(必须为 1 |
| `DATABASE_URL` | `sqlite:///data/db/papers.db` | 数据库路径 |
| `CHROMA_ENABLED` | `false` | 启用语义搜索 |
| `CHROMA_DIR` | `data/chroma` | ChromaDB 数据目录 |
| `EMBED_API_BASE` | — | Embedding API 地址 |
| `EMBED_API_KEY` | — | Embedding API Key |
| `EMBED_MODEL` | — | Embedding 模型名 |
| `EMBED_DIMENSIONS` | `0` | 向量维度 |
| `LAYOUT_MODEL_PATH` | `data/models/doclayout_yolo_docstructbench_imgsz1024.onnx` | DocLayout-YOLO ONNX 模型路径(可选) |
| `LAYOUT_IMGSZ` | `1024` | 模型输入尺寸 |
| `LAYOUT_THRESHOLD` | `0.2` | 布局检测置信度阈值(可选) |
| `LAYOUT_DEVICE` | `auto` | 推理设备:auto/cpu/cuda/directml/openvino/...(可选) |
### 4. 初始化数据库
```bash
uv run python -m app.cli init-db
```
### 5. 启动服务
```bash
uv run python -m app.main
```
> 调度器依赖单 worker:不可使用 `--workers > 1`,否则每日任务会被重复触发。
打开浏览器访问 `http://127.0.0.1:8000` 即可。
---
## 常用命令
### 手动抓取
```bash
# 自动探测今天/昨天
uv run python -m app.cli crawl
# 指定日期
uv run python -m app.cli crawl 2025-01-15 --top 20
# 强制重抓(即使已有数据)
uv run python -m app.cli crawl --force
```
### 手动触发总结
```bash
# 单篇
uv run python -m app.cli summarize 2401.01234
# 批量(所有待总结论文)
uv run python -m app.cli summarize
# 指定后端和 PDF 模式
uv run python -m app.cli summarize --backend claude --pdf-mode inject
```
### 管理后台
打开浏览器访问 `http://127.0.0.1:8000/admin/login`,使用 `.env` 中配置的用户名密码登录。
管理后台包含:
- **仪表盘**:统计卡、调度器控制、存储信息、最近活动
- **论文管理**:搜索、筛选、单篇/批量删除
- **日志**:运行日志、总结状态、失败重试
### 运行测试
```bash
uv run pytest
```
### 代码检查
```bash
uv run ruff format # 格式化代码
uv run ruff check --fix # 自动修复 lint 问题
```
---
## 安全提示
- 管理后台使用 Session 认证,请务必在 `.env` 中设置强密码和随机 `SECRET_KEY`
- 默认仅监听 `127.0.0.1`,如需内网访问请配合反向代理与 HTTPS。
- 项目面向本地 / 内网部署,不包含多用户账号体系与公网防护。
---
## 许可证
本项目仅供学习与个人使用,请遵守 HuggingFace、arXiv 与上游论文作者的相关条款。