5c028d7952
包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。 Co-authored-by: Cursor <cursoragent@cursor.com>
120 lines
7.8 KiB
Markdown
120 lines
7.8 KiB
Markdown
# snapAna 进度文档
|
||
|
||
> 维护原则:完成或推进一个功能后在这里追加/更新条目;下次接手时先读这里再读代码。
|
||
|
||
## v0.1 (MVP) · 2026-05-22
|
||
|
||
### 后端 (FastAPI + SQLite)
|
||
|
||
- [x] 项目骨架:`backend/app/{core,models,schemas,providers,services,api}`,零迁移启动(`init_db` 自动建表 + 装配 FTS5 触发器)。
|
||
- [x] 数据模型:
|
||
- `screenshots`(含 `file_hash` 唯一、`captured_at`/`ai_status` 索引)
|
||
- `screenshot_meta` (1:1) + `screenshots_fts` (FTS5 over ocr_text/ai_title/ai_summary/ai_suggestion)
|
||
- `tags` + `screenshot_tags` 多对多
|
||
- `categories`(首次启动自动灌入 8 个默认分类)
|
||
- `todos`(AI 抽取的待办,状态:pending/doing/done/dropped)
|
||
- `jobs`(OCR/VLM/FULL 三种类型,含重试计数与最后错误)
|
||
- `watch_folders`(含 `is_sensitive` 字段,敏感目录禁上传)
|
||
- `settings`(键值表,存 Provider JSON)
|
||
- [x] 文件监听:`watcher.py` 使用 PollingObserver,新增/重命名都会触发;写入后等待文件大小稳定再入库。
|
||
- [x] 入库:sha256 去重,相同内容仅更新路径;同步生成 webp 缩略图。
|
||
- [x] 手动批量导入:`POST /api/watch/import`,后台任务扫描目录。
|
||
- [x] Provider 抽象:`OCRProvider`/`VLMProvider`;内置 `TesseractOCR` 与 `OpenAICompatVLM`(兼容 Ollama / GLM / MiniMax / OpenAI / OpenRouter)。
|
||
- [x] 分析流水线:`analyze_screenshot` -> OCR -> VLM -> 写 meta -> 解析 category/tags/todos;敏感目录禁止 base64 上传。
|
||
- [x] 异步 worker:`AnalyzeWorker` 单例,启动时复位上次 `running` 任务,asyncio.Semaphore 控制并发,失败自动按 `MAX_RETRIES` 重排。
|
||
- [x] REST 接口:
|
||
- `GET /api/screenshots`(分页 + 过滤 + FTS5 关键词)
|
||
- `GET /api/screenshots/{id}`、`PATCH`、`DELETE`、`POST .../reanalyze`、`/file`、`/thumb`
|
||
- `GET /api/screenshots/random`、`/stats`
|
||
- `GET/PATCH/DELETE /api/todos`、`GET /api/todos/summary`
|
||
- `GET/POST/PATCH/DELETE /api/watch/folders`、`POST /api/watch/import`、`GET /api/watch/queue`
|
||
- `GET /api/settings`(api_key 脱敏)、`GET/PUT /api/settings/providers/{key}`
|
||
- `GET/POST/PATCH/DELETE /api/settings/categories`、`GET /api/settings/tags`
|
||
|
||
### 前端 (React + Vite + Tailwind + react-window)
|
||
|
||
- [x] 路由:首页 / 库 / 随机 / 待办 / 设置
|
||
- [x] 首页:四宫格状态卡 + 每日回顾随机 6 张 + 分类分布
|
||
- [x] 库浏览:左侧筛选侧栏(关键词、分类、时间区间、排序、状态、收藏、热门标签) + react-window 虚拟滚动卡片网格 + 分页
|
||
- [x] 详情抽屉:原图 + AI 标题/摘要/建议 + OCR 文本(可复制)+ 分类切换 + 标签编辑 + 待办列表 + 元信息 + 收藏/重分析/移除
|
||
- [x] 随机展示页:单张大图 + 元信息侧栏 + 「再来一张」
|
||
- [x] 待办页:四个状态 Tab + 卡片列表 + 完成/搁置/重置 + 跳回原图
|
||
- [x] 设置页:
|
||
- 监听目录增删改 + 「重扫」
|
||
- OCR / VLM Provider 配置(OCR 支持 Tesseract,VLM 走 OpenAI 兼容)
|
||
- 分类管理(颜色 + 提示词)
|
||
|
||
### 工程化
|
||
|
||
- [x] `start-dev.ps1` 一键启动(自动建 venv + npm install + 并发启动后端与前端)
|
||
- [x] `.gitignore`、根 `README.md`、`backend/README.md`、`.env.example`
|
||
- [x] CORS、SQLite WAL / busy_timeout 等优化
|
||
|
||
## v0.1.6 · 待办/搜索/标签/排序
|
||
|
||
- [x] **待办**:分页 + 标题/备注关键词搜索
|
||
- [x] **库搜索**:FTS 前缀 + LIKE 子串(「三花」可匹配「三花猫」)+ 标签名模糊
|
||
- [x] **标签页** `/tags`:全部标签浏览、搜索、排序、点击跳转库筛选
|
||
- [x] **库排序**:导入时间、标题、文件大小等 8 种
|
||
- [x] **EXIF 地点**:入库读 GPS/拍摄时间,自动加 `地点:` 标签;重分析保留
|
||
|
||
## v0.1.5 · OCR 补跑队列
|
||
|
||
- [x] **OCR 专用任务** `JobKind.OCR`:仅重跑 OCR/视觉识文,不改动 AI 结果
|
||
- [x] **批量入队** `POST /api/watch/jobs/enqueue-ocr-failed`(AI 成功 + OCR 失败)
|
||
- [x] **单张补跑** `POST /api/screenshots/{id}/reocr`
|
||
- [x] Worker:FULL 任务优先于 OCR;OCR 失败不污染 `ai_status`
|
||
- [x] 队列页「OCR 待补」统计 + 补跑按钮;详情页「补跑 OCR」
|
||
|
||
## v0.1.4 · 队列详情页
|
||
|
||
- [x] **队列 API**:`GET /api/watch/jobs` 分页列出任务(含 `last_error`、缩略图、路径)
|
||
- [x] **队列操作**:`POST /api/watch/jobs/retry-failed` 重试失败任务;`POST /api/watch/jobs/reset-stale` 复位僵尸 RUNNING
|
||
- [x] **Worker 优化**:`status()` 改用 `GROUP BY` 计数;空闲时自动复位超时 RUNNING
|
||
- [x] **前端队列页**:侧栏「队列」入口;失败/运行中/排队/完成 Tab + 分页;展示完整错误信息;首页队列卡片可点击跳转
|
||
|
||
## v0.1.3 · UNC 网络路径 + Provider 测试
|
||
|
||
- [x] **UNC / 网络路径**:`path_utils.py` 规范化 `\\NAS\share\...`;入库、监听、原图读取不再用 `as_posix()` 破坏 UNC
|
||
- [x] **监听目录**:`POST /api/watch/validate-path` 测试路径可达性;设置页「测试路径」按钮
|
||
- [x] **Provider 测试**:`POST /api/settings/providers/{key}/test`;OCR(Tesseract/Paddle/HTTP/视觉)与视觉 AI 均支持连通性探活
|
||
|
||
## v0.1.2 · 多 OCR 引擎 + 识别模式
|
||
|
||
- [x] **OCR 引擎扩展**:Tesseract、PaddleOCR、HTTP API、视觉模型识文(OpenAI 兼容)
|
||
- [x] **文字识别方式**:设置页可选「传统 OCR / 视觉 AI / 混合」
|
||
- `ocr`:仅 OCR 引擎识文
|
||
- `vision`:视觉大模型识文(用 VLM 配置)
|
||
- `hybrid`:OCR 优先,失败时自动视觉识文,再交给 AI 分析
|
||
- [x] 新增 Provider:`ocr_vision.py`、`ocr_http.py`、`ocr_paddle.py`、`openai_vision_client.py`
|
||
- [x] API:`GET/PUT /api/settings/recognition-mode`
|
||
|
||
## v0.1.1 · 代码审核修复
|
||
|
||
- [x] **P1**:拆分 worker/analyze 事务。AI 调用全程在事务外执行,OCR/VLM 之间用三段短事务标记/写回,彻底消除「分析期间 SQLite 写锁」问题。
|
||
- [x] **P2**:详情页 PATCH `{ category_id: null }` 现在能真正清空分类(用 Pydantic `model_fields_set` 区分未传与显式 null),同时校验 category 存在性。
|
||
- [x] **P2**:`screenshots.category_id` 升级为 `ForeignKey(..., ondelete="SET NULL")`;`init_db()` 内置轻量迁移,旧库会清理悬空 `category_id`。
|
||
- [x] **P2**:跨线程唤醒 worker 改用 `loop.call_soon_threadsafe`(新接口 `worker.notify_threadsafe()`)。FastAPI 同步路由与 BackgroundTasks 都改走 threadsafe 入口。
|
||
- [x] **P3**:`GET /api/settings/providers/{key}` 返回新的 `ProviderConfigOut`,含 `api_key_mask` 字段;前端 `Settings.tsx` 去掉强转。
|
||
- [x] **P3**:`init_db()` 现在直接调用 `ensure_default_categories()`,首次访问设置/筛选页就能看到全部默认分类。
|
||
|
||
## 已知限制 & 后续可做
|
||
|
||
- 没接语义搜索 / CLIP 向量(在 plan 的「可扩展点」里预留思路)
|
||
- 没做 dedup(pHash),相同内容不同分辨率会算两条
|
||
- VLM 调用没做 RPS 限流,仅靠 `ANALYZE_CONCURRENCY`
|
||
- Tesseract 在 Windows 上需用户自行安装;可补一个一键检测脚本
|
||
- 前端筛选 Tag 只有第一个生效(多 Tag 交集后端未支持)
|
||
- 缩略图未做 LRU 清理,长时间运行需要手动清 `.data/thumbs/`
|
||
- SQLite 不支持 ALTER TABLE 加外键。已建过的旧库虽然不会再有悬空 `category_id`,但底层约束仍缺失;如果在意可以删 `.data/snapana.db` 让新表生效
|
||
|
||
## 操作回顾(首次部署)
|
||
|
||
1. `git clone` 或者直接进入仓库根目录
|
||
2. `.\start-dev.ps1` (首次约 1-2 分钟装依赖)
|
||
3. 浏览器打开 <http://127.0.0.1:5173>
|
||
4. 「设置」→ 添加监听目录(例如 `D:/Pictures/Screenshots`),勾选「敏感」可禁上传
|
||
5. 「设置」→ 配置 OCR / VLM Provider,保存
|
||
6. 等待首页右上角「队列」归零(或在「库」里看 `分析中 / 完成` 标记)
|
||
7. 享受筛选、随机、待办
|