AI 值班 Web 平台 - 详细需求规格说明书 (PRD).md 11 KB

AI 值班 Web 平台 - 详细需求规格说明书 (PRD)

版本: v8.0 (Execution Ready) 日期: 2025-XX-XX 项目代号: AI-Watch-Pro 核心架构: SPA Served by Backend (Vue3 build -> FastAPI static) 包管理: uv (Python) 关键技术: OpenCV Grab-Only, WebSocket, APScheduler, MySQL


1. 系统总体架构

1.1 技术栈清单

  • 后端 (Server):
    • 语言: Python 3.10+ (由 uv 管理)
    • Web 框架: FastAPI
    • 服务器: Uvicorn
    • 视觉处理: OpenCV (opencv-python-headless) - 多线程
    • 数据库: MySQL 8.0 (ORM: SQLAlchemy, Driver: pymysql)
    • 任务调度: APScheduler (AsyncIOScheduler)
    • AI 客户端: OpenAI SDK (兼容通义千问/GPT-4o/Gemini)
  • 前端 (Client):
    • 框架: Vue 3 (Composition API)
    • 构建: Vite
    • UI 库: Element Plus
    • 状态管理: Pinia
    • 图表: ECharts
  • 部署模式: 前端 npm run build 生成静态文件,由 FastAPI 的 StaticFiles 统一托管,实现单端口服务。

1.2 目录结构规范

ai-watch-platform/
├── .venv/                      # uv 虚拟环境
├── backend/
│   ├── app/
│   │   ├── api/                # REST API 路由 (v1)
│   │   ├── core/               # 配置 (config.py, security.py)
│   │   ├── models/             # SQLAlchemy 数据库模型
│   │   ├── schemas/            # Pydantic 数据校验模型
│   │   ├── services/           # 核心业务逻辑
│   │   │   ├── video_core.py   # [重点] 视频流线程池管理
│   │   │   ├── llm_agent.py    # AI 调用封装
│   │   │   └── scheduler.py    # 定时任务
│   │   ├── static/             # 存放运行时生成的报警截图
│   │   └── main.py             # 启动入口 (含前端托管逻辑)
│   ├── dist/                   # [Vue打包产物] css/js/index.html
│   └── requirements.txt        # 依赖列表
├── frontend/                   # Vue 源代码
├── run.py                      # 根目录启动脚本
└── pyproject.toml              # uv 配置 (可选)

2. 数据库设计 (Schema)

所有表均使用 utf8mb4 字符集。

2.1 用户表 (users)

虽然目前只有 Admin,但预留扩展性。 | 字段 | 类型 | 说明 | | :--- | :--- | :--- | | id | INT (PK) | 自增主键 | | username | VARCHAR(50) | 唯一,默认 admin | | hashed_password | VARCHAR(255)| 加密后的密码 | | is_active | BOOLEAN | 默认 True |

2.2 摄像头表 (cameras)

字段 类型 说明
id INT (PK) 自增
name VARCHAR(100) 摄像头备注名 (如: 1号车间)
stream_url VARCHAR(500) RTSP 或 HTTP-FLV/MP4 地址
status INT 0:离线, 1:在线 (由后台心跳更新)
created_at DATETIME 创建时间

2.3 模型配置表 (model_configs)

字段 类型 说明
id INT (PK)
name VARCHAR(50) 配置别名 (如: GPT-4o-Mini)
base_url VARCHAR(255) API 基础地址
api_key VARCHAR(255) 密钥 (前端展示时需脱敏)
model_name VARCHAR(100) 实际模型ID (e.g., gpt-4o)

2.4 值班任务表 (tasks)

字段 类型 说明
id INT (PK)
name VARCHAR(100) 任务名
model_config_id INT (FK) 关联使用的模型
camera_ids JSON 摄像头ID数组 [1, 5, 12]
prompt TEXT 检测提示词
cron_expression VARCHAR(50) 轮询频率 (如 */5 * * * *)
is_running BOOLEAN 开/关状态

2.5 报警日志表 (task_logs)

字段 类型 说明
id BIGINT (PK)
task_id INT (FK) 关联任务
camera_id INT (FK) 关联摄像头
check_time DATETIME 巡检时间
snapshot_path VARCHAR(255) 关键: 图片相对路径 /static/snapshots/...
ai_result TEXT AI 返回的完整分析
is_alarm BOOLEAN 是否异常

3. 功能模块详细规格

3.1 认证模块 (Auth Module)

  • 前端逻辑:
    • 登录页输入账号 admin / HNYZ0821
    • 调用 POST /api/v1/login
    • 获取 JWT Token 存入 localStorage。
    • Axios 拦截器:所有请求头自动携带 Authorization: Bearer <token>
    • 如果 Token 失效 (401),自动跳转回登录页。
  • 后端逻辑:
    • 验证用户名密码。
    • 签发 JWT (过期时间建议设为 7 天)。

3.2 仪表盘模块 (Dashboard & Real-time Monitor)

此模块需解决 20 路并发显示的性能问题。

  • 功能描述:
    • 展示 20 个摄像头的实时画面(低延迟)。
    • 展示今日异常统计、任务运行状态。
  • 后端实现 (WebSocket + Grab-Only):
    • WebSocket 端点: ws://host/ws/stream
    • 推流循环:
      • 创建一个后台 asyncio 任务。
      • 每 1000ms (1秒) 循环一次。
      • 调用 VideoManager.get_all_snapshots()
      • 该方法遍历所有 20 个 LowCostStream 对象,触发一次 retrieve() 解码,获取最新帧。
      • 将 20 张图片压缩为 JPEG (质量 60),转 Base64。
      • 打包成 JSON: {"cam_1": "base64...", "cam_2": "base64..."}
      • 通过 WebSocket 群发给所有已连接的客户端。
  • 前端实现:
    • 建立 WebSocket 连接。
    • 接收到 JSON 后,解析并直接修改对应 <img> 标签的 src 属性。
    • 优化: 如果某摄像头 ID 在 JSON 中为 null,显示“信号中断”占位图。

3.3 视频资源管理模块 (Video Manager)

  • 功能: 增删改查摄像头。
  • 后端核心逻辑 (VideoManager 单例):
    • 初始化: FastAPI 启动时 (@app.on_event("startup")),从数据库读取所有摄像头,并为每一个创建一个 LowCostStream 线程。
    • Grab-Only 线程逻辑:
      • 死循环执行 cap.grab() (只清空缓冲区,不解码,CPU < 1%)。
      • get_snapshot() 被调用时,执行一次 cap.retrieve() (解码,消耗 CPU)。
      • 断线重连: 如果 grab() 失败,线程休眠 5 秒后尝试 cap.open()
    • 新增 API: 写入数据库 -> 调用 VideoManager.add_stream(url) 启动新线程。
    • 删除 API: 删除数据库记录 -> 调用 VideoManager.stop_stream(id) 销毁线程。

3.4 任务调度模块 (AI Task Scheduler)

这是系统的“大脑”。

  • 功能: 定义何时、看哪里、查什么。
  • 输入:
    • 选择 10 个摄像头。
    • Prompt: "检查工人是否佩戴安全帽,若未佩戴返回异常"。
    • 频率: 每 5 分钟。
  • 后端逻辑 (APScheduler):
    1. 任务创建时,向调度器添加一个 Job。
    2. Job 执行流程:
      • 步骤 A (极速截帧): 遍历这 10 个摄像头,调用 video_manager.get_snapshot(id)。由于是内存操作,10 路截帧耗时 < 0.5秒。
      • 步骤 B (落盘): 将获取到的图片写入 /backend/app/static/snapshots/{date}/{uuid}.jpg
      • 步骤 C (AI 分析):
        • 使用 asyncio.gather 并发调用 LLM 接口 (防止一个请求卡住后面 9 个)。
        • 构造请求: Image (Base64/URL) + Prompt。
        • 系统提示词 (System Prompt): "你是一个安防助手。请简短回答。如果发现异常,请在回复开头加上 [ALARM] 标记。"
      • 步骤 D (入库):
        • 解析 AI 回复,检测是否包含 [ALARM]
        • image_path (相对路径), ai_result, is_alarm 写入 task_logs 表。

3.5 报警与报表模块 (Reporting)

  • 功能: 历史回溯与导出。
  • 前端:
    • 表格展示日志,支持按“仅看异常”筛选。
    • 图片预览: 点击缩略图,弹出 <el-dialog> 显示大图。图片源地址为 /static/snapshots/...
  • 后端:
    • 静态文件挂载: 必须在 main.py 中配置 app.mount("/static", ...),否则前端无法访问磁盘上的图片。
    • 导出 API:
      • 查询数据库 -> 生成 Excel (使用 pandasopenpyxl)。
      • Excel 中需包含完整的 HTTP 链接 (如 http://192.168.1.10:8000/static/...),以便用户下载后点击查看。

4. API 接口定义 (RESTful v1)

所有接口前缀: /api/v1

方法 路径 描述 请求体/参数
Auth
POST /login 获取 Token {"username": "admin", "password": "..."}
Cameras
GET /cameras 获取列表
POST /cameras 新增摄像头 {"name": "...", "url": "..."}
DELETE /cameras/{id} 删除摄像头
Models
GET /models 获取模型配置
POST /models 新增配置 {"base_url": "...", "api_key": "..."}
Tasks
GET /tasks 获取任务列表
POST /tasks 创建任务 {"camera_ids": [1,2], "prompt": "...", "cron": "*/5..."}
POST /tasks/{id}/toggle 启停任务 {"running": true}
Logs
GET /logs 获取日志 ?page=1&only_alarm=true
GET /logs/export 导出Excel

5. 开发环境准备 (uv 指南)

为了确保依赖环境一致,请严格执行以下命令。

5.1 初始化

# 1. 创建虚拟环境 (速度极快)
uv venv --python python@3.13 .venv 

# 2. 激活环境
# Windows
.venv\Scripts\activate
# Linux/Mac
source .venv/bin/activate

5.2 安装依赖

创建 backend/requirements.txt:

fastapi==0.109.0
uvicorn[standard]==0.27.0
sqlalchemy==2.0.25
pymysql==1.1.0
opencv-python-headless==4.9.0.80
apscheduler==3.10.4
openai==1.10.0
python-multipart==0.0.6
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
openpyxl==3.1.2
websockets==12.0

执行安装:

uv pip install -r backend/requirements.txt

6. 部署与交付逻辑

这是实现 "后端启动前端" 的最终步骤。

  1. 前端打包: 在 frontend/ 目录下运行 npm run build。 配置 vite.config.tsoutDir 设置为 ../backend/dist

  2. 后端静态托管: 在 backend/app/main.py 底部添加:

    # 必须放在所有 API 路由之后
        
    # 1. 挂载 Vue 的静态资源 (js/css/img)
    app.mount("/assets", StaticFiles(directory="../backend/dist/assets"), name="assets")
        
    # 2. 挂载报警截图 (数据)
    app.mount("/static", StaticFiles(directory="backend/app/static"), name="static")
    
    # 3. Catch-All 路由 (SPA 核心)
    @app.get("/{full_path:path}")
    async def catch_all(full_path: str):
        # 允许直接访问 dist 根目录文件 (如 favicon.ico)
        dist_path = "../backend/dist"
        file_path = os.path.join(dist_path, full_path)
        if os.path.exists(file_path) and os.path.isfile(file_path):
            return FileResponse(file_path)
        # 否则一律返回 index.html
        return FileResponse(os.path.join(dist_path, "index.html"))
    
    1. 启动命令: bash uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 此时,访问 http://localhost:8000 即可看到完整的 Web 平台。