<div align="center">
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
</div>

# 语义分割系统（SegServer）

> 基于 React + FastAPI + SAM 2 的全栈交互式图像/视频语义分割与标注平台。
>
> 支持本地多媒体资产上传、服务器端按帧解析、交互式 Canvas 标注、视频片段传播、GT mask 导入、模板分类管理和标注数据结构化导出；工作区点/框 AI 推理走可选 SAM 2.1 tiny/small/base+/large，前端会显示真实 GPU/模型状态。SAM 3 源码和脚本在仓库中保留，但由于当前系统不提供文本提示，产品入口已隐藏，后端也不暴露 `sam3` 模型。

---

## 核心功能

- **多媒体资产管理** — 支持视频（MP4/AVI/MOV）和 DICOM 医学影像上传，项目库会在导入时显示上传进度条、已上传字节、DICOM 文件数量和上传后的解析任务进度；视频导入与生成帧分离，生成帧时选择目标 FPS，项目卡片可重命名、复制或删除项目及其关联帧、标注和任务记录；复制时可选择“新项目重置”只保留媒体/帧序列，或“全内容复制”连同标注和 mask 元数据一起复制
- **AI 智能分割引擎** — 当前产品入口启用 SAM 2.1 四个变体（tiny/small/base+/large）选择；侧栏和工作区跳转入口使用 Bot + Sparkles 组合图标强化 AI 识别；支持点分割（point）、框分割（box）、交互式正/反点细化、提示点单点删除、AI 候选单独删除、自动分割（auto）和 Celery 后台 video predictor 传播，前端默认只采用最高分候选避免重叠备选同时显示
- **交互式画布标注** — 基于 Konva 的高性能 Canvas，工作区和 AI 画布会默认居中放大底图并保留边距；工作区支持缩放/平移/手工多边形/矩形/圆/画笔/橡皮擦、polygon 顶点直接拖动/删除、边中点插点、双击边界插点、区域合并/去除、撤销/重做；mask 不再显示黄色 seed point，也不提供 seed point 拖动；画笔和橡皮擦支持尺寸调节，画笔可按当前语义分类生成连续区域并自动合并连通的选中 mask，橡皮擦可从选中 mask 扣除区域；删除传播 seed 或传播结果时会同步删除同一传播链上的自动传播 mask，但保留其他帧独立 AI 推理/人工标注 mask；未选中特定 mask 时按右侧语义分类树的内部优先级叠放显示，AI 智能分割页单独提供正/反点和框选，实时渲染 Mask 遮罩
- **GT Mask 导入** — 工作区可导入 8-bit 二值/灰度 maskid 图或 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图；导入前会显示本地预览，不符合 8-bit 灰度/maskid 图要求时反馈错误，尺寸不同会按当前帧长宽最近邻拉伸；后端按 maskid 匹配当前模板类别并生成高精度 polygon 标注，导入后与普通 mask 一样不显示黄色 seed point，并共用拓扑锚点统计、边缘平滑、顶点编辑、分类和保存链路；超出现有类别的 maskid 可由用户选择舍弃或导入为“未定义类别”等待重新命名
- **本体字典管理** — 可配置的分类体系、颜色映射、稳定且跨图一致的 maskid；所有模板默认带 `maskid: 0` 的黑色“待分类”保留类，该类固定在语义分类树最后、不可删除也不可拖到上层；模板库“生效中模板架构清单”可用鼠标复制现有模板为当前用户私有副本，详情页“语义分类树（拖拽调层级）”支持新建分类、拖拽调层级和垃圾桶删除 label，模板编辑弹窗和右侧分类树也可拖拽调整内部图层覆盖顺序，maskid 不参与排序
- **项目工作区** — 项目创建、帧浏览、多图层标注、自动传播帧提示、进度追踪
- **数据导出** — 工作区使用统一“分割结果导出”入口，可选择整体视频、特定范围帧或当前图片；特定范围帧支持输入帧号或在时间轴进度条上拖拽选择，并导出 COCO JSON、maskid/GT 像素值映射、原始图片、分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图；GT/Pro/Mix 的重叠覆盖顺序和右侧语义分类树内部优先级一致，GT_label 固定为 8-bit uint8 PNG，背景为 0，类别值使用模板中的真实 maskid，`maskid: 0` 的“待分类”在 GT_label 中与背景同为 0，在 Pro_label 中与背景同为黑色 `[0,0,0]`，缺失 maskid 的旧标注才补下一个可用正整数，正整数 maskid 超出 1-255 会拒绝导出

---

## 系统架构

```
┌─────────────────────────────────────────────────────────────┐
│  前端展示层 (React 19 + Vite + TailwindCSS)                │
│  localhost:3000                                             │
│  Zustand(状态) + Axios(API) + WebSocket(实时进度)           │
│  Konva(Canvas渲染) + lucide-react(图标)                     │
└──────────────────────────┬──────────────────────────────────┘
                           │ HTTP / WebSocket
┌──────────────────────────▼──────────────────────────────────┐
│  业务逻辑层 (FastAPI + Python 3.11)                        │
│  localhost:8000                                             │
│  ├── /api/auth     登录认证                                  │
│  ├── /api/admin    管理员用户管理、审计日志、演示出厂重置    │
│  ├── /api/projects 项目 & 视频帧 CRUD                       │
│  ├── /api/templates 本体字典（分类/颜色/z-index）            │
│  ├── /api/media    文件上传 & 异步拆帧任务创建             │
│  ├── /api/tasks    Celery 后台任务状态/取消/重试/详情       │
│  ├── /api/ai       SAM 2 推理与模型状态                     │
│  └── /api/export   COCO JSON / PNG / 统一分割结果导出      │
└──────────────────────────┬──────────────────────────────────┘
                           │ SQLAlchemy 2.0
┌──────────────────────────▼──────────────────────────────────┐
│  数据持久化层                                               │
│  PostgreSQL 14  — 项目/帧/标注/Mask/Task 元数据             │
│  Redis 6        — Celery broker/result backend + 进度 pub/sub │
│  MinIO          — 对象存储（原始视频/解析帧/Mask图像）       │
└─────────────────────────────────────────────────────────────┘
```

---

## 技术栈

| 层级 | 技术选型 | 版本 |
|------|----------|------|
| 前端框架 | React + TypeScript | React 19, TS 5.8 |
| 构建工具 | Vite | v6 |
| 样式方案 | TailwindCSS + 自定义深色主题 | v4 |
| 状态管理 | Zustand | - |
| Canvas 渲染 | Konva + react-konva | - |
| 几何布尔运算 | polygon-clipping | 0.15+ |
| HTTP 客户端 | Axios | - |
| 后端框架 | FastAPI | v0.136+ |
| 数据库 ORM | SQLAlchemy（依赖中包含 Alembic） | 2.0+ |
| 数据库 | PostgreSQL | 14 |
| 队列 Broker | Redis | 6 |
| 后台任务 | Celery worker | 5.6+ |
| 对象存储 | MinIO | 2025+ |
| AI 推理 | SAM 2.1 (Meta) + PyTorch，可选 tiny/small/base+/large | - |
| 视频处理 | FFmpeg + OpenCV | 4.4+ |
| DICOM 处理 | pydicom | 3.0+ |

---

## 目录结构

```
Seg_Server/
├── backend/                       # FastAPI 后端
│   ├── main.py                    # 应用入口（CORS/生命周期/路由注册/WebSocket）
│   ├── config.py                  # 环境变量配置（Pydantic Settings）
│   ├── database.py                # SQLAlchemy 引擎 + Session
│   ├── models.py                  # ORM 模型（User/Project/Frame/Template/Annotation/Mask/AuditLog/ProcessingTask）
│   ├── schemas.py                 # Pydantic 请求/响应校验模型
│   ├── minio_client.py            # MinIO 上传/下载/预签名URL封装
│   ├── redis_client.py            # Redis 连接封装
│   ├── progress_events.py         # 任务进度事件 payload 与 Redis 发布
│   ├── statuses.py                # 项目/任务状态常量
│   ├── 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/                   # API 路由
│   │   ├── auth.py                # 用户表、密码哈希、JWT 登录和 /api/auth/me
│   │   ├── admin.py               # 管理员用户 CRUD 和审计日志
│   │   ├── projects.py            # 项目 & 帧 CRUD
│   │   ├── templates.py           # 本体字典管理
│   │   ├── media.py               # 上传 & 解析
│   │   ├── ai.py                  # SAM 推理与模型状态接口
│   │   └── export.py              # 数据导出
│   └── services/                  # 业务服务
│       ├── 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 状态与推理分发
│       └── frame_parser.py        # FFmpeg 拆帧 / pydicom 读片
├── src/                           # React 前端
│   ├── main.tsx                   # 应用挂载点
│   ├── App.tsx                    # 根组件（模块路由 + 鉴权）
│   ├── store/
│   │   └── useStore.ts            # Zustand 全局状态
│   ├── lib/
│   │   ├── api.ts                 # Axios 实例 + API 方法封装
│   │   ├── websocket.ts           # WebSocket 客户端（解析进度）
│   │   └── utils.ts               # cn() 工具函数
│   └── components/                # 组件（扁平化目录）
│       ├── Login.tsx              # 登录页
│       ├── Sidebar.tsx            # 左侧导航栏
│       ├── UserAdmin.tsx          # 管理员用户管理后台
│       ├── Dashboard.tsx          # 总体概况仪表盘（任务进度/任务控制）
│       ├── ProjectLibrary.tsx     # 项目库列表
│       ├── VideoWorkspace.tsx     # 核心分割工作区布局
│       ├── CanvasArea.tsx         # Konva 画布（缩放/平移/手工绘制/选点/Mask渲染）
│       ├── ToolsPalette.tsx       # 左侧紧凑工具栏（高度不足时滚动）
│       ├── OntologyInspector.tsx  # 右侧本体/属性检查面板
│       ├── FrameTimeline.tsx      # 底部时间轴
│       ├── AISegmentation.tsx     # AI 智能分割引擎界面
│       ├── TransientNotice.tsx    # 非阻塞自动消失短提示
│       └── TemplateRegistry.tsx   # 模板库管理
├── models/                        # SAM 2 模型权重（.pt 文件）
├── uploads/                       # 临时上传目录
├── frames/                        # 临时帧目录
├── doc/                           # 当前实现审计、接口契约与后续实施文档
├── logo_square.png                # 侧边栏与 favicon 使用的根目录方形 Logo
├── public/
│   └── logo.png                   # 旧版保留 Logo 静态资源
├── start_services.sh              # 一键启动所有服务脚本
├── server.ts                      # Express + Vite 前端入口（不再提供旧版 mock API）
├── index.html                     # SPA HTML 入口
├── vite.config.ts                 # Vite 构建配置
├── package.json                   # npm 依赖与脚本
└── tsconfig.json                  # TypeScript 配置
```

---

## 项目文档

当前实现审计与接口契约文档在 `doc/` 目录：

- `doc/01-purpose-and-word-summary.md` — 项目目的、Word 方案摘要与当前落地程度
- `doc/03-frontend-element-audit.md` — 前端逐元素功能审计，标注真实可用、部分可用、Mock/UI-only、接口不通
- `doc/04-api-contracts.md` — 前后端接口契约和已知不一致
- `doc/06-fastapi-docs-explained.md` — `http://192.168.3.11:8000/docs` 的作用说明
- `doc/10-installation.md` — 独立安装部署指南，覆盖 PostgreSQL、Redis、MinIO、FastAPI、Celery、前端和 SAM 2.1 权重

---

## 环境准备

### 系统要求

- **OS**: Ubuntu 22.04 LTS
- **GPU**: NVIDIA GPU（推荐 RTX 4090 或同等算力），用于 SAM 2 推理
- **CUDA**: 12.x / 13.x
- **Node.js**: 22.x+
- **Python**: 主后端使用 3.11（通过 Miniconda/Anaconda 管理）；历史保留的 SAM 3 环境不是当前必需运行条件

### 安装系统级依赖

```bash
# 更新包索引
sudo apt update

# 安装 PostgreSQL、Redis、FFmpeg、构建工具
sudo apt install -y postgresql postgresql-contrib redis-server ffmpeg \
    libpq-dev build-essential curl ca-certificates gnupg

# 安装 MinIO（二进制方式）
mkdir -p ~/minio_data
cd /tmp
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/
```

---

## 部署流程

### 步骤 1: 配置 PostgreSQL 数据库

```bash
# 启动服务
sudo systemctl start postgresql redis-server

# 创建数据库和用户
sudo -u postgres psql -c "CREATE DATABASE segserver;"
sudo -u postgres psql -c "CREATE USER seguser WITH PASSWORD 'segpass123';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE segserver TO seguser;"
sudo -u postgres psql -d segserver -c "GRANT ALL ON SCHEMA public TO seguser;"
sudo -u postgres psql -c "ALTER DATABASE segserver OWNER TO seguser;"
```

### 步骤 2: 启动 MinIO

```bash
nohup minio server ~/minio_data --console-address :9001 > /tmp/minio.log 2>&1 &

# 验证
# API:   http://localhost:9000
# 控制台: http://localhost:9001 （minioadmin / minioadmin）
```

### 步骤 3: 创建 Conda 环境并安装 Python 依赖

```bash
# 创建环境
conda create -n seg_server python=3.11 -y
conda activate seg_server

# 安装 PyTorch（根据 CUDA 版本选择）
# CUDA 12.x 用户:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

# CPU 用户（无 GPU）:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

# 安装后端依赖
cd ~/Desktop/Seg_Server/backend
pip install -r requirements.txt
```

### 步骤 4: 下载 SAM 2 模型权重

```bash
cd ~/Desktop/Seg_Server/backend
python download_sam2.py

# 模型将下载到 ~/Desktop/Seg_Server/models/
# 推荐放置 SAM 2.1 文件名：
# sam2.1_hiera_tiny.pt
# sam2.1_hiera_small.pt
# sam2.1_hiera_base_plus.pt
# sam2.1_hiera_large.pt
#
# 兼容旧版 SAM 2 文件名：
# sam2_hiera_tiny.pt / sam2_hiera_small.pt / sam2_hiera_base_plus.pt / sam2_hiera_large.pt
```

> **注意**：当前系统磁盘紧张时，建议仅保留 `sam2.1_hiera_tiny.pt` 或兼容旧名 `sam2_hiera_tiny.pt`，删除其他模型以释放空间。前端可以选择四个变体，但只有本地存在对应 checkpoint 的变体会显示可用。

### 步骤 5: 历史保留的 SAM 3 环境

当前产品入口不再启用 SAM 3：前端隐藏 SAM 3 相关入口，后端 registry 只暴露 SAM 2.1 变体，`model=sam3` 会返回不支持。以下脚本和 helper 仅作为以后恢复 SAM 3 研究路径的保留文件，正常部署不需要执行。

```bash
cd ~/Desktop/Seg_Server
./backend/setup_sam3_env.sh

# 仅在后续恢复 SAM 3 实验路径时使用。
```

官方 `facebook/sam3` 权重约 3.45 GB，当前没有类似 SAM 2 `tiny/small/base/large` 的官方小权重梯度。本项目不会提交权重文件；由于当前系统不提供文本提示，SAM 3 不在模型状态接口和前端 UI 中展示。

### 步骤 6: 配置环境变量

后端通过 `backend/config.py` 中的 Pydantic Settings 读取 `backend/.env`。如需覆盖默认值，请编辑以下文件：

**backend/.env**（数据库/Redis/MinIO/SAM 路径）:
```ini
db_url=postgresql://seguser:segpass123@localhost:5432/segserver
redis_url=redis://localhost:6379/0
minio_endpoint=192.168.3.11:9000
minio_access_key=minioadmin
minio_secret_key=minioadmin
minio_secure=false
sam_model_path=/home/wkmgc/Desktop/Seg_Server/models/sam2.1_hiera_tiny.pt
sam_model_config=configs/sam2.1/sam2.1_hiera_t.yaml
sam_default_model=sam2.1_hiera_tiny
# 以下 sam3_* 配置为历史保留项；当前产品入口不读取它们来暴露 SAM 3。
# sam3_model_version=sam3
# sam3_checkpoint_path=/home/wkmgc/Desktop/Seg_Server/sam3权重/sam3.pt
# sam3_external_enabled=true
# sam3_external_python=/home/wkmgc/miniconda3/envs/sam3/bin/python
# sam3_timeout_seconds=300
cors_origins=["http://localhost:3000","http://192.168.3.11:3000"]
jwt_secret_key=change-this-to-a-long-random-production-secret
access_token_expire_minutes=1440
default_admin_username=admin
default_admin_password=123456
```

前端根目录的 `.env.example` 包含 AI Studio 注入变量和前端 API 配置：

```ini
VITE_API_BASE_URL=http://192.168.3.11:8000
VITE_WS_PROGRESS_URL=ws://192.168.3.11:8000/ws/progress
```

如果未配置 `VITE_API_BASE_URL`，前端会按当前浏览器 hostname 推导 `http://<host>:8000`。

### 步骤 7: 启动后端服务

```bash
cd ~/Desktop/Seg_Server/backend
source ~/miniconda3/etc/profile.d/conda.sh
conda activate seg_server
uvicorn main:app --host 0.0.0.0 --port 8000

# 或使用后台模式
nohup uvicorn main:app --host 0.0.0.0 --port 8000 > /tmp/fastapi.log 2>&1 &
```

后端启动后将自动：
- 创建数据库表（如果不存在）
- 检查 MinIO bucket 是否存在
- 测试 Redis 连接
- 懒加载所选 SAM 2.1 模型；`GET /api/ai/models/status` 会返回 tiny/small/base+/large 和 GPU 的真实可用状态，`selected_model=sam3` 会返回不支持
- `/api/ai/predict` 支持 AI 参数 `crop_to_prompt`、`auto_filter_background` 和 `min_score`，用于点/框 prompt 的局部裁剪推理、回映射和背景过滤
- `/api/ai/smooth-mask` 支持对当前 mask polygon 做后端边缘平滑，返回新的 polygon、bbox、面积和拓扑锚点；前端应用时会把结果写成新的实际 mask 几何，并走正常标注保存链路
- `/api/ai/propagate/task` 支持从当前帧 seed 区域向视频片段创建后台传播任务：当前使用所选 SAM 2.1 变体的 `SAM2VideoPredictor.add_new_mask()` + `propagate_in_video()`；同步 `/api/ai/propagate` 仍作为单 seed 兼容接口保留

### 步骤 6.1: 启动 Celery Worker

```bash
cd ~/Desktop/Seg_Server/backend
source ~/miniconda3/etc/profile.d/conda.sh
conda activate seg_server
celery -A celery_app:celery_app worker --loglevel=info --pool=solo --concurrency=1

# 或使用后台模式
nohup celery -A celery_app:celery_app worker --loglevel=info --pool=solo --concurrency=1 > /tmp/celery.log 2>&1 &
```

视频导入只创建项目并把源视频保存到 MinIO，不会自动拆帧；项目库导入面板会用 Axios 上传回调显示上传进度、百分比和字节数。用户在项目库点击“生成帧”后，再选择目标 FPS 并调用 `POST /api/media/parse`。DICOM 批量导入会在前端选择、后端上传、worker 下载和 pydicom 读取四个环节按文件名自然顺序排序，保证 `1.dcm、2.dcm、10.dcm` 这种序列按可见数字顺序转成项目帧；上传阶段同样显示进度条和本次有效 `.dcm` 文件数量，上传完成后项目库会轮询解析任务进度直到完成、失败或取消。项目卡片支持复制项目：`新项目重置` 会复制项目媒体字段和已生成帧序列但不复制标注，`全内容复制` 会额外复制标注和关联 mask 元数据，任务运行历史不复制。项目库和模板库的成功/失败反馈使用非阻塞短提示，会自动消失，不再用浏览器 `alert()` 阻塞后续操作；项目删除、模板删除、用户改密码/删除和演示出厂重置等高风险操作使用站内确认弹窗。该接口只创建 `processing_tasks` 记录并把任务投递给 Celery；真正的 FFmpeg/OpenCV/pydicom 拆帧由 worker 执行。接口支持 `parse_fps`、`max_frames` 和 `target_width`，用于生成后续 SAM 2 视频处理可复用的标准帧序列；视频/DICOM 解析后都按 `frame_%06d.jpg` 连续生成项目帧，帧表会记录 `timestamp_ms` 和 `source_frame_number`，任务完成结果会返回 `frame_sequence` 元数据。worker 每次更新任务状态后会发布到 Redis `seg:progress` 频道，FastAPI 订阅后转发到 `/ws/progress`，前端 Dashboard 可实时更新。Dashboard 的任务进度区展示 queued/running/success/failed/cancelled 最近任务，处理中统计只计算 queued/running；WebSocket 状态由浏览器 `onopen/onclose/onerror` 驱动，客户端会定时发送 `ping` 心跳，服务端返回 `status` 确认连接。Dashboard 也可调用 `/api/tasks/{id}/cancel`、`/api/tasks/{id}/retry` 和 `/api/tasks/{id}` 完成任务取消、重试与失败详情查看。

### 步骤 7: 安装前端依赖并构建

```bash
cd ~/Desktop/Seg_Server

# 安装依赖
npm install

# 类型检查
npm run lint

# 生产构建
npm run build

# 启动前端服务
npm start

# 或使用后台模式
nohup npm start > /tmp/frontend.log 2>&1 &
```

---

## 一键启动（推荐）

项目根目录提供了 `start_services.sh` 脚本，可一键启动所有服务：

```bash
cd ~/Desktop/Seg_Server
./start_services.sh
```

脚本将依次检查并启动：PostgreSQL → Redis → MinIO → FastAPI 后端 → Celery Worker → 前端。

### 开发重启

如果只是确认本机开发服务使用最新代码，优先用：

```bash
cd ~/Desktop/Seg_Server
./restart_dev_services.sh
```

热更新规则：

| 改动 | 需要重启什么 | 说明 |
|------|--------------|------|
| 前端组件/样式 | 一般不需要 | Vite 会热更新 |
| 前端依赖、`.env`、`vite.config.ts` | 重启前端 | 依赖和环境变量只在进程启动时读取 |
| FastAPI 路由/普通后端代码 | 需要重启后端 | 本项目开发重启脚本用独立后台进程运行后端，后端改动后应显式重启，确保运行态和代码一致 |
| `backend/.env`、模型路径、依赖 | 重启后端 | 配置和依赖在进程启动时生效 |
| Celery 任务、拆帧、自动传播、SAM runner | 必须重启 Celery worker | worker 不会自动加载代码改动 |

`restart_dev_services.sh` 会检查 PostgreSQL/Redis/MinIO，停止旧 FastAPI/Celery/前端进程，用 `setsid` 作为独立后台进程重新启动三者，并检查 `http://localhost:8000/health` 和 `http://localhost:3000`。脚本退出后服务仍会继续运行；pid 文件默认写到 `/tmp/seg_server_*.pid`，日志默认写到：

```text
/tmp/seg_server_fastapi.log
/tmp/seg_server_celery.log
/tmp/seg_server_frontend.log
/tmp/seg_server_minio.log
```

---

## 访问地址与默认凭证

| 服务 | 地址 | 说明 |
|------|------|------|
| 前端界面 | http://localhost:3000 | admin / 123456 |
| 后端 API 文档 | http://localhost:8000/docs | Swagger UI |
| MinIO 控制台 | http://localhost:9001 | minioadmin / minioadmin |
| PostgreSQL | localhost:5432 | seguser / segpass123 |

后端启动时会自动种子化默认管理员 `admin / 123456`，密码以哈希形式存入 `users` 表。登录成功返回签名 JWT，前端会把 token 写入 `localStorage` 并通过 `Authorization: Bearer <token>` 调用业务接口；页面刷新后会用 `/api/auth/me` 恢复当前用户。

当前项目、帧、标注、任务、Dashboard 和导出接口已经按当前 JWT 用户拥有的项目隔离；模板支持系统模板（`owner_user_id IS NULL`）和用户模板。角色分为 `admin`、`annotator`、`viewer`：`admin/annotator` 可调用写入类业务接口，`viewer` 只能读取；管理员会在侧栏看到“用户管理”，可通过 `/api/admin/users` 新增、停用/启用、改角色、改密码和删除无项目用户，并通过 `/api/admin/audit-logs` 查看登录与用户管理审计。演示部署还提供“恢复演示出厂设置”，站内二次确认后调用 `/api/admin/demo-factory-reset`，只保留默认 admin、演示视频项目和一个已按文件名自然顺序生成帧的演示 DICOM 项目。生产部署时必须在 `backend/.env` 覆盖 `JWT_SECRET_KEY` 并修改默认管理员密码。

系统默认模板会在后端启动时幂等补齐，当前包括“腹腔镜胆囊切除术”和“头颈部CT分割”；头颈部 CT 默认分类名使用纯中文，不带括号英文翻译。所有新建、复制、导入和后端返回的模板都会归一化带上黑色 `maskid: 0` 的“待分类”保留类，并固定在语义分类树最后。恢复演示出厂设置只删除用户私有模板，并会按内置权威定义重建缺失的默认系统模板、覆盖恢复被修改或删减的默认语义分类树。模板库左侧“生效中模板架构清单”里的复制按钮会把任一模板复制成当前用户私有副本，并保留分类名称、颜色、maskid、内部层级顺序和规则。

---

## 可用命令

### 前端

```bash
npm install       # 安装依赖
npm run dev       # 运行 tsx server.ts，Express + Vite 中间件（端口 3000）
npm run build     # 生产构建（输出到 dist/）
npm run lint      # TypeScript 类型检查
npm run test      # Vitest watch 模式
npm run test:run  # Vitest 单次运行
npm start         # Node.js 运行 server.ts（生产静态服务）
```

### 后端

```bash
# 在 conda seg_server 环境中
cd backend
pip install -r requirements-dev.txt                         # 安装后端测试依赖
pytest tests                                                # 后端接口测试
uvicorn main:app --host 0.0.0.0 --port 8000 --reload    # 开发模式（热重载）
uvicorn main:app --host 0.0.0.0 --port 8000             # 生产模式
celery -A celery_app:celery_app worker --loglevel=info --pool=solo --concurrency=1  # 后台任务 worker
```

---

## 常见问题

### Q1: 磁盘空间不足导致 PyTorch / sam2 安装失败

**现象**: `OSError: [Errno 28] No space left on device`

**解决**:
```bash
# 1. 清理系统包缓存
sudo apt autoremove -y && sudo apt clean

# 2. 清理 conda 缓存
conda clean --all -y

# 3. 仅保留最小模型
rm ~/Desktop/Seg_Server/models/sam2.1_hiera_large.pt
rm ~/Desktop/Seg_Server/models/sam2.1_hiera_base_plus.pt
rm ~/Desktop/Seg_Server/models/sam2.1_hiera_small.pt

# 4. 如需安装 sam2 包，确保有 >5GB 可用空间后再执行
```

### Q2: SAM 2 推理返回 dummy polygons（矩形框）

**原因**: `sam2` Python 包未安装，或模型权重路径不正确。

**解决**:
```bash
# 1. 确认模型文件存在
ls ~/Desktop/Seg_Server/models/sam2.1_hiera_tiny.pt

# 2. 安装 sam2（需 >5GB 磁盘空间）
cd /tmp
git clone --depth 1 https://github.com/facebookresearch/segment-anything-2.git
cd segment-anything-2
pip install -e . --no-build-isolation

# 3. 重启后端服务
```

### Q3: MinIO 报 `XMinioStorageFull`

**原因**: 系统磁盘可用空间低于 MinIO 默认阈值。

**解决**: 清理解析产生的临时帧文件或扩展磁盘空间。

### Q4: 前端无法连接后端 API

**检查清单**:
1. 后端是否已启动（`curl http://localhost:8000/health`）
2. `backend/.env` 中的 `cors_origins` 是否包含 `http://localhost:3000`
3. 前端是否配置了正确的 `VITE_API_BASE_URL`；未配置时会按当前浏览器 hostname 推导 `http://<host>:8000`

### Q5: 如何验证 AI 推理或 COCO 导出接口

**当前状态**:

- 前端 `predictMask()` 已发送后端需要的 `image_id`、`prompt_type`、`prompt_data`，并把后端 `polygons` 转成 Konva `pathData`。
- 工作区点选/框选会使用当前帧的数据库 `frame.id` 调用 `/api/ai/predict`。
- 工作区 SAM 2.1 交互式细化包含反向点时会启用后端背景过滤；若反向点排除了当前候选区域并返回空结果，前端会移除旧候选 mask。
- AI 页面只显示本页最新生成的 SAM 2.1 候选，不会把工作区已有 mask 带入 AI 画布；重复执行高精度分割会替换上一次 AI 页候选；新生成 mask 会写入全局 `masks` 并自动选中，右侧分类树可直接给生成结果换标签；如果换标签的 mask 属于传播链，系统会同步更新前后帧对应传播 mask 的分类元数据；“推送至工作区编辑”会切回工作区的多边形调整工具并保留选择和当前帧视角，不会因工作区重新加载而跳回第一帧。
- 工作区传播功能会使用当前打开参考帧的全部 mask 作为 seed，按用户设置的传播起始帧和传播结束帧向前/向后追踪；用户可直接修改数字框，也可先点击“自动传播”进入时间轴范围选择模式，在播放进度条或视频处理进度条上点击/拖拽选择范围，再点击“开始传播”。工作区顶栏可单独选择本次传播使用的 SAM 2.1 tiny/small/base+/large 权重，不提供 SAM2/SAM3 家族切换；前端提交传播前会先保存当前项目中的 draft/dirty mask，使 seed 优先携带稳定的后端 `source_annotation_id`，再把传播权重 id、seed、seed 来源 id 和方向组装为 `/api/ai/propagate/task` 后台任务。后端入队时会规范化/校验权重 id，并把规范化后的 id 写入任务 payload/result；worker 会按 seed 来源、方向和 seed 签名去重，同权重且未改变的 mask 二次传播时直接跳过，已改变或换用其他权重的 mask 会先删除同源旧自动传播标注再重传；旧版本使用前端临时 `source_mask_id` 生成的传播结果会按同一参考帧、方向和语义信息兼容清理，中间帧人工新增或修改同一物体后重新传播时，也会在写入目标帧新结果前按语义和空间重叠清理旧传播结果，且写入前清理不受旧结果传播方向限制，避免向前传播时与早先向后生成的旧 mask 叠加。若历史或外部 seed metadata 仍带 `geometry_smoothing`，后端仍会在 forward/backward 两个方向保存前应用同一平滑参数；当前工作区平滑按钮应用后会直接改写实际 polygon，因此后续传播以新几何参与签名和追踪。任务进度写入 `processing_tasks` 并可在 Dashboard 查看/取消/重试，工作区轮询任务状态并刷新已保存标注。传播结果回显后，视频处理进度条会把自动传播生成的帧区段标为蓝色，人工/AI 标注帧显示为红色竖线；每次自动传播成功处理过的范围会在当前会话中额外叠加同一蓝色系、最新传播最亮、旧传播逐次变暗且第 5 次及更早统一为阈值旧记录色的纯色片段，用于辨认第一次、第二次、第 N 次传播；这些传播历史片段会按当前仍存在的传播 mask 自动裁剪，删除 mask 后无 mask 的帧不会继续显示红/蓝颜色；普通状态下点击视频处理进度条或红/蓝帧标识可跳转到对应帧，底部缩略图也会用红色边框标识人工/AI 标注帧、蓝色边框标识传播/推理帧；如果同一帧同时有人工作业和传播结果，红色人工/AI 标注框优先保留，蓝色传播状态以内描边表达；当前帧如果同时是人工/AI 标注帧，会显示青色外框加红色内描边，固定为外层当前帧、内层标注框。
- 右侧实例属性面板的“边缘平滑强度”滑杆会先防抖预览；点击“应用边缘平滑”后会把平滑结果作为新的实际 polygon 写入当前 mask，并同步写入同一传播链前后对应 mask，整次操作进入同一个撤销/重做历史步骤，应用后强度重置为 0，用户可继续用“调整多边形”编辑新多边形。分类和平滑这类跨传播链操作保存时会保留传播来源 metadata，避免原本的自动传播帧在时间轴上被改成红色人工/AI 标注帧。
- 前端 `exportCoco()` 已对齐到 `/api/export/{projectId}/coco`，`exportMasks()` 已对齐到 `/api/export/{projectId}/masks`，统一导出 `exportSegmentationResults()` 已对齐到 `/api/export/{projectId}/results`。
- 工作区“分割结果导出”按钮已绑定下载流程；点击后可在下拉栏选择整体视频、特定范围帧或当前图片，默认选择当前图片，并勾选分开 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图。选择特定范围帧时，可直接修改帧号，也可在播放进度条或视频处理进度条上拖拽选择范围；选择 Mix_label 时可调遮罩透明度，默认 0.3，并显示当前/待导出第一帧预览。导出前会先保存当前待归档的前端 mask。下载 ZIP 命名为 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`，项目名会替换文件系统不安全字符；时间戳来自帧 `timestampMs` 并格式化为 `0h00m00s000ms`，帧号使用项目抽帧后的 1-based 帧顺序，不使用原视频帧号。统一导出 ZIP 固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`；GT_label 固定输出 8-bit uint8 PNG，像素值使用类别真实 maskid，`maskid: 0` 的“待分类”保持 0，Pro_label 中保持黑色 `[0,0,0]`，缺失 maskid 的旧标注才补下一个可用正整数并写入映射 JSON，正整数 maskid 超出 1-255 会拒绝导出，因此同一模板导出的 GT_label 可直接再导入；选择分开 mask 时输出 `分开Mask分割结果/`，按帧子目录和类别 maskid 合并命名；选择 GT_label、Pro_label、Mix_label 时分别输出 `GT_label图/`、`Pro_label彩色分割结果/`、`Mix_label重叠覆盖彩色分割结果/`，重叠区域按右侧语义分类树内部优先级从低到高覆盖。
- 工作区左侧工具栏“导入 GT Mask”按钮已绑定 `/api/ai/import-gt-mask`，入口位于“重叠区域去除”之后；选择文件后会先显示导入结果预览，并让用户决定未知 maskid 的处理方式，可“舍弃未知类别”或“导入为未定义”。后端使用 `cv2.IMREAD_UNCHANGED` 读取 mask 并校验 dtype；导入格式限定为 8-bit 灰度 maskid 图或 8-bit RGB 三通道完全相同的 `[X,X,X]` maskid 图，0 为背景，X 为 1-255 的 maskid；16-bit/uint16 GT_label 和全背景 0 图都会被拒绝，全背景错误信息为“GT Mask 图片中没有非背景 maskid 区域。”；尺寸不同会自动按当前帧长宽最近邻拉伸；导入时使用高精度 contour，尽量保留边缘细节，同时对单个轮廓设置点数上限以控制前端性能；导入后刷新并回显已保存标注，但不显示或拖动 seed point，后续可像普通 mask 一样做拓扑统计、边缘平滑和 polygon 编辑。
- 工作区保存状态按钮会按当前项目待保存数量显示“保存 X 个改动”或“已全部保存”；点击后会把未保存 mask 写入 `POST /api/ai/annotate`，并把 dirty mask 写入 `PATCH /api/ai/annotations/{id}`。
- 工作区“清空遮罩”会通过 `DELETE /api/ai/annotations/{id}` 删除当前帧已保存标注，并清空当前帧本地 mask。

**验证**:

```bash
curl http://localhost:8000/health
curl http://localhost:8000/api/export/1/coco
curl http://localhost:8000/api/export/1/masks
```

---

## 开发团队

本项目基于 Google AI Studio 模板构建，经全栈化改造后用于工业级语义分割场景。

---

> 如需添加新功能或修复问题，请遵循项目根目录 `工程分析/代码编纂工作流.md` 中定义的代码编纂流程。
