Files
Pre_Seg_Server/doc/08-current-design-freeze.md
admin 689a9ba283 feat: 建立 SAM2 标注闭环基线
- 打通工作区真实标注闭环:支持手工多边形、矩形、圆形、点区域和线段生成 mask,并可保存、回显、更新和删除后端 annotation。

- 增强 polygon 编辑器:支持顶点拖动、顶点删除、边中点插入、多 polygon 子区域选择编辑,以及区域合并和区域去除。

- 接入 GT mask 导入:后端支持二值/多类别 mask 拆分、contour 转 polygon、distance transform seed point,前端支持导入、回显和 seed point 拖动编辑。

- 完善导出能力:COCO JSON 导出对齐前端,PNG mask ZIP 同时包含单标注 mask、按 zIndex 融合的 semantic_frame 和 semantic_classes.json。

- 打通异步任务管理:新增任务取消、重试、失败详情接口与 Dashboard 控件,worker 支持取消状态检查并通过 Redis/WebSocket 推送 cancelled 事件。

- 对接 Dashboard 后端数据:概览统计、解析队列和实时流转记录从 FastAPI 聚合接口与 WebSocket 更新。

- 增强 AI 推理参数:前端发送 crop_to_prompt、auto_filter_background 和 min_score,后端支持点/框 prompt 局部裁剪推理、结果回映射和负向点/低分过滤。

- 接入 SAM3 基础设施:新增独立 Python 3.12 sam3 环境安装脚本、外部 worker helper、后端桥接和真实 Python/CUDA/包/HF checkpoint access 状态检测。

- 保留 SAM3 授权边界:当前官方 facebook/sam3 gated 权重未授权时状态接口会返回不可用,不伪装成可推理。

- 增强前端状态管理:新增 mask undo/redo 历史栈、AI 模型选择状态、保存状态 dirty/draft/saved 流转和项目状态归一化。

- 更新前端 API 封装:补充 annotation CRUD、GT mask import、mask ZIP export、task cancel/retry/detail、AI runtime status 和 prediction options。

- 更新 UI 控件:ToolsPalette、AISegmentation、VideoWorkspace 和 CanvasArea 接入真实操作、导入导出、撤销重做、任务控制和模型状态。

- 新增 polygon-clipping 依赖,用于前端区域 union/difference 几何运算。

- 完善后端 schemas/status/progress:补充 AI 模型外部状态字段、任务 cancelled 状态和进度事件 payload。

- 补充测试覆盖:新增后端任务控制、SAM3 桥接、GT mask、导出融合、AI options 测试;补充前端 Canvas、Dashboard、VideoWorkspace、ToolsPalette、API 和 store 测试。

- 更新 README、AGENTS 和 doc 文档:冻结当前需求/设计/测试计划,标注真实功能、剩余 Mock、SAM3 授权边界和后续实施顺序。
2026-05-01 15:26:25 +08:00

13 KiB
Raw Blame History

当前设计冻结文档

冻结日期2026-05-01

本文档描述当前代码结构、数据流、接口契约和测试边界。后续实现如果改变这些设计,应同步更新本文档和测试。

总体架构

当前系统由三层组成:

  • React + TypeScript 前端 SPA。
  • FastAPI 后端 API。
  • PostgreSQL、MinIO、Redis、SAM 2 / SAM 3 等外部基础设施。

开发时前端通过 server.ts 启动 Express + Vite middleware后端通过 backend/main.py 启动 FastAPI。前端业务接口主要访问 FastAPI不依赖 server.ts 中保留的旧 mock API。

前端模块

模块 文件 设计职责
应用入口 src/App.tsx 根据登录状态和 activeModule 切换页面
全局状态 src/store/useStore.ts Zustand store保存项目、帧、模板、mask、工具状态和 mask 撤销/重做历史栈
API 封装 src/lib/api.ts Axios 客户端、字段映射、AI 响应转换
配置 src/lib/config.ts 推导 API 和 WebSocket 地址
WebSocket src/lib/websocket.ts 进度流连接、订阅和重连
模型状态 src/components/ModelStatusBadge.tsx 展示 GPU 与当前 SAM 模型真实可用状态
登录页 src/components/Login.tsx 调用登录 API写入 store
Dashboard src/components/Dashboard.tsx 展示统计、任务控制、失败详情和 WebSocket 进度消息
项目库 src/components/ProjectLibrary.tsx 项目列表、新建、导入视频/DICOM
工作区 src/components/VideoWorkspace.tsx 加载帧和模板组织工具栏、Canvas、本体面板、时间轴
Canvas src/components/CanvasArea.tsx 显示帧、缩放平移、点/框提示、渲染 mask
工具栏 src/components/ToolsPalette.tsx 切换工具、跳转 AI 页面、触发 mask 撤销/重做
时间轴 src/components/FrameTimeline.tsx 帧导航和播放
本体面板 src/components/OntologyInspector.tsx 模板选择、分类树、本地自定义分类
AI 页面 src/components/AISegmentation.tsx 独立 AI 推理视图,使用当前项目帧
模板库 src/components/TemplateRegistry.tsx 模板 CRUD、分类编辑、导入、排序

后端模块

模块 文件 设计职责
应用入口 backend/main.py FastAPI app、CORS、路由注册、健康检查、WebSocket
配置 backend/config.py Pydantic settings
数据库 backend/database.py SQLAlchemy engine、session、Base
模型 backend/models.py Project、Frame、Template、Annotation、Mask、ProcessingTask
Schema backend/schemas.py Pydantic 请求/响应模型
Auth backend/routers/auth.py 开发登录
Projects backend/routers/projects.py 项目与帧 CRUD
Templates backend/routers/templates.py 模板 CRUD 和 mapping_rules 打包/解包
Media backend/routers/media.py 上传媒体和拆帧
AI backend/routers/ai.py SAM 2 / SAM 3 可选推理、模型状态和标注保存
Export backend/routers/export.py COCO 和 PNG mask 导出
SAM 2 backend/services/sam2_engine.py SAM 2 懒加载、状态检测和点/框/自动推理
SAM 3 backend/services/sam3_engine.py, backend/services/sam3_external_worker.py, backend/setup_sam3_env.sh SAM 3 状态检测、独立 Python 3.12 环境桥接和文本语义推理适配
SAM Registry backend/services/sam_registry.py 模型选择、GPU 状态和推理分发

状态模型

前端 store 的核心对象:

  • Project项目基本信息、状态、帧数、fps、媒体路径。
  • Frame:帧 ID、项目 ID、索引、图片 URL、宽高。
  • Template / TemplateClass:模板和分类定义。
  • Mask:前端渲染用 mask包含 pathDatasegmentationbboxarea
  • maskHistory / maskFuturemask 编辑历史栈,用于撤销和重做。
  • activeModule:当前页面。
  • activeTool:当前工具。
  • aiModel:当前选择的 AI 模型,取值为 sam2sam3

关键数据流

登录

  1. Login 收集用户名和密码。
  2. login() 调用 POST /api/auth/login
  3. 成功后 store 写入 tokenApp 渲染主界面。

项目导入

  1. ProjectLibrary 创建项目。
  2. 上传视频或 DICOM 到 /api/media/upload/api/media/upload/dicom
  3. 调用 /api/media/parse 创建异步拆帧任务。
  4. Celery worker 执行 FFmpeg/OpenCV/pydicom 拆帧,持续更新 processing_tasks,并发布 Redis seg:progress
  5. 刷新项目列表。

任务控制

  1. Dashboard 从 GET /api/dashboard/overview 读取 queued/running/failed/cancelled 任务。
  2. 用户取消任务时,前端调用 POST /api/tasks/{task_id}/cancel;后端写入 cancelled、设置 finished_at,并尝试 celery_app.control.revoke(..., terminate=True)
  3. worker 在下载、解析、上传、写帧等关键阶段刷新任务状态;如果发现 cancelled,停止后续写入并发布 cancelled 事件。
  4. 用户重试任务时,前端调用 POST /api/tasks/{task_id}/retry;后端基于原任务 payload 创建新任务,记录 retry_of 并重新投递 Celery。
  5. 用户打开详情时,前端调用 GET /api/tasks/{task_id},弹窗展示 error、payload、result、Celery ID 和时间。

工作区加载

  1. VideoWorkspace 根据 currentProject.id 调用 getProjectFrames()
  2. 若无帧但项目有 video_path,触发 parseMedia(),通过 getTask() 轮询任务完成后重新取帧。
  3. 帧数据映射为 store Frame[]
  4. 当前帧传入 CanvasArea

AI 点/框推理

  1. 用户在 Canvas 选择正向点、反向点或框选。
  2. CanvasArea 读取当前帧 ID 和宽高。
  3. predictMask() 归一化坐标并携带当前 model 调用 /api/ai/predict
  4. 后端加载帧图片并通过 SAM registry 分发到 SAM 2 或 SAM 3。
  5. 前端把 polygons 转为 mask写入 store。
  6. Canvas 按当前帧过滤并渲染 mask。
  7. 新 mask 会带上当前选择的模板分类元数据,包括 classIdclassNameclassZIndex 和保存状态 draft
  8. 用户点击“结构化归档保存”后,前端将像素 segmentation 转成 normalized mask_data.polygons;未保存 mask 调用 POST /api/ai/annotatedirty mask 调用 PATCH /api/ai/annotations/{annotation_id}
  9. 工作区加载项目帧后通过 GET /api/ai/annotations 取回已保存标注并转成前端 mask。
  10. 工作区“清空遮罩”删除当前帧已保存标注,并清除当前帧本地 mask。

手工绘制与历史栈

  1. 用户在 ToolsPalette 选择多边形、矩形、圆、点或线工具。
  2. CanvasArea 将交互坐标转换成像素 polygon。
  3. 新 mask 写入 pathData、像素 segmentationbboxarea 和当前模板分类元数据。
  4. addMask()setMasks()updateMask()clearMasks() 会维护 maskHistory/maskFuture
  5. 工具栏按钮、AI 页按钮和 Canvas Ctrl+Z/Ctrl+Y 调用 undoMasks() / redoMasks()

Polygon 逐点编辑

  1. 用户点击 Canvas 上的 mask path 后,CanvasArea 记录 selectedMaskId 并显示该 mask 第一条 polygon 的顶点控制点。
  2. 拖动顶点后,前端重算 pathData、像素 segmentationbboxarea
  3. 如果 mask 已有 annotationId,编辑会把 saveStatus 标成 dirtysaved=false
  4. 归档保存时复用现有 PATCH /api/ai/annotations/{annotation_id} 链路,把更新后的 normalized polygon 写回后端。
  5. 选中顶点后 Delete/Backspace 可删除顶点;前端保持 polygon 至少三点。

区域合并与去除

  1. 用户选择 area_mergearea_remove 后,点击多个当前帧 mask 组成选择集。
  2. CanvasAreaMask.segmentation 转为 polygon-clipping 的 MultiPolygon。
  3. area_merge 使用 union更新第一个选中的主 mask并从前端 store 移除后续被合并 mask如果被移除 mask 已保存,会调用工作区传入的删除回调删除后端标注。
  4. area_remove 使用 difference从第一个选中的主 mask 中扣除后续选中 mask扣除对象本身保留。
  5. 结果会重算 pathDatasegmentationbboxarea,已保存主 mask 会进入 dirty 状态并复用归档 PATCH 链路。

GT Mask 导入

  1. 工作区“导入 GT Mask”选择图片文件。
  2. 前端 importGtMask() 以 multipart form-data 调用 POST /api/ai/import-gt-mask,携带 project_idframe_id
  3. 后端验证项目、帧、模板后使用 OpenCV 读取灰度 mask。
  4. 后端按非零像素值拆分多类别标签。
  5. 后端对每个类别的前景做 contour 提取,每个连通域保存为一个 Annotation
  6. points 字段保存距离变换中心 seed pointmask_data.polygons 保存 normalized polygonmask_data.gt_label_value 保存原始像素类别值。
  7. 前端重新读取项目标注并回显。
  8. annotationToMask() 会把 normalized seed point 转成像素坐标Canvas 以可拖拽点显示;拖动后 buildAnnotationPayload() 会把点再归一化写回后端。

模板管理

  1. TemplateRegistry 从后端读取模板。
  2. 编辑态在组件本地维护分类列表。
  3. 保存时调用 createTemplate()updateTemplate()
  4. 后端把 classesrules 打包进 mapping_rules
  5. 返回时再解包给前端。
  6. OntologyInspector 可以选择具体分类;选择结果进入全局 storeCanvasAreaAISegmentation 新建/更新 mask 时使用。

导出

  1. 后端根据项目、帧、标注和模板生成 COCO JSON。
  2. PNG mask 导出会把 normalized polygon 渲染为单标注二值 mask。
  3. PNG mask 导出还会按 mask_data.class.zIndex 或模板 z_index 从低到高覆盖,生成每帧语义融合 mask。
  4. ZIP 内写入 semantic_classes.json,记录语义值到类别、颜色和 zIndex 的映射。
  5. 前端“导出 JSON 标注集”和“导出 PNG Mask ZIP”按钮都会在导出前保存待归档标注然后下载对应文件。

接口契约

接口详情见 doc/04-api-contracts.md。测试中重点固定以下契约:

  • updateProject() 使用 PATCH /api/projects/{id}
  • exportCoco() 使用 GET /api/export/{projectId}/coco
  • exportMasks() 使用 GET /api/export/{projectId}/masks
  • cancelTask() 使用 POST /api/tasks/{taskId}/cancel
  • retryTask() 使用 POST /api/tasks/{taskId}/retry
  • predictMask() 使用 POST /api/ai/predict,请求体为 image_idprompt_typeprompt_datamodel
  • saveAnnotation() 使用 POST /api/ai/annotate
  • importGtMask() 使用 POST /api/ai/import-gt-mask multipart form-data。
  • getProjectAnnotations() 使用 GET /api/ai/annotations
  • updateAnnotation() 使用 PATCH /api/ai/annotations/{annotationId}
  • deleteAnnotation() 使用 DELETE /api/ai/annotations/{annotationId}
  • 后端 /api/ai/predict 支持 point、box、semantic 三种 prompt_type并通过 model 选择 SAM 2 或 SAM 3。
  • 后端 /api/ai/predict 支持可选 optionscrop_to_prompt 会对 point/box prompt 做局部裁剪推理并回映射 polygonauto_filter_background 会按 min_score 和负向点过滤结果。
  • 后端 /api/ai/models/status 返回 GPU、SAM 2、SAM 3 的真实运行状态SAM 3 状态包含外部 Python 环境与 checkpoint access 的可用性。
  • point prompt 支持旧数组形式和 { points, labels } 对象形式。

外部依赖边界

测试不直接依赖以下真实服务:

  • PostgreSQL后端测试使用内存 SQLite。
  • MinIO上传、下载、预签名 URL 使用 monkeypatch。
  • Redis单测使用 monkeypatch 验证进度事件发布,不依赖真实 Redis 服务。
  • SAMAI 推理测试使用 fake registry。
  • 浏览器 Canvas/Konva 图片加载:前端测试 mock react-konvause-image

已知占位设计

以下能力属于当前冻结版本的占位或半可用功能:

  • Dashboard 初始快照来自 GET /api/dashboard/overview;解析队列由 processing_tasks queued/running/failed/cancelled 任务生成。
  • 已保存标注支持通过“应用分类”、polygon 顶点拖动/删除、边中点插入、多 polygon 子区域编辑和区域合并/去除进入 dirty 状态并归档更新;复杂洞结构编辑尚未实现。
  • SAM 3 文本语义分割取决于官方依赖、GPU 运行环境和 Hugging Face gated 权重授权;状态接口会暴露真实可用性,未授权时 available=false
  • 自定义分类只存在本地组件状态。
  • GT mask 导入已完成多类别像素值拆分、contour、distance transform seed point 和前端 seed point 拖拽编辑骨架提取、HDBSCAN 聚类和模板自动映射尚未实现。