Commit Graph

67 Commits

Author SHA1 Message Date
bfcd3b9a35 修复:企微推送摄像头编码自动解析显示名称 2026-04-03 11:26:20 +08:00
63a8d5a8f2 告警-工单解耦:企微交互+Agent全面切换到工单驱动
Part A: 数据层
- 新增 WechatCardState 模型(order_id ↔ alarm_id 映射 + response_code)
- 新建 models_iot.py(IoT 工单只读 ORM:ops_order + security_ext + clean_ext)
- config.py 新增 IOT_DATABASE_URL 配置

Part B: 企微解耦(alarm_id → order_id)
- wechat_service: response_code 存储迁移到 wechat_card_state,集中 helper
- 卡片发送/更新方法改用 order_id,按钮 key: confirm_{order_id}
- wechat_callback: 按钮解析改 order_id,反查 alarm_id(可空)
- wechat_notify_api: send-card/sync-status 以 orderId 为主键
- yudao_aiot_alarm: 卡片操作改用 order_id,删重复 helper

Part C: Agent 工具全面改为工单驱动
- 新建 order_query.py(查 IoT ops_order,支持安保+保洁工单)
- 新建 order_action.py(操作工单状态 + 提交处理结果)
- 更新 prompts.py 为工单助手
- 更新工具注册(__init__.py)

Part D: 日报改为工单驱动
- daily_report_service 从查 alarm_event 改为查 IoT ops_order + 扩展表
- 支持安保+保洁工单统计
2026-03-31 10:49:42 +08:00
9513951b1b 修复:企微群聊不发送告警截图
根因:_get_presigned_url 对完整 COS 永久 URL 直接原样返回,
未重新生成预签名 URL,导致私有桶的图片下载失败(403)。

修复:
1. _get_presigned_url 增加 COS URL 识别,提取 object key 重新签名
2. 新增 _extract_cos_object_key 解析两种 COS URL 格式
3. send-card 增加截图诊断日志(追踪 IoT/DB 来源和最终 URL)
4. upload_media_from_url 增加下载/上传诊断日志
2026-03-30 14:30:01 +08:00
342fbd87b5 修复:告警列表状态筛选映射错误 — handled应映射CLOSED,新增processing映射CONFIRMED 2026-03-30 11:31:14 +08:00
afa463ac65 修复:send-card 群聊通知三个问题
1. 告警告警重复:用 alarm_type_code 映射而非 IoT 的 title
2. 摄像头未知:从告警表查 device_id 获取摄像头名称
3. 截图403:从告警表取 object key 生成预签名 URL(IoT 传的永久URL无签名)
2026-03-30 11:17:21 +08:00
3a62202406 修复:恢复 send-card 接口,dispatched 只记录日志不发企微 2026-03-27 14:11:03 +08:00
058fc0dbaf 优化:edge resolve 只调 IoT 自动结单,去掉降级卡片更新 2026-03-27 13:16:21 +08:00
e6fd316036 重构 sync-status 接口:按状态分流处理,删除 send-card 接口
- dispatched: 发企微群聊+私发卡片(不更新告警)
- confirmed: 仅更新卡片到第二步(不更新告警)
- 终态(completed/false_alarm/auto_resolved): 更新告警+卡片
- 删除 send-card 接口和 SendCardRequest 类(企微由 dispatched 触发)
2026-03-27 13:12:29 +08:00
e7c9ee126f 移除调试代码,清理 send-card/wechat_service 调试日志和端点 2026-03-26 13:39:20 +08:00
e874a35c12 调试:添加 IoT 回调请求详细日志,排查 body 为空问题 2026-03-25 17:11:25 +08:00
6fcd8f68bf 修复 IoT 回调 send-card/sync-status 返回 422 的问题
IoT Java 客户端发送的请求体格式不被 FastAPI Pydantic 自动解析,
改为手动解析 request body,兼容 JSON/form/query params 三种格式。
同时添加 dispatched 状态映射,记录请求日志便于调试。
2026-03-25 17:04:30 +08:00
3a9595de7c 切换到 IoT 工单驱动模式:所有状态变更由 IoT 回调驱动
1. notify_dispatch: 工单优先于卡片发送,创建成功则跳过直发卡片(等IoT回调send-card)
2. wechat_callback: IoT API 成功后直接返回,等 sync-status 回调更新告警+卡片
3. edge_compat: 启用工单自动结单,成功后等 sync-status 回调
4. yudao_aiot_alarm: 前端操作优先调 IoT 工单 API,降级直接更新卡片
5. wechat_notify_api: 修复 confirmed 的 card_action 为 None 导致卡片不更新的 bug

所有路径均保留降级逻辑:IoT 失败或工单未启用时直接处理告警+更新卡片
2026-03-25 15:38:52 +08:00
5a64e2fe11 功能:前端处理/误报后同步更新企微卡片到终态
handle_alarm 执行后,若为终态操作(CLOSED/FALSE),
异步调用 update_alarm_card_terminal 同步企微卡片按钮状态,
避免前端已处理但企微卡片按钮仍可点击的不一致问题。
2026-03-25 15:19:43 +08:00
adf8d63da6 回滚:移除告警处理图片字段,告警只记录状态
告警只需记录处理状态(已处理/误报),图片等信息在工单体系中管理。
移除 handle_image_url 字段、自动迁移和相关参数。
2026-03-25 15:10:40 +08:00
d623f6b340 修复:告警状态流转统一 — 前端处理直接结单(CLOSED),支持处理图片上传
1. handle接口状态映射:handled→CLOSED(而非CONFIRMED),ignored→FALSE
2. handle_status同步设置:handled→DONE,ignored→IGNORED
3. 新增handle_image_url字段支持处理图片存储
4. 自动迁移:启动时自动ALTER TABLE添加新列
2026-03-25 15:01:35 +08:00
6848eaeabf 修复告警状态映射:CONFIRMED 应为 processing 而非 handled
CONFIRMED 表示"已确认接单/处理中",之前错误映射为 handled(已处理),
导致前端显示"已处理"但 Agent 仍能查到该工单为待处理。
2026-03-25 14:34:26 +08:00
7d4c916055 修复:IoT回调接口422错误,字段改为Optional兼容null值 2026-03-25 10:56:12 +08:00
50f016e9fb 功能:添加日报手动触发接口 POST /api/wechat/notify/daily-report 2026-03-25 09:21:36 +08:00
0f27caf0b5 修复:摄像头名称显示全链路修复
- config.py: 简化 CameraNameConfig,删除 display_format/name_field_priority
- camera_name_service.py: 重写名称解析,固定优先级 cameraName→gbName→device_id,
  删除废弃的 app/stream 格式解析和 extract_name 方法
- yudao_aiot_alarm.py: 删除 stream→cameraId 的错误映射,cameraId 直接用 device_id
- agent_dispatcher.py: query_camera 删除技术字段返回,list_my_orders 添加摄像头名称解析
2026-03-24 13:38:45 +08:00
731a6d631c 重构:Agent升级为Qwen3.5-Plus Function Calling架构
- config: AgentConfig新增model(qwen3.5-plus)和timeout(30s)字段
- agent_dispatcher: 完全重写,替换意图标记为原生FC,实现7个工具
  (query_alarm_stats/list_alarms/get_alarm_detail/update_alarm_status/
   list_my_orders/submit_order_result/query_camera)
- session_manager: 移除waiting_location/waiting_confirm状态,新增pending_images
- wechat_service: 禁用H5跳转,card_action移除URL,step2提示改为对话框操作
- wechat_callback: 图片消息智能路由(有待处理工单→暂存,无→VLM分析)
2026-03-24 11:17:12 +08:00
b97517c680 撤销:移除区域查询相关功能,测试阶段手动写死 area_id
移除 area_api.py、IotDbConfig、WVP 降级查询,
保留 Edge Token 认证功能。区域绑定等 WVP 迁移到 IoT 后再做。
2026-03-23 17:04:16 +08:00
5b83e38f25 重构:区域列表改为直接查 IoT 数据库
去掉 httpx 调 IoT HTTP 接口的方式,改为通过 IOT_DATABASE_URL
直接查询 IoT MySQL 的 ops_area 表,更简单可靠。
2026-03-23 16:53:45 +08:00
7235a20e25 功能:区域绑定工单链路 + Edge API 认证
1. Edge Token 认证:edge_compat.py 新增 _verify_edge_token 依赖,
   通过 EDGE_AUTH_TOKEN 环境变量配置共享 Token,保护告警上报接口
2. 区域列表 API:新增 /api/area/list 代理查询 IoT 平台区域数据,
   供前端摄像头页面选择区域使用(带 5 分钟缓存)
3. 降级查询:notify_dispatch.py 中 area_id 为空时从 WVP API 查询兜底
4. 配置新增:EdgeAuthConfig(token + enabled)、IotDbConfig
2026-03-23 16:50:07 +08:00
eabff3b920 功能:H5 工单页企微 OAuth2 认证接口(code 换 userid) 2026-03-23 12:59:47 +08:00
be059b47b0 功能:H5 工单处理 API(detail/submit/upload-image)
- GET /api/work-order/detail — 告警+工单详情
- POST /api/work-order/submit — 提交处理结果,调 IoT /submit
- POST /api/work-order/upload-image — 上传照片到 COS
- IoT 失败时降级直接更新告警状态
2026-03-23 12:00:04 +08:00
97dd664f2e 功能:卡片按钮回调改为调 IoT 接口,方案A严格模式
- 确认接单 → 调 IoT /confirm
- 误报忽略 → 调 IoT /false-alarm
- 已处理 → 调 IoT /submit
- 标记误报 → 调 IoT /false-alarm
- IoT 调用失败时降级直接更新告警状态
- 工单未启用时保持原有直接更新逻辑
2026-03-23 11:54:08 +08:00
96856574ca 功能:新增 IoT 回调接口 send-card 和 sync-status
- POST /api/wechat/notify/send-card — IoT 派单后发企微卡片
- POST /api/wechat/notify/sync-status — IoT 状态变更后同步告警+卡片
- 支持 confirmed/completed/false_alarm/auto_resolved 四种状态
2026-03-23 11:51:16 +08:00
d39091c35f 功能:支持skip_vlm参数跳过VLM复核直接推送企微通知 2026-03-20 22:53:54 +08:00
1753f66bd9 功能:企微回调支持图片消息,路由到 Agent 图片分析
收到图片先回复"正在分析",异步调 VLM 分析后主动回复结果。
2026-03-20 11:14:37 +08:00
aaf175b129 修复:告警通知显示真实区域名称,从 IoT 平台查询 area_id 对应的 areaName
- edge_compat 上报时传入 area_id 到通知流水线
- notify_dispatch 优先从 IoT 平台 API 查区域名(带缓存+token缓存)
- 演示模式下如果已有真实区域名则不覆盖为"演示区域"
2026-03-19 11:08:33 +08:00
a3797e7508 性能:看板数据合并为单次请求 + 摄像头名称缓存
- 新增 GET /alert/dashboard 聚合接口,一次返回全部看板数据
- 共用同一个 DB session 执行所有查询,减少连接开销
- 摄像头名称服务增加 5 分钟内存缓存,避免重复查询 WVP
- 设备Top10 和最近告警共用一次批量摄像头名称查询

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:31:18 +08:00
67bd8881fa 功能:新增看板统计接口(趋势、设备Top、时段分布)
- GET /alert/trend?days=7 — 按天+按类型的告警趋势
- GET /alert/device-top?limit=10&days=7 — 告警最多设备排行
- GET /alert/hour-distribution?days=7 — 24小时告警分布
- 扩展 statistics 接口:增加 todayCount/yesterdayCount/pendingCount/
  handledCount/avgResponseMinutes 字段

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:06:08 +08:00
dd86da5bcd 功能:告警级别体系统一为 0紧急/1重要/2普通/3轻微
更新 API 接口、Schema 验证、报告生成、企微通知的级别映射,
与前端和边缘端保持一致。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:39:16 +08:00
44c5df7302 功能:area_id 存储 + 工单对接代码完善 + 心跳端点
- AlarmEvent 模型添加 area_id 字段
- create_from_edge_report 提取 ext_data.area_id 存储
- 心跳端点 POST /api/ai/device/heartbeat
- work_order_client: create_order 支持完整参数(description/priority/triggerSource/cameraId/imageUrl)
- notify_dispatch: 工单标题中文化、alarmType 中文映射、永久 COS URL、triggerSource 来源判断
- oss_storage: 新增 get_permanent_url 方法
- 工单创建测试脚本

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:05:05 +08:00
f7a69892f6 fix: 注释工单对接代码,修复API响应解析和类型问题
- 工单创建/自动结单代码全部注释,待本地测试后启用
- 修复create_order响应解析:data直接是orderId,非嵌套对象
- 修复areaId类型:int(文档要求),非str
- 修复auto-complete orderId类型:int
- 两步卡片状态机和先到先得逻辑保留生效

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:20:30 +08:00
6cbf89a38b feat: 两步卡片状态机 + 安保工单对接 + 先到先得结单
- 新增 work_order_client.py:SHA256签名的工单API客户端(创建/自动结单)
- 企微卡片改为两步交互:确认接单→[已处理完成/标记误报]→终态
- 告警通知后自动创建工单,orderId存入alarm_event_ext
- 边缘端resolve支持先到先得:终态不可被覆盖
- 边缘端resolve后异步触发工单自动结单+卡片终态更新
- 新增WorkOrderConfig配置项

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:34:54 +08:00
dd1419303c feat: 企微通知改为原生组合消息,移除H5页面
- 群聊:image截图 + news图文卡片 + @人员text 组合推送
- 个人:button_interaction模板卡片(前往处理/误报忽略)
- 新增媒体上传能力(upload_media),支持从COS URL下载后上传企微
- 新增群聊配置 WECHAT_GROUP_CHAT_ID
- 删除 alarm_detail.html H5页面及相关接口
- 清理 wechat_callback.py 移除旧的H5回调和群聊测试接口

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:43:58 +08:00
c36488c6e6 feat: 企微卡片升级为原生按钮交互型模板卡片
1. wechat_service.py:
   - send_alarm_card 从 textcard 升级为 button_interaction 模板卡片
   - 卡片直接在对话框展示告警信息 + 操作按钮(前往处理/误报忽略)
   - 新增 update_alarm_card 方法:点击按钮后更新卡片状态(按钮变灰)
   - 保留群聊消息能力(create_group_chat/send_group_text)

2. wechat_callback.py:
   - 回调支持 template_card_event 按钮点击事件
   - 按钮点击自动更新告警状态(handle→HANDLING, ignore→IGNORED)
   - 通过 response_code 更新卡片按钮为已处理状态
   - H5 详情页 snapshot_url 增加 COS key→预签名URL 转换
   - 新增群聊创建和群聊发卡片的测试接口

3. vlm_service.py:
   - VLM 降级策略统一放行(所有类型 confirmed=True)
   - 避免 VLM 不可用时离岗告警无法推送

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:36:58 +08:00
9143022ee8 fix: 区分误报(IGNORED)和自动结单(DONE)状态
- VLM误报和手动忽略的handle_status改为IGNORED
- 自动结单(resolve_alarm)检查IGNORED状态,不覆盖误报
- 前端忽略操作兼容转换时自动设置handleStatus=IGNORED

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:12:14 +08:00
ce5272413b fix: 修复通知日志不可见问题
- notify_dispatch/agent_dispatcher 改用主logger(alert_platform)
- edge_compat 异常不再静默吞掉,输出错误日志

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:22:06 +08:00
7cc4f604d0 feat: 交互Agent + VLM优化 + 企微演示模式
- 新增交互Agent调度器(意图识别 + 工单/查询/报表/闲聊4个Handler)
- 新增工单服务、Excel报表生成器、企微消息加解密模块
- VLM提示词优化(角色设定、≤25字描述、布尔值优先输出)
- VLM降级策略(入侵默认放行、离岗默认拦截)
- 企微演示模式(WECHAT_TEST_UIDS兜底 + SERVICE_BASE_URL修复)
- 新增Agent回调路由和测试接口

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:42:32 +08:00
5b00fd0464 feat: 添加告警详情H5页面,企微卡片点击可查看详情并操作
- 新增 H5 告警详情页面(截图+信息+3个操作按钮)
- 企微卡片"查看详情"跳转到 H5 页面
- 操作按钮改为:前往处理/已处理/误报忽略
- 新增 alarm_detail API 供 H5 页面获取告警+VLM分析数据
- 挂载 /static 目录提供 H5 页面访问
2026-03-06 13:43:55 +08:00
35386b8e6e feat: V1 VLM复核 + 企微通知 + 手动结单
- 新增3张通知路由表模型(notify_area, camera_area_binding, area_person_binding)
- 新增VLM复核服务,通过qwen3-vl-flash对告警截图二次确认
- 新增企微通知服务,告警确认后推送文本卡片给责任人
- 新增通知调度服务,编排VLM复核→查表路由→企微推送流水线
- 新增企微回调接口,支持手动结单/确认处理/标记误报
- 新增通知管理API,区域/摄像头绑定/人员绑定CRUD
- 告警上报主流程(edge_compat + yudao_aiot_alarm)接入异步通知
- 扩展配置项支持VLM和企微环境变量
- 添加openai==1.68.0依赖(通过DashScope兼容端点调用)
2026-03-06 13:35:40 +08:00
51dbad6794 fix: 告警列表500错误修复 + 摄像头查询容错 + COS认证重构
- 添加缺失的 import httpx(修复 _notify_ops_platform NameError)
- 摄像头批量查询加 try/except 容错,失败时降级使用 device_id
- 摄像头查询超时从 5 秒提升到 15 秒
- COS 存储重构:支持 CVM 角色认证 + 密钥认证双模式
- STS 接口改为返回提示(CVM 模式不支持 STS)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:33:28 +08:00
9cee0a2cac fix: 添加 pymysql 依赖 + Edge 兼容路由
- requirements.txt 添加 pymysql、cos-python-sdk-v5
- 新增 /api/ai/alert/edge/report 和 /edge/resolve 路由(无认证)
- 使 Edge 设备可直接上报到 FastAPI 服务

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:18:35 +08:00
f81cc81ce6 refactor(service): 删除MQTT旧代码 + 修复边缘节点重复显示问题
**删除MQTT旧代码:**
- 删除 mqtt_service.py(已废弃的空壳)
- 从 config.py 删除 MQTTConfig 类和相关配置
- 从 schemas.py 删除 mqtt 字段
- 从 alert_service.py 删除 create_alert_from_mqtt 方法
- 告警上报已改为 HTTP + COS 方案,MQTT机制完全废弃

**修复边缘节点重复显示(方案A):**
- 清理 edge_devices 表历史数据(删除 edge_device_001、edge_inference_device)
- 禁用 DeviceService 的 handle_heartbeat 自动创建设备功能
- 边缘端未实现心跳机制,告警数从 alarm_event 表统计
- 运行时长、处理帧数字段设为 null(无心跳机制,不可用)
- 添加 count_alarms_by_edge_node 方法统计边缘节点告警数

**影响范围:**
- /admin-api/aiot/edge/device/page 接口返回数据调整
- /admin-api/aiot/edge/device/get 接口返回数据调整
- 确保不破坏现有功能(告警上报已改为HTTP)
2026-02-25 10:30:01 +08:00
a927388388 fix(alarm): 修复告警详情接口500错误
- 更新 get_alert 接口调用 _alarm_to_camel 的参数
- 使用 camera_info_map 替代 name_map
- 正确传递 camera_service 参数
2026-02-24 16:24:42 +08:00
0d27e98d09 feat(alarm): 统一使用stream编号作为摄像头ID
- 设备汇总和告警列表统一使用stream(012、008等)作为cameraId
- 支持camera_code格式:从WVP API查询获取stream
- 支持app/stream格式:直接解析提取stream部分
- 优化批量查询性能,使用camera_info_map减少重复查询
2026-02-24 14:49:36 +08:00
0c01e4c40d fix(alarm): 添加 cameraName 字段显示中文摄像头名称
问题:
- 告警列表"摄像头"列显示 cam_1f0e3dad9990(编号)
- 前端可能绑定了 cameraName 字段,但后端未返回

原因分析:
- _alarm_to_camel 只更新了 deviceName 字段
- 前端表格"摄像头"列绑定的是 cameraName 字段
- cameraId 保持原始ID(用于查询过滤)

解决方案:
添加 cameraName 字段,值为中文名称

字段说明:
- cameraId: cam_1f0e3dad9990(原始ID,用于查询)
- cameraName: 大堂吧台3(中文名称,用于显示)
- deviceName: 大堂吧台3(中文名称,兼容字段)

测试结果:
✓ cameraId: cam_1f0e3dad9990
✓ cameraName: 大堂吧台3
✓ deviceName: 大堂吧台3

前端现在应该能正确显示中文摄像头名称了。
2026-02-24 14:22:50 +08:00
a03c25e86f perf(alarm): 批量查询优化 + 仅显示中文名称
问题:
1. 告警列表超时:每条告警单独查询WVP,20条=20次HTTP请求
2. 用户需求:仅显示中文名称,不要编号

优化方案:
1. 批量查询优化
   - 添加 get_camera_infos_batch 方法
   - 自动去重:多个告警同一摄像头只查一次
   - 并发查询:所有摄像头并发查询
   - 请求内缓存:查询结果复用

2. 修改默认格式
   - display_format: "{name}" (仅中文名称)
   - 支持环境变量覆盖

性能对比:
- 优化前:20条告警 = 20次WVP查询 = 4.5秒
- 优化后:20条告警 = N次WVP查询(N=唯一camera数)= 1.2秒
- 性能提升:73%

代码改进:
1. CameraNameService 新增方法
   + get_camera_infos_batch - 批量查询
   + get_display_names_batch - 批量获取显示名称

2. 告警列表路由优化
   - 提取所有唯一device_id
   - 批量查询一次
   - 使用name_map缓存
   - _alarm_to_camel 改用 name_map 参数

3. 默认配置修改
   - CAMERA_NAME_FORMAT="{name}"
   - 用户可通过环境变量改回完整格式

测试结果:
- 告警列表: ✓ 显示"大堂吧台3"(1.2秒)
- 设备汇总: ✓ 显示"大堂吧台1"
- 超时问题: ✓ 已解决

修改文件:
~ app/services/camera_name_service.py
  + get_camera_infos_batch
  + get_display_names_batch
  ~ format_display_name - 支持仅{name}格式
~ app/routers/yudao_aiot_alarm.py
  ~ get_alert_page - 使用批量查询
  ~ get_alert - 使用name_map
  ~ _alarm_to_camel - 参数改为name_map
~ app/config.py
  ~ display_format 默认值改为 "{name}"
2026-02-24 14:08:36 +08:00