# 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://: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、/propagate/task、/models/status、/auto、/annotate │ │ └── export.py # /api/export/{project_id}/coco、/masks │ └── services/ │ ├── frame_parser.py # FFmpeg/OpenCV 拆帧、pydicom 读片、帧上传 │ ├── propagation_task_runner.py # Celery 自动传播任务 runner │ ├── 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 ├── TransientNotice.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`:建议的后续实施顺序。 - `doc/10-installation.md`:完整安装部署流程,覆盖 PostgreSQL、Redis、MinIO、FastAPI、Celery、前端和 SAM 2.1 权重。 --- ## 构建与运行命令 ### 前端 / Node 入口 ```bash 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 后端 ```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 `。 - `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` - `POST /api/ai/propagate/task` - `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 创建项目、拉取列表、删除项目;删除当前项目后会清空工作区当前项目、帧、mask 和选区。 3. 上传资源:视频走 `/api/media/upload`,只上传源文件并关联项目,不自动拆帧;DICOM 批量走 `/api/media/upload/dicom`。 4. 生成帧入队:用户在项目库点击“生成帧”,选择目标 FPS 后前端调用 `/api/media/parse`;后端创建 `ProcessingTask` 并投递 Celery,接口支持 `parse_fps`、`max_frames` 和 `target_width` 标准帧序列参数;项目库和模板库的成功/失败短反馈使用非阻塞 `TransientNotice`,会自动消失。 5. worker 执行:Celery worker 用 FFmpeg 优先拆视频帧,失败后用 OpenCV fallback,DICOM 使用 pydicom;视频帧按 `frame_%06d.jpg` 连续命名并记录 `timestamp_ms`、`source_frame_number` 和任务 `frame_sequence` 元数据。 6. 帧展示:`VideoWorkspace.tsx` 调用 `/api/projects/{id}/frames`,`CanvasArea.tsx` 和 `FrameTimeline.tsx` 显示当前帧与时间轴缩略图;`CanvasArea` 会按容器和帧尺寸默认居中放大底图并保留边距;`FrameTimeline` 会根据已保存标注回显到 `Mask.metadata` 的传播来源,把自动传播生成的帧在视频处理进度条显示为蓝色区段,人工/AI 标注帧显示红色竖线;视频处理进度条和红/蓝标识可点击跳转到对应帧;底部缩略图中人工/AI 标注帧用红色边框、自动传播/推理帧用蓝色边框,当前帧仍以青色外框高亮优先;若当前帧同时是人工/AI 标注帧,则在青色外框内增加红色内描边;只有进入自动传播范围选择模式时,播放进度条和视频处理进度条才显示黄色范围框,并可点击/拖拽选择传播起止帧;前端 `Frame` 会保留后端返回的帧序列时间戳和源帧号。 7. 手工标注:`CanvasArea.tsx` 支持多边形、矩形、圆、点区域和线段生成 polygon mask;多边形可按 Enter 或点击首节点闭合;绘制工具可在已有 mask 上继续落点;工具栏有“调整多边形”入口,左侧 `ToolsPalette` 使用紧凑垂直布局并在高度不足时自身滚动;点击 mask 后可按住顶点直接拖动并实时更新 polygon,也可删除 polygon 顶点、通过边中点或双击边界插入新顶点,并能选择编辑多 polygon mask 的单个子区域;选中整块 mask 可用 Delete/Backspace 删除,已保存 mask 会同步后端删除;区域合并/去除会隐藏编辑手柄并显示已选数量,第一个选中的主区域用黄色实线轮廓,后续参与合并/扣除的区域用红色虚线轮廓,使用 `polygon-clipping` 做 union/difference,内含去除结果用 even-odd 规则渲染 hole;Zustand 维护 `maskHistory/maskFuture` 支持撤销/重做。 8. AI 分割:前端工具包括 SAM 2.1 变体选择、正向点、反向点和框选;AI 画布会按容器和当前帧尺寸默认居中放大底图并保留边距;工作区和 AI 页面都可点击已有提示点删除单点,AI 页面也可删除最近锚点、删除选中候选或清空本页锚点;这些删除入口会限制在当前提示点/本页 AI 候选范围内,避免误删工作区已有 mask。SAM 2.1 框选会建立候选 mask,后续正/反点通过 `interactive` prompt 携带原始框和累计点细化同一个候选 mask;AI 页面框选会先固化 `promptBox`,执行分割时只框选发送 `box` prompt,框选后继续加正/反点发送 `interactive` prompt;重复执行高精度分割会替换上一次 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` 可按分数和负向点过滤结果。 9. 视频片段传播:工作区以当前打开帧作为参考帧,使用该帧全部 mask 作为 seed,并用传播起始帧和传播结束帧指定追踪范围;用户可直接修改数字框,也可点击“自动传播”进入时间轴范围选择模式,在播放进度条或视频处理进度条上点击/拖拽选择范围,再点击“开始传播”。工作区顶栏有独立“传播权重”选择器,可为本次传播二次选择 SAM 2.1 tiny/small/base+/large 权重,不提供 SAM2/SAM3 家族切换,也不影响 AI 单帧分割权重;前端会按传播权重 id、seed mask、seed 来源 id 和前/后方向组装 `steps` 并调用 `POST /api/ai/propagate/task` 创建 `propagate_masks` 后台任务;后端入队时会规范化/校验权重 id 并把规范化后的 id 写入任务 payload/result;Celery worker 顺序执行各 step,避免多个视频 tracker 并发抢占 GPU;每个 step 会根据 seed 来源 id、权重、方向和 seed 签名做幂等判断,未改变的 seed 直接跳过,已改变的 seed 会先删除同源旧自动传播标注再重传;后端按项目帧序列下载片段帧,当前使用所选 SAM 2.1 权重变体的 `SAM2VideoPredictor.add_new_mask()` + `propagate_in_video()`,并把后续帧结果保存为 `Annotation`。工作区轮询 `GET /api/tasks/{task_id}` 展示进度并刷新标注,Dashboard 也能显示/取消/重试传播任务。 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/task`;若用户尚未显式设置范围,第一次点击会进入时间轴范围选择模式,第二次点击“开始传播”才提交后台任务;当前启用所选 SAM 2.1 变体的视频 predictor 后台任务,运行中轮询任务进度,完成后刷新后端已保存标注;同步 `POST /api/ai/propagate` 仍作为单 seed 兼容接口保留。 - 工作区顶栏短状态会自动消失;保存、导出、导入 GT、传播进行中和无帧项目提示会保留到状态变化。 - 工作区“清空遮罩”会调用 `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` 只负责前端开发/静态服务,不承担业务 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 编辑时闪烁。**不要随意修改该逻辑。**