修复管理员删除自己的bug,规范代码注释 #45

Merged
hnu202326010204 merged 5 commits from lianghao_branch into develop 1 week ago

@ -1,378 +1,703 @@
# MuseGuard 后端框架
# MuseGuard 后端服务
基于对抗性扰动的多风格图像生成防护系统 - 后端API服务
MuseGuard 是一个基于对抗性扰动的多风格图像生成防护系统,旨在保护艺术家的作品不被 AI 模型恶意学习和模仿。本项目为 MuseGuard 的后端服务,基于 Flask 框架开发,提供 RESTful API 接口,支持异步任务处理、用户管理、图像处理等功能。
## 目录
## Linux 环境配置MySQL、Redis、Python等
- [项目简介](#项目简介)
- [技术架构](#技术架构)
- [项目结构](#项目结构)
- [环境配置](#环境配置)
- [部署流程](#部署流程)
- [数据库设计](#数据库设计)
- [API 接口](#api-接口)
- [前后端连接](#前后端连接)
### 1. 安装系统依赖
## 项目简介
MuseGuard 后端服务主要负责处理前端请求、管理用户数据、调度图像处理任务以及与底层算法模块交互。核心功能包括:
- **用户认证与权限管理**:基于 JWT 的身份验证支持普通用户、VIP 用户和管理员三种角色。
- **图像加噪防护**集成多种对抗性扰动算法ASPL, SimAC, CAAT, PID, Glaze 等),支持针对不同场景(人脸、风格迁移等)的防护。
- **异步任务调度**:使用 Redis + RQ 实现耗时算法任务的异步处理,支持任务状态追踪和日志查看。
- **效果评估**提供微调训练、图像质量评估FID, LPIPS, SSIM, PSNR和热力图分析功能。
- **资源管理**:管理用户上传的图片、生成的防护图片以及训练模型等资源。
## 🏗 技术架构
- **Web 框架**: Flask 3.0
- **数据库**: MySQL 8.0 (数据存储) + Redis 6.0 (缓存与消息队列)
- **ORM**: SQLAlchemy
- **任务队列**: RQ (Redis Queue)
- **环境管理**: Conda
- **部署环境**: Linux (AutoDL)
## 项目结构
```bash
sudo apt update
sudo apt install -y build-essential python3 python3-venv python3-pip git
```
src/backend/
├── app/
│ ├── algorithms/ # 算法相关代码
│ │ ├── evaluate/ # 评估算法模块
│ │ ├── finetune/ # 微调算法模块
│ │ ├── perturbation/ # 加噪算法模块
│ │ └── processor/ # 图像预处理模块
│ ├── controllers/ # 控制器层 (API 接口实现)
│ │ ├── admin_controller.py # 管理员相关接口
│ │ ├── auth_controller.py # 用户认证接口
│ │ ├── image_controller.py # 图像管理接口
│ │ ├── task_controller.py # 任务管理接口
│ │ └── user_controller.py # 用户信息接口
│ ├── database/ # 数据库模型定义
│ │ └── __init__.py # 数据库模型初始化
│ ├── repositories/ # 数据访问层 (DAO)
│ │ ├── base_repository.py # 基础仓储类
│ │ ├── config_repository.py # 配置信息仓储
│ │ ├── image_repository.py # 图像数据仓储
│ │ ├── task_repository.py # 任务数据仓储
│ │ └── user_repository.py # 用户数据仓储
│ ├── scripts/ # 算法执行脚本 (Shell)
│ │ ├── attack_*.sh # 各种攻击算法执行脚本
│ │ ├── eva_*.sh # 评估任务执行脚本
│ │ └── finetune_*.sh # 微调任务执行脚本
│ ├── services/ # 业务逻辑层
│ │ ├── image_service.py # 图像处理业务逻辑
│ │ ├── task_service.py # 任务管理业务逻辑
│ │ ├── user_service.py # 用户管理业务逻辑
│ │ └── ...
│ ├── utils/ # 工具函数
│ │ ├── file_utils.py # 文件操作工具
│ │ └── jwt_utils.py # JWT 认证工具
│ └── workers/ # RQ Worker 任务处理逻辑
│ ├── evaluate_worker.py # 评估任务处理器
│ ├── finetune_worker.py # 微调任务处理器
│ ├── heatmap_worker.py # 热力图任务处理器
│ └── perturbation_worker.py # 加噪任务处理器
├── config/ # 配置文件
│ ├── algorithm_config.py # 算法参数配置
│ ├── settings.py # 应用全局配置
│ └── settings.env # 环境变量配置 (需自行创建)
├── static/ # 静态资源 (图片存储)
├── app.py # 应用工厂函数入口
├── init_db.py # 数据库初始化脚本
├── run.py # 开发环境启动脚本
├── worker.py # RQ Worker 启动脚本
├── start.sh # 一键启动脚本
├── stop.sh # 一键停止脚本
├── status.sh # 状态检查脚本
└── requirements.txt # Python 依赖列表
```
## 环境配置
### 2. 安装 MySQL
本项目使用 Conda 进行环境管理。
### 1. 创建 Conda 环境
老版使用
```bash
# 启动 Redis
sudo service mysqld start
# 停止 Redis
sudo service mysqld stop
# 重启 Redis
sudo service mysqld restart
# 查看 Redis 状态
sudo service mysqld status
# 创建名为 flask 的环境,指定 python 版本
conda create -n flask python=3.10
# 激活环境
conda activate flask
```
### 2. 安装依赖
```bash
sudo apt install -y mysql-server
sudo systemctl enable mysql
sudo systemctl start mysql
# 安全初始化可选建议设置root密码
sudo mysql_secure_installation
# 安装项目依赖
pip install -r requirements.txt
# 登录MySQL创建数据库和用户
mysql -u root -p
# 安装 PyTorch (根据 CUDA 版本选择)
# 示例: CUDA 11.8
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
```
在MySQL命令行中执行
```sql
CREATE DATABASE museguard DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# CREATE USER 'museguard'@'localhost' IDENTIFIED BY 'yourpassword';
# GRANT ALL PRIVILEGES ON museguard.* TO 'museguard'@'localhost';
# FLUSH PRIVILEGES;
EXIT;
### 3. 配置环境变量
`src/backend/config/` 目录下创建 `settings.env` 文件:
```ini
# 数据库配置
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=museguard_schema
# Redis 配置
REDIS_URL=redis://localhost:6379/0
# JWT 配置
JWT_SECRET_KEY=your-secret-key
SECRET_KEY=your-app-secret-key
# 邮件配置 (可选)
MAIL_SERVER=smtp.example.com
MAIL_PORT=465
MAIL_USERNAME=your_email@example.com
MAIL_PASSWORD=your_email_password
```
### 3. 安装 Redis
## 部署流程
### 1. 基础环境准备
确保服务器已安装以下基础软件:
- **Miniconda/Anaconda**: 用于 Python 环境管理
- **MySQL 8.0+**: 数据库服务
- **Redis 6.0+**: 缓存与消息队列服务
- **CUDA Toolkit**: (可选) 如果需要 GPU 加速
### 2. 启动基础服务
确保 MySQL 和 Redis 服务已启动。
老版使用service命令
```bash
# 启动 MySQL (根据系统不同命令可能不同)
service mysql start
# 或者
systemctl start mysql
# 启动 Redis
sudo service redis-server start
# 停止 Redis
sudo service redis-server stop
# 重启 Redis
sudo service redis-server restart
# 查看 Redis 状态
sudo service redis-server status
redis-server --daemonize yes
```
```bash
sudo apt install -y redis-server
sudo systemctl enable redis-server
sudo systemctl start redis-server
### 3. 初始化数据库
# 测试
redis-cli ping
# 返回PONG表示正常
```
#### 3.1 创建数据库和用户
首次部署需要手动创建 MySQL 数据库和用户。
### 4. Python 虚拟环境与依赖
**步骤 1登录 MySQL**
在Linux换成conda管理
```bash
cd /path/to/your/project/src/backend
python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
# 使用 root 用户登录 MySQL
mysql -u root -p
# 输入 root 密码
```
### 5. 配置数据库连接
**步骤 2创建数据库**
编辑 `config/settings.py``setting.env` 文件,设置如下内容:
```python
DROP DATABASE IF EXISTS muse_guard;
CREATE DATABASE muse_guard DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;
```sql
-- 创建数据库(使用 UTF-8 字符集)
CREATE DATABASE museguard_schema CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://museguard:yourpassword@localhost:3306/museguard?charset=utf8mb4'
REDIS_URL = 'redis://localhost:6379/0'
-- 查看数据库是否创建成功
SHOW DATABASES;
```
### 6. 初始化数据库
**步骤 3创建数据库用户并授权**
```sql
-- 创建用户(请修改密码为安全密码)
CREATE USER 'museguard_user'@'localhost' IDENTIFIED BY 'your_secure_password';
-- 授予该用户对数据库的所有权限
GRANT ALL PRIVILEGES ON museguard_schema.* TO 'museguard_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
-- 查看用户权限
SHOW GRANTS FOR 'museguard_user'@'localhost';
-- 退出 MySQL
EXIT;
```
**步骤 4测试数据库连接**
```bash
python init_db.py
# 使用新创建的用户登录,验证权限
mysql -u museguard_user -p museguard_schema
# 输入刚才设置的密码
# 登录成功后,查看当前数据库
SELECT DATABASE();
# 应该显示: museguard_schema
# 退出
EXIT;
```
### 7. 启动服务
#### 3.2 配置数据库连接
`src/backend/config/` 目录下创建或编辑 `settings.env` 文件,填入数据库连接信息:
```ini
# ==================== 数据库配置 ====================
# MySQL 连接配置(必填)
DB_HOST=localhost # 数据库主机地址
DB_PORT=3306 # 数据库端口
DB_USER=museguard_user # 步骤 3 创建的数据库用户名
DB_PASSWORD=your_secure_password # 步骤 3 设置的密码
DB_NAME=museguard_schema # 步骤 2 创建的数据库名
# ==================== Redis 配置 ====================
# Redis 连接配置(必填)
REDIS_URL=redis://localhost:6379/0
# ==================== JWT 配置 ====================
# JWT 密钥(请修改为随机字符串)
JWT_SECRET_KEY=your-random-jwt-secret-key-change-this-in-production
SECRET_KEY=your-random-flask-secret-key-change-this-in-production
# ==================== 邮件配置(可选)====================
# 用于发送验证码等功能,如不需要可暂时不配置
MAIL_SERVER=smtp.example.com
MAIL_PORT=465
MAIL_USE_SSL=True
MAIL_USERNAME=your_email@example.com
MAIL_PASSWORD=your_email_password
MAIL_DEFAULT_SENDER=your_email@example.com
# ==================== 算法配置(可选)====================
# 是否启用真实算法(默认 false
USE_REAL_ALGORITHMS=true
# RQ 队列配置
RQ_QUEUE_NAME=perturbation_tasks
TASK_TIMEOUT=3600
```
**注意事项:**
- `DB_USER``DB_PASSWORD` 必须与步骤 3 中创建的用户信息一致
- `DB_NAME` 必须与步骤 2 中创建的数据库名一致
- `JWT_SECRET_KEY``SECRET_KEY` 请务必修改为随机字符串,可使用以下命令生成:
```bash
python -c "import secrets; print(secrets.token_hex(32))"
```
#### 3.3 运行数据库初始化脚本
配置文件填写完成后,运行初始化脚本创建数据表和基础数据。
```bash
# 启动Flask后端
python run.py
# 1. 确保已激活 flask 环境
conda activate flask
# 启动RQ Worker另开终端
source venv/bin/activate
cd /path/to/your/project/src/backend
rq worker museguard
# 2. 进入后端根目录
cd src/backend
# 3. 运行初始化脚本
python init_db.py
```
---
**初始化脚本会自动完成以下操作:**
## 项目结构
1. **创建所有数据表**(如 users, tasks, images, perturbation, finetune 等)
2. **初始化角色数据**admin, vip, normal 三种角色)
3. **初始化任务状态数据**waiting, processing, completed, failed, cancelled
4. **初始化图片类型数据**original, perturbed, heatmap 等)
5. **初始化加噪算法配置**ASPL, SimAC, CAAT, PID, Glaze, Quick 等 10 种算法)
6. **初始化微调方式配置**DreamBooth, LoRA, Textual Inversion
7. **初始化数据集类型**(人脸、艺术品)
8. **初始化任务类型**perturbation, finetune, heatmap, evaluate
9. **创建测试用户**(可选,包含 admin_test, vip_test, normal_test 三个测试账号)
**初始化成功提示:**
```
backend/
├── app/ # 主应用目录
│ ├── algorithms/ # 算法实现
│ │ ├── perturbation_engine.py # 对抗性扰动引擎
│ │ └── evaluation_engine.py # 评估引擎
│ ├── controllers/ # 控制器(路由处理)
│ │ ├── auth_controller.py # 认证控制器
│ │ ├── user_controller.py # 用户配置控制器
│ │ ├── task_controller.py # 任务控制器
| | ├── demo_controller.py # 首页示例控制器
│ │ ├── image_controller.py # 图像控制器
│ │ └── admin_controller.py # 管理员控制器
│ ├── models/ # 数据模型
│ │ └── __init__.py # SQLAlchemy模型定义
│ ├── services/ # 业务逻辑服务
│ │ ├── auth_service.py # 认证服务
│ │ ├── task_service.py # 任务处理服务
│ │ └── image_service.py # 图像处理服务
│ └── utils/ # 工具类
│ └── file_utils.py # 文件处理工具
├── config/ # 配置文件
│ └── settings.py # 应用配置
├── uploads/ # 文件上传目录
├── static/ # 静态文件
│ ├── originals/ # 重命名后的原始图片
│ ├── perturbed/ # 加噪后的图片
│ ├── model_outputs/ # 模型生成的图片
│ │ ├── clean/ # 原图的模型生成结果
│ │ └── perturbed/ # 加噪图的模型生成结果
│ ├── heatmaps/ # 热力图
│ └── demo/ # 演示图片
│ ├── original/ # 演示原始图片
│ ├── perturbed/ # 演示加噪图片
│ └── comparisons/ # 演示对比图
├── app.py # Flask应用工厂
├── run.py # 启动脚本
├── init_db.py # 数据库初始化脚本
└── requirements.txt # Python依赖
数据库初始化完成!
```
## 功能特性
### 用户功能
- ✅ 用户注册(邮箱验证,同一邮箱只能注册一次)
- ✅ 用户登录/登出
- ✅ 密码修改
- ✅ 任务创建和管理
- ✅ 图片上传(单张/压缩包批量)
- ✅ 加噪处理4种算法SimAC、CAAT、PID、ASPL
- ✅ 扰动强度自定义
- ✅ 防净化版本选择
- ✅ 智能配置记忆:自动保存用户上次选择的配置
- ✅ 处理结果下载
- ✅ 图片质量对比查看FID、LPIPS、SSIM、PSNR、热力图
- ✅ 模型生成对比分析
- ✅ 预设演示图片浏览
### 管理员功能
- ✅ 用户管理(增删改查)
- ✅ 系统统计信息查看
### 算法实现
- ✅ ASPL算法虚拟实现原始版本 + 防净化版本)
- ✅ SimAC算法虚拟实现原始版本 + 防净化版本)
- ✅ CAAT算法虚拟实现原始版本 + 防净化版本)
- ✅ PID算法虚拟实现原始版本 + 防净化版本)
- ✅ 图像质量评估指标计算
- ✅ 模型生成效果对比
- ✅ 热力图生成
## 安装和运行
### 1. 环境准备
#### 使用虚拟环境(推荐)
**为什么需要虚拟环境?**
- ✅ **避免依赖冲突**:不同项目使用不同版本的包
- ✅ **环境隔离**不污染系统Python环境
- ✅ **版本一致性**:确保团队环境统一
- ✅ **易于管理**:可以随时删除重建
**测试用户账号:**
| 用户名 | 密码 | 角色 | 邮箱 |
|--------|------|------|------|
| admin_test | Admin123__ | 管理员 | admin@test.com |
| vip_test | Vip123__ | VIP用户 | vip@test.com |
| normal_test | Normal123__ | 普通用户 | normal@test.com |
**验证初始化结果:**
```bash
# 创建虚拟环境
python -m venv venv
# 登录 MySQL 查看表结构
mysql -u museguard_user -p museguard_schema
# 激活虚拟环境
# Windows:
venv\\Scripts\\activate
# Linux/Mac:
source venv/bin/activate
# 查看所有表
SHOW TABLES;
# 更新pip推荐
python -m pip install --upgrade pip
# 查看某个表的数据(例如查看角色表)
SELECT * FROM role;
# 安装依赖
pip install -r requirements.txt
# 查看用户表
SELECT user_id, username, email, role_id, is_active FROM users;
# 查看加噪算法配置
SELECT perturbation_configs_id, perturbation_code, perturbation_name FROM perturbation_configs;
# 退出
EXIT;
```
### 2. 数据库配置
**常见问题排查:**
确保已安装MySQL数据库并创建数据库。
1. **连接失败**:检查 `settings.env` 中的数据库配置是否正确
2. **权限错误**:确认数据库用户是否有足够的权限(重新执行步骤 3 的授权命令)
3. **表已存在**:如需重新初始化,先手动删除所有表或删除数据库后重新创建
```sql
DROP DATABASE museguard_schema;
CREATE DATABASE museguard_schema CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
修改 `config/.env` 中的数据库连接配置:
### 4. 启动服务
### 3. 初始化数据库
使用提供的脚本一键启动 Web 服务和 Worker 服务。
```bash
# 运行数据库初始化脚本
python init_db.py
# 1. 赋予脚本执行权限
chmod +x start.sh stop.sh status.sh
# 2. 启动服务
./start.sh
```
### 4. 启动应用
脚本会自动:
1. 激活 `flask` conda 环境
2. 检查 MySQL 和 Redis 状态
3. 启动 Flask Web 服务 (默认端口 6006)
4. 启动 RQ Worker 服务 (用于处理后台任务)
### 5. 验证服务
```bash
# 开发模式启动
python run.py
# 查看服务状态
./status.sh
# 或者使用Flask命令
flask run
# 或者查看日志
tail -f nohup.out
```
应用将在 `http://localhost:5000` 启动
### 6. 停止服务
### 5. 系统测试
```bash
./stop.sh
```
访问 `http://localhost:5000/static/test.html` 进入功能测试页面:
## 数据库设计
## API接口文档
主要数据表包括:
### 认证接口 (`/api/auth`)
- **users**: 用户信息表
- **role**: 角色表 (admin, vip, normal)
- **tasks**: 任务主表,记录任务状态、类型等
- **perturbation**: 加噪任务详情表
- **finetune**: 微调任务详情表
- **evaluate**: 评估任务详情表
- **heatmap**: 热力图任务详情表
- **images**: 图片资源表
- **configs**: 各类配置表 (perturbation_configs, finetune_configs 等)
- `POST /register` - 用户注册
- `POST /login` - 用户登录
- `POST /change-password` - 修改密码
- `GET /profile` - 获取用户信息
- `POST /logout` - 用户登出
## API 接口
### 任务管理 (`/api/task`)
> 详细的 API 接口文档请参考:[`doc/project/02-设计文档/backend-api.md`](../../doc/project/02-设计文档/backend-api.md)
- `POST /create` - 创建任务(使用默认配置)
- `POST /upload/<batch_id>` - 上传图片到指定任务
- `GET /<batch_id>/config` - 获取任务配置(显示用户上次选择)
- `PUT /<batch_id>/config` - 更新任务配置(自动保存为用户偏好)
- `GET /load-config` - 加载用户上次配置
- `POST /save-config` - 保存用户配置偏好
- `POST /start/<batch_id>` - 开始处理任务
- `GET /list` - 获取任务列表
- `GET /<batch_id>` - 获取任务详情
- `GET /<batch_id>/status` - 获取处理状态
API 基础路径: `/api`
### 图片管理 (`/api/image`)
### 认证模块 (`/api/auth`)
- `GET /file/<image_id>` - 查看图片
- `GET /download/<image_id>` - 下载图片
- `GET /batch/<batch_id>/download` - 批量下载
- `GET /<image_id>/evaluations` - 获取评估结果
- `POST /compare` - 对比图片
- `GET /heatmap/<path>` - 获取热力图
- `DELETE /delete/<image_id>` - 删除图片
- `POST /auth/register` - 用户注册(需邮箱验证码)
- `POST /auth/login` - 用户登录
- `POST /auth/code` - 发送邮箱验证码
- `POST /auth/change-password` - 修改密码(需登录)
- `POST /auth/change-email` - 修改邮箱(需验证码)
- `POST /auth/change-username` - 修改用户名(需登录)
- `POST /auth/forgot-password` - 忘记密码(需验证码)
- `GET /auth/profile` - 获取当前用户信息
- `POST /auth/logout` - 退出登录
### 用户设置 (`/api/user`)
### 用户模块 (`/api/user`)
- `GET /config` - 获取用户配置(已弃用,配置集成到任务流程中)
- `PUT /config` - 更新用户配置(已弃用,通过任务配置自动保存)
- `GET /algorithms` - 获取可用算法(动态从数据库加载)
- `GET /stats` - 获取用户统计
- `GET /user/config` - 获取用户配置
- `PUT /user/config` - 更新用户配置
### 管理员功能 (`/api/admin`)
### 任务模块 (`/api/task`)
- `GET /users` - 用户列表
- `GET /users/<user_id>` - 用户详情
- `POST /users` - 创建用户
- `PUT /users/<user_id>` - 更新用户
- `DELETE /users/<user_id>` - 删除用户
- `GET /stats` - 系统统计
#### 通用任务接口
### 演示功能 (`/api/demo`)
- `GET /task` - 获取任务列表(支持筛选)
- `GET /task/<task_id>` - 获取任务详情
- `GET /task/<task_id>/status` - 查询任务状态
- `POST /task/<task_id>/cancel` - 取消任务
- `GET /task/<task_id>/logs` - 获取任务日志
- `GET /task/quota` - 查看任务配额
- `GET /images` - 获取演示图片列表
- `GET /image/original/<filename>` - 获取演示原始图片
- `GET /image/perturbed/<filename>` - 获取演示加噪图片
- `GET /image/comparison/<filename>` - 获取演示对比图片
- `GET /algorithms` - 获取算法演示信息
- `GET /stats` - 获取演示统计数据
#### 加噪任务接口
## 默认账户
- `GET /task/perturbation/configs` - 获取可用的加噪算法列表
- `GET /task/perturbation/style-presets` - 获取风格迁移预设风格
- `POST /task/perturbation` - 创建加噪任务(支持上传图片)
- `PATCH /task/perturbation/<task_id>` - 更新加噪任务参数
- `POST /task/perturbation/<task_id>/start` - 启动加噪任务
- `GET /task/perturbation` - 获取所有加噪任务
- `GET /task/perturbation/<task_id>` - 获取加噪任务详情
系统初始化后会创建3个管理员账户
#### 微调任务接口
- 用户名:`admin1`, `admin2`, `admin3`
- 默认密码:`admin123`
- 邮箱:`admin1@museguard.com` 等
- `GET /task/finetune/configs` - 获取微调方式列表
- `POST /task/finetune/from-perturbation` - 基于加噪结果创建微调任务
- `POST /task/finetune/from-upload` - 基于上传图片创建微调任务VIP
- `POST /task/finetune/<task_id>/start` - 启动微调任务
- `GET /task/finetune` - 获取所有微调任务
- `GET /task/finetune/<task_id>` - 获取微调任务详情
- `GET /task/finetune/<task_id>/coords` - 获取3D可视化坐标数据
## 技术栈
#### 热力图任务接口
- **Web框架**: Flask 2.3.3
- **数据库ORM**: SQLAlchemy 3.0.5
- **数据库**: MySQL通过PyMySQL连接
- **认证**: JWT (Flask-JWT-Extended)
- **跨域**: Flask-CORS
- **图像处理**: Pillow + NumPy
- **数学计算**: NumPy
- `POST /task/heatmap` - 创建热力图任务
- `POST /task/heatmap/<task_id>/start` - 启动热力图任务
- `GET /task/heatmap` - 获取所有热力图任务
- `GET /task/heatmap/<task_id>` - 获取热力图任务详情
## 开发说明
#### 评估任务接口
### 虚拟实现说明
- `POST /task/evaluate` - 创建评估任务
- `POST /task/evaluate/<task_id>/start` - 启动评估任务
- `GET /task/evaluate` - 获取所有评估任务
- `GET /task/evaluate/<task_id>` - 获取评估任务详情
当前所有算法都是**虚拟实现**,用于框架搭建和测试:
### 图像模块 (`/api/image`)
1. **对抗性扰动算法**: 使用随机噪声模拟真实算法效果
2. **评估指标**: 基于像素差异的简化计算
3. **模型生成**: 通过图像变换模拟DreamBooth/LoRA效果
#### 图像上传与获取
### 扩展指南
- `POST /image/original` - 上传原始图片
- `GET /image/file/<image_id>` - 获取单张图片文件
- `GET /image/task/<task_id>` - 获取任务的所有图片base64
要集成真实算法:
#### 图像预览接口
1. 替换 `app/algorithms/perturbation_engine.py` 中的虚拟实现
2. 替换 `app/algorithms/evaluation_engine.py` 中的评估计算
3. 根据需要调整配置参数
- `GET /image/preview/flow/<flow_id>` - 获取工作流所有图片预览
- `GET /image/preview/task/<task_id>` - 获取单个任务图片预览
- `GET /image/preview/compare/<flow_id>` - 获取对比预览图片
### 目录权限
#### 按任务类型获取图片
确保以下目录有写入权限:
- `GET /image/perturbation/<task_id>` - 获取加噪结果图片base64
- `GET /image/heatmap/<task_id>` - 获取热力图base64
- `GET /image/finetune/<task_id>` - 获取微调生成图片base64
- `GET /image/evaluate/<task_id>` - 获取评估报告图片base64
- `uploads/` - 用户上传文件
- `static/originals/` - 重命名后的原始图片
- `static/perturbed/` - 加噪后的图片
- `static/model_outputs/` - 模型生成的图片
- `static/heatmaps/` - 热力图文件
- `static/demo/` - 演示图片(需要手动添加演示文件)
#### 图像下载接口
## 许可证
- `GET /image/perturbation/<task_id>/download` - 下载加噪结果压缩包
- `GET /image/heatmap/<task_id>/download` - 下载热力图压缩包
- `GET /image/finetune/<task_id>/download` - 下载微调结果压缩包
- `GET /image/evaluate/<task_id>/download` - 下载评估报告压缩包
本项目仅用于学习和研究目的。
#### 图像管理
- `DELETE /image/<image_id>` - 删除单张图片
https://docs.pingcode.com/baike/2645380
### 管理员模块 (`/api/admin`)
- `GET /admin/users` - 获取用户列表(分页)
- `GET /admin/users/<user_id>` - 获取用户详情
- `POST /admin/users` - 创建用户
- `PUT /admin/users/<user_id>` - 更新用户信息
- `DELETE /admin/users/<user_id>` - 删除用户
- `GET /admin/stats` - 获取系统统计信息
### 支持的加噪算法
功能流程正确(本地)
- 测试网页
- 配置正确加载
- 微调算法执行时机
云端正常调用算法
算法正常执行
云端部署,本地可直接访问
api规范
前端对接
| ID | 算法代码 | 算法名称 | 适用场景 |
|----|---------|---------|---------|
| 1 | aspl | ASPL算法 | 通用防护 |
| 2 | simac | SimAC算法 | 人脸防护 |
| 3 | caat | CAAT算法 | 通用防护 |
| 4 | caat_pro | CAAT Pro算法 | 通用防护(增强版) |
| 5 | pid | PID算法 | 通用防护 |
| 6 | glaze | Glaze算法 | 艺术风格防护 |
| 7 | anti_customize | 防定制生成 | 人脸防护(专用) |
| 8 | anti_face_edit | 防人脸编辑 | 人脸防护(专用) |
| 9 | style_protection | 风格迁移防护 | 艺术品防护(需指定风格) |
| 10 | quick | 快速防护算法 | 快速测试基于PID |
### 认证说明
conda activate flask
pip install accelerate
conda install -c conda-forge accelerate
- 除 `/auth/register`、`/auth/login`、`/auth/code` 外,所有接口均需要 JWT 认证
- 请在请求头中添加:`Authorization: Bearer <your_token>`
- 管理员接口需要管理员角色权限
## 前后端连接 (AutoDL 自定义服务)
本项目部署在 AutoDL 算力云平台上,通过 **SSH 端口转发**功能暴露后端接口给前端访问。
### 为什么使用 SSH 端口转发?
使用 SSH 端口转发SSH Tunneling相比直接公网暴露服务具有以下优势
#### 安全优势
1. **加密传输**:所有数据通过 SSH 加密隧道传输,防止中间人攻击和数据窃听
2. **无需公网 IP**:不需要 AutoDL 实例具有公网 IP 地址,降低被攻击风险
3. **防火墙保护**:后端服务仅监听 `127.0.0.1`(本地回环),外部无法直接访问
4. **访问控制**:只有持有 SSH 密钥/密码的用户才能建立端口转发,天然的身份验证
#### 成本优势
1. **节省流量费用**AutoDL 公网流量通常需要额外付费SSH 端口转发可节省成本
2. **无需额外配置**:不需要购买域名、配置 SSL 证书等额外服务
3. **灵活计费**:开发调试时可随时断开连接,按需使用
#### 开发便利性
1. **本地开发体验**:前端可以像访问本地服务一样访问远程后端(`localhost:6006`
2. **无需修改代码**:前后端代码无需区分开发/生产环境的 API 地址
3. **热重载友好**:配合前端热重载,开发体验接近本地全栈开发
4. **多环境隔离**:可同时转发多个 AutoDL 实例到不同本地端口,轻松切换环境
#### 运维优势
1. **简单稳定**SSH 是成熟的协议,稳定性高,断线自动重连(使用 `autossh`
2. **易于调试**:可直接在本地浏览器查看网络请求,使用开发者工具调试
3. **日志集中**:所有请求日志在 AutoDL 服务器端,便于排查问题
4. **版本管理**:本地可使用 Git 管理代码,推送到服务器后立即生效
### 1. AutoDL 端口配置
后端服务默认监听 `6006` 端口Flask Web 服务)。
### 2. 设置 SSH 端口转发
#### 查看 AutoDL 实例的 SSH 连接信息
1. 登录 AutoDL 控制台
2. 进入你的容器实例页面
3. 找到 **"SSH 连接"** 或 **"自定义服务"** 部分
4. 复制提供的 SSH 端口转发命令,格式类似:
```bash
ssh -CNg -L 6006:127.0.0.1:6006 root@connect.xxx.seetacloud.com -p <your_port>
```
**命令说明:**
- `-C`: 压缩数据传输
- `-N`: 不执行远程命令,仅用于端口转发
- `-g`: 允许远程主机连接本地转发端口
- `-L 6006:127.0.0.1:6006`: 将本地 6006 端口转发到远程服务器的 6006 端口
- `root@connect.cqa1.seetacloud.com`: AutoDL 服务器地址
- `-p 30588`: SSH 连接端口(每个实例不同,请在 AutoDL 控制台查看)
**注意事项:**
1. `connect.cqa1.seetacloud.com` 和端口 `30588` 是示例,请根据你的 AutoDL 实例信息修改
2. 在 AutoDL 控制台的 **"容器实例"** -> **"SSH 连接"** 中可以找到你的连接信息
3. 执行命令后需要输入 AutoDL 实例的 root 密码
4. 命令执行后会保持运行状态(不要关闭终端),此时端口转发已建立
### 3. 验证端口转发
端口转发建立后,在本地浏览器访问:
```
http://localhost:6006
```
如果能看到后端 API 响应(可能是 404 或欢迎页面),说明转发成功。
### 4. 前端配置
#### 本地开发环境配置
在前端项目的配置文件中,将后端 API 地址设置为本地转发地址。
**方式 1使用环境变量推荐**
在前端项目根目录创建 `.env.development` 文件:
```ini
# 开发环境配置
VITE_API_BASE_URL=http://localhost:6006/api
```
**方式 2使用 Vite 代理配置**
编辑 `vite.config.js`
```javascript
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:6006', // 本地转发地址
changeOrigin: true,
rewrite: (path) => path // 保持 /api 前缀
}
}
}
})
```
#### 生产环境配置
如果需要部署到生产环境,可以:
1. **使用 AutoDL 公网地址**(如果开通了公网访问)
2. **使用内网穿透工具**(如 ngrok, frp
3. **部署到云服务器**(如阿里云、腾讯云)
### 5. 完整使用流程
**本地开发完整步骤:**
1. **启动 AutoDL 后端服务**
```bash
# SSH 登录到 AutoDL 实例
ssh root@connect.cqa1.seetacloud.com -p 30588
# 启动后端服务
cd /root/autodl-tmp/MuseGuard/src/backend
./start.sh
```
2. **在本地建立 SSH 端口转发**(新开一个本地终端)
```bash
ssh -CNg -L 6006:127.0.0.1:6006 root@connect.cqa1.seetacloud.com -p 30588
# 输入密码后保持运行
```
3. **启动前端服务**(本地)
```bash
cd /path/to/frontend
npm run dev
```
4. **访问前端应用**
```
http://localhost:5173 # Vite 默认端口
```
### 6. 常见问题
**Q1: 端口转发命令执行后立即退出?**
- 检查 SSH 连接信息是否正确
- 确认 AutoDL 实例是否正在运行
- 检查密码是否输入正确
**Q2: 本地无法访问 localhost:6006**
- 确认端口转发命令仍在运行
- 检查 AutoDL 后端服务是否已启动(`./status.sh`
- 尝试使用 `127.0.0.1:6006` 代替 `localhost:6006`
**Q3: 前端请求后端接口 CORS 错误?**
- 后端已配置 `Flask-CORS`,应该不会出现跨域问题
- 检查前端请求的 URL 是否正确
- 查看后端日志确认请求是否到达
**Q4: SSH 连接断开后端口转发失效?**
- 使用 `autossh` 实现自动重连:
```bash
autossh -M 0 -CNg -L 6006:127.0.0.1:6006 root@connect.cqa1.seetacloud.com -p 30588
```
- 或者在 `~/.ssh/config` 中配置 `ServerAliveInterval` 保持连接
### 注意事项
- **端口转发保活**SSH 端口转发需要保持终端运行,建议使用 `tmux``screen` 在后台运行
- **安全性**:端口转发仅在本地有效,外部无法访问,相对安全
- **性能**:所有请求都通过 SSH 加密传输,可能会有轻微延迟
- **多实例**:如果有多个 AutoDL 实例,注意区分不同的 SSH 端口和转发端口
- **服务保活**:建议使用 `tmux``nohup` 保持后端服务在后台运行,防止 SSH 断开后服务停止。`start.sh` 脚本已包含后台运行逻辑

@ -183,7 +183,7 @@ def delete_user(user_id):
current_user_id = get_jwt_identity()
# 不能删除自己
if user_id == current_user_id:
if user_id == int(get_jwt_identity()):
return jsonify({'error': '不能删除自己的账户'}), 400
user = User.query.get(user_id)

@ -1,6 +1,5 @@
"""
任务管理控制器
适配新数据库结构提供加噪微调热力图数值评估等任务相关接口
"""
from flask import Blueprint, request, jsonify

@ -1,5 +1,5 @@
"""
任务处理服务适配新数据库结构和路径配置
任务处理服务
处理加噪微调热力图评估等核心业务逻辑
使用Redis Queue进行异步任务处理

@ -1,5 +1,5 @@
"""
RQ Worker 数值评估任务处理器仅使用真实算法
RQ Worker 数值评估任务处理器
生成原始图与扰动图微调后的模型生成效果对比报告
"""
@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
def run_evaluate_task(task_id, clean_ref_dir, clean_output_dir,
perturbed_output_dir, output_dir, image_size=512):
"""
执行数值评估任务仅使用真实算法
执行数值评估任务
Args:
task_id: 任务ID

@ -1,6 +1,5 @@
"""
RQ Worker 微调任务处理器 - 适配新数据库结构
仅支持真实算法移除虚拟算法调用
RQ Worker 微调任务处理器
"""
import os
@ -22,7 +21,7 @@ def run_finetune_task(task_id, finetune_method, train_images_dir,
output_model_dir, class_dir, coords_save_path, validation_output_dir,
finetune_type, custom_params=None):
"""
执行微调任务仅使用真实算法
执行微调任务
Args:
task_id: 任务ID
@ -95,7 +94,7 @@ def run_finetune_task(task_id, finetune_method, train_images_dir,
# DreamBooth/LoRA: 直接使用模板
instance_prompt_prefix = instance_prompt
# 处理 Validation Prompt (拼接后缀)
# 处理 Validation Prompt
prompt_suffix = finetune.custom_prompt.strip() if finetune.custom_prompt else ""
if prompt_suffix:
@ -207,7 +206,7 @@ def _run_real_finetune(finetune_method, task_id, train_images_dir, output_model_
class_dir, coords_save_path, validation_output_dir,
instance_prompt, class_prompt, validation_prompt, finetune_type, custom_params, log_file):
"""
运行真实微调算法参考sh脚本配置
运行真实微调算法
Args:
finetune_method: 微调方法
@ -240,7 +239,7 @@ def _run_real_finetune(finetune_method, task_id, train_images_dir, output_model_
if not script_path:
raise ValueError(f"Finetune method {finetune_method} not configured")
# 覆盖提示词参数(从数据库读取)
# 覆盖提示词参数
if 'instance_prompt' in default_params:
default_params['instance_prompt'] = instance_prompt
if 'class_prompt' in default_params:
@ -273,7 +272,7 @@ def _run_real_finetune(finetune_method, task_id, train_images_dir, output_model_
])
elif finetune_method == 'textual_inversion':
# Textual Inversion 特有参数 (不需要 class_data_dir)
# Textual Inversion 特有参数
cmd_args.extend([
f"--coords_save_path={coords_save_path}",
])
@ -354,30 +353,6 @@ def _run_real_finetune(finetune_method, task_id, train_images_dir, output_model_
os.makedirs(output_model_dir)
logger.info(f"Cleanup completed. Only validation images and coords.json are kept.")
# # 清理class_dir参考sh脚本
# if finetune_method in ['dreambooth', 'lora']:
# logger.info(f"Cleaning class directory: {class_dir}")
# if os.path.exists(class_dir):
# shutil.rmtree(class_dir)
# os.makedirs(class_dir)
# # 清理output_model_dir中的非图片文件
# logger.info(f"Cleaning non-image files in output directory: {output_model_dir}")
# if os.path.exists(output_model_dir):
# image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp', '.tiff'}
# for item in os.listdir(output_model_dir):
# item_path = os.path.join(output_model_dir, item)
# if os.path.isfile(item_path):
# _, ext = os.path.splitext(item)
# if ext.lower() not in image_extensions:
# try:
# os.remove(item_path)
# logger.info(f"Removed non-image file: {item}")
# except Exception as e:
# logger.warning(f"Failed to remove {item}: {str(e)}")
return {
'status': 'success',
@ -388,7 +363,7 @@ def _run_real_finetune(finetune_method, task_id, train_images_dir, output_model_
def _save_generated_images(task_id, output_dir, finetune_type):
"""
保存微调生成的验证图片到数据库适配新数据库结构
保存微调生成的验证图片到数据库
新数据库结构
- Task表tasks_id (主键), flow_id, tasks_type_id

@ -1,7 +1,6 @@
"""
RQ Worker 热力图任务处理器 - 适配新数据库结构
RQ Worker 热力图任务处理器
生成原始图与扰动图的注意力差异热力图
仅支持真实算法移除虚拟算法调用
"""
import os
@ -21,14 +20,14 @@ logger = logging.getLogger(__name__)
def run_heatmap_task(task_id, original_image_path, perturbed_image_path,
output_dir, perturbed_image_id=None):
"""
执行热力图生成任务仅使用真实算法
执行热力图生成任务
Args:
task_id: 任务ID
original_image_path: 原始图片路径
perturbed_image_path: 扰动图片路径
output_dir: 输出目录
perturbed_image_id: 扰动图片ID用于建立father关系
perturbed_image_id: 扰动图片ID
Returns:
任务执行结果
@ -228,7 +227,7 @@ def _save_heatmap_image(task_id, heatmap_file_path, father_image_id=None):
Args:
task_id: 任务ID
heatmap_file_path: 热力图文件完整路径
father_image_id: 父图片ID(原始图片ID)
father_image_id: 父图片ID
"""
from app import db
from app.database import Image, ImageType

@ -1,7 +1,5 @@
"""
RQ Worker任务处理器 - 加噪任务
适配新数据库结构: Task + Perturbation + Images
仅支持真实算法移除虚拟算法调用
"""
import os
@ -24,7 +22,7 @@ logger = logging.getLogger(__name__)
def run_perturbation_task(task_id, algorithm_code, epsilon, input_dir, output_dir,
class_dir, custom_params=None):
"""
执行对抗性扰动任务仅使用真实算法
执行对抗性扰动任务
Args:
task_id: 任务ID对应 tasks 表的 tasks_id
@ -139,7 +137,7 @@ def run_perturbation_task(task_id, algorithm_code, epsilon, input_dir, output_di
def _run_real_algorithm(script_path, conda_env, algorithm_code, task_id,
epsilon, input_dir, output_dir, class_dir, custom_params, log_file):
"""
运行真实算法参考sh脚本配置
运行真实算法
Args:
script_path: 算法脚本路径
@ -307,7 +305,7 @@ def _run_real_algorithm(script_path, conda_env, algorithm_code, task_id,
def _save_perturbed_images(task_id, output_dir):
"""
保存扰动图片到数据库适配新数据库结构
保存扰动图片到数据库
新数据库结构
- Task表tasks_id (主键), flow_id, tasks_type_id

@ -67,39 +67,14 @@ class Config:
MODEL_ORIGINAL_FOLDER = os.path.join(MODEL_OUTPUTS_FOLDER, 'original') # 原图的模型生成结果
MODEL_PERTURBED_FOLDER = os.path.join(MODEL_OUTPUTS_FOLDER, 'perturbed') # 加噪图的模型生成结果
# 微调训练相关配置
CLASS_DATA_FOLDER = os.path.join(STATIC_ROOT, 'class') # 类别数据目录(用于 prior preservation
MODEL_DATA_FOLDER = os.path.join(STATIC_ROOT, 'model_data') # 模型数据目录(用于微调训练数据存储)
CLASS_DATA_FOLDER = os.path.join(STATIC_ROOT, 'class') # 类别数据目录
MODEL_DATA_FOLDER = os.path.join(STATIC_ROOT, 'model_data') # 模型数据目录
# 可视化与分析配置
EVA_RES_FOLDER = os.path.join(STATIC_ROOT, 'eva_res') # 评估结果根目录
COORDS_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'position') # 3D坐标可视化数据(用于训练轨迹)
POSITIONS_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'position') # 位置数据与coords相同LoRA使用未使用
COORDS_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'position') # 3D坐标可视化数据
POSITIONS_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'position') # 位置数据
HEATDIF_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'heatdif') # 热力图差异数据
NUMBERS_SAVE_FOLDER = os.path.join(EVA_RES_FOLDER, 'numbers') # 数值结果数据
# 预设演示图像配置
DEMO_IMAGES_FOLDER = os.path.join(STATIC_ROOT, 'demo') # 演示图片根目录
DEMO_ORIGINAL_FOLDER = os.path.join(DEMO_IMAGES_FOLDER, 'original') # 演示原始图片
DEMO_PERTURBED_FOLDER = os.path.join(DEMO_IMAGES_FOLDER, 'perturbed') # 演示加噪图片
DEMO_COMPARISONS_FOLDER = os.path.join(DEMO_IMAGES_FOLDER, 'comparisons') # 演示对比图
# 算法配置
ALGORITHMS = {
'simac': {
'name': 'SimAC算法',
'description': 'Simple Anti-Customization Method for Protecting Face Privacy',
'default_epsilon': 8.0
},
'caat': {
'name': 'CAAT算法',
'description': 'Perturbing Attention Gives You More Bang for the Buck',
'default_epsilon': 16.0
},
'pid': {
'name': 'PID算法',
'description': 'Prompt-Independent Data Protection Against Latent Diffusion Models',
'default_epsilon': 4.0
}
}
class DevelopmentConfig(Config):
"""开发环境配置"""

@ -11,56 +11,56 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
# 检查Flask应用
echo "📌 Flask 应用:"
echo "Flask 应用:"
if [ -f logs/flask.pid ]; then
FLASK_PID=$(cat logs/flask.pid)
if ps -p $FLASK_PID > /dev/null 2>&1; then
echo " 运行中 (PID: $FLASK_PID)"
echo " 📍 URL: http://127.0.0.1:6006"
echo " 📍 测试: http://127.0.0.1:6006/static/test.html"
echo " 运行中 (PID: $FLASK_PID)"
echo " URL: http://127.0.0.1:6006"
echo " 测试: http://127.0.0.1:6006/static/test.html"
else
echo " 未运行 (PID文件存在但进程不存在)"
echo " 未运行 (PID文件存在但进程不存在)"
fi
else
if pgrep -f "python run.py" > /dev/null 2>&1; then
FLASK_PID=$(pgrep -f "python run.py")
echo " ⚠️ 运行中但无PID文件 (PID: $FLASK_PID)"
echo " 运行中但无PID文件 (PID: $FLASK_PID)"
else
echo " 未运行"
echo " 未运行"
fi
fi
echo ""
# 检查Worker
echo "📌 RQ Worker:"
echo "RQ Worker:"
if [ -f logs/worker.pid ]; then
WORKER_PID=$(cat logs/worker.pid)
if ps -p $WORKER_PID > /dev/null 2>&1; then
echo " 运行中 (PID: $WORKER_PID)"
echo " 运行中 (PID: $WORKER_PID)"
else
echo " 未运行 (PID文件存在但进程不存在)"
echo " 未运行 (PID文件存在但进程不存在)"
fi
else
if pgrep -f "python worker.py" > /dev/null 2>&1; then
WORKER_PID=$(pgrep -f "python worker.py")
echo " ⚠️ 运行中但无PID文件 (PID: $WORKER_PID)"
echo " 运行中但无PID文件 (PID: $WORKER_PID)"
else
echo " 未运行"
echo " 未运行"
fi
fi
echo ""
# 检查Redis
echo "📌 Redis:"
echo "Redis:"
if redis-cli ping > /dev/null 2>&1; then
echo " 运行中"
echo " 运行中"
else
echo " 未运行"
echo " 未运行"
fi
echo ""
# 检查日志文件
echo "📌 日志文件:"
echo "日志文件:"
if [ -f logs/flask.log ]; then
FLASK_LOG_SIZE=$(du -h logs/flask.log | cut -f1)
echo " Flask: logs/flask.log ($FLASK_LOG_SIZE)"

@ -29,11 +29,11 @@ def main():
# 创建worker
worker = Worker([queue], connection=redis_conn)
print(f"🚀 RQ Worker启动成功!")
print(f"📡 Redis: {AlgorithmConfig.REDIS_URL}")
print(f"📋 Queue: {AlgorithmConfig.RQ_QUEUE_NAME}")
print(f"🔄 使用{'真实' if AlgorithmConfig.USE_REAL_ALGORITHMS else '虚拟'}算法")
print(f"等待任务...")
print(f"RQ Worker启动成功!")
print(f"Redis: {AlgorithmConfig.REDIS_URL}")
print(f"Queue: {AlgorithmConfig.RQ_QUEUE_NAME}")
print(f"使用{'真实' if AlgorithmConfig.USE_REAL_ALGORITHMS else '虚拟'}算法")
print(f"等待任务...")
# 启动worker
worker.work()

Loading…
Cancel
Save