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:
58
doc/01-purpose-and-word-summary.md
Normal file
58
doc/01-purpose-and-word-summary.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 目的与 Word 方案摘要
|
||||
|
||||
## 为什么要做这个系统
|
||||
|
||||
Word 文档《语义分割系统构建方案.docx》的核心目标是建设一个面向视频和连续帧的智能语义分割标注系统,解决传统标注工具在以下场景中的痛点:
|
||||
|
||||
- 视频或连续帧数量大,逐帧人工画 mask 成本高。
|
||||
- 高分辨率图像上同时存在底图、点、框、多边形和遮罩,DOM 渲染难以支撑重交互。
|
||||
- AI 分割需要低延迟点选/框选反馈,普通 REST 往返在密集交互场景下体验较差。
|
||||
- 语义分割要求一个像素只能归属一个类别,因此需要模板、颜色、z-index 和类别优先级来解决遮罩重叠。
|
||||
- 历史 GT mask 如果只是作为静态像素图层叠加,后续修改不灵活;Word 方案希望把 mask 降维成可编辑的点区域。
|
||||
|
||||
所以这个系统的业务目的不是单纯播放视频,而是把“视频/DICOM 数据接入、拆帧、AI 辅助分割、语义分类、标注导出”串成一个工作台。
|
||||
|
||||
## Word 中的目标架构
|
||||
|
||||
Word 方案描述的理想系统包含:
|
||||
|
||||
- React/Vue + Konva 的高性能 Canvas 工作台。
|
||||
- FastAPI 后端,使用 WebSocket 处理实时交互与任务进度。
|
||||
- Celery + Redis 处理视频拆帧等长任务。
|
||||
- FFmpeg/OpenCV 解析视频,pydicom 解析医学影像。
|
||||
- 本地 CUDA 上的 SAM 3 推理。
|
||||
- GT mask 导入后通过距离变换、骨架提取、聚类等算法降维为点区域。
|
||||
- 模板库管理分类、颜色和 z-index,用于语义分割遮罩重叠裁决。
|
||||
- PostgreSQL 存储项目、帧、模板和点区域数据。
|
||||
|
||||
## 当前代码已落地的部分
|
||||
|
||||
| 目标 | 当前代码状态 | 依据 |
|
||||
|------|--------------|------|
|
||||
| React 前端工作台 | 已落地 | `src/App.tsx`、`src/components/*.tsx` |
|
||||
| Konva Canvas | 已落地 | `CanvasArea.tsx`、`AISegmentation.tsx` 使用 `react-konva` |
|
||||
| FastAPI 后端 | 已落地 | `backend/main.py` |
|
||||
| PostgreSQL ORM | 已落地 | `backend/database.py`、`backend/models.py` |
|
||||
| MinIO 对象存储 | 已落地 | `backend/minio_client.py` |
|
||||
| Redis 连接 | 已落地 | 用于 Celery broker/result backend,并通过 `seg:progress` pub/sub 转发任务进度 |
|
||||
| 视频拆帧 | 已落地 | `backend/services/frame_parser.py`、`backend/routers/media.py` |
|
||||
| DICOM 批量导入 | 部分落地 | 上传和解析存在,项目级体验还需完善 |
|
||||
| WebSocket 进度 | 已落地 | 拆帧进度写入任务表后发布到 Redis `seg:progress`,FastAPI 广播到 `/ws/progress` |
|
||||
| SAM 推理 | 部分落地 | 后端已有 SAM 2 / SAM 3 选择和真实模型状态接口;SAM 3 依赖官方运行环境,当前环境不满足时会标为不可用 |
|
||||
| 模板库 | 部分落地 | 分类、颜色、z-index 能存储和编辑;重叠裁决算法未落地 |
|
||||
| 标注持久化 | 部分落地 | 后端有 `Annotation` 表,前端已接入新增、回显、分类更新和当前帧删除;逐点几何编辑未落地 |
|
||||
| COCO / Mask 导出 | 部分落地 | `backend/routers/export.py`;COCO JSON 前端按钮已接入,PNG mask ZIP 尚未提供前端按钮 |
|
||||
|
||||
## 当前代码尚未落地的目标
|
||||
|
||||
- SAM 3:当前已提供 `sam3_engine.py` 适配入口和状态检测;要实际运行仍需安装官方 `facebookresearch/sam3` 依赖并满足 Python 3.12+、PyTorch 2.7+、CUDA 12.6+。
|
||||
- Celery 异步任务队列:已注册 Celery app 和拆帧 worker task,`/api/media/parse` 会创建任务表记录并入队。
|
||||
- GT mask 导入:当前前端没有 GT Label 导入入口,后端也没有对应路由。
|
||||
- Mask 到点区域的拓扑降维:当前没有距离变换、骨架提取、HDBSCAN 等实现。
|
||||
- 类别优先级融合:模板有 z-index,但没有后端融合算法。
|
||||
- 撤销/重做:工具栏有按钮,但没有历史栈。
|
||||
- 结构化归档保存:工作区按钮已调用 `POST /api/ai/annotate` 保存当前未归档 mask,并通过 `PATCH /api/ai/annotations/{id}` 更新 dirty mask。
|
||||
|
||||
## 结论
|
||||
|
||||
当前项目已经从 UI 原型推进到“可上传、可异步拆帧、可实时查看任务进度、可浏览项目帧、可维护模板、可点/框 AI 推理、可保存标注、可导出 COCO、可查看 Dashboard 后端概览”的全栈雏形,但离 Word 中描述的完整智能标注系统还有明显差距。下一阶段最重要的是继续补齐手工绘制、撤销重做和真实语义文本分割。
|
||||
104
doc/02-current-implementation-map.md
Normal file
104
doc/02-current-implementation-map.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# 当前实现地图
|
||||
|
||||
## 运行入口
|
||||
|
||||
### 前端入口
|
||||
|
||||
- React 挂载:`src/main.tsx`
|
||||
- 根组件:`src/App.tsx`
|
||||
- 前端服务:`server.ts`
|
||||
- 默认访问:`http://localhost:3000`
|
||||
|
||||
`server.ts` 的角色比较特殊:它既负责在开发模式下创建 Vite middleware,也在生产模式下服务 `dist/`。同时它还保留了旧版 mock API:`/api/login`、`/api/projects`、`/api/templates`。当前前端业务 API 主要不走这些 mock,而是走 `src/lib/api.ts` 指向的 FastAPI。
|
||||
|
||||
### 后端入口
|
||||
|
||||
- FastAPI 应用:`backend/main.py`
|
||||
- 默认访问:`http://localhost:8000`
|
||||
- API 文档:`http://localhost:8000/docs`
|
||||
- 健康检查:`GET /health`
|
||||
|
||||
后端启动时会通过 lifespan 执行:
|
||||
|
||||
- 创建数据库表。
|
||||
- 检查 MinIO bucket。
|
||||
- 测试 Redis。
|
||||
- Seed 默认模板。
|
||||
- 如果存在 `Data_MyVideo_1.mp4`,创建默认项目并拆前 100 帧。
|
||||
|
||||
## 前端模块切换
|
||||
|
||||
`App.tsx` 使用 Zustand 中的 `activeModule` 做模块切换,没有使用路由库。
|
||||
|
||||
| activeModule | 组件 | 页面 |
|
||||
|--------------|------|------|
|
||||
| `dashboard` | `Dashboard` | 系统概况 |
|
||||
| `projects` | `ProjectLibrary` | 项目库 |
|
||||
| `workspace` | `VideoWorkspace` | 分割工作区 |
|
||||
| `ai` | `AISegmentation` | AI 智能分割页 |
|
||||
| `templates` | `TemplateRegistry` | 模板库 |
|
||||
|
||||
未登录时,`App.tsx` 直接渲染 `Login`。
|
||||
|
||||
## 全局状态
|
||||
|
||||
全局状态在 `src/store/useStore.ts` 中,主要包括:
|
||||
|
||||
- 登录状态:`isAuthenticated`、`token`
|
||||
- 项目:`projects`、`currentProject`
|
||||
- 工作区:`activeModule`、`activeTool`、`frames`、`currentFrameIndex`
|
||||
- 标注与 mask:`annotations`、`masks`
|
||||
- 模板:`templates`、`activeTemplateId`
|
||||
- UI:`isLoading`、`error`
|
||||
|
||||
当前状态管理是前端内存状态,没有持久化到 localStorage,除了登录 token。
|
||||
|
||||
## 数据流
|
||||
|
||||
### 登录
|
||||
|
||||
1. `Login.tsx` 调用 `login()`。
|
||||
2. `src/lib/api.ts` 请求 `POST /api/auth/login`。
|
||||
3. FastAPI `backend/routers/auth.py` 校验 `admin / 123456`。
|
||||
4. 前端把返回 token 写入 localStorage。
|
||||
|
||||
### 项目与拆帧
|
||||
|
||||
1. `ProjectLibrary.tsx` 调用 `getProjects()` 获取项目。
|
||||
2. 上传视频时先 `createProject()`,再 `uploadMedia()`,再 `parseMedia()`。
|
||||
3. 后端 `media.py` 把原始文件上传到 MinIO。
|
||||
4. `parseMedia()` 创建 `processing_tasks` 记录并投递 Celery worker。
|
||||
5. Celery worker 下载 MinIO 文件,调用 `frame_parser.py` 拆帧。
|
||||
6. worker 把拆出的帧重新上传 MinIO,写入 `frames` 表,并更新任务状态。
|
||||
7. 工作区通过 `GET /api/tasks/{id}` 等待任务完成,再通过 `GET /api/projects/{id}/frames` 获取预签名图片 URL。
|
||||
|
||||
### 工作区浏览
|
||||
|
||||
1. `VideoWorkspace.tsx` 根据 `currentProject.id` 加载帧。
|
||||
2. `CanvasArea.tsx` 用当前帧 URL 加载底图。
|
||||
3. `FrameTimeline.tsx` 显示缩略图和当前帧索引。
|
||||
4. 播放按钮会推进 `currentFrameIndex`,从而更新画布底图。
|
||||
|
||||
### 模板管理
|
||||
|
||||
1. `TemplateRegistry.tsx` 调用模板 API。
|
||||
2. 后端 `templates.py` 把 `classes` 和 `rules` 打包进 `mapping_rules` JSON 字段。
|
||||
3. `OntologyInspector.tsx` 读取全局 `templates` 和 `activeTemplateId` 展示分类树。
|
||||
|
||||
## 后端数据模型
|
||||
|
||||
| 模型 | 表 | 用途 |
|
||||
|------|----|------|
|
||||
| `Project` | `projects` | 项目元数据,包含视频路径、缩略图、状态、fps |
|
||||
| `Frame` | `frames` | 拆帧后的图片记录 |
|
||||
| `Template` | `templates` | 模板、本体类别、颜色、z-index、mapping_rules |
|
||||
| `Annotation` | `annotations` | 标注数据、点、bbox、mask_data |
|
||||
| `Mask` | `masks` | mask 文件元数据 |
|
||||
|
||||
## 当前主要风险点
|
||||
|
||||
- 前端 API/WS 地址虽然已支持环境变量和 hostname 推导,但部署时仍需要确认浏览器可访问 `:8000` 后端。
|
||||
- AI 语义文本提示在选择 SAM 3 且运行环境满足官方依赖时走 SAM 3;当前环境若不满足会在模型状态中标明不可用。
|
||||
- 工作区顶部“导出 JSON 标注集”和“结构化归档保存”已接入导出、标注新增和 dirty 标注更新;清空当前帧遮罩会删除对应后端标注。撤销重做和手工绘制仍未持久化。
|
||||
- Dashboard 初始统计、队列和活动日志来自后端聚合接口;解析队列来自 `processing_tasks`,worker 进度通过 Redis `seg:progress` 转发到 WebSocket。
|
||||
- 后端路由大多未做真实鉴权。
|
||||
146
doc/03-frontend-element-audit.md
Normal file
146
doc/03-frontend-element-audit.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# 前端逐元素审计
|
||||
|
||||
状态说明:
|
||||
|
||||
- 真实可用:接真实状态或后端接口,可以完成主要动作。
|
||||
- 部分可用:能展示或完成一部分,但存在关键缺口。
|
||||
- Mock / UI-only:只有展示或本地状态变化,没有真实业务效果。
|
||||
- 接口不通:前端调用与后端接口不一致,按当前代码大概率失败。
|
||||
|
||||
## App 与导航
|
||||
|
||||
| 元素 | 位置 | 状态 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 登录拦截 | `App.tsx` | 真实可用 | 未登录显示 `Login`,登录后显示主界面 |
|
||||
| 模块切换 | `Sidebar.tsx` + `App.tsx` | 真实可用 | 切换 `dashboard/projects/workspace/ai/templates` |
|
||||
| Logo | `Sidebar.tsx` | 真实可用 | 使用 `/logo.png`,文件存在于 `public/logo.png` |
|
||||
| GPU 状态圆标 | `Sidebar.tsx` | 真实可用 | 通过 `GET /api/ai/models/status` 显示 GPU/CPU 和当前模型可用性 |
|
||||
|
||||
## 登录页
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 用户名/密码输入 | 真实可用 | 默认填入 `admin / 123456` |
|
||||
| 安全登录按钮 | 真实可用 | 调用 `POST /api/auth/login` |
|
||||
| 错误提示 | 真实可用 | 捕获后端错误并显示 |
|
||||
| 安全审计说明文字 | Mock / UI-only | UI 文案,没有真实审计功能 |
|
||||
|
||||
## Dashboard 系统概况
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| WebSocket 连接状态 | 真实可用 | 前端通过 `src/lib/config.ts` 推导或读取 `VITE_WS_PROGRESS_URL`,后端有 `/ws/progress` |
|
||||
| 解析队列任务 | 真实可用 | 初始数据来自 `GET /api/dashboard/overview`,按 `processing_tasks` queued/running 任务生成 |
|
||||
| WebSocket 更新任务 | 真实可用 | Celery worker 更新 `processing_tasks` 后发布 Redis `seg:progress`,FastAPI 广播 progress/complete/error |
|
||||
| 项目、任务、标注、系统负载统计 | 真实可用 | 初始数据来自 `GET /api/dashboard/overview`,系统负载按主机 load average 估算 |
|
||||
| 近期实时流转记录 | 真实可用 | 初始数据来自任务、项目、标注和模板记录;WebSocket status/complete/error 会继续追加 |
|
||||
|
||||
## 项目库 ProjectLibrary
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 项目列表 | 真实可用 | 调用 `GET /api/projects` |
|
||||
| 项目卡片缩略图 | 真实可用 | 后端返回 MinIO 预签名 `thumbnail_url` 时显示 |
|
||||
| 点击项目进入工作区 | 真实可用 | 设置 `currentProject` 后切到 `workspace` |
|
||||
| 新建项目 | 真实可用 | 调用 `POST /api/projects` |
|
||||
| 导入视频文件 | 真实可用 | 创建项目、上传文件、触发拆帧、刷新项目列表 |
|
||||
| 解析 FPS 滑块 | 真实可用 | 值传入 `createProject({ parse_fps })` |
|
||||
| 导入 DICOM 序列 | 部分可用 | 可上传 `.dcm` 并触发解析;体验和错误反馈较粗 |
|
||||
| 项目状态徽标 | 真实可用 | 项目状态统一为 `pending/parsing/ready/error`,前端兼容归一化旧状态值 |
|
||||
| 更多按钮 | Mock / UI-only | 有图标,没有菜单或事件 |
|
||||
| alert 成功/失败提示 | 真实可用但粗糙 | 使用浏览器 `alert` |
|
||||
|
||||
## 工作区 VideoWorkspace
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 当前项目名 | 真实可用 | 读取 `currentProject.name` |
|
||||
| 自动加载项目帧 | 真实可用 | 调用 `GET /api/projects/{id}/frames` |
|
||||
| 无帧时触发解析 | 真实可用 | 如果 `video_path` 存在会调用 `parseMedia()` 创建异步任务,并轮询 `GET /api/tasks/{id}` 等待完成 |
|
||||
| SAM 模型状态徽标 | 真实可用 | 调用 `GET /api/ai/models/status`,显示当前选择的 SAM 2/SAM 3 是否可用 |
|
||||
| 已保存标注回显 | 真实可用 | 加载工作区帧后调用 `GET /api/ai/annotations` 并渲染已保存 mask |
|
||||
| “导出 JSON 标注集”按钮 | 真实可用 | 导出前会保存未归档 mask,然后调用 `exportCoco()` 下载 JSON |
|
||||
| “结构化归档保存”按钮 | 真实可用 | 未保存 mask 写入 `POST /api/ai/annotate`;dirty mask 写入 `PATCH /api/ai/annotations/{id}` |
|
||||
|
||||
## CanvasArea 画布
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 当前帧底图显示 | 真实可用 | `useImage(frameUrl)` 加载当前帧 URL |
|
||||
| 滚轮缩放 | 真实可用 | 改变 Konva Stage scale |
|
||||
| 拖拽平移 | 真实可用 | activeTool 为 `move` 时 Stage draggable |
|
||||
| 光标坐标显示 | 真实可用 | 根据 pointer position 计算 |
|
||||
| 正向/反向选点 | 部分可用 | UI 能加点,并按当前帧 `frame.id` 调用 `/api/ai/predict`;需点击归档保存才持久化 |
|
||||
| 框选 | 部分可用 | UI 能画框,并把框坐标归一化后调用后端推理;需点击归档保存才持久化 |
|
||||
| AI 推理中提示 | 真实可用 | 请求期间会显示 |
|
||||
| Mask 渲染 | 部分可用 | 前端会把推理/已保存标注转成 Konva `pathData` 渲染 |
|
||||
| 应用分类 | 真实可用 | 将当前选择的模板分类应用到本帧 mask;已保存 mask 会标为 dirty,归档保存时更新后端 |
|
||||
| 清空遮罩 | 真实可用 | 工作区中会删除当前帧已保存标注并清空当前帧本地 mask |
|
||||
| 保存状态计数 | 真实可用 | 底部显示已保存、未保存、待更新数量 |
|
||||
| 当前图层树文字 | Mock / UI-only | 固定显示 `OBJECT_VEHICLE_01` |
|
||||
|
||||
## ToolsPalette 工具栏
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 拖拽/选择 | 真实可用 | 控制 Canvas 是否可拖拽 |
|
||||
| 多边形/矩形/圆/点/线 | Mock / UI-only | 只切换 activeTool,没有对应绘制逻辑 |
|
||||
| 区域合并/去除 | Mock / UI-only | 只切换 activeTool,没有后端或前端算法 |
|
||||
| 正向选点/反向选点/框选 | 部分可用 | 会影响 Canvas 交互,并能触发已对齐的 AI 推理接口 |
|
||||
| 魔法棒 SAM 触发 | 部分可用 | 切到 AI 页面;不是直接执行推理 |
|
||||
| 撤销/重做 | Mock / UI-only | 按钮无事件 |
|
||||
|
||||
## FrameTimeline 时间轴
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 帧缩略图 | 真实可用 | 使用 `frames[].url` |
|
||||
| 点击缩略图跳帧 | 真实可用 | 调用 `setCurrentFrame(idx)` |
|
||||
| 顶部 range 拖动 | 真实可用 | 改变当前帧 |
|
||||
| 播放/暂停 | 真实可用 | 当前代码按 `parse_fps/original_fps` 推进帧,最多 30fps |
|
||||
| 方向键切帧 | Mock / UI-only | Word 提到,但当前没有键盘监听 |
|
||||
|
||||
## OntologyInspector 本体面板
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模板选择 | 部分可用 | 读取全局 templates,可切换 activeTemplateId |
|
||||
| 分类树展示 | 真实可用 | 显示模板 classes 和本地 customClasses |
|
||||
| 添加自定义分类 | 部分可用 | 只存在组件本地状态,不保存到后端 |
|
||||
| 置信度条 | Mock / UI-only | 固定 `0.9412` |
|
||||
| 拓扑锚点数量 | Mock / UI-only | 固定 `12 节点` |
|
||||
| 重新提取骨架按钮 | Mock / UI-only | 无事件 |
|
||||
|
||||
## AISegmentation 独立 AI 页
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模型选择 SAM2/SAM3 | 真实可用 | 选择写入 Zustand,`predictMask()` 会把 `model` 传给后端 SAM registry |
|
||||
| 正向/反向点 | 部分可用 | 可在当前项目帧上加点,并可调用 AI 推理接口 |
|
||||
| 语义文本输入 | 部分可用 | 纯文本会以 `semantic` prompt 调用后端;选择 SAM 3 且运行环境满足官方依赖时走 SAM 3 文本语义推理,否则状态接口会标明不可用 |
|
||||
| 参数开关 | Mock / UI-only | `cropMode`、`autoDeleteBg` 只改本地状态 |
|
||||
| 执行高精度语义分割 | 部分可用 | 使用当前项目帧调用 `/api/ai/predict`;没有当前帧时按钮禁用 |
|
||||
| 上传替换底图 | Mock / UI-only | 按钮无事件 |
|
||||
| 清空全体锚点 | 部分可用 | 清空前端 points 和 masks |
|
||||
| 退档推送至工作区重组 | 部分可用 | 只切回工作区,共用 masks store,但没有保存/确认流程 |
|
||||
| 背景图 | 部分可用 | 优先显示当前项目帧;没有项目帧时仍回退到 Unsplash 演示图 |
|
||||
|
||||
## TemplateRegistry 模板库
|
||||
|
||||
| 元素 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模板列表 | 真实可用 | 调用 `GET /api/templates` |
|
||||
| 新建方案 | 真实可用 | 调用 `POST /api/templates` |
|
||||
| 编辑模板 | 真实可用 | 调用 `PATCH /api/templates/{id}` |
|
||||
| 删除模板 | 真实可用 | 调用 `DELETE /api/templates/{id}` |
|
||||
| 添加/删除分类 | 真实可用 | 保存在模板 `mapping_rules.classes` |
|
||||
| 拖拽排序 | 真实可用 | 重算 zIndex,保存时写后端 |
|
||||
| JSON 批量导入 | 部分可用 | 前端解析 JSON 并加入编辑态,保存后才落库 |
|
||||
| 载入腹腔镜 35 分类 | 真实可用 | 前端内置数据;后端也 seed 默认模板 |
|
||||
| mapping rules | 部分可用 | 可存 `rules`,但无实际映射执行引擎 |
|
||||
|
||||
## 总体结论
|
||||
|
||||
当前前端真实可用的主链路是:登录、Dashboard 后端概览、项目列表、新建项目、上传视频/DICOM、拆帧、浏览帧、播放帧、工作区点/框 AI 推理、标注保存/回显、COCO 导出、模板 CRUD。
|
||||
|
||||
当前最主要的 Mock 或未打通链路是:撤销重做、手工几何绘制、GT 导入、mask 降维点区域、真正的文本语义分割和语义优先级融合。
|
||||
193
doc/04-api-contracts.md
Normal file
193
doc/04-api-contracts.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# 接口契约清单
|
||||
|
||||
## 前端 API 基础配置
|
||||
|
||||
位置:`src/lib/config.ts`、`src/lib/api.ts`
|
||||
|
||||
```ts
|
||||
API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://<current-browser-host>:8000'
|
||||
timeout: 30000
|
||||
```
|
||||
|
||||
前端 request interceptor 会从 localStorage 读取 `token`,附加:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
当前后端多数接口没有鉴权依赖,所以这个 header 主要是前端侧行为。
|
||||
|
||||
## 前端封装的 API
|
||||
|
||||
| 函数 | 方法与路径 | 状态 | 说明 |
|
||||
|------|------------|------|------|
|
||||
| `login(username, password)` | `POST /api/auth/login` | 对齐 | 后端返回 `{ token, username }`,前端只使用 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}` |
|
||||
| `deleteProject(id)` | `DELETE /api/projects/{id}` | 对齐 | 当前 UI 未明显接入 |
|
||||
| `getTemplates()` | `GET /api/templates` | 对齐 | 前端从 `mapping_rules` 取 classes/rules |
|
||||
| `createTemplate(payload)` | `POST /api/templates` | 对齐 | 后端会打包 classes/rules 到 mapping_rules |
|
||||
| `updateTemplate(id, payload)` | `PATCH /api/templates/{id}` | 对齐 | 模板编辑页使用 |
|
||||
| `deleteTemplate(id)` | `DELETE /api/templates/{id}` | 对齐 | 模板编辑页使用 |
|
||||
| `uploadMedia(file, projectId)` | `POST /api/media/upload` | 对齐 | multipart form-data |
|
||||
| `uploadDicomBatch(files, projectId)` | `POST /api/media/upload/dicom` | 对齐 | multipart form-data |
|
||||
| `parseMedia(projectId)` | `POST /api/media/parse?project_id=...` | 对齐 | 创建异步拆帧任务并返回 task |
|
||||
| `getTask(taskId)` | `GET /api/tasks/{task_id}` | 对齐 | 查询异步任务状态 |
|
||||
| `getProjectFrames(projectId)` | `GET /api/projects/{id}/frames` | 对齐 | 后端返回预签名 image_url |
|
||||
| `predictMask(payload)` | `POST /api/ai/predict` | 对齐 | 前端发送 `image_id/prompt_type/prompt_data/model`,并把后端 `polygons` 转为 `masks[].pathData` |
|
||||
| `getAiModelStatus(selectedModel?)` | `GET /api/ai/models/status` | 对齐 | 返回 GPU、SAM 2、SAM 3 的真实运行状态 |
|
||||
| `getProjectAnnotations(projectId, frameId?)` | `GET /api/ai/annotations` | 对齐 | 前端加载工作区时用于回显已保存标注 |
|
||||
| `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}` | 对齐 | 工作区清空当前帧已保存标注 |
|
||||
| `getDashboardOverview()` | `GET /api/dashboard/overview` | 对齐 | Dashboard 初始统计、队列和活动日志 |
|
||||
| `exportCoco(projectId)` | `GET /api/export/{projectId}/coco` | 对齐 | 后端实际是 `GET /api/export/{project_id}/coco` |
|
||||
|
||||
## 后端 FastAPI 接口
|
||||
|
||||
以下列表来自当前运行的 OpenAPI:
|
||||
|
||||
| 方法 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| POST | `/api/auth/login` | 登录 |
|
||||
| POST | `/api/projects` | 创建项目 |
|
||||
| GET | `/api/projects` | 项目列表 |
|
||||
| GET | `/api/projects/{project_id}` | 项目详情 |
|
||||
| PATCH | `/api/projects/{project_id}` | 更新项目 |
|
||||
| DELETE | `/api/projects/{project_id}` | 删除项目 |
|
||||
| POST | `/api/projects/{project_id}/frames` | 添加帧记录 |
|
||||
| GET | `/api/projects/{project_id}/frames` | 项目帧列表 |
|
||||
| GET | `/api/projects/{project_id}/frames/{frame_id}` | 单帧详情 |
|
||||
| POST | `/api/templates` | 创建模板 |
|
||||
| GET | `/api/templates` | 模板列表 |
|
||||
| GET | `/api/templates/{template_id}` | 模板详情 |
|
||||
| PATCH | `/api/templates/{template_id}` | 更新模板 |
|
||||
| DELETE | `/api/templates/{template_id}` | 删除模板 |
|
||||
| POST | `/api/media/upload` | 上传视频/图片/DICOM 单文件 |
|
||||
| POST | `/api/media/upload/dicom` | 批量上传 DICOM |
|
||||
| POST | `/api/media/parse` | 创建 Celery 拆帧任务 |
|
||||
| GET | `/api/tasks` | 查询后台任务列表 |
|
||||
| GET | `/api/tasks/{task_id}` | 查询单个后台任务 |
|
||||
| POST | `/api/ai/predict` | SAM 2 / SAM 3 可选推理 |
|
||||
| GET | `/api/ai/models/status` | GPU 和 SAM 模型状态 |
|
||||
| POST | `/api/ai/auto` | 自动分割 |
|
||||
| POST | `/api/ai/annotate` | 保存 AI 标注 |
|
||||
| GET | `/api/ai/annotations` | 查询项目标注,可选按帧过滤 |
|
||||
| PATCH | `/api/ai/annotations/{annotation_id}` | 更新已保存标注 |
|
||||
| DELETE | `/api/ai/annotations/{annotation_id}` | 删除已保存标注 |
|
||||
| GET | `/api/dashboard/overview` | Dashboard 聚合快照 |
|
||||
| GET | `/api/export/{project_id}/coco` | 导出 COCO JSON |
|
||||
| GET | `/api/export/{project_id}/masks` | 导出 PNG mask ZIP |
|
||||
| GET | `/health` | 健康检查 |
|
||||
| WS | `/ws/progress` | WebSocket 进度通道,未出现在 OpenAPI paths 中 |
|
||||
|
||||
## 关键请求体
|
||||
|
||||
### 登录
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "123456"
|
||||
}
|
||||
```
|
||||
|
||||
### 创建项目
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "example.mp4",
|
||||
"description": "导入说明",
|
||||
"parse_fps": 30
|
||||
}
|
||||
```
|
||||
|
||||
### 创建/更新模板
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "腹腔镜胆囊切除术",
|
||||
"color": "#06b6d4",
|
||||
"z_index": 0,
|
||||
"classes": [
|
||||
{
|
||||
"id": "cls-1",
|
||||
"name": "胆囊",
|
||||
"color": "#ffae00",
|
||||
"zIndex": 280,
|
||||
"category": "腹腔镜胆囊切除术"
|
||||
}
|
||||
],
|
||||
"rules": []
|
||||
}
|
||||
```
|
||||
|
||||
### AI 推理请求体
|
||||
|
||||
前端 `predictMask()` 当前已适配后端 `PredictRequest`:
|
||||
|
||||
```json
|
||||
{
|
||||
"image_id": 123,
|
||||
"model": "sam2",
|
||||
"prompt_type": "point",
|
||||
"prompt_data": {
|
||||
"points": [[0.5, 0.5]],
|
||||
"labels": [1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`prompt_type` 支持:
|
||||
|
||||
- `point`
|
||||
- `box`
|
||||
- `semantic`,选择 `sam3` 时进入 SAM 3 文本语义推理;选择 `sam2` 时仍回退到 auto segmentation
|
||||
|
||||
后端响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"polygons": [
|
||||
[[0.25, 0.25], [0.75, 0.25], [0.75, 0.75], [0.25, 0.75]]
|
||||
],
|
||||
"scores": [0.5]
|
||||
}
|
||||
```
|
||||
|
||||
前端会把上面的 `polygons` 转成:
|
||||
|
||||
```json
|
||||
{
|
||||
"masks": [
|
||||
{
|
||||
"pathData": "M 160 90 L 480 90 L 480 270 L 160 270 Z",
|
||||
"segmentation": [[160, 90, 480, 90, 480, 270, 160, 270]],
|
||||
"bbox": [160, 90, 320, 180]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 已完成的接口对齐
|
||||
|
||||
- `updateProject()` 已从 `PUT` 改为 `PATCH`。
|
||||
- `exportCoco()` 已从 `/api/export/coco/{projectId}` 改为 `/api/export/{projectId}/coco`。
|
||||
- Canvas 已使用真实 `frame.id` 作为 `image_id`。
|
||||
- 点和框坐标已转成后端需要的归一化坐标。
|
||||
- 后端 `polygons` 已在前端转成 Konva 可渲染的 path。
|
||||
- `saveAnnotation()` 已接入 `POST /api/ai/annotate`。
|
||||
- `getProjectAnnotations()` 已接入 `GET /api/ai/annotations`。
|
||||
- `updateAnnotation()` 已接入 `PATCH /api/ai/annotations/{annotationId}`。
|
||||
- `deleteAnnotation()` 已接入 `DELETE /api/ai/annotations/{annotationId}`。
|
||||
- `parseMedia()` 已改为创建 Celery 后台任务,并返回 `ProcessingTask`。
|
||||
- `getTask()` 已接入 `GET /api/tasks/{taskId}`。
|
||||
- `getDashboardOverview()` 已从 `processing_tasks` 聚合解析队列。
|
||||
- 工作区导出按钮已调用 `exportCoco()`,并会先保存未归档 mask。
|
||||
|
||||
## 仍需处理的接口问题
|
||||
|
||||
- WebSocket 地址已从 `VITE_WS_PROGRESS_URL` 读取,未配置时从 `API_BASE_URL` 推导;部署时仍要确认浏览器能访问该地址。
|
||||
- Celery worker 进度会写 PostgreSQL 任务表,同时发布到 Redis `seg:progress`;FastAPI 订阅后广播到 `/ws/progress`。
|
||||
- 已保存标注目前支持分类级更新和整帧清空删除;逐点几何编辑器尚未实现。
|
||||
115
doc/05-implementation-plan.md
Normal file
115
doc/05-implementation-plan.md
Normal 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 打通;剩余重点是任务控制。
|
||||
|
||||
## 阶段 6:GT 导入与点区域
|
||||
|
||||
这是 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 图,应从当前项目帧或上传文件进入。
|
||||
103
doc/06-fastapi-docs-explained.md
Normal file
103
doc/06-fastapi-docs-explained.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# `/docs` 是什么
|
||||
|
||||
地址:
|
||||
|
||||
- 本机:`http://localhost:8000/docs`
|
||||
- 局域网:`http://192.168.3.11:8000/docs`
|
||||
|
||||
这个页面不是文件列表,也不是项目文档目录。它是 FastAPI 自动生成的 Swagger UI,用来展示和调试后端 HTTP API。
|
||||
|
||||
## 为什么会自动出现
|
||||
|
||||
FastAPI 会根据代码里的路由和 Pydantic schema 自动生成 OpenAPI 描述,然后用 Swagger UI 展示出来。
|
||||
|
||||
相关代码在:
|
||||
|
||||
- `backend/main.py` 创建 `FastAPI(...)`
|
||||
- `backend/routers/*.py` 定义 `@router.get(...)`、`@router.post(...)` 等接口
|
||||
- `backend/schemas.py` 定义请求体和响应体
|
||||
|
||||
## 页面上 GET / POST / PATCH / DELETE 是什么
|
||||
|
||||
这些是 HTTP 方法,不是文件。
|
||||
|
||||
| 方法 | 含义 | 例子 |
|
||||
|------|------|------|
|
||||
| GET | 读取数据 | `GET /api/projects` 获取项目列表 |
|
||||
| POST | 创建或触发动作 | `POST /api/media/upload` 上传文件 |
|
||||
| PATCH | 局部更新 | `PATCH /api/templates/{template_id}` 更新模板 |
|
||||
| DELETE | 删除 | `DELETE /api/projects/{project_id}` 删除项目 |
|
||||
|
||||
你看到的每一行,都是后端暴露给前端调用的一个接口。
|
||||
|
||||
## `/docs` 能做什么
|
||||
|
||||
可以:
|
||||
|
||||
- 查看后端目前有哪些接口。
|
||||
- 展开接口查看参数、请求体和响应格式。
|
||||
- 点击 `Try it out` 直接发请求测试后端。
|
||||
- 检查接口返回错误,比如 400、401、404、500。
|
||||
|
||||
不能:
|
||||
|
||||
- 查看前端页面源码。
|
||||
- 直接代表某个功能已经完整可用。
|
||||
- 展示 WebSocket 的完整交互,因为 OpenAPI 主要描述 HTTP 接口。
|
||||
|
||||
## 和前端有什么关系
|
||||
|
||||
前端的 `src/lib/api.ts` 会调用这些接口。例如:
|
||||
|
||||
- 登录页调用 `/api/auth/login`
|
||||
- 项目库调用 `/api/projects`
|
||||
- 上传视频调用 `/api/media/upload`
|
||||
- 拆帧调用 `/api/media/parse`
|
||||
- 模板库调用 `/api/templates`
|
||||
|
||||
所以 `/docs` 是检查“后端提供了什么”的地方;前端是否真的用对了,还要对照 `src/lib/api.ts`。
|
||||
|
||||
## 目前通过 `/docs` 能看到的接口
|
||||
|
||||
当前后端接口包括:
|
||||
|
||||
- Auth:登录
|
||||
- Projects:项目 CRUD、项目帧 CRUD
|
||||
- Templates:模板 CRUD
|
||||
- Media:上传视频/DICOM、触发拆帧
|
||||
- AI:SAM 2 / SAM 3 可选推理、模型状态、自动分割、保存标注
|
||||
- Export:导出 COCO JSON、导出 PNG masks
|
||||
- Health:健康检查
|
||||
|
||||
## 为什么看起来像“列举文件和请求”
|
||||
|
||||
因为 Swagger UI 默认按接口分组,把每个 endpoint 展开成一行。它列举的是“后端可被调用的功能入口”,不是项目文件。
|
||||
|
||||
真正的项目文件在本地目录里,例如:
|
||||
|
||||
- 前端:`src/components/*.tsx`
|
||||
- 后端路由:`backend/routers/*.py`
|
||||
- 后端模型:`backend/models.py`
|
||||
|
||||
## 如何用 `/docs` 验证一个接口
|
||||
|
||||
以项目列表为例:
|
||||
|
||||
1. 打开 `/docs`。
|
||||
2. 找到 `GET /api/projects`。
|
||||
3. 点开。
|
||||
4. 点击 `Try it out`。
|
||||
5. 点击 `Execute`。
|
||||
6. 查看 Response body。
|
||||
|
||||
如果这里能返回数据,但前端项目库加载失败,那问题多半在前端 API 地址、CORS、字段映射或浏览器网络请求。
|
||||
|
||||
## 另一个机器可读入口
|
||||
|
||||
OpenAPI JSON 在:
|
||||
|
||||
```text
|
||||
http://localhost:8000/openapi.json
|
||||
```
|
||||
|
||||
这是给工具读取的接口描述,Swagger UI 就是基于它渲染出来的。
|
||||
120
doc/07-current-requirements-freeze.md
Normal file
120
doc/07-current-requirements-freeze.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 当前需求冻结文档
|
||||
|
||||
冻结日期:2026-05-01
|
||||
|
||||
本文档描述当前仓库已经实现或明确保留为占位的需求。测试用例以本文档为准,不把早期设想或 Word 文档中的远期能力当作当前版本必须实现的功能。
|
||||
|
||||
## R1 登录与会话
|
||||
|
||||
- 系统提供登录页。
|
||||
- 默认开发凭证为 `admin / 123456`。
|
||||
- 登录成功后前端保存 token,并进入主应用。
|
||||
- 登录失败时显示错误信息。
|
||||
- 当前 token 是开发用固定 token,不做真实 JWT 校验。
|
||||
|
||||
## R2 项目管理
|
||||
|
||||
- 前端展示项目库,并从 `GET /api/projects` 获取项目列表。
|
||||
- 用户可以新建项目,前端调用 `POST /api/projects`。
|
||||
- 用户可以选择项目,进入工作区。
|
||||
- 用户可以导入视频文件,前端创建项目、上传文件、触发拆帧、刷新项目列表。
|
||||
- 用户可以导入 DICOM 序列,前端上传 DICOM、触发拆帧、刷新项目列表。
|
||||
- 后端支持项目创建、列表、详情、局部更新和删除。
|
||||
- 后端支持项目帧创建、列表和单帧查询。
|
||||
|
||||
## R3 媒体上传与拆帧
|
||||
|
||||
- 后端允许上传视频、图片、DICOM 文件,其他扩展名返回 400。
|
||||
- 未提供项目 ID 上传时,后端自动创建项目。
|
||||
- 提供项目 ID 上传时,后端把上传对象关联到该项目。
|
||||
- 拆帧接口根据项目 `source_type` 处理视频或 DICOM。
|
||||
- 拆帧完成后写入 `frames` 记录,并把项目状态设为 `ready`。
|
||||
- 拆帧接口会创建 `processing_tasks` 记录并投递 Celery worker。
|
||||
- 前端可通过 `GET /api/tasks/{task_id}` 查询任务状态。
|
||||
|
||||
## R4 工作区与帧浏览
|
||||
|
||||
- 工作区根据当前项目加载帧列表。
|
||||
- 若项目有媒体但无帧,工作区会尝试触发拆帧后重新加载。
|
||||
- Canvas 显示当前帧图片。
|
||||
- Canvas 支持滚轮缩放、移动工具拖拽、鼠标坐标显示。
|
||||
- 时间轴支持缩略图点击切帧、range 拖动切帧、播放/暂停顺序推进帧。
|
||||
- 播放帧率使用项目 `parse_fps` 或 `original_fps`,限制在 1 到 30 FPS。
|
||||
|
||||
## R5 工具栏
|
||||
|
||||
- 工具栏可以切换当前 active tool。
|
||||
- 正向点、反向点、框选工具会影响 Canvas 交互。
|
||||
- 魔法棒按钮切换到 AI 页面。
|
||||
- 多边形、矩形、圆、点、线、合并、去除、撤销、重做当前只提供 UI 状态或占位按钮,不完成真实绘制/算法。
|
||||
|
||||
## R6 AI 推理
|
||||
|
||||
- 前端可以在 AI 页面选择 `sam2` 或 `sam3`,选择结果存放在全局 store。
|
||||
- 前端和工作区通过 `GET /api/ai/models/status` 展示 GPU、SAM 2 和 SAM 3 的真实运行状态。
|
||||
- 前端 `predictMask()` 调用 `POST /api/ai/predict`。
|
||||
- 前端发送后端契约:`image_id`、`prompt_type`、`prompt_data`、`model`。
|
||||
- 点提示传 `{ points, labels }`,正向点 label 为 1,反向点 label 为 0。
|
||||
- 框选提示传归一化 `[x1, y1, x2, y2]`。
|
||||
- 语义文本提示传 `semantic`;选择 `sam3` 且环境满足依赖时走 SAM 3 文本语义推理,选择 `sam2` 时回退到自动分割。
|
||||
- 后端返回 `polygons` 和 `scores`。
|
||||
- 前端把后端 `polygons` 转成 Konva `pathData`、`segmentation`、`bbox`、`area`。
|
||||
- AI 推理结果先存放在前端 store 的 `masks` 中,点击“结构化归档保存”后持久化到后端标注表。
|
||||
|
||||
## R7 标注保存
|
||||
|
||||
- 后端提供 `POST /api/ai/annotate` 保存标注。
|
||||
- 保存时必须存在项目;如果传入 `frame_id`,帧也必须存在。
|
||||
- 后端提供 `GET /api/ai/annotations` 查询项目标注,可选按 `frame_id` 过滤。
|
||||
- 后端提供 `PATCH /api/ai/annotations/{annotation_id}` 更新已保存标注的 `mask_data`、`points`、`bbox` 和 `template_id`。
|
||||
- 后端提供 `DELETE /api/ai/annotations/{annotation_id}` 删除已保存标注。
|
||||
- 当前前端“结构化归档保存”会保存当前项目未保存 mask,并会更新已标记为 dirty 的已保存 mask。
|
||||
- 工作区“清空遮罩”会删除当前帧已保存标注,并清空当前帧未保存 mask。
|
||||
- 工作区加载项目帧后会查询已保存标注并回显。
|
||||
|
||||
## R8 模板库
|
||||
|
||||
- 前端展示模板列表,调用 `GET /api/templates`。
|
||||
- 用户可以新建、编辑、删除模板。
|
||||
- 模板分类存放在 `mapping_rules.classes`,规则存放在 `mapping_rules.rules`。
|
||||
- 前端支持添加/删除分类、拖拽排序后重算 `zIndex`、JSON 批量导入、加载腹腔镜默认分类。
|
||||
- 后端支持模板创建、列表、详情、局部更新和删除。
|
||||
|
||||
## R9 本体检查面板
|
||||
|
||||
- 工作区右侧可以选择模板。
|
||||
- 面板显示模板分类和组件本地自定义分类。
|
||||
- 用户可以选择具体分类;新 AI mask 会记录 `classId`、`className`、`classZIndex`,并在保存时写入 `mask_data.class`。
|
||||
- 添加自定义分类只存在组件本地状态,不保存到后端。
|
||||
- 置信度、拓扑锚点和重新提取骨架按钮当前为展示/占位。
|
||||
|
||||
## R10 Dashboard 与 WebSocket
|
||||
|
||||
- Dashboard 显示基础统计、解析队列和活动日志。
|
||||
- Dashboard 初始数据来自 `GET /api/dashboard/overview`。
|
||||
- 后端聚合项目数、处理中任务数、标注数、帧数、模板数和主机 load average。
|
||||
- 解析队列由 `processing_tasks` 中的 queued/running 任务生成;活动日志由最近任务、项目、标注和模板记录生成。
|
||||
- Dashboard 会连接 `/ws/progress`。
|
||||
- 收到 progress、complete、error、status 消息时,前端会更新队列或日志。
|
||||
- Celery worker 每次更新 `processing_tasks` 后会发布 Redis `seg:progress` 事件,FastAPI 订阅并广播给 `/ws/progress` 客户端。
|
||||
- 后端 WebSocket 接收到客户端消息后返回 status heartbeat。
|
||||
|
||||
## R11 导出
|
||||
|
||||
- 后端支持 `GET /api/export/{project_id}/coco` 导出 COCO JSON。
|
||||
- 后端支持 `GET /api/export/{project_id}/masks` 导出 PNG mask ZIP。
|
||||
- 当前前端 `exportCoco()` API 封装已对齐后端路径。
|
||||
- 工作区“导出 JSON 标注集”按钮已绑定下载事件;导出前会先保存当前未归档 mask。
|
||||
|
||||
## R12 配置
|
||||
|
||||
- 前端 API 地址由 `src/lib/config.ts` 统一推导。
|
||||
- `VITE_API_BASE_URL` 优先级高于自动推导。
|
||||
- `VITE_WS_PROGRESS_URL` 优先级高于从 API 地址推导 WebSocket 地址。
|
||||
- 未设置环境变量时,前端按当前浏览器 hostname 推导 `http://<host>:8000`。
|
||||
|
||||
## R13 文档与测试
|
||||
|
||||
- `doc/` 目录保存当前实现审计、接口契约、需求冻结、设计冻结和测试计划。
|
||||
- 测试应覆盖当前冻结需求中的真实功能、半可用行为和明确占位行为。
|
||||
- 对外部服务依赖 PostgreSQL、MinIO、Redis、SAM 模型的测试应使用 mock 或测试替身,不依赖真实服务可用性。
|
||||
155
doc/08-current-design-freeze.md
Normal file
155
doc/08-current-design-freeze.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 当前设计冻结文档
|
||||
|
||||
冻结日期: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、工具状态 |
|
||||
| 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 页面 |
|
||||
| 时间轴 | `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` | SAM 3 状态检测和文本语义推理适配 |
|
||||
| SAM Registry | `backend/services/sam_registry.py` | 模型选择、GPU 状态和推理分发 |
|
||||
|
||||
## 状态模型
|
||||
|
||||
前端 store 的核心对象:
|
||||
|
||||
- `Project`:项目基本信息、状态、帧数、fps、媒体路径。
|
||||
- `Frame`:帧 ID、项目 ID、索引、图片 URL、宽高。
|
||||
- `Template` / `TemplateClass`:模板和分类定义。
|
||||
- `Mask`:前端渲染用 mask,包含 `pathData`、`segmentation`、`bbox`、`area`。
|
||||
- `activeModule`:当前页面。
|
||||
- `activeTool`:当前工具。
|
||||
- `aiModel`:当前选择的 AI 模型,取值为 `sam2` 或 `sam3`。
|
||||
|
||||
## 关键数据流
|
||||
|
||||
### 登录
|
||||
|
||||
1. `Login` 收集用户名和密码。
|
||||
2. `login()` 调用 `POST /api/auth/login`。
|
||||
3. 成功后 store 写入 token,App 渲染主界面。
|
||||
|
||||
### 项目导入
|
||||
|
||||
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. `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 会带上当前选择的模板分类元数据,包括 `classId`、`className`、`classZIndex` 和保存状态 `draft`。
|
||||
8. 用户点击“结构化归档保存”后,前端将像素 `segmentation` 转成 normalized `mask_data.polygons`;未保存 mask 调用 `POST /api/ai/annotate`,dirty mask 调用 `PATCH /api/ai/annotations/{annotation_id}`。
|
||||
9. 工作区加载项目帧后通过 `GET /api/ai/annotations` 取回已保存标注并转成前端 mask。
|
||||
10. 工作区“清空遮罩”删除当前帧已保存标注,并清除当前帧本地 mask。
|
||||
|
||||
### 模板管理
|
||||
|
||||
1. `TemplateRegistry` 从后端读取模板。
|
||||
2. 编辑态在组件本地维护分类列表。
|
||||
3. 保存时调用 `createTemplate()` 或 `updateTemplate()`。
|
||||
4. 后端把 `classes`、`rules` 打包进 `mapping_rules`。
|
||||
5. 返回时再解包给前端。
|
||||
6. `OntologyInspector` 可以选择具体分类;选择结果进入全局 store,供 `CanvasArea` 和 `AISegmentation` 新建/更新 mask 时使用。
|
||||
|
||||
### 导出
|
||||
|
||||
1. 后端根据项目、帧、标注和模板生成 COCO JSON。
|
||||
2. PNG mask 导出会把 normalized polygon 渲染为二值 mask 并打包 ZIP。
|
||||
3. 前端“导出 JSON 标注集”按钮会在导出前保存待归档标注,然后下载 COCO JSON。
|
||||
|
||||
## 接口契约
|
||||
|
||||
接口详情见 `doc/04-api-contracts.md`。测试中重点固定以下契约:
|
||||
|
||||
- `updateProject()` 使用 `PATCH /api/projects/{id}`。
|
||||
- `exportCoco()` 使用 `GET /api/export/{projectId}/coco`。
|
||||
- `predictMask()` 使用 `POST /api/ai/predict`,请求体为 `image_id`、`prompt_type`、`prompt_data`、`model`。
|
||||
- `saveAnnotation()` 使用 `POST /api/ai/annotate`。
|
||||
- `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/models/status` 返回 GPU、SAM 2、SAM 3 的真实运行状态。
|
||||
- point prompt 支持旧数组形式和 `{ points, labels }` 对象形式。
|
||||
|
||||
## 外部依赖边界
|
||||
|
||||
测试不直接依赖以下真实服务:
|
||||
|
||||
- PostgreSQL:后端测试使用内存 SQLite。
|
||||
- MinIO:上传、下载、预签名 URL 使用 monkeypatch。
|
||||
- Redis:单测使用 monkeypatch 验证进度事件发布,不依赖真实 Redis 服务。
|
||||
- SAM:AI 推理测试使用 fake registry。
|
||||
- 浏览器 Canvas/Konva 图片加载:前端测试 mock `react-konva` 和 `use-image`。
|
||||
|
||||
## 已知占位设计
|
||||
|
||||
以下能力属于当前冻结版本的占位或半可用功能:
|
||||
|
||||
- Dashboard 初始快照来自 `GET /api/dashboard/overview`;解析队列由 `processing_tasks` queued/running 任务生成。
|
||||
- 多边形、矩形、圆、点、线手工绘制未实现。
|
||||
- 合并、去除、撤销、重做未实现。
|
||||
- 工作区导出 PNG mask ZIP 按钮尚未提供。
|
||||
- 已保存标注支持通过“应用分类”进入 dirty 状态并归档更新;暂未提供逐点几何编辑器。
|
||||
- SAM 3 文本语义分割取决于官方依赖和 GPU 运行环境;状态接口会暴露真实可用性。
|
||||
- 自定义分类只存在本地组件状态。
|
||||
49
doc/09-test-plan.md
Normal file
49
doc/09-test-plan.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 当前测试计划
|
||||
|
||||
本文档把 `doc/07-current-requirements-freeze.md` 中的冻结需求映射到测试。测试目标是覆盖当前真实行为和明确占位行为。
|
||||
|
||||
## 测试分层
|
||||
|
||||
| 层级 | 工具 | 覆盖范围 |
|
||||
|------|------|----------|
|
||||
| 前端单元/组件 | Vitest + Testing Library | API 封装、store、组件交互、Mock/UI-only 状态 |
|
||||
| 后端路由 | pytest + FastAPI TestClient | Auth、Projects、Templates、AI、Export、Media 的接口契约 |
|
||||
| 静态契约 | TypeScript / py_compile | 类型和 Python 语法 |
|
||||
|
||||
## 覆盖矩阵
|
||||
|
||||
| 需求 | 测试文件 | 覆盖点 |
|
||||
|------|----------|--------|
|
||||
| R1 登录与会话 | `src/components/Login.test.tsx`, `backend/tests/test_auth.py` | 成功登录、失败提示、后端 401 |
|
||||
| R2 项目管理 | `src/lib/api.test.ts`, `backend/tests/test_projects.py` | 前端字段映射、PATCH 更新、后端 CRUD、帧列表 |
|
||||
| R3 媒体上传与拆帧 | `backend/tests/test_media.py` | 扩展名校验、自动建项目、关联项目、创建异步任务、worker 注册帧 |
|
||||
| R4 工作区与帧浏览 | `src/components/VideoWorkspace.test.tsx`, `src/components/FrameTimeline.test.tsx` | 加载帧、无帧触发解析、切帧、播放 |
|
||||
| R5 工具栏 | `src/components/ToolsPalette.test.tsx` | 工具切换、AI 跳转、占位按钮存在 |
|
||||
| R6 AI 推理 | `src/lib/api.test.ts`, `src/components/CanvasArea.test.tsx`, `src/components/AISegmentation.test.tsx`, `src/components/ModelStatusBadge.test.tsx`, `backend/tests/test_ai.py` | 点/框/semantic 契约、模型选择、GPU/SAM 状态、状态徽标、坐标归一化、正负点 labels、polygons 转 path、后端 fake registry |
|
||||
| R7 标注保存 | `src/components/VideoWorkspace.test.tsx`, `src/components/CanvasArea.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_ai.py` | 保存标注、加载回显、更新 dirty 标注、清空删除已保存标注、项目不存在、帧不存在 |
|
||||
| R8 模板库 | `src/lib/api.test.ts`, `backend/tests/test_templates.py` | mapping_rules 解包/打包、模板 CRUD |
|
||||
| R9 本体检查面板 | `src/components/OntologyInspector.test.tsx` | 模板选择、分类展示、具体分类选择、自定义分类本地添加 |
|
||||
| R10 Dashboard 与 WebSocket | `src/lib/api.test.ts`, `src/lib/websocket.test.ts`, `src/components/Dashboard.test.tsx`, `backend/tests/test_dashboard.py`, `backend/tests/test_main.py`, `backend/tests/test_progress_events.py` | 后端概览接口、任务表驱动队列、Redis 进度事件 payload/发布、地址推导、消息订阅、队列更新、heartbeat |
|
||||
| R11 导出 | `src/components/VideoWorkspace.test.tsx`, `src/lib/api.test.ts`, `backend/tests/test_export.py` | COCO 按钮下载、导出前自动保存、COCO 路径、JSON 结构、mask ZIP |
|
||||
| R12 配置 | `src/lib/config.test.ts` | env 优先、hostname 推导、WS 推导 |
|
||||
| R13 文档与测试 | `doc/09-test-plan.md` | 测试覆盖矩阵 |
|
||||
|
||||
## 运行命令
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
npm run test:run
|
||||
npm run lint
|
||||
npm run build
|
||||
|
||||
pip install -r backend/requirements-dev.txt
|
||||
pytest backend/tests
|
||||
python -m py_compile backend/routers/ai.py backend/routers/templates.py backend/schemas.py
|
||||
```
|
||||
|
||||
## 当前不做的测试
|
||||
|
||||
- 不启动真实 PostgreSQL、MinIO、Redis 或 SAM 模型。
|
||||
- 不做真实视频大文件拆帧性能测试。
|
||||
- 不用浏览器 E2E 验证视觉细节。
|
||||
- 不把当前明确 Mock/UI-only 的按钮当成真实业务成功路径测试。
|
||||
32
doc/README.md
Normal file
32
doc/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# 项目文档索引
|
||||
|
||||
本目录用于记录当前代码库的真实状态、目标设计与实现差距。文档依据包括:
|
||||
|
||||
- 根目录 Word 文档:`语义分割系统构建方案.docx`
|
||||
- 前端源码:`src/App.tsx`、`src/components/*.tsx`、`src/lib/api.ts`、`src/store/useStore.ts`
|
||||
- 后端源码:`backend/main.py`、`backend/routers/*.py`、`backend/schemas.py`、`backend/models.py`
|
||||
- 运行时 OpenAPI:`http://localhost:8000/openapi.json`
|
||||
|
||||
## 文档结构
|
||||
|
||||
| 文档 | 内容 |
|
||||
|------|------|
|
||||
| [01-purpose-and-word-summary.md](./01-purpose-and-word-summary.md) | 为什么要做这个系统,Word 方案中的目标,以及当前代码的落地程度 |
|
||||
| [02-current-implementation-map.md](./02-current-implementation-map.md) | 当前系统怎么运行,前后端、存储、数据流具体怎么串起来 |
|
||||
| [03-frontend-element-audit.md](./03-frontend-element-audit.md) | 前端逐页面/逐元素审计:真实可用、半可用、Mock/UI-only、接口不通 |
|
||||
| [04-api-contracts.md](./04-api-contracts.md) | 前端 API 封装、后端 FastAPI 接口、已完成对齐项和剩余接口问题 |
|
||||
| [05-implementation-plan.md](./05-implementation-plan.md) | 后续要把 Mock 变成真实功能的建议实施顺序 |
|
||||
| [06-fastapi-docs-explained.md](./06-fastapi-docs-explained.md) | `http://192.168.3.11:8000/docs` 是什么,怎么看和怎么用 |
|
||||
| [07-current-requirements-freeze.md](./07-current-requirements-freeze.md) | 当前版本需求冻结,测试以此为准 |
|
||||
| [08-current-design-freeze.md](./08-current-design-freeze.md) | 当前版本设计冻结,记录模块、数据流和接口边界 |
|
||||
| [09-test-plan.md](./09-test-plan.md) | 需求到测试文件的覆盖矩阵和运行命令 |
|
||||
|
||||
## 状态标记
|
||||
|
||||
| 标记 | 含义 |
|
||||
|------|------|
|
||||
| 真实可用 | 已接真实前端状态或后端 API,按当前代码能完成主要动作 |
|
||||
| 部分可用 | 有真实数据或真实 UI,但存在关键缺口,例如只读、不能持久化、缺少错误处理 |
|
||||
| Mock / UI-only | 只有展示或本地状态变化,没有真实业务效果 |
|
||||
| 接口不通 | 前端调用和后端接口契约不一致,按当前代码大概率失败 |
|
||||
| 目标设计 | Word 方案中提出,但当前代码尚未实现 |
|
||||
Reference in New Issue
Block a user