feat: 完善分割工作区导入导出与管理流程
- 新增基于 JWT 当前用户的登录恢复、角色权限、用户管理、审计日志和演示出厂重置后台接口与前端管理页。 - 重串 GT_label 导出和 GT Mask 导入逻辑:导出保留类别真实 maskid,导入仅接受灰度或 RGB 等通道 maskid 图,支持未知 maskid 策略、尺寸最近邻拉伸和导入预览。 - 统一分割结果导出体验:默认当前帧,按项目抽帧顺序和 XhXXmXXsXXXms 时间戳命名 ZIP 与图片,补齐 GT/Pro/Mix/分开 Mask 输出和映射 JSON。 - 调整工作区左侧工具栏:移除创建点/线段入口,新增画笔、橡皮擦及尺寸控制,并按绘制、布尔、导入/AI 工具分组分隔。 - 扩展 Canvas 编辑能力:画笔按语义分类绘制并可自动并入连通选中 mask,橡皮擦对选中区域扣除,优化布尔操作、选区、撤销重做和保存状态联动。 - 优化自动传播时间轴显示:同一蓝色系按传播新旧递进变暗,老传播记录达到阈值后统一旧记录色,并维护范围选择与清空后的历史显示。 - 将 AI 智能分割入口替换为更明确的 AI 元素图标,并同步侧栏、工作区和 AI 页面入口表现。 - 完善模板分类、maskid 工具函数、分类树联动、遮罩透明度、边缘平滑和传播链同步相关前端状态。 - 扩展后端项目、媒体、任务、Dashboard、模板和传播 runner 的用户隔离、任务控制、进度事件与兼容处理。 - 补充前后端测试,覆盖用户管理、GT_label 往返导入导出、GT Mask 校验和预览、画笔/橡皮擦、时间轴传播历史、导出范围、WebSocket 与 API 封装。 - 更新 AGENTS、README 和 doc 文档,记录当前接口契约、实现状态、测试计划、安装说明和 maskid/GT_label 规则。
This commit is contained in:
@@ -15,13 +15,14 @@ timeout: 30000
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
当前后端多数接口没有鉴权依赖,所以这个 header 主要是前端侧行为。
|
||||
当前后端业务接口会校验该 header。缺失、过期或无效 token 返回 401;项目、帧、标注、任务、Dashboard 和导出会按当前用户拥有的项目过滤。
|
||||
|
||||
## 前端封装的 API
|
||||
|
||||
| 函数 | 方法与路径 | 状态 | 说明 |
|
||||
|------|------------|------|------|
|
||||
| `login(username, password)` | `POST /api/auth/login` | 对齐 | 后端返回 `{ token, username }`,前端只使用 token |
|
||||
| `login(username, password)` | `POST /api/auth/login` | 对齐 | 后端返回 `{ token, token_type, username, user }`,前端保存 token 和当前用户 |
|
||||
| `getCurrentUser()` | `GET /api/auth/me` | 对齐 | 用已有 Bearer token 恢复当前登录用户 |
|
||||
| `getProjects()` | `GET /api/projects` | 对齐 | 前端映射 `frame_count`、`thumbnail_url` 等字段 |
|
||||
| `createProject(payload)` | `POST /api/projects` | 对齐 | 支持 `name`、`description`、`parse_fps` |
|
||||
| `updateProject(id, payload)` | `PATCH /api/projects/{id}` | 对齐 | 后端是 `PATCH /api/projects/{id}` |
|
||||
@@ -46,10 +47,11 @@ Authorization: Bearer <token>
|
||||
| `saveAnnotation(payload)` | `POST /api/ai/annotate` | 对齐 | 工作区归档保存当前项目未保存 mask |
|
||||
| `updateAnnotation(annotationId, payload)` | `PATCH /api/ai/annotations/{annotation_id}` | 对齐 | 工作区归档保存 dirty mask |
|
||||
| `deleteAnnotation(annotationId)` | `DELETE /api/ai/annotations/{annotation_id}` | 对齐 | 工作区清空当前帧已保存标注 |
|
||||
| `importGtMask(file, projectId, frameId, templateId?)` | `POST /api/ai/import-gt-mask` | 对齐 | multipart 上传 GT mask,后端按非零像素值/连通域生成 polygon 标注和 seed point |
|
||||
| `importGtMask(file, projectId, frameId, templateId?, options?)` | `POST /api/ai/import-gt-mask` | 对齐 | multipart 上传 GT mask;支持 `unknown_color_policy=discard/undefined`;后端仅接受灰度 maskid 图或 RGB 三通道完全相同的 `[X,X,X]` maskid 图,0 为背景、X 为 maskid;按模板 `maskId` 匹配类别,未知 maskid 可舍弃或导入为未定义类别;尺寸不同会最近邻拉伸到当前帧,连通域会生成 polygon 标注和 seed point |
|
||||
| `getDashboardOverview()` | `GET /api/dashboard/overview` | 对齐 | Dashboard 初始统计、队列和活动日志 |
|
||||
| `exportCoco(projectId)` | `GET /api/export/{projectId}/coco` | 对齐 | 后端实际是 `GET /api/export/{project_id}/coco` |
|
||||
| `exportMasks(projectId)` | `GET /api/export/{projectId}/masks` | 对齐 | 下载单标注 mask、语义融合 mask 和类别映射 ZIP |
|
||||
| `exportSegmentationResults(projectId, options)` | `GET /api/export/{projectId}/results` | 对齐 | 新的统一导出入口;支持 `scope=all/range/current`、`outputs=separate,gt_label,pro_label,mix_label`、`mix_opacity`、`start_frame/end_frame` 和 `frame_id` 参数,返回包含 COCO JSON、maskid/GT 像素值映射、原始帧图片和所选 mask PNG 的 ZIP;`mask_type=separate/gt_label/pro_label/mix_label/both` 仍兼容 |
|
||||
|
||||
## 后端 FastAPI 接口
|
||||
|
||||
@@ -58,6 +60,10 @@ Authorization: Bearer <token>
|
||||
| 方法 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| POST | `/api/auth/login` | 登录 |
|
||||
| GET | `/api/auth/me` | 当前用户 |
|
||||
| GET/POST/PATCH/DELETE | `/api/admin/users` | 管理员用户管理 |
|
||||
| GET | `/api/admin/audit-logs` | 管理员审计日志 |
|
||||
| POST | `/api/admin/demo-factory-reset` | 演示部署恢复出厂设置;请求体需 `confirmation=RESET_DEMO_FACTORY` |
|
||||
| POST | `/api/projects` | 创建项目 |
|
||||
| GET | `/api/projects` | 项目列表 |
|
||||
| GET | `/api/projects/{project_id}` | 项目详情 |
|
||||
@@ -92,6 +98,7 @@ Authorization: Bearer <token>
|
||||
| GET | `/api/dashboard/overview` | Dashboard 聚合快照 |
|
||||
| GET | `/api/export/{project_id}/coco` | 导出 COCO JSON |
|
||||
| GET | `/api/export/{project_id}/masks` | 导出 PNG mask ZIP |
|
||||
| GET | `/api/export/{project_id}/results` | 统一导出分割结果 ZIP,包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json`、`原始图片/` 和按参数选择的 `分开Mask分割结果/`、`GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`;GT_label 背景为 0,类别值使用模板中的真实 maskid,缺失 maskid 的旧标注才补下一个可用正整数 |
|
||||
| GET | `/health` | 健康检查 |
|
||||
| WS | `/ws/progress` | WebSocket 进度通道,未出现在 OpenAPI paths 中 |
|
||||
|
||||
@@ -163,6 +170,7 @@ POST /api/media/parse?project_id=1&parse_fps=15&max_frames=120&target_width=960
|
||||
"name": "胆囊",
|
||||
"color": "#ffae00",
|
||||
"zIndex": 280,
|
||||
"maskId": 1,
|
||||
"category": "腹腔镜胆囊切除术"
|
||||
}
|
||||
],
|
||||
@@ -250,7 +258,7 @@ SAM 2 点提示和 auto fallback 当前只采用最高分候选 mask,避免同
|
||||
"bbox": [0.1, 0.1, 0.2, 0.2],
|
||||
"label": "胆囊",
|
||||
"color": "#ff0000",
|
||||
"class_metadata": {"id": "c1", "name": "胆囊", "color": "#ff0000", "zIndex": 20},
|
||||
"class_metadata": {"id": "c1", "name": "胆囊", "color": "#ff0000", "zIndex": 20, "maskId": 1},
|
||||
"template_id": 2
|
||||
}
|
||||
}
|
||||
@@ -293,7 +301,7 @@ SAM 2.1 变体使用对应 video predictor 的 mask seed 传播;`model=sam2`
|
||||
- `getProjectAnnotations()` 已接入 `GET /api/ai/annotations`。
|
||||
- `updateAnnotation()` 已接入 `PATCH /api/ai/annotations/{annotationId}`。
|
||||
- `deleteAnnotation()` 已接入 `DELETE /api/ai/annotations/{annotationId}`。
|
||||
- `importGtMask()` 已接入 `POST /api/ai/import-gt-mask`,导入后端生成的 polygon 标注、原始 `gt_label_value` 和 seed point。
|
||||
- `importGtMask()` 已接入 `POST /api/ai/import-gt-mask`,导入后端生成的 polygon 标注、原始 `gt_label_value`、原图尺寸/是否拉伸信息和 seed point。导入端使用 `cv2.IMREAD_UNCHANGED` 保留低数值/16-bit GT_label 图的像素值;灰度图和 RGB 三通道相等图均按模板 `maskId` 匹配类别,不再按彩色图 RGB 颜色匹配类别;超出现有类别时由 `unknown_color_policy` 决定舍弃或写为 `gt_unknown_class` 未定义类别。
|
||||
- `exportMasks()` 已接入 `GET /api/export/{projectId}/masks`。
|
||||
- `parseMedia()` 已改为创建 Celery 后台任务,并返回 `ProcessingTask`。
|
||||
- `queuePropagationTask()` 已接入 `/api/ai/propagate/task`,自动传播不再依赖长时间同步 HTTP 请求。
|
||||
@@ -302,8 +310,9 @@ SAM 2.1 变体使用对应 video predictor 的 mask seed 传播;`model=sam2`
|
||||
- `retryTask()` 已接入 `POST /api/tasks/{taskId}/retry`。
|
||||
- `getDashboardOverview()` 已从 `processing_tasks` 聚合解析队列。
|
||||
- Dashboard 任务列表已展示 queued/running/success/failed/cancelled 任务,并可通过 `getTask()` 查看失败详情;`summary.parsing_task_count` 仍只统计 queued/running。
|
||||
- 工作区导出按钮已调用 `exportCoco()` / `exportMasks()`,并会先保存未归档 mask。
|
||||
- 工作区“分割结果导出”已调用 `exportSegmentationResults()`,并会先保存未归档 mask;旧的 `exportCoco()` / `exportMasks()` 仍保留为兼容接口。
|
||||
- PNG mask ZIP 已包含每帧 `semantic_frame_*.png` 和 `semantic_classes.json`,重叠区域按 zIndex 裁决。
|
||||
- 统一导出 ZIP 下载文件名为 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`;项目名来自 `Project.name` 并会替换文件系统不安全字符,时间戳来自帧 `timestamp_ms` 并格式化为 `0h00m00s000ms`,帧号使用项目抽帧后的 1-based `frame_index + 1`,不使用原视频 `source_frame_number`。ZIP 内包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`。原始图片按 `视频名称_时间戳_项目帧序号` 命名;选择分开 mask 时写入 `分开Mask分割结果/{视频名称_时间戳_项目帧序号}_分别导出/{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`,同一帧同一类别会合并为一张二值 mask;选择 GT_label 图时写入 `GT_label图/{视频名称_时间戳_项目帧序号}.png`;选择 Pro_label 彩色图时写入 `Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`;选择 Mix_label 叠加图时写入 `Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`,透明度由 `mix_opacity` 控制,默认 0.3。导出时 maskid 与 GT_label 像素值相同;有模板 maskid 的类别保留真实 maskid,缺失 maskid 的旧标注补下一个可用正整数并写入映射 JSON,跨图一致;maskid 不参与覆盖排序,覆盖顺序仍使用内部拖拽排序字段。
|
||||
|
||||
## 仍需处理的接口问题
|
||||
|
||||
|
||||
Reference in New Issue
Block a user