功能新增: - 新增 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,记录后端属性分析、分类置顶显示、上下文提示、自动传播按钮、传播帧标记、测试覆盖和当前剩余限制。
20 KiB
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 Modules;Python 3.11 后端环境;历史保留的 sam3 Python 3.12 conda 环境不是当前必需运行条件 |
项目结构
Seg_Server/
├── server.ts # Express + Vite 前端入口;不再提供旧版 /api 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 入口
npm install
# 开发模式:运行 tsx server.ts,Express 集成 Vite middleware,端口 3000
npm run dev
# 生产构建:输出 dist/
npm run build
# Vite 预览
npm run preview
# 生产模式运行 server.ts,服务 dist/
npm start
# TypeScript 类型检查
npm run lint
# 删除 dist/
npm run clean
FastAPI 后端
cd backend
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
一键启动
./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/loginGET/POST/PATCH/DELETE /api/projectsGET/POST /api/projects/{project_id}/framesGET/POST/PATCH/DELETE /api/templatesPOST /api/media/uploadPOST /api/media/upload/dicomPOST /api/media/parseGET /api/tasksGET /api/tasks/{task_id}POST /api/tasks/{task_id}/cancelPOST /api/tasks/{task_id}/retryPOST /api/ai/predictPOST /api/ai/propagateGET /api/ai/models/statusPOST /api/ai/autoPOST /api/ai/annotatePOST /api/ai/import-gt-maskGET /api/ai/annotationsPATCH/DELETE /api/ai/annotations/{annotation_id}GET /api/dashboard/overviewGET /api/export/{project_id}/cocoGET /api/export/{project_id}/masksGET /healthWS /ws/progress
存储
- PostgreSQL 存储项目、帧、模板、标注、mask 和后台任务元数据。
- MinIO 存储上传视频、DICOM、拆出的帧、缩略图等对象;前端展示使用预签名 URL。
- Redis 当前作为 Celery broker/result backend,并用于连接检查。
主要业务流程
- 登录:
Login.tsx调用POST /api/auth/login,默认开发凭证为admin / 123456。 - 项目管理:
ProjectLibrary.tsx调用项目 API 创建项目、拉取列表、删除项目;删除当前项目后会清空工作区当前项目、帧、mask 和选区。 - 上传资源:视频走
/api/media/upload,只上传源文件并关联项目,不自动拆帧;DICOM 批量走/api/media/upload/dicom。 - 生成帧入队:用户在项目库点击“生成帧”,选择目标 FPS 后前端调用
/api/media/parse;后端创建ProcessingTask并投递 Celery,接口支持parse_fps、max_frames和target_width标准帧序列参数。 - worker 执行:Celery worker 用 FFmpeg 优先拆视频帧,失败后用 OpenCV fallback,DICOM 使用 pydicom;视频帧按
frame_%06d.jpg连续命名并记录timestamp_ms、source_frame_number和任务frame_sequence元数据。 - 帧展示:
VideoWorkspace.tsx调用/api/projects/{id}/frames,CanvasArea.tsx和FrameTimeline.tsx显示当前帧与时间轴缩略图;FrameTimeline会根据已保存标注回显到Mask.metadata的传播来源,把自动传播生成的帧在顶部进度条对应区段标为浅蓝色,当前帧位置由播放进度条末端、时间提示和缩略图高亮表达;前端Frame会保留后端返回的帧序列时间戳和源帧号。 - 手工标注:
CanvasArea.tsx支持多边形、矩形、圆、点区域和线段生成 polygon mask;多边形可按 Enter 或点击首节点闭合;绘制工具可在已有 mask 上继续落点;工具栏有“调整多边形”入口,点击 mask 后可按住顶点直接拖动并实时更新 polygon,也可删除 polygon 顶点、通过边中点或双击边界插入新顶点,并能选择编辑多 polygon mask 的单个子区域;选中整块 mask 可用 Delete/Backspace 删除,已保存 mask 会同步后端删除;区域合并/去除会隐藏编辑手柄并显示已选数量,第一个选中的主区域用黄色实线轮廓,后续参与合并/扣除的区域用红色虚线轮廓,使用polygon-clipping做 union/difference,内含去除结果用 even-odd 规则渲染 hole;Zustand 维护maskHistory/maskFuture支持撤销/重做。 - AI 分割:前端工具包括 SAM 2.1 变体选择、正向点、反向点和框选;工作区和 AI 页面都可点击已有提示点删除单点,AI 页面也可删除最近锚点、删除选中候选或清空本页锚点;这些删除入口会限制在当前提示点/本页 AI 候选范围内,避免误删工作区已有 mask。SAM 2.1 框选会建立候选 mask,后续正/反点通过
interactiveprompt 携带原始框和累计点细化同一个候选 mask;AI 页面框选会先固化promptBox,执行分割时只框选发送boxprompt,框选后继续加正/反点发送interactiveprompt;重复执行高精度分割会替换上一次 AI 页候选,只保留最新一个候选。包含反向点时工作区会传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可按分数和负向点过滤结果。 - 视频片段传播:工作区以当前打开帧作为参考帧,使用该帧全部 mask 作为 seed,并用传播起始帧和传播结束帧指定追踪范围;前端只保留一个“自动传播”按钮,会按 seed mask 和前/后方向顺序调用单 seed
POST /api/ai/propagate,避免多个视频 tracker 并发抢占 GPU;后端按项目帧序列下载片段帧,当前使用所选 SAM 2.1 变体的SAM2VideoPredictor.add_new_mask()+propagate_in_video(),并把后续帧结果保存为Annotation。 - GT 导入:工作区“导入 GT Mask”调用
/api/ai/import-gt-mask;后端按非零像素值和连通域生成 polygon 标注,并用 distance transform 生成 seed point;前端回显 seed point,拖动后可归档更新。 - 模板管理:
TemplateRegistry.tsx管理分类、颜色和 z-index;OntologyInspector.tsx在工作区显示当前模板分类树。 - 导出:后端支持 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/templatesmock;当前前端真实 API 调用走 FastAPI 的/api/auth/*、/api/projects、/api/templates等接口。Dashboard.tsx初始统计、任务进度和活动日志来自GET /api/dashboard/overview;任务进度来自processing_tasksqueued/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只负责前端开发/静态服务,不承担业务 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 编辑时闪烁。不要随意修改该逻辑。