Files
Pre_Seg_Server/AGENTS.md
admin 29a1a87e52 feat: 完善 SAM2.1 模型选择与标注工作流
- 后端 SAM2 引擎新增 sam2.1_hiera_tiny、sam2.1_hiera_small、sam2.1_hiera_base_plus、sam2.1_hiera_large 四个变体定义,并按变体维护 checkpoint/config、image predictor、video predictor、加载状态、错误信息和真实状态回报。

- 后端 SAM registry 仅暴露当前产品启用的 SAM2.1 变体,保留 sam2 作为 tiny 兼容别名,拒绝 sam3 产品入口,并把 point、box、interactive、auto、propagate 都分发到所选 SAM2.1 变体。

- 后端默认配置和下载脚本切换到 SAM2.1 checkpoint 命名,支持 legacy SAM2 checkpoint fallback,并在状态消息中标出 fallback 使用情况。

- 前端全局 AI 模型状态新增 SAM2.1 tiny/small/base+/large 类型和默认 tiny,API 请求默认携带 sam2.1_hiera_tiny,AI 页面提供模型变体选择和所选模型状态展示。

- AI 智能分割页移除当前产品不使用的 SAM3/文本提示入口,保留正向点、反向点、框选和参数开关;AI 页只展示本页生成的候选 mask,并支持遮罩清晰度调节、候选 mask 上继续加正/反点、清空本页候选、推送到工作区编辑。

- 工作区和 Canvas 补强 SAM2 交互式细化链路:框选后正/反点继续细化同一个候选 mask,反向点请求启用背景过滤,空结果会移除被否定候选;AI 推送到工作区后保留选中态和未保存 draft mask。

- 工作区标注保存闭环补强:未保存 mask 可归档保存,dirty saved mask 可更新,保存后用后端 saved annotation 替换已提交 draft,清空/删除已保存 mask 时同步后端删除。

- Dashboard 任务进度区改为展示 queued、running、success、failed、cancelled 最近任务,处理中统计只计算 queued/running,并保留近期完成记录。

- 时间轴在顶部时间进度条和底部缩略图导航轴之间新增已编辑帧标记带,基于当前项目帧内 masks 标出已有编辑/标注的帧,并支持点击标记跳转。

- 前端测试覆盖 SAM2.1 变体选择、模型状态徽标、AI 页候选隔离、遮罩透明度、候选上追加正/反点、推送工作区保留选择、Canvas 交互式细化、VideoWorkspace 传播/保存、Dashboard 进度和时间轴已编辑帧标记。

- 后端测试覆盖 SAM2.1 变体状态、sam2 alias 兼容、sam3 禁用、semantic 禁用、传播标注保存、Dashboard 最近任务状态和 SAM3 历史测试跳过说明。

- README、AGENTS 和 doc 文档同步当前真实进度,更新 SAM2.1 变体、SAM3 禁用、接口契约、设计冻结、需求冻结、前端元素审计、实施计划、FastAPI docs 说明和测试矩阵。
2026-05-01 23:39:53 +08:00

308 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — AI 编码助手项目指南
> 本文件面向 AI 编码助手。阅读者应假设对该项目一无所知。以下信息基于当前仓库实际文件、脚本和源码不要把早期设计目标当作已实现事实。任何代码和功能修改都要落实到文档和测试上如果生成git commit信息要逐个列点把所有修改都列上重要的、大的修改放前面不重要的、小的修改列在后面。
---
## 项目概述
本项目是一个**语义分割系统**Semantic Segmentation System当前形态是 React 前端 + FastAPI 后端的全栈 Web 应用,用于视频/DICOM 医学影像上传、显式视频生成帧、交互式 Canvas 标注、视频片段传播、GT mask 导入、可选 SAM 2.1 tiny/small/base+/large 辅助分割、模板分类管理和标注导出。SAM 3 相关源码和安装脚本保留在仓库中,但由于当前产品不提供文本提示,前端入口已隐藏,后端 registry 也不暴露 `sam3` 模型。
- **项目名称**: `react-example``package.json` 中的 `name`
- **前端入口**: `src/main.tsx``src/App.tsx`
- **前端服务入口**: `server.ts`Express + Vite 中间件 / 生产静态服务,并保留少量旧版 mock API
- **后端入口**: `backend/main.py`FastAPI
- **默认前端地址**: `http://localhost:3000`
- **默认后端地址**: `http://localhost:8000`
- **前端 API 配置**: `src/lib/config.ts`,优先读取 `VITE_API_BASE_URL`,未配置时按当前浏览器 hostname 推导 `http://<host>:8000`
- **业务文档**: `语义分割系统构建方案.docx`(项目根目录)
---
## 技术栈
| 层级 | 技术 |
|------|------|
| 前端框架 | React 19 + TypeScript 5.8 |
| 构建工具 | Vite 6 |
| 前端样式 | TailwindCSS 4 + 自定义深色主题 |
| 前端状态 | Zustand`src/store/useStore.ts` |
| 前端请求 | Axios`src/lib/api.ts` |
| 实时通信 | WebSocket 客户端(`src/lib/websocket.ts` |
| Canvas 渲染 | Konva + react-konva + use-image |
| 几何布尔运算 | polygon-clipping |
| 图标库 | lucide-react |
| 动画依赖 | motion`package.json` 中声明) |
| AI SDK 依赖 | `@google/genai`(在 `package.json` 中声明;当前业务源码未直接调用) |
| 后端框架 | FastAPI + Uvicorn |
| ORM / 数据库 | SQLAlchemy + PostgreSQL |
| 缓存 / 队列 Broker | Redis |
| 后台任务 | Celery worker |
| 对象存储 | MinIO |
| AI 推理 | 当前启用 SAM 2.1 + PyTorch可选 tiny/small/base+/large`GET /api/ai/models/status` 返回真实 GPU 和各 SAM 2.1 变体状态SAM 3 源码保留但产品入口禁用 |
| 视频 / 影像处理 | FFmpeg / OpenCV / pydicom |
| 运行时 | Node.js ES ModulesPython 3.11 后端环境;历史保留的 `sam3` Python 3.12 conda 环境不是当前必需运行条件 |
---
## 项目结构
```
Seg_Server/
├── server.ts # Express + Vite 前端入口;保留 /api/login、/api/projects、/api/templates mock
├── index.html # SPA HTML 入口
├── vite.config.ts # Vite 配置;含 @/* 路径别名与 DISABLE_HMR 逻辑
├── tsconfig.json # TypeScript 配置;@/* 映射到项目根目录
├── package.json # npm 依赖与脚本
├── .env.example # AI Studio/Gemini 前端环境变量模板
├── metadata.json # AI Studio 元数据
├── public/
│ └── logo.png # Sidebar 使用的 /logo.png
├── doc/ # 当前实现审计、接口契约和后续实施文档
├── start_services.sh # 本地一键启动 PostgreSQL/Redis/MinIO/FastAPI/Celery/前端
├── backend/ # FastAPI 后端
│ ├── main.py # 应用入口、lifespan、CORS、路由注册、WebSocket
│ ├── config.py # Pydantic Settings读取 backend/.env
│ ├── database.py # SQLAlchemy Engine / Session
│ ├── models.py # Project/Frame/Template/Annotation/Mask/ProcessingTask ORM
│ ├── schemas.py # Pydantic 请求/响应模型
│ ├── minio_client.py # MinIO 上传、下载、预签名 URL
│ ├── redis_client.py # Redis 连接封装
│ ├── celery_app.py # Celery app 配置
│ ├── worker_tasks.py # Celery 任务入口
│ ├── download_sam2.py # SAM 2 权重下载脚本
│ ├── setup_sam3_env.sh # 历史保留的 SAM 3 独立 Python 3.12 环境安装脚本;当前产品入口禁用
│ ├── requirements.txt # Python 依赖
│ ├── routers/
│ │ ├── auth.py # /api/auth/login
│ │ ├── projects.py # /api/projects 与 /api/projects/{id}/frames
│ │ ├── templates.py # /api/templates
│ │ ├── media.py # /api/media/upload、/upload/dicom、/parse
│ │ ├── ai.py # /api/ai/predict、/propagate、/models/status、/auto、/annotate
│ │ └── export.py # /api/export/{project_id}/coco、/masks
│ └── services/
│ ├── frame_parser.py # FFmpeg/OpenCV 拆帧、pydicom 读片、帧上传
│ ├── sam2_engine.py # SAM 2.1 变体选择、单帧推理和 video predictor 传播封装
│ ├── sam3_engine.py # 历史保留的 SAM 3 桥接实现;当前未接入 registry
│ ├── sam3_external_worker.py # 历史保留的独立 sam3 helper当前未被产品入口调用
│ └── sam_registry.py # 当前暴露 SAM 2.1 变体、GPU 状态与推理分发
└── src/ # React 前端
├── main.tsx # React StrictMode 挂载
├── App.tsx # 登录拦截 + 模块切换
├── index.css # TailwindCSS 导入 + 全局样式
├── store/useStore.ts # Zustand 全局状态
├── lib/api.ts # Axios API 封装
├── lib/websocket.ts # 解析进度 WebSocket 客户端
├── lib/utils.ts # cn() 工具函数
└── components/ # 扁平化组件目录
├── Login.tsx
├── Sidebar.tsx
├── Dashboard.tsx
├── ProjectLibrary.tsx
├── VideoWorkspace.tsx
├── CanvasArea.tsx
├── ToolsPalette.tsx
├── OntologyInspector.tsx
├── FrameTimeline.tsx
├── AISegmentation.tsx
└── TemplateRegistry.tsx
```
以下目录/文件通常是运行产物或本地数据,已在 `.gitignore` 中忽略:`node_modules/``dist/``models/``uploads/``frames/``Data_*/``*.mp4``*.dcm``*.7z``backend/.env`、日志文件等。
`doc/` 目录是当前项目的事实文档入口。修改功能前优先查看:
- `doc/03-frontend-element-audit.md`:哪些前端元素是真功能,哪些是 Mock/UI-only。
- `doc/04-api-contracts.md`:前后端接口契约,以及当前不一致点。
- `doc/05-implementation-plan.md`:建议的后续实施顺序。
---
## 构建与运行命令
### 前端 / Node 入口
```bash
npm install
# 开发模式:运行 tsx server.tsExpress 集成 Vite middleware端口 3000
npm run dev
# 生产构建:输出 dist/
npm run build
# Vite 预览
npm run preview
# 生产模式运行 server.ts服务 dist/;仍保留 server.ts 中的旧版 mock API
npm start
# TypeScript 类型检查
npm run lint
# 删除 dist/
npm run clean
```
### FastAPI 后端
```bash
cd backend
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
```
### 一键启动
```bash
./start_services.sh
```
该脚本会依次检查/启动 PostgreSQL、Redis、MinIO、FastAPI 后端、Celery worker 和前端。
---
## 运行时架构
### 前端
- 单页应用,无路由库;模块切换由 `useStore().activeModule` 控制。
- 模块值包括:`dashboard``projects``ai``workspace``templates`
- 默认模块是 `workspace`
- 未登录时渲染 `Login`
- 登录成功后 token 写入 `localStorage`Axios request interceptor 会附加 `Authorization: Bearer <token>`
- `App.tsx` 在登录后调用 `getProjects()` 初始化项目列表。
### 后端
- 主后端是 `backend/main.py` 的 FastAPI 服务。
- `lifespan` 启动时会:
- 创建数据库表;
- 检查/创建 MinIO bucket `seg-media`
- 测试 Redis 连接;
- 后台 seed 默认模板;
- 如果本地存在 `Data_MyVideo_1.mp4`,后台 seed 默认演示项目并拆前 100 帧。
- API 路由包括:
- `POST /api/auth/login`
- `GET/POST/PATCH/DELETE /api/projects`
- `GET/POST /api/projects/{project_id}/frames`
- `GET/POST/PATCH/DELETE /api/templates`
- `POST /api/media/upload`
- `POST /api/media/upload/dicom`
- `POST /api/media/parse`
- `GET /api/tasks`
- `GET /api/tasks/{task_id}`
- `POST /api/tasks/{task_id}/cancel`
- `POST /api/tasks/{task_id}/retry`
- `POST /api/ai/predict`
- `POST /api/ai/propagate`
- `GET /api/ai/models/status`
- `POST /api/ai/auto`
- `POST /api/ai/annotate`
- `POST /api/ai/import-gt-mask`
- `GET /api/ai/annotations`
- `PATCH/DELETE /api/ai/annotations/{annotation_id}`
- `GET /api/dashboard/overview`
- `GET /api/export/{project_id}/coco`
- `GET /api/export/{project_id}/masks`
- `GET /health`
- `WS /ws/progress`
### 存储
- PostgreSQL 存储项目、帧、模板、标注、mask 和后台任务元数据。
- MinIO 存储上传视频、DICOM、拆出的帧、缩略图等对象前端展示使用预签名 URL。
- Redis 当前作为 Celery broker/result backend并用于连接检查。
---
## 主要业务流程
1. 登录:`Login.tsx` 调用 `POST /api/auth/login`,默认开发凭证为 `admin / 123456`
2. 项目管理:`ProjectLibrary.tsx` 调用项目 API 创建项目、拉取列表。
3. 上传资源:视频走 `/api/media/upload`只上传源文件并关联项目不自动拆帧DICOM 批量走 `/api/media/upload/dicom`
4. 生成帧入队:用户在项目库点击“生成帧”,选择目标 FPS 后前端调用 `/api/media/parse`;后端创建 `ProcessingTask` 并投递 Celery接口支持 `parse_fps``max_frames``target_width` 标准帧序列参数。
5. worker 执行Celery worker 用 FFmpeg 优先拆视频帧,失败后用 OpenCV fallbackDICOM 使用 pydicom视频帧按 `frame_%06d.jpg` 连续命名并记录 `timestamp_ms``source_frame_number` 和任务 `frame_sequence` 元数据。
6. 帧展示:`VideoWorkspace.tsx` 调用 `/api/projects/{id}/frames``CanvasArea.tsx``FrameTimeline.tsx` 显示当前帧与时间轴缩略图;`FrameTimeline` 会根据当前项目帧内的 `masks` 在进度条和缩略图导航轴之间标出已有编辑/标注的帧;前端 `Frame` 会保留后端返回的帧序列时间戳和源帧号。
7. 手工标注:`CanvasArea.tsx` 支持多边形、矩形、圆、点区域和线段生成 polygon mask多边形可按 Enter 或点击首节点闭合;绘制工具可在已有 mask 上继续落点;工具栏有“调整多边形”入口,点击 mask 可拖动/删除 polygon 顶点、通过边中点或双击边界插入新顶点,并能选择编辑多 polygon mask 的单个子区域;选中整块 mask 可用 Delete/Backspace 删除,已保存 mask 会同步后端删除;区域合并/去除会隐藏编辑手柄并显示已选数量,使用 `polygon-clipping` 做 union/difference内含去除结果用 even-odd 规则渲染 holeZustand 维护 `maskHistory/maskFuture` 支持撤销/重做。
8. AI 分割:前端工具包括 SAM 2.1 变体选择、正向点、反向点和框选SAM 2.1 框选会建立候选 mask后续正/反点通过 `interactive` prompt 携带原始框和累计点细化同一个候选 mask包含反向点时工作区会传 `options.auto_filter_background=true``min_score=0.05`,如果后端过滤为空则移除旧候选 mask。后端 `ai.py` 期望按 `image_id``prompt_type``prompt_data``model` 和可选 `options` 调用 SAM registry。当前 registry 暴露 `sam2.1_hiera_tiny``sam2.1_hiera_small``sam2.1_hiera_base_plus``sam2.1_hiera_large`,并兼容 `sam2` 作为 tiny 别名;`model=sam3` 会被拒绝,`semantic` 文本提示也被禁用。SAM 2.1 支持点/框/interactive/自动分割和 video predictor 传播多候选默认只采用最高分区域避免重叠候选同时显示AI 页面只渲染本页新生成的候选 mask不会把工作区已有 mask 带入 AI 画布AI 页面生成的 mask 会写入全局 `masks` 并自动选中,右侧分类树可直接改标签,推送到工作区会切到“调整多边形”并保留选择。`options.crop_to_prompt` 可对点/框/interactive prompt 做局部裁剪推理并回映射,`options.auto_filter_background` 可按分数和负向点过滤结果。
9. 视频片段传播:工作区“传播片段”把当前选中 mask 或当前帧第一个 mask 作为 seed调用 `POST /api/ai/propagate`;后端按项目帧序列下载片段帧,当前使用所选 SAM 2.1 变体的 `SAM2VideoPredictor.add_new_mask()` + `propagate_in_video()`,并把后续帧结果保存为 `Annotation`
10. GT 导入:工作区“导入 GT Mask”调用 `/api/ai/import-gt-mask`;后端按非零像素值和连通域生成 polygon 标注,并用 distance transform 生成 seed point前端回显 seed point拖动后可归档更新。
11. 模板管理:`TemplateRegistry.tsx` 管理分类、颜色和 z-index`OntologyInspector.tsx` 在工作区显示当前模板分类树。
12. 导出:后端支持 COCO JSON 和 PNG mask ZIP 导出PNG ZIP 包含单标注 mask、按 zIndex 融合的语义 mask 和 `semantic_classes.json`
---
## 当前实现注意事项
- `src/lib/config.ts` 会优先读取 `VITE_API_BASE_URL``VITE_WS_PROGRESS_URL`;未配置时按当前浏览器 hostname 推导后端 `:8000` 地址。
- 前端 `predictMask()` 已按后端 `PredictRequest` 发送 `image_id``prompt_type``prompt_data``model`,并将后端 `polygons` 转成 Konva 可渲染的 `pathData`
- 手工绘制工具会生成可保存的 `Mask.segmentation`;撤销/重做通过 `maskHistory/maskFuture` 工作。
- Polygon 顶点编辑和新增顶点会重算 `pathData/segmentation/bbox/area`;已保存 mask 进入 dirty 状态后复用归档 PATCH 链路。
- 区域合并/去除会重算主 mask 的几何;合并已保存的次级 mask 时会通过工作区回调删除对应后端标注。
- 前端 `importGtMask()` 已对齐后端 `/api/ai/import-gt-mask`;工作区“导入 GT Mask”会导入后端生成的多类别标注和 seed point 并回显。
- 前端 `exportCoco()` 已对齐后端 `/api/export/{project_id}/coco`;前端 `exportMasks()` 已对齐后端 `/api/export/{project_id}/masks`;工作区导出按钮会先保存当前待归档 mask。
- 工作区“结构化归档保存”按钮已接入 `POST /api/ai/annotate``PATCH /api/ai/annotations/{id}`;加载工作区时会通过 `GET /api/ai/annotations` 回显已保存标注。
- 工作区“传播片段”按钮已接入 `POST /api/ai/propagate`;当前启用所选 SAM 2.1 变体的视频 predictor完成后刷新后端已保存标注。
- 工作区“清空遮罩”会调用 `DELETE /api/ai/annotations/{id}` 删除当前帧已保存标注,并清空当前帧本地 mask。
- 项目状态已统一为 `pending``parsing``ready``error`;前端 `src/lib/api.ts` 会兼容归一化旧库中可能存在的 `Ready``Parsing``Error`
- 项目库的视频导入与生成帧是两个独立动作:导入视频只上传源文件,生成帧按钮才会带 `parse_fps` 调用 `/api/media/parse`;工作区不会再因“有视频但无帧”自动创建拆帧任务。
- `server.ts` 仍有旧版 `/api/login``/api/projects``/api/templates` mock当前前端真实 API 调用主要走 FastAPI 的 `/api/auth/*``/api/projects``/api/templates` 等接口。
- `Dashboard.tsx` 初始统计、任务进度和活动日志来自 `GET /api/dashboard/overview`;任务进度来自 `processing_tasks` queued/running/success/failed/cancelled处理中统计只计算 queued/running支持取消 queued/running 任务、重试 failed/cancelled 任务和查看失败详情。Celery worker 通过 Redis pub/sub 的 `seg:progress` 频道推送细粒度进度,再由 FastAPI 广播到 `/ws/progress`;前端 WebSocket 客户端通过 `onopen/onclose/onerror` 更新连接状态,并定时发送 `ping` 心跳。
---
## 代码风格与约定
### 样式规范
- 深色主题为主,常见背景色包括 `#0a0a0a``#111``#0d0d0d``#151515``#1e1e1e`
- 青色(如 `cyan-400` / `cyan-500`)用于激活状态、主按钮和关键指标。
- 前端样式主要使用 TailwindCSS 工具类,通过 `cn()` 合并条件类名。
- `src/index.css` 使用 TailwindCSS 4 的 `@import "tailwindcss";`
### 组件规范
- 组件使用函数组件 + Hooks。
- 当前组件目录是扁平结构:`src/components/*.tsx`,不是按模块子目录分层。
- Props 类型优先使用 TypeScript `interface`
- UI 文本保持中文。
- 代码与注释优先使用英文。
### 命名规范
- 组件文件使用 PascalCase例如 `AISegmentation.tsx`
- 工具文件使用 camelCase例如 `utils.ts`
- 类型和接口使用 PascalCase。
---
## 测试策略
当前仓库已配置前端 Vitest 测试和后端 pytest 测试。测试依据 `doc/07-current-requirements-freeze.md``doc/08-current-design-freeze.md``doc/09-test-plan.md`
- 前端测试配置:`vitest.config.ts`,共享 setup 在 `src/test/setup.tsx`
- 前端测试命令:`npm run test:run`
- 后端测试依赖:`backend/requirements-dev.txt`
- 后端测试命令:`pytest backend/tests`,或在 `backend/` 目录执行 `pytest tests`
- 基础静态校验:`npm run lint``npm run build``python -m py_compile backend/routers/ai.py backend/routers/templates.py backend/schemas.py`
- 后端测试使用内存 SQLite、fake MinIO 和 fake SAM registry不依赖真实 PostgreSQL、MinIO、Redis 或模型权重。
---
## 安全注意事项
- FastAPI 登录是开发用硬编码凭证:`admin / 123456`
- 登录成功返回固定 token`fake-jwt-token-for-admin`,没有真实 JWT 签名校验。
- Axios 会附加 Bearer token但后端大多数业务路由当前没有鉴权依赖。
- `backend/.env``.gitignore` 忽略不要提交真实数据库、MinIO、Redis、模型路径等敏感配置。
- `start_services.sh` 中包含本机路径和 sudo 启动逻辑,迁移机器时要审查。
- Express `server.ts` 的旧版 mock API 只适合开发/兼容场景,不能当生产鉴权或持久化方案。
---
## AI Studio / Vite 特定配置
- `.env.example` 包含 `GEMINI_API_KEY``APP_URL`,说明这些值由 AI Studio 注入。
- `vite.config.ts` 通过 `loadEnv``GEMINI_API_KEY` 注入到 `process.env.GEMINI_API_KEY`
- `vite.config.ts` 中的 `DISABLE_HMR` 逻辑用于关闭 HMR避免 AI Studio agent 编辑时闪烁。**不要随意修改该逻辑。**