docs: 添加告警平台与芋道前端对接文档
包含以下内容: - 后端 API 接口详细说明 - 芋道前端集成步骤 - 边缘端对接示例代码 - 阿里云 OSS 配置说明 - 大模型分析配置(可选) - 部署说明
This commit is contained in:
531
docs/芋道前端对接文档.md
Normal file
531
docs/芋道前端对接文档.md
Normal file
@@ -0,0 +1,531 @@
|
||||
# AI 告警平台与芋道前端对接文档
|
||||
|
||||
> 本文档指导如何在芋道前端项目(yudao-ui-admin-vben)中集成告警平台功能。
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 告警平台后端
|
||||
- **技术栈**: FastAPI + SQLite + 阿里云 OSS
|
||||
- **职责**: 接收边缘端告警、存储告警证据、提供 REST API
|
||||
- **端口**: 8000
|
||||
|
||||
### 1.2 芋道前端
|
||||
- **技术栈**: Vue 3 + Vben Admin + Ant Design Vue
|
||||
- **职责**: 告警列表展示、详情查看、人工处理
|
||||
- **复用**: 用户体系、权限管理、页面布局
|
||||
|
||||
---
|
||||
|
||||
## 二、后端 API 接口
|
||||
|
||||
### 2.1 基础信息
|
||||
- **Base URL**: `http://localhost:8000`
|
||||
- **文档地址**: `http://localhost:8000/docs`
|
||||
|
||||
### 2.2 接口列表
|
||||
|
||||
#### 2.2.1 健康检查
|
||||
```http
|
||||
GET /health
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"database": "healthy"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.2 创建告警(边缘端调用)
|
||||
```http
|
||||
POST /api/v1/alerts
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
**请求参数**:
|
||||
- `data` (FormField): JSON 字符串
|
||||
```json
|
||||
{
|
||||
"camera_id": "cam-001",
|
||||
"roi_id": "roi-01",
|
||||
"alert_type": "leave_post",
|
||||
"algorithm": "LeavePostAlgorithm",
|
||||
"confidence": 85,
|
||||
"duration_minutes": 5,
|
||||
"trigger_time": "2024-01-20T10:30:00Z",
|
||||
"message": "离岗告警"
|
||||
}
|
||||
```
|
||||
- `snapshot` (File, 可选): 告警抓拍图片
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"alert_no": "ALT20240120103000ABC12345",
|
||||
"camera_id": "cam-001",
|
||||
"roi_id": "roi-01",
|
||||
"alert_type": "leave_post",
|
||||
"algorithm": "LeavePostAlgorithm",
|
||||
"confidence": 85,
|
||||
"duration_minutes": 5,
|
||||
"trigger_time": "2024-01-20T10:30:00Z",
|
||||
"message": "离岗告警",
|
||||
"snapshot_url": "https://your-bucket.oss-cn-hangzhou.aliyuncs.com/alerts/xxx.jpg",
|
||||
"status": "pending",
|
||||
"created_at": "2024-01-20T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.3 查询告警列表
|
||||
```http
|
||||
GET /api/v1/alerts
|
||||
```
|
||||
**查询参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| cameraId | string | 否 | 摄像头ID |
|
||||
| alertType | string | 否 | 告警类型 |
|
||||
| status | string | 否 | 处理状态 |
|
||||
| startTime | datetime | 否 | 开始时间 |
|
||||
| endTime | datetime | 否 | 结束时间 |
|
||||
| page | int | 否 | 页码,默认1 |
|
||||
| pageSize | int | 否 | 每页条数,默认20 |
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"alerts": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"pageSize": 20
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.4 获取告警详情
|
||||
```http
|
||||
GET /api/v1/alerts/{alertId}
|
||||
```
|
||||
|
||||
#### 2.2.5 处理告警
|
||||
```http
|
||||
PUT /api/v1/alerts/{alertId}/handle
|
||||
```
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"status": "confirmed",
|
||||
"remark": "确认为真实告警"
|
||||
}
|
||||
```
|
||||
**状态枚举**: `pending` | `confirmed` | `ignored` | `resolved`
|
||||
|
||||
#### 2.2.6 获取告警统计
|
||||
```http
|
||||
GET /api/v1/alerts/statistics
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"total": 100,
|
||||
"pending": 10,
|
||||
"confirmed": 50,
|
||||
"ignored": 20,
|
||||
"resolved": 20,
|
||||
"by_type": {
|
||||
"leave_post": 80,
|
||||
"intrusion": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、芋道前端集成步骤
|
||||
|
||||
### 3.1 创建 API 文件
|
||||
|
||||
在 `apps/web-antd/src/api/` 目录下创建 `alert` 目录,并添加 `alert.ts`:
|
||||
|
||||
```typescript
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace AlertApi {
|
||||
export interface Alert {
|
||||
id: number;
|
||||
alertNo: string;
|
||||
cameraId: string;
|
||||
roiId?: string;
|
||||
alertType: string;
|
||||
algorithm?: string;
|
||||
confidence?: number;
|
||||
durationMinutes?: number;
|
||||
triggerTime: string;
|
||||
message?: string;
|
||||
snapshotUrl?: string;
|
||||
status: 'pending' | 'confirmed' | 'ignored' | 'resolved';
|
||||
handleRemark?: string;
|
||||
handledBy?: string;
|
||||
handledAt?: string;
|
||||
aiAnalysis?: Record<string, any>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface AlertListParams {
|
||||
pageNo: number;
|
||||
pageSize: number;
|
||||
cameraId?: string;
|
||||
alertType?: string;
|
||||
status?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
}
|
||||
|
||||
export interface AlertListResponse {
|
||||
alerts: Alert[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface AlertStatistics {
|
||||
total: number;
|
||||
pending: number;
|
||||
confirmed: number;
|
||||
ignored: number;
|
||||
resolved: number;
|
||||
by_type: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface HandleAlertRequest {
|
||||
status: 'confirmed' | 'ignored' | 'resolved';
|
||||
remark?: string;
|
||||
}
|
||||
}
|
||||
|
||||
export function getAlertList(params: AlertApi.AlertListParams) {
|
||||
return requestClient.get<AlertApi.AlertListResponse>('/api/v1/alerts', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function getAlertDetail(alertId: number) {
|
||||
return requestClient.get<AlertApi.Alert>(`/api/v1/alerts/${alertId}`);
|
||||
}
|
||||
|
||||
export function handleAlert(alertId: number, data: AlertApi.HandleAlertRequest) {
|
||||
return requestClient.put<AlertApi.Alert>(`/api/v1/alerts/${alertId}/handle`, data, {
|
||||
params: { handledBy: 'currentUser' },
|
||||
});
|
||||
}
|
||||
|
||||
export function getAlertStatistics() {
|
||||
return requestClient.get<AlertApi.AlertStatistics>('/api/v1/alerts/statistics');
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 创建路由配置
|
||||
|
||||
在 `apps/web-antd/src/router/routes/modules/` 下创建 `alert.ts`:
|
||||
|
||||
```typescript
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/alert',
|
||||
name: 'AlertCenter',
|
||||
meta: {
|
||||
title: '告警中心',
|
||||
icon: 'lucide:bell',
|
||||
keepAlive: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'AlertList',
|
||||
meta: {
|
||||
title: '告警列表',
|
||||
noCache: true,
|
||||
},
|
||||
component: () => import('#/views/alert/list/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
```
|
||||
|
||||
将此路由添加到主路由配置中(编辑 `apps/web-antd/src/router/routes/modules/` 下的 `dashboard.ts` 或其他菜单配置)。
|
||||
|
||||
### 3.3 创建页面组件
|
||||
|
||||
在 `apps/web-antd/src/views/` 下创建 `alert/list/` 目录:
|
||||
|
||||
**data.ts**:
|
||||
```typescript
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
|
||||
export function useAlertFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{ fieldName: 'cameraId', label: '摄像头ID', component: 'Input', componentProps: { placeholder: '请输入摄像头ID', allowClear: true } },
|
||||
{ fieldName: 'alertType', label: '告警类型', component: 'Input', componentProps: { placeholder: '请输入告警类型', allowClear: true } },
|
||||
{
|
||||
fieldName: 'status',
|
||||
label: '处理状态',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '待处理', value: 'pending' },
|
||||
{ label: '已确认', value: 'confirmed' },
|
||||
{ label: '已忽略', value: 'ignored' },
|
||||
{ label: '已解决', value: 'resolved' },
|
||||
],
|
||||
placeholder: '请选择处理状态',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{ fieldName: 'createTime', label: '创建时间', component: 'RangePicker', componentProps: { ...getRangePickerDefaultProps(), allowClear: true } },
|
||||
];
|
||||
}
|
||||
|
||||
export function useAlertColumns(): VxeTableGridOptions['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 40 },
|
||||
{ field: 'id', title: '编号', minWidth: 80 },
|
||||
{ field: 'alertNo', title: '告警编号', minWidth: 150 },
|
||||
{ field: 'cameraId', title: '摄像头', minWidth: 100 },
|
||||
{ field: 'alertType', title: '告警类型', minWidth: 100 },
|
||||
{ field: 'algorithm', title: '算法', minWidth: 120 },
|
||||
{ field: 'confidence', title: '置信度', minWidth: 80, slots: { default: 'confidence' } },
|
||||
{ field: 'durationMinutes', title: '离岗时长', minWidth: 100, slots: { default: 'duration' } },
|
||||
{ field: 'status', title: '状态', minWidth: 100, slots: { default: 'status' } },
|
||||
{ field: 'createdAt', title: '创建时间', minWidth: 180, formatter: 'formatDateTime' },
|
||||
{ title: '操作', width: 150, fixed: 'right', slots: { default: 'actions' } },
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
**index.vue**:
|
||||
参考芋道现有的 IoT 告警页面 `apps/web-antd/src/views/iot/alert/record/index.vue` 进行修改。
|
||||
|
||||
---
|
||||
|
||||
## 四、边缘端对接示例
|
||||
|
||||
### 4.1 Python (ai_edge 项目)
|
||||
|
||||
在 `ai_edge` 项目的 `main.py` 中添加告警上报功能:
|
||||
|
||||
```python
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
class AlertReporter:
|
||||
ALERT_PLATFORM_URL = "http://localhost:8000/api/v1/alerts"
|
||||
|
||||
def report_alert(
|
||||
self,
|
||||
camera_id: str,
|
||||
roi_id: str,
|
||||
alert_type: str,
|
||||
algorithm: str,
|
||||
confidence: float,
|
||||
duration_minutes: int,
|
||||
message: str,
|
||||
screenshot: bytes,
|
||||
):
|
||||
alert_data = {
|
||||
"camera_id": camera_id,
|
||||
"roi_id": roi_id,
|
||||
"alert_type": alert_type,
|
||||
"algorithm": algorithm,
|
||||
"confidence": int(confidence * 100),
|
||||
"duration_minutes": duration_minutes,
|
||||
"trigger_time": datetime.utcnow().isoformat() + "Z",
|
||||
"message": message,
|
||||
}
|
||||
|
||||
files = {
|
||||
"snapshot": ("alert.jpg", screenshot, "image/jpeg"),
|
||||
"data": (None, json.dumps(alert_data), "application/json"),
|
||||
}
|
||||
|
||||
response = requests.post(self.ALERT_PLATFORM_URL, files=files)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
```
|
||||
|
||||
### 4.2 在推理服务中调用
|
||||
|
||||
在 `EdgeInferenceService._handle_detections` 方法中调用:
|
||||
|
||||
```python
|
||||
def _handle_detections(self, camera_id: str, roi, frame: VideoFrame, alerts: list):
|
||||
for alert in alerts:
|
||||
# 上报到云端告警平台
|
||||
self._reporter.report_to_platform(
|
||||
camera_id=camera_id,
|
||||
roi_id=roi.roi_id,
|
||||
alert_type=alert.get("alert_type"),
|
||||
algorithm="LeavePostAlgorithm",
|
||||
confidence=alert.get("confidence", 1.0),
|
||||
duration_minutes=alert.get("duration_minutes", 0),
|
||||
message=alert.get("message", ""),
|
||||
screenshot=frame.image,
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、阿里云 OSS 配置
|
||||
|
||||
### 5.1 配置项
|
||||
|
||||
在告警平台的 `.env` 文件中配置:
|
||||
|
||||
```env
|
||||
OSS_ACCESS_KEY_ID=your_access_key_id
|
||||
OSS_ACCESS_KEY_SECRET=your_access_key_secret
|
||||
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
|
||||
OSS_BUCKET_NAME=your_bucket_name
|
||||
OSS_URL_PREFIX=https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com
|
||||
```
|
||||
|
||||
### 5.2 权限要求
|
||||
|
||||
OSS Bucket 需要配置以下权限:
|
||||
- **CORS**: 允许前端跨域访问
|
||||
- **公共读**: 告警图片需要可以公开访问
|
||||
|
||||
---
|
||||
|
||||
## 六、大模型分析配置(可选)
|
||||
|
||||
### 6.1 配置项
|
||||
|
||||
```env
|
||||
AI_MODEL_ENDPOINT=http://localhost:8001
|
||||
AI_MODEL_API_KEY=your_api_key
|
||||
```
|
||||
|
||||
### 6.2 大模型 API 格式
|
||||
|
||||
告警平台期望大模型服务提供以下接口:
|
||||
|
||||
```http
|
||||
POST /analyze
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"alert_id": 1,
|
||||
"snapshot_url": "https://xxx/alert.jpg",
|
||||
"alert_info": {
|
||||
"camera_id": "cam-001",
|
||||
"roi_id": "roi-01",
|
||||
"alert_type": "leave_post",
|
||||
"confidence": 85,
|
||||
"duration_minutes": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**:
|
||||
```json
|
||||
{
|
||||
"risk_level": "HIGH",
|
||||
"description": "检测到人员在非工作区域长时间停留,建议现场核实",
|
||||
"suggestion": "可能是误报,建议确认监控区域工作安排",
|
||||
"confidence_score": 0.92
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、部署说明
|
||||
|
||||
### 7.1 后端部署
|
||||
|
||||
```bash
|
||||
# 1. 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 2. 配置环境变量
|
||||
cp .env.example .env
|
||||
# 编辑 .env 文件
|
||||
|
||||
# 3. 启动服务
|
||||
python -m app.main
|
||||
```
|
||||
|
||||
### 7.2 使用 Gunicorn 生产部署
|
||||
|
||||
```bash
|
||||
gunicorn app.main:app -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000
|
||||
```
|
||||
|
||||
### 7.3 Docker 部署
|
||||
|
||||
创建 `Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.10-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
COPY . .
|
||||
EXPOSE 8000
|
||||
CMD ["python", "-m", "app.main"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、注意事项
|
||||
|
||||
1. **芋道项目权限**: 告警相关接口需要芋道后端配合实现用户认证
|
||||
2. **跨域配置**: 告警平台需要配置 CORS 以允许芋道前端访问
|
||||
3. **图片存储**: 阿里云 OSS 需要配置 CORS 允许前端直接访问图片
|
||||
4. **时区处理**: 建议统一使用 UTC 时间,前端展示时转换为本地时间
|
||||
5. **大模型服务**: AI 分析功能可选,需要部署大模型服务支持
|
||||
|
||||
---
|
||||
|
||||
## 九、目录结构总结
|
||||
|
||||
```
|
||||
# 告警平台后端
|
||||
alert_platform/
|
||||
├── app/
|
||||
│ ├── main.py # FastAPI 入口
|
||||
│ ├── config.py # 配置
|
||||
│ ├── models.py # SQLAlchemy 模型
|
||||
│ ├── schemas.py # Pydantic 模型
|
||||
│ ├── services/
|
||||
│ │ ├── alert_service.py # 告警业务逻辑
|
||||
│ │ ├── oss_storage.py # OSS 存储
|
||||
│ │ └── ai_analyzer.py # AI 分析
|
||||
│ └── utils/
|
||||
│ └── logger.py # 日志
|
||||
├── data/ # SQLite 数据库
|
||||
├── uploads/ # 本地临时存储
|
||||
├── requirements.txt
|
||||
├── .env.example
|
||||
└── README.md
|
||||
|
||||
# 芋道前端需要创建的文件
|
||||
yudao-ui-admin-vben/
|
||||
└── apps/web-antd/src/
|
||||
├── api/
|
||||
│ └── alert/
|
||||
│ └── alert.ts # 告警 API
|
||||
├── router/routes/modules/
|
||||
│ └── alert.ts # 告警路由
|
||||
└── views/alert/
|
||||
└── list/
|
||||
├── data.ts # 列表配置
|
||||
└── index.vue # 列表页面
|
||||
```
|
||||
Reference in New Issue
Block a user