Files
iot-device-management-service/docs/芋道前端对接文档.md

532 lines
13 KiB
Markdown
Raw Normal View History

# 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 # 列表页面
```