Files
Pre_Seg_Server/doc/08-current-design-freeze.md
admin b6a276cb8d feat: 完善工作区交互提示与后端属性分析
功能新增:
- 新增 POST /api/ai/analyze-mask 后端接口,基于 mask polygon、bbox、points 和 score 返回置信度来源、面积、拓扑锚点和后端分析提示。
- 前端新增 analyzeMask API 封装,并在本体检查面板读取选中 mask 的后端几何属性和重新提取拓扑锚点结果。
- 右侧语义分类树点击分类时,会给当前选中 mask 换标签、更新 class 元数据,并将选中 mask 移到前端渲染最上层,方便继续编辑。
- 分割工作区画布新增上下文操作提示,覆盖多边形 Enter 完成、Esc 取消、首节点闭合、拖拽图形、点区域、SAM 点/框提示、区域合并/去除选择顺序和多边形编辑。
- AI 智能分割画布新增正向点、反向点、边界框选和视口控制的上下文提示。
- 自动传播交互收敛为参考帧加起止帧范围加单个“自动传播”按钮,默认使用当前参考帧全部 mask 作为 seed。
- 时间轴改为用浅蓝色进度条区段标记自动传播生成的帧,而不是已编辑帧竖线提示。

Bugfix:
- AI 分割页无当前帧时移除外部演示背景图,改为明确空状态提示,避免误以为外部图片可参与真实推理。
- 工具栏魔法棒文案改为“打开 AI 智能分割”,避免误导为直接触发 SAM 推理。
- Canvas 底部当前图层信息改为显示真实选中 mask 标签和 annotation id,不再使用固定占位文本。
- 已保存标注回显时保留 mask metadata 中的传播来源、score 等字段,供时间轴和属性面板识别。
- 清理 server.ts 中遗留的 /api/login、/api/projects、/api/templates 内存 mock API,避免和 FastAPI 真实后端混淆。

测试:
- 补充 analyze-mask 后端测试,覆盖后端几何属性和锚点返回。
- 补充 api.analyzeMask 前端契约测试,覆盖 normalized polygon、bbox、points 和 extract_skeleton payload。
- 补充本体面板测试,覆盖后端属性读取、自定义分类写回后端模板、选中 mask 换标签和置顶显示。
- 补充 Canvas 测试,覆盖上下文提示、多边形完成提示、布尔选择顺序提示、当前图层真实显示和编辑优先级。
- 补充 AI 分割测试,覆盖无帧空状态和提示工具上下文提示。
- 更新 Konva 测试 mock,支持拖动过程、stroke/dash/fillRule 等渲染断言。

文档:
- 更新 README 和 AGENTS,说明 server.ts 不再保留业务 mock API。
- 更新 doc/02、doc/03、doc/04、doc/05、doc/07、doc/08、doc/09,记录后端属性分析、分类置顶显示、上下文提示、自动传播按钮、传播帧标记、测试覆盖和当前剩余限制。
2026-05-02 02:10:37 +08:00

23 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。前端业务接口访问 FastAPIserver.ts 不再保留旧版 /api/* mock。

前端模块

模块 文件 设计职责
应用入口 src/App.tsx 根据登录状态和 activeModule 切换页面
全局状态 src/store/useStore.ts Zustand store保存项目、帧、模板、mask、当前选中 mask ids、工具状态和 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 模板选择、分类树、后端自定义分类、mask 后端属性分析
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 推理、视频传播、模型状态和标注保存
Export backend/routers/export.py COCO 和 PNG mask 导出
SAM 2 backend/services/sam2_engine.py SAM 2 懒加载、状态检测、点/框/自动推理和视频 mask 传播
SAM 3 backend/services/sam3_engine.py, backend/services/sam3_external_worker.py, backend/setup_sam3_env.sh 历史保留的 SAM 3 桥接源码和脚本;当前未接入 registry
SAM Registry backend/services/sam_registry.py 当前暴露 SAM 2.1 四个变体、GPU 状态和推理分发

状态模型

前端 store 的核心对象:

  • Project项目基本信息、状态、帧数、fps、媒体路径。
  • Frame:帧 ID、项目 ID、索引、图片 URL、宽高、序列时间戳和原视频源帧号。
  • Template / TemplateClass:模板和分类定义。
  • Mask:前端渲染用 mask包含 pathDatasegmentationbboxarea
  • selectedMaskIdsCanvas 当前选中的 mask id 列表,供右侧本体面板对已选区域直接换标签。
  • maskHistory / maskFuturemask 编辑历史栈,用于撤销和重做。
  • activeModule:当前页面。
  • activeTool:当前工具。
  • aiModel:当前启用的 AI 模型,取值为 sam2.1_hiera_tinysam2.1_hiera_smallsam2.1_hiera_base_plussam2.1_hiera_large,默认 sam2.1_hiera_tiny

关键数据流

登录

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

项目导入与生成帧

  1. ProjectLibrary 创建项目。
  2. 导入视频时上传源视频到 /api/media/upload 并关联项目;该步骤不调用 /api/media/parse
  3. 用户在项目卡片点击“生成帧”,在弹窗中选择目标 FPS。
  4. 前端调用 /api/media/parse 创建异步拆帧任务;可通过 parse_fpsmax_framestarget_width 指定标准帧序列参数。
  5. Celery worker 执行 FFmpeg/OpenCV/pydicom 拆帧,视频帧按 frame_%06d.jpgframe_000000.jpg 连续命名,并按目标宽度缩放。
  6. worker 写入 frames.timestamp_msframes.source_frame_number,并在任务 result.frame_sequence 中记录 FPS、帧数、时长、尺寸和对象存储前缀。
  7. worker 持续更新 processing_tasks,并发布 Redis seg:progress
  8. 刷新项目列表。

任务控制

  1. Dashboard 从 GET /api/dashboard/overview 读取 queued/running/success/failed/cancelled 任务queued/running 代表当前进度success/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 和时间。
  6. Dashboard 通过 /ws/progress 接收 Redis seg:progress 转发事件;前端 WebSocket 客户端在 onopen/onclose/onerror 主动更新连接状态,并定时发送 ping 心跳,服务端返回 status 确认连接仍活跃。

工作区加载

  1. VideoWorkspace 根据 currentProject.id 调用 getProjectFrames()
  2. 若无帧但项目有 video_path,显示“尚未生成帧”的状态提示,不自动触发 parseMedia()
  3. 帧数据映射为 store Frame[],包含 timestampMssourceFrameNumber,供时间轴和后续视频传播使用。
  4. 工作区调用 GET /api/ai/annotations 回显已保存标注时,会替换当前项目帧中的已保存 mask但保留没有 annotationId 的未保存 draft mask这保证 AI 页推送到工作区的候选 mask 不会被异步回显覆盖,并会在合并完成后恢复仍然存在的已选 mask id。
  5. CanvasArea 会把全局 selectedMaskIds 中仍存在于当前帧的 id 同步回本地选区,避免帧初始化时的临时清空覆盖 AI 页推送过来的选中态。
  6. FrameTimeline 根据已保存标注回显到 Mask.metadatasource / propagated_from_frame_id 计算自动传播生成的帧,并在顶部时间进度条对应帧区段覆盖浅蓝色;当前帧不额外渲染竖线,由播放进度条末端、时间提示和缩略图高亮表达。
  7. 当前帧传入 CanvasArea

AI 点/框推理

  1. 用户在 Canvas 选择正向点、反向点或框选。
  2. CanvasArea 读取当前帧 ID 和宽高。
  3. SAM 2.1 框选会创建一个候选 mask并记录原始框后续正向点/反向点会累计到同一候选上。
  4. predictMask() 归一化坐标并携带当前 model 调用 /api/ai/predict;同时有框和点时发送 interactive prompt。
  5. SAM 2.1 请求中只要存在反向点,CanvasArea 会额外发送 options.auto_filter_background=trueoptions.min_score=0.05,让后端移除低分结果和包含负向点的 polygon。
  6. 后端加载帧图片并通过 SAM registry 分发到所选 SAM 2.1 变体;model=sam2 会兼容归一化为 tinymodel=sam3 会被拒绝。
  7. 前端把 polygons 转为 mask交互式细化会替换同一个候选 mask而不是新增多个 mask。
  8. 若带反向点的 SAM 2.1 细化返回空结果,前端会删除当前旧候选 mask 并提示反向点已排除该区域。
  9. AI 页面只按本页最新生成的候选 id 渲染 mask不把工作区已有 mask 带入 AI 画布;每次 runInference() 都先过滤掉旧 aiMaskIds 对应候选,再写入本次最高分候选。
  10. AI 页面候选 mask 的 Path 点击事件会先判断当前工具;正向/反向选点工具下点击 mask 会继续追加提示点,其他工具下才选中 mask。
  11. 工作区 SAM 提示点由 CanvasArea 本地 points 状态维护;点击已渲染提示点会先 cancelBubble,再删除对应点并按剩余提示重新调用 runInference(),避免同一次点击继续触发 Stage 加点或 Path 选择。
  12. AI 页面边界框选由 promptBox/boxStart/boxCurrent 维护;拖拽时渲染蓝色虚线框,鼠标释放后固化 promptBox 并清空旧提示点,避免旧点误绑定到新框。
  13. AI 页面执行分割时,如果只有 promptBox 则发送 box prompt如果 promptBoxpoints 同时存在,predictMask() 会发送 interactive prompt。
  14. AI 页面提示点由本地 points 状态维护;点击已渲染提示点会按 index 删除对应点,“删除最近锚点”会删除数组最后一个点,不改动候选 mask 列表。
  15. AI 页面候选 mask 删除只接受当前 aiMaskIds 范围内的已选 id“删除选中候选”和 Delete/Backspace 都复用该范围过滤,避免删除工作区已有 mask。
  16. AI 页面参数开关文案只做展示增强:“局部专注模式(自动裁剪无锚区域)”仍控制 cropMode/crop_to_prompt,“严格除杂模式(自动清理干涉点)”仍控制 autoDeleteBg/auto_filter_background/min_score
  17. AI 页面“遮罩清晰度”滑杆只调节候选 mask 的 Konva preview opacity不写入 Mask.segmentation、分类元数据或后端 payload。
  18. AI 画布左上角根据正向点、反向点、边界框选和视口控制显示上下文提示,说明点击/拖拽、删除提示点和执行推理的操作方式。
  19. Canvas 按当前帧过滤并渲染 mask。
  20. 新 mask 会带上当前选择的模板分类元数据,包括 classIdclassNameclassZIndexmetadata.source=ai_segmentation 和保存状态 draft
  21. 用户点击“结构化归档保存”后,前端将像素 segmentation 转成 normalized mask_data.polygons;未保存 mask 调用 POST /api/ai/annotatedirty mask 调用 PATCH /api/ai/annotations/{annotation_id};保存成功后本次提交的 draft mask id 会从本地保留列表中排除,并由后端 saved annotation 回显替换。
  22. 工作区加载项目帧后通过 GET /api/ai/annotations 取回已保存标注并转成前端 mask。
  23. 工作区“清空遮罩”删除当前帧已保存标注,并清除当前帧本地 mask。

视频片段传播

  1. 用户在工作区打开一帧作为参考帧;该帧全部 mask 都会作为传播 seed不再提供传播对象下拉。
  2. 用户设置传播起始帧和传播结束帧,并点击唯一的“自动传播”按钮。
  3. VideoWorkspace 以当前参考帧为 seed将起止帧拆成 backward 和/或 forward 两段;只包含当前帧时不传播。
  4. VideoWorkspacebuildAnnotationPayload() 把每个 seed mask 转成 normalized polygon、bbox、label、color 和 class 元数据。
  5. 前端对每个 seed、每个方向顺序调用 POST /api/ai/propagateinclude_source=falsesave_annotations=true;顺序调用是为了避免多个视频 tracker 并发抢占 GPU。
  6. 后端按项目帧序列截取片段,下载对应帧到临时 frame_%06d.jpg 目录,保持当前帧在片段中的相对索引。
  7. model 为任一 SAM 2.1 变体时,sam2_engine 使用对应 checkpoint/config 加载 SAM2VideoPredictor.add_new_mask() 注入 seed mask再用 propagate_in_video() 传播。
  8. model=sam3 当前不支持SAM 3 video tracker 代码保留但没有接入产品路径。
  9. 后端把传播返回的 normalized polygon 保存为后续帧 Annotation,跳过源帧,mask_data.source 记录模型传播来源。
  10. 前端传播完成后重新调用 GET /api/ai/annotations 并回显新标注;annotationToMask() 会保留传播来源 metadata供时间轴浅蓝色进度条区段显示。

手工绘制与历史栈

  1. 用户在 ToolsPalette 选择多边形、矩形、圆、点或线工具。
  2. CanvasArea 将交互坐标转换成像素 polygon。
  3. 多边形工具逐次记录节点,三点后点击首节点或按 Enter 时生成闭合 polygon。
  4. Canvas 左上角根据当前工具和操作阶段显示上下文提示;多边形提示会随已放置点数切换,明确 Enter 完成、Esc 取消和点击首节点闭合。
  5. mask path 只在 moveedit_polygonarea_mergearea_remove 工具下拦截点击;绘制和 AI prompt 工具点击已有 mask 时继续冒泡给 Stage。
  6. 新 mask 写入 pathData、像素 segmentationbboxarea 和当前模板分类元数据。
  7. addMask()setMasks()updateMask()clearMasks() 会维护 maskHistory/maskFuture
  8. 工具栏按钮、AI 页按钮和 Canvas Ctrl+Z/Ctrl+Y 调用 undoMasks() / redoMasks()

Polygon 逐点编辑

  1. 用户选择“调整多边形”或“拖拽/选择”后点击 Canvas 上的 mask pathCanvasArea 记录 selectedMaskId 并显示该 mask 第一条 polygon 的顶点控制点和边中点插入手柄。
  2. 顶点 mousedown/dragstart 会立即设置当前顶点选择;拖动过程中通过 dragMove 实时重算 pathData、像素 segmentationbboxarea,不需要先单击顶点再拖动。
  3. 点击边中点手柄会在该边中点插入新顶点;在“调整多边形”工具下双击 polygon path 会在最接近的线段上按双击位置插入新顶点。
  4. 如果 mask 已有 annotationId,编辑会把 saveStatus 标成 dirtysaved=false
  5. 归档保存时复用现有 PATCH /api/ai/annotations/{annotation_id} 链路,把更新后的 normalized polygon 写回后端。
  6. 选中顶点后 Delete/Backspace 可删除顶点;前端保持 polygon 至少三点。
  7. 未选中具体顶点但选中了 mask 时Delete/Backspace 从前端 store 删除该 mask如果包含 annotationId,通过工作区回调调用后端删除接口。

区域合并与去除

  1. 用户选择 area_mergearea_remove 后,点击多个当前帧 mask 组成选择集。
  2. 合并/去除模式隐藏 polygon 顶点和边中点编辑手柄,并在右下角显示已选数量;少于两个 mask 时操作按钮禁用。
  3. Canvas 左上角提示布尔选择顺序:第一个选中的是主区域,后续区域参与合并或扣除。
  4. 布尔选择态按选择顺序区分角色:第一个选中的主区域使用黄色实线轮廓,后续参与合并/扣除的区域使用红色虚线轮廓;所有已选区域填充透明度保持一致,避免被误解为阴影模式异常。
  5. CanvasAreaMask.segmentation 转为 polygon-clipping 的 MultiPolygon。
  6. area_merge 使用 union更新第一个选中的主 mask并从前端 store 移除后续被合并 mask如果被移除 mask 已保存,会调用工作区传入的删除回调删除后端标注。
  7. area_remove 使用 difference从第一个选中的主 mask 中扣除后续选中 mask扣除对象本身保留如果 difference 产生内洞,segmentation 保留外圈和 hole ring渲染时使用 even-odd fill。
  8. 结果会重算 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. CanvasArea 把当前选中的 mask id 同步到全局 selectedMaskIds;切换工具、切换帧或卸载 Canvas 时会清空选择。
  7. AISegmentation 生成 mask 后会写入全局 masks 并把生成的 mask id 写入 selectedMaskIds;点击 AI 页预览 mask 也会更新 selectedMaskIds
  8. AI 页“推送至工作区编辑”会切换到工作区并把 activeTool 设为 edit_polygonCanvasArea 初始读取全局 selectedMaskIds,让 AI 页选中的 mask 在工作区继续保持选中。
  9. 工作区帧/标注异步加载完成后,hydrateSavedAnnotations() 会合并本地未保存 draft mask 和后端已保存 mask不会用后端回显结果直接覆盖整个 masks store。
  10. OntologyInspector 可以选择具体分类;选择结果进入全局 storeCanvasAreaAISegmentation 新建/更新 mask 时使用。
  11. 如果 selectedMaskIds 中存在当前 store 的 mask点击分类时会立即更新这些 mask 的 templateIdclassIdclassNameclassZIndexlabelcolor
  12. 同一次点击会把这些已选 mask 移动到前端 masks 数组末尾;CanvasArea 按数组顺序渲染,后渲染的 Path 显示在最上层,方便用户继续编辑刚换标签的区域。该显示置顶不改变模板 zIndex 或后端导出语义覆盖规则。
  13. 已保存 mask 被重新分类后进入 dirtysaved=false,继续复用工作区归档保存的 PATCH 链路。

导出

  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
  • propagateMasks() 使用 POST /api/ai/propagate,请求体为 project_idframe_idmodelseeddirectionmax_frames
  • 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}
  • parseMedia() 使用 POST /api/media/parse?project_id=...,可选 parse_fpsmax_framestarget_width,用于生成标准帧序列。
  • getProjectFrames() 返回帧图像 URL、宽高、timestamp_mssource_frame_number
  • 后端 /api/ai/predict 当前支持 SAM 2.1 的 point、box、interactivesemantic 文本提示禁用并返回 400。
  • SAM 2.1 是点/框交互式分割模型不做文本语义分割AI 页面已经移除纯文本输入。
  • SAM 2.1 点提示和 auto fallback 只返回一个最高分候选,避免同一提示产生多个重叠候选 mask。
  • SAM 3 前端入口、后端 registry 入口和状态展示均已禁用;model=sam3 会返回不支持。
  • 后端 /api/ai/predict 支持可选 optionscrop_to_prompt 会对 point/box/interactive prompt 做局部裁剪推理并回映射 polygonauto_filter_background 会按 min_score 和负向点过滤结果。
  • 后端 /api/ai/propagate 当前支持所选 SAM 2.1 mask seed 视频传播;当前前端默认向后传播 30 帧并保存结果标注。
  • 后端 /api/ai/models/status 返回 GPU 和四个 SAM 2.1 变体的真实运行状态。
  • 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/success/failed/cancelled 任务生成,处理中统计只计算 queued/running。
  • 已保存标注支持通过“应用分类”、polygon 顶点拖动/删除、边中点插入、多 polygon 子区域编辑和区域合并/去除进入 dirty 状态并归档更新;选中整块 mask 可用 Delete/Backspace 删除并同步后端;复杂洞结构编辑尚未实现。
  • SAM 3 文本语义分割已从当前产品路径中禁用相关源码保留恢复时需要重新接入前端入口、registry、状态接口和测试。
  • 自定义分类通过 PATCH /api/templates/{id} 写入当前激活模板的 mapping_rules.classes
  • 选中 mask 后,本体面板调用 POST /api/ai/analyze-mask 显示后端模型置信度、拓扑锚点数量、面积等属性;“重新提取拓扑锚点”会带 extract_skeleton=true 重新请求后端分析。
  • GT mask 导入已完成多类别像素值拆分、contour、distance transform seed point 和前端 seed point 拖拽编辑骨架提取、HDBSCAN 聚类和模板自动映射尚未实现。