Files
congsh 5c028d7952 Initial commit: snapAna 截图智能整理工具
包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 15:45:50 +08:00

120 lines
7.8 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.
# 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 支持 TesseractVLM 走 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] WorkerFULL 任务优先于 OCROCR 失败不污染 `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`OCRTesseract/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. 享受筛选、随机、待办