# ✅ 巡检任务功能更新总结 ## 🎯 功能实现 根据需求,已实现完整的巡检任务记录和AI识别流程。 ## 📋 新增功能 ### 1. ✅ 自动创建巡检记录 **何时创建**:巡检任务启动时自动创建 **InspectionTaskRecord字段**: - `recordId`: 自动生成的记录ID - `taskId`: 关联的巡检任务ID - `executeTime`: 执行开始时间 - `duration`: 执行时长(秒) - `accessory`: 视频URL(原始;处理后) - `result`: AI识别结果摘要 - `status`: 0=成功, 1=失败, 2=部分成功 ### 2. ✅ 自动保存视频 **视频保存流程**: 1. 从RTSP流录制视频(按task.duration时长) 2. 上传原始视频到MinIO 3. 保存URL到`record.accessory` 4. 继续分析处理 ### 3. ✅ 调用Python服务识别 **识别流程**: 1. 创建`HttpYoloDetector`连接Python服务 2. 逐帧提取并调用YOLOv8检测 3. 每10帧检测一次(可调整) 4. 绘制检测框到视频上 5. 生成带标注的处理后视频 ### 4. ✅ 更新识别结果 **result字段内容**: ``` 共检测到 5 个问题,详情:垃圾(3) 烟雾(2) ``` ### 5. ✅ 创建不重复告警 **去重机制**: - 使用位置+类别生成唯一键 - 相同对象只创建一次告警 - 允许10像素的位置波动 - 60秒未检测到自动清除 **AlarmRecord包含**: - 告警类型、内容、置信度 - 关联的任务ID和设备ID - 告警图片(MinIO存储) - 视频帧位置 - 未处理状态 ## 🔄 完整执行流程 ``` 1. 用户启动巡检任务 ↓ 2. InspectionTaskServiceImpl.executeInspectionTask() ├── 创建InspectionTaskRecord (status=1执行中) ├── 更新InspectionTask (status=1执行中) └── 调用performVideoAnalysisWithRecord() ↓ 3. performVideoAnalysisWithRecord() ├── 录制RTSP视频流(30秒) ├── 上传原始视频到MinIO ├── 更新record.accessory = "原始视频URL" └── 调用analyzeVideoAndUpdateRecord() ↓ 4. VideoAnalysisService.analyzeVideoWithRecord() ├── 逐帧分析视频 ├── 每10帧调用Python API检测 ├── 发现新对象 → createAlarmRecordForRecord() │ ├── 提取检测区域图片 │ ├── 上传告警图片到MinIO │ └── 创建AlarmRecord(去重) ├── 绘制检测框 ├── 保存处理后视频 ├── 上传处理后视频到MinIO ├── 更新record.accessory += ";处理后视频URL" └── 更新record.result = "检测结果摘要" ↓ 5. 完成 ├── 更新record.status = 0 (成功) ├── 更新record.duration = 实际执行时长 └── 更新task.status = 2 (已完成) ``` ## 📦 新增/修改的文件 ### 新增文件 1. **IInspectionTaskRecordService.java** - 巡检记录服务接口 2. **IInspectionTaskRecordServiceImpl.java** - 巡检记录服务实现 3. **INSPECTION-WORKFLOW.md** - 详细工作流程文档 4. **INSPECTION-FEATURE-SUMMARY.md** - 本文档 ### 修改文件 1. **InspectionTaskServiceImpl.java** - 添加依赖注入(InspectionTaskRecordMapper, MinioService, VMinioObjectService) - 修改`executeInspectionTask()` - 创建记录 - 新增`performVideoAnalysisWithRecord()` - 录制视频并分析 - 新增`analyzeVideoAndUpdateRecord()` - 调用分析服务 - 新增`updateRecordFailed()` - 更新失败状态 2. **VideoAnalysisService.java** - 添加InspectionTaskRecordMapper依赖 - 更新Python服务URL为容器名 - 更新模型名称为yolov8_detector - 新增`analyzeVideoWithRecord()` - 带记录的视频分析 - 新增`processVideoWithRecord()` - 处理视频并记录结果 - 新增`createAlarmRecordForRecord()` - 创建去重告警 - 新增`uploadProcessedVideoForRecord()` - 上传处理后视频 ## 🎯 数据流转 ### InspectionTaskRecord字段变化 ``` 创建时: recordId: [auto] taskId: 1001 executeTime: 2025-09-30 14:30:00 status: 1 (执行中) accessory: null result: null duration: null 录制视频后: accessory: "http://.../inspection_1001_xxx.mp4" 分析完成后: accessory: "http://.../inspection_1001_xxx.mp4;http://.../processed_xxx.mp4" result: "共检测到 3 个问题,详情:垃圾(2) 烟雾(1)" duration: 32 status: 0 (成功) ``` ### AlarmRecord创建条件 仅当满足以下条件时创建告警: 1. ✅ 检测到新对象(不在缓存中) 2. ✅ 位置和类别不重复 3. ✅ 置信度超过阈值(Python服务的conf参数) ## 💾 数据库查询示例 ### 查看任务执行历史 ```sql -- 查看任务的所有执行记录 SELECT r.record_id, r.execute_time, r.duration, r.status, r.result, (SELECT COUNT(*) FROM v_alarm_record a WHERE a.task_id = r.task_id AND a.create_time >= r.execute_time) as alarm_count FROM v_inspection_task_record r WHERE r.task_id = 1001 ORDER BY r.execute_time DESC; ``` ### 查看记录详情 ```sql -- 查看单条记录的完整信息 SELECT r.*, t.device_id, d.ip as device_ip FROM v_inspection_task_record r JOIN v_inspection_task t ON r.task_id = t.task_id JOIN v_device d ON t.device_id = d.device_id WHERE r.record_id = 2001; ``` ### 查看记录的所有告警 ```sql -- 查看某次执行产生的告警 SELECT a.alarm_id, a.alarm_type, a.alarm_content, a.confidence, a.frame_position, m.object_url as alarm_image_url FROM v_alarm_record a LEFT JOIN v_minio_object m ON a.image_oss_id = m.object_id WHERE a.task_id = 1001 AND a.create_time >= (SELECT execute_time FROM v_inspection_task_record WHERE record_id = 2001) AND a.create_time <= DATE_ADD((SELECT execute_time FROM v_inspection_task_record WHERE record_id = 2001), INTERVAL (SELECT duration FROM v_inspection_task_record WHERE record_id = 2001) SECOND) ORDER BY a.create_time; ``` ## 🔧 配置参数 ### 关键配置位置 **VideoAnalysisService.java**: ```java // Python服务地址(使用容器名) private static final String PYTHON_API_URL = "http://rtsp-python-service:8000/api/detect/file"; // 模型名称 private static final String MODEL_NAME = "yolov8_detector"; // 检测频率(每N帧) if (frameCount % 10 == 0) { ... } // 去重时间窗口(60秒) (currentId - entry.getValue()) > grabber.getFrameRate() * 60 ``` ### 可调整参数 | 参数 | 位置 | 默认值 | 说明 | |------|------|--------|------| | 检测频率 | processVideoWithRecord | 10帧 | 降低可提升性能 | | 去重容差 | generateDetectionKey | 10像素 | 提高容差减少告警 | | 去重时间窗口 | processVideoWithRecord | 60秒 | 缩短窗口增加告警 | | 模型名称 | MODEL_NAME | yolov8_detector | 与Python配置对应 | ## 🚀 API接口 ### Python服务接口 **请求**: ```http POST http://rtsp-python-service:8000/api/detect/file Content-Type: multipart/form-data model_name: yolov8_detector file: [图像文件] ``` **响应**: ```json { "model_name": "yolov8_detector", "detections": [ { "label": "[yolov8_detector] 垃圾", "confidence": 0.95, "x": 100, "y": 200, "width": 150, "height": 180, "color": 65280 } ], "inference_time": 45.6 } ``` ## 🎬 使用示例 ### 示例1: 创建并执行巡检任务 ```java // 1. 创建任务 InspectionTask task = new InspectionTask(); task.setDeviceId(5001L); task.setDuration(30); // 30秒 task.setStatus(0); // 待执行 inspectionTaskService.insertInspectionTask(task); // 2. 启动任务(异步) inspectionTaskService.executeInspectionTask(task.getTaskId()); // 3. 查询执行记录 List records = inspectionTaskRecordService.selectInspectionTaskRecordList( new InspectionTaskRecord().setTaskId(task.getTaskId()) ); ``` ### 示例2: 查询告警 ```java // 查询某任务的所有告警 AlarmRecord query = new AlarmRecord(); query.setTaskId(1001L); query.setStatus(0); // 未处理 List alarms = alarmRecordService.selectAlarmRecordList(query); ``` ## ⚠️ 注意事项 ### 1. 执行时间 - 录制视频需要时间(与duration设置一致) - AI分析需要额外时间(取决于视频长度和CPU性能) - 总执行时间 ≈ duration + 分析时间 ### 2. 存储空间 每次执行会产生: - 原始视频(~10-50MB,30秒) - 处理后视频(~10-50MB) - 告警图片(每个~100-500KB) 建议定期清理历史数据。 ### 3. Python服务调用 - 使用HTTP调用Python服务 - 每帧调用可能较慢(已优化为每10帧) - CPU模式下建议降低检测频率 ### 4. MinIO存储 - 确保bucket已创建: - `inspection-videos`(巡检视频) - `alarm-images`(告警图片) - 确保外部MinIO服务可访问 ## 🔍 测试清单 ### 部署后测试 - [ ] Python服务可访问 ```bash curl http://rtsp-python-service:8000/health curl http://rtsp-python-service:8000/api/models ``` - [ ] MinIO bucket已创建 ```bash # 登录MinIO管理界面创建bucket # 或使用mc命令创建 ``` - [ ] 创建测试任务 ```sql INSERT INTO v_inspection_task (device_id, duration, status) VALUES (1, 30, 0); ``` - [ ] 执行任务并查看记录 ```sql SELECT * FROM v_inspection_task_record ORDER BY create_time DESC LIMIT 1; ``` - [ ] 查看生成的告警 ```sql SELECT * FROM v_alarm_record ORDER BY create_time DESC LIMIT 10; ``` - [ ] 验证视频URL可访问 ``` 访问record.accessory中的URL ``` ## 📊 预期结果 ### 成功执行的记录 ```json { "recordId": 2001, "taskId": 1001, "executeTime": "2025-09-30 14:30:00", "duration": 32, "accessory": "http://49.232.154.205:10900/inspection-videos/inspection_1001_1696056600000.mp4;http://49.232.154.205:10900/inspection-videos/processed_1696056632000.mp4", "result": "共检测到 5 个问题,详情:垃圾(3) 烟雾(2)", "status": 0 } ``` ### 生成的告警 ```json { "alarmId": 3001, "deviceId": 5001, "taskId": 1001, "alarmType": "detection", "alarmContent": "垃圾 - 置信度: 0.95", "imageOssId": 4001, "framePosition": 150, "confidence": 0.95, "status": 0 } ``` ## 🛠️ 维护和优化 ### 1. 清理历史数据 ```sql -- 删除30天前的记录 DELETE FROM v_inspection_task_record WHERE execute_time < DATE_SUB(NOW(), INTERVAL 30 DAY); -- 删除已处理的告警 DELETE FROM v_alarm_record WHERE status = 1 AND create_time < DATE_SUB(NOW(), INTERVAL 7 DAY); ``` ### 2. 性能监控 ```sql -- 查看最近的执行统计 SELECT DATE(execute_time) as date, COUNT(*) as total_executions, SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as success_count, AVG(duration) as avg_duration FROM v_inspection_task_record WHERE execute_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(execute_time) ORDER BY date DESC; ``` ### 3. 告警统计 ```sql -- 查看最近的告警统计 SELECT DATE(create_time) as date, alarm_type, COUNT(*) as count, AVG(confidence) as avg_confidence FROM v_alarm_record WHERE create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(create_time), alarm_type ORDER BY date DESC, count DESC; ``` ## 📞 故障排查 ### 问题1: Record未创建 **症状**:执行任务但`v_inspection_task_record`表无数据 **检查**: ```sql SELECT * FROM v_inspection_task WHERE task_id = ?; ``` **解决**: - 确认任务状态为0(待执行) - 查看后端日志 - 检查Mapper XML配置 ### 问题2: Accessory为空 **症状**:Record创建了但accessory字段为空 **检查**: ```bash # 查看MinIO上传日志 docker-compose logs backend | grep "MinIO" # 测试MinIO连接 curl http://49.232.154.205:10900/minio/health/live ``` **解决**: - 确认MinIO服务可访问 - 检查application.yml中的MinIO配置 - 确认bucket已创建 ### 问题3: Result为空 **症状**:视频已保存但result字段为空 **检查**: ```bash # 查看Python服务日志 docker-compose logs python-service # 测试Python服务 curl http://rtsp-python-service:8000/api/models ``` **解决**: - 确认Python服务运行正常 - 确认best.pt模型文件存在 - 检查容器间网络通信 ### 问题4: 告警重复 **症状**:相同对象产生多个告警 **调整去重参数**: ```java // 在generateDetectionKey中增大容差 int x = rect.x() / 20 * 20; // 从10改为20 int y = rect.y() / 20 * 20; ``` ## 📖 相关文档 - `INSPECTION-WORKFLOW.md` - 详细工作流程 - `YOLOV8-SETUP.md` - YOLOv8模型配置 - `DEPLOYMENT-NOTES.md` - 部署配置说明 - `DOCKER-QUICK-START.md` - Docker快速开始 --- **功能状态**: ✅ 已实现 **测试状态**: 待测试 **文档版本**: 1.0 **最后更新**: 2025-09-30 �� **巡检任务记录功能已完整实现!**