feat: 打通全栈标注闭环、异步拆帧与模型状态

后端能力:

- 新增 Celery app、worker task、ProcessingTask 模型、/api/tasks 查询接口和 media_task_runner,将 /api/media/parse 改为创建后台任务并由 worker 执行 FFmpeg/OpenCV/pydicom 拆帧。

- 新增 Redis 进度事件模块和 FastAPI Redis pub/sub 订阅,将 worker 任务进度广播到 /ws/progress;Dashboard 后端概览接口改为聚合 projects/frames/annotations/templates/processing_tasks。

- 统一项目状态为 pending/parsing/ready/error,新增共享 status 常量,并让前端兼容归一化旧状态值。

- 扩展 AI 后端:新增 SAM registry、SAM2 真实运行状态、SAM3 状态检测与文本语义推理适配入口,以及 /api/ai/models/status GPU/模型状态接口。

- 补齐标注保存/更新/删除、COCO/PNG mask 导出相关后端契约和模板 mapping_rules 打包/解包行为。

前端能力:

- 新增运行时 API/WS 地址推导配置,前端 API 封装对齐 FastAPI 路由、字段映射、任务轮询、标注归档、导出下载和 AI 预测响应转换。

- Dashboard 改为读取 /api/dashboard/overview,并订阅 WebSocket progress/complete/error/status 更新解析队列和实时流转记录。

- 项目库导入视频/DICOM 后创建项目、上传媒体、触发异步解析并刷新真实项目列表。

- 工作区加载真实帧、无帧时触发解析任务、回显已保存标注、保存未归档 mask、更新 dirty mask、清空当前帧后端标注、导出 COCO JSON。

- Canvas 支持当前帧点/框提示调用后端 AI、渲染推理/已保存 mask、应用模板分类并维护保存状态计数;时间轴按项目 fps 播放。

- AI 页面新增 SAM2/SAM3 模型选择,预测请求携带 model;侧边栏和工作区新增真实 GPU/SAM 状态徽标。

- 模板库和本体面板接入真实模板 CRUD、分类编辑、拖拽排序、JSON 导入、默认腹腔镜分类和本地自定义分类选择。

测试与文档:

- 新增 Vitest 配置、前端测试 setup、API/config/websocket/store/组件测试,覆盖登录、项目库、Dashboard、Canvas、工作区、模型状态、时间轴、本体和模板库。

- 新增 pytest 后端测试夹具和 auth/projects/templates/media/AI/export/dashboard/tasks/progress 测试,使用 SQLite、fake MinIO、fake SAM registry 和 Redis monkeypatch 隔离外部服务。

- 新增 doc/ 文档结构,冻结当前需求、设计、接口契约、测试计划、前端逐元素审计、实现地图和后续实施计划,并同步更新 README 与 AGENTS。

验证:

- conda run -n seg_server pytest backend/tests:27 passed。

- npm run test:run:54 passed。

- npm run lint、npm run build、compileall、git diff --check 均通过;Vite 仅提示大 chunk 警告。
This commit is contained in:
2026-05-01 13:29:14 +08:00
parent 4d65c37c73
commit f020ff3b4f
78 changed files with 7089 additions and 456 deletions

View File

@@ -0,0 +1,115 @@
# 后续实施建议
目标是把当前“能看、能上传、能拆帧”的系统推进到“能真实完成标注闭环”的系统。
## 阶段 1先修接口契约已完成基础对齐
优先级最高。AI 点/框推理和 COCO 导出的基础契约已经按当前代码完成对齐。
已完成:
1. `src/lib/api.ts``updateProject()` 已改为 `PATCH`
2. `exportCoco()` 路径已改为 `/api/export/{projectId}/coco`
3. Canvas 调 AI 时已使用当前帧真实 `frame.id` 作为 `image_id`
4. Canvas 点/框坐标已转成后端需要的归一化坐标。
5. 后端 `polygons` 已转成前端可渲染的 Konva path。
剩余边界:
1. SAM 3 真实推理需要独立满足官方 Python 3.12+、PyTorch 2.7+、CUDA 12.6+ 环境。
2. 标注删除/更新接口已打通基础能力;逐点几何编辑器尚未实现。
## 阶段 2打通标注保存已完成基础闭环
当前工作区可将未保存 mask 写入后端标注表,并在加载项目帧后回显。
已完成:
1. 前端根据 `Mask.segmentation` 构造后端需要的 normalized `mask_data.polygons`
2. 用户点击“结构化归档保存”后,未保存 mask 调用 `POST /api/ai/annotate`dirty mask 调用 `PATCH /api/ai/annotations/{annotation_id}`
3. 后端保存或更新 `project_id``frame_id``template_id``mask_data``bbox`;具体分类写入 `mask_data.class`
4. 工作区加载帧后调用 `GET /api/ai/annotations` 回显已保存标注。
5. 工作区“清空遮罩”调用 `DELETE /api/ai/annotations/{annotation_id}` 删除当前帧已保存标注。
剩余建议:
1. 加入保存冲突处理和批量保存错误提示。
2. 增加逐点几何编辑器,让已保存 mask 的 polygon 本身可以被修改后 PATCH。
## 阶段 3接入导出按钮已完成 COCO JSON
当前工作区“导出 JSON 标注集”会先保存未归档 mask再调用 COCO 导出接口。
建议:
1. 增加“导出 PNG Mask ZIP”按钮调用 `/api/export/{projectId}/masks`
2. 无标注时给出更明确的空导出提示。
## 阶段 4替换 Dashboard mock
当前 Dashboard 已通过 `GET /api/dashboard/overview` 读取后端聚合快照,不再使用硬编码初始统计、队列或活动日志。
已完成:
- 聚合项目、帧、标注、模板数量和主机 load average。
-`processing_tasks` queued/running 任务生成解析队列。
- 按最近任务、项目、标注、模板记录生成活动流。
剩余建议:
1. 为任务增加取消、重试和失败详情 UI。
2. 为 Dashboard 增加任务历史筛选和失败详情入口。
## 阶段 5异步拆帧和进度
Word 方案中提到 Celery + Redis。当前已经有 Celery app、worker task 和 `processing_tasks` 表。
已完成:
1. 新建 Celery app。
2. `POST /api/media/parse` 只创建任务并立即返回 task id。
3. worker 执行 FFmpeg/OpenCV/pydicom。
4. worker 写 PostgreSQL 任务进度。
5. worker 发布 Redis `seg:progress`FastAPI 广播到 `/ws/progress`
剩余建议:
1. 为任务增加取消、重试和失败详情接口。
2. 前端 Dashboard 保留轮询兜底,并补充失败详情 UI。
Dashboard 的解析队列现在已经从“项目状态派生”升级为任务表驱动,实时推送也已通过 Redis/WebSocket 打通;剩余重点是任务控制。
## 阶段 6GT 导入与点区域
这是 Word 方案中最复杂的部分,当前完全未实现。
建议拆成小步:
1. 先支持上传二值/多类别 mask。
2. 后端按类别提取 connected components。
3. 用 OpenCV distance transform 找正向点。
4. 暂时不做骨架/HDBSCAN先生成最小可用点集。
5. 前端以可拖拽点显示并保存。
6. 后续再做骨架和聚类增强。
## 阶段 7模板优先级融合
当前模板有 z-index但没有真正用于语义冲突裁决。
建议:
1. 标注保存时记录 template class id / name / zIndex。
2. 导出 mask 时按 zIndex 从低到高覆盖。
3. 同类 mask 做 union。
4. 跨类重叠由高 zIndex 覆盖低 zIndex。
这一步完成后,系统才真正符合“语义分割一个像素一个类别”的目标。
## 阶段 8清理 UI 文案与 Mock
建议统一这些文案和真实能力:
- SAM/GPU 状态已改为 `GET /api/ai/models/status` 驱动。
- 撤销/重做按钮接历史栈,否则隐藏。
- “重新提取内侧中轴树骨架”接真实接口,否则标为未实现。
- AI 独立页不要固定 Unsplash 图,应从当前项目帧或上传文件进入。