package com.sercurityControl.proteam.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSON; import com.securityControl.common.core.constant.CacheConstants; import com.securityControl.common.core.utils.DateUtils; import com.securityControl.common.core.utils.StringUtils; import com.securityControl.common.redis.service.RedisService; import com.sercurityControl.proteam.domain.TEquipment; import com.sercurityControl.proteam.domain.TImageLibrary; import com.sercurityControl.proteam.mapper.TEquipmentMapper; import com.sercurityControl.proteam.mapper.TImageLibraryMapper; import com.sercurityControl.proteam.service.TImageLibraryService; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.*; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * @author xxx */ @Component @Slf4j public class VideoUtil { private static final Map responseMp = new HashMap<>(16); @Resource public RedisService redisService; /** * 统一视频平台地址 */ @Value("${video.address}") private String VIDEO_ADDRESS; /** * 统一视频平台账号 */ @Value("${video.username}") private String VIDEO_USERNAME; /** * 统一视频平台密码 */ @Value("${video.password}") private String VIDEO_PASSWORD; /** * 图片文件存储在本地的根路径 */ /* @Value("${file.path}") private String localFilePath;*/ /** * 人工智能平台请求接口 */ @Value("${ai.url}") private String url; /** * 配置是否启用抓图到人工智能平台(0-未启用,1-启用) */ private Integer VIDEO_START=0; @Autowired private TImageLibraryService tImageLibraryService; @Autowired private TImageLibraryMapper tImageLibraryMapper; @Autowired private TEquipmentMapper tEquipmentMapper; @Resource(name = "testTaskExecutor") private ThreadPoolTaskExecutor taskExecutor; /** * 违章类型 */ private static final String[] RISK_CONSTANTS = new String[]{"未佩戴安全帽", "未规范着装", "未佩戴安全带", "警戒区闯入", "吸烟", "作业无监护", "登高行为", "作业现场无人"}; /** * 登录统一视频平台登录接口 */ private final String LOGIN_URL = "/uvp-backend-common/api/v1/authorization"; /** * 统一视频平台获取设备列表 */ private final String DEVICE_LIST = "/uvp-backend-mc/api/v1/resource/getDevListByDev?ak=%s&token=%s×tamp=%s&nonce=%s"; /** * 统一视频平台单次抓图 */ private final String CATCH_PICTURE = "/uvp-micro-service/storage/api/v1/snap?ak=%s&token=%s×tamp=%s&nonce=%s"; /** * 统一视屏平台下载图片文件 */ private final String DOWNLOAD_PICTURE = "/uvp-micro-service/download?fileid=%s&ak=%s&token=%s×tamp=%s&nonce=%s"; /** * 从第三方文件服务器中下载图片 */ public void downloadPic() { if (Objects.equals(0, 0)) { log.warn("++++++++++++++++未启用人工智能平台相关功能之图片下载+++++++++++"); return; } log.info("++++++++启用人工智能平台之图片下载++++++++++++"); String token = getToken(); if (StringUtils.isEmpty(token)) { log.error("==========单次抓图,获取统一视频平台token异常======"); return; } //获取所有的设备列表 List equipmentList = tEquipmentMapper.getAllEquipmentList(); if (CollUtil.isEmpty(equipmentList)) { log.info("=============本地设备列表数据为空========"); return; } for (TEquipment equipment : equipmentList) { taskExecutor.submit(() -> { Integer status = equipment.getStatus(); if (1 != status) { //log.info("==========设备未启用code为:{}", equipment.getEquipCode()); return; } if (null == equipment.getFileId()) { return; } String COMPLETE_DOWNLOAD_PICTURE = VIDEO_ADDRESS + String.format(DOWNLOAD_PICTURE, equipment.getFileId(), VIDEO_USERNAME, token, DateUtils.getTimeStamp(), UUID.randomUUID()); log.info("============统一视频下载图片地址为:{}", COMPLETE_DOWNLOAD_PICTURE); HttpResponse execute = HttpUtil.createGet(COMPLETE_DOWNLOAD_PICTURE).execute(); boolean ok = execute.isOk(); log.info("===========设备code:{},请求统一视屏中心下载图片结果是否成功:{}==========", equipment.getEquipCode(), ok ? "成功" : "失败"); if (ok) { log.info("===============统一视频下载图片请求成功==============="); String responseBody = execute.body(); //交给人工智能平台处理 //aiProcess(responseBody, equipment.getEquipCode(), equipment.getFileId()); } else { log.error("=============统一视频下载图片请求接口失败============="); } }); } } /** * 人工智能平台处理图片判断风险 * * @param base64Img 图片 * @param equipCode 设备code * @param fileId 第三方文件id */ private void aiProcess(String base64Img, String equipCode, String fileId) { log.info("==============进入人工智能处理图片信息流程============="); Map body = new HashMap<>(16); //aqm:安全帽,gz:未着装规范,aqd:未佩戴安全帽,jjqcr:警戒区闯入,xy:吸烟,zywjh:作业无监护 String[] arr = new String[]{"aqm", "gz", "aqd", "jjqcr", "xy", "zywjh"}; body.put("detect_type", arr); body.put("format", "0"); body.put("image", base64Img); HttpResponse execute = HttpUtil.createPost(url).body(JSON.toJSONString(body)).execute(); boolean ok = execute.isOk(); log.info("===========请求人工智能平台结果是否成功:{}==========", ok ? "成功" : "失败"); if (ok) { String responseBody = execute.body(); responseData responseData = JSON.parseObject(responseBody, responseData.class); List imageDefect = responseData.getImageDefect(); //本次动作 String className = imageDefect.stream().map(ImageDefect::getClassName).collect(Collectors.joining(",")); //是否含有违章行为 boolean illegal = hasIllegalBehavior(imageDefect); log.info("动作是否违章:{}", illegal ? "没有违章" : "违章"); log.info("-------动作是否违章:{}-------", illegal ? "没有违章" : "违章"); //获取上次动作 Map preEquipMap = (Map) responseMp.get(equipCode); String preClassName = (String) preEquipMap.get("className"); //有违章&&非重复动作 boolean repeatAndIllegal = hasIllegalBehaviorAndRepeat(illegal, preClassName, className); if (repeatAndIllegal) { log.info("设备code:{},发生动作变化,变化之前动作:{},变化之后动作:{}", equipCode, preClassName, className); log.info("------------设备code:{},发生动作变化,变化之前动作:{},变化之后动作:{}--------------", equipCode, preClassName, className); TImageLibrary imageLibrary = new TImageLibrary(); imageLibrary.setClassName(className); /*todo 上传到oss服务器*/ imageLibrary.setImgUrl(""); imageLibrary.setFileId(fileId); imageLibrary.setEquipCode(equipCode); imageLibrary.setStartTime(DateUtils.getNowDate()); imageLibrary.setEndTime(DateUtils.getNowDate()); tImageLibraryService.insert(imageLibrary); //查询该动作最新的一条数据 if (null != preClassName) { //修改最近动作结束时间 TImageLibrary preImage = tImageLibraryMapper.getByClassNameAndCode(preClassName, equipCode); if (null != preImage) { preImage.setEndTime(DateUtils.getNowDate()); tImageLibraryService.updateEndTime(preImage); } } } //记录本次动作 Map afterEquipMap = new HashMap<>(16); afterEquipMap.put("className", className); responseMp.put(equipCode, afterEquipMap); } else { log.error("--------请求人工智能平台失败:{}", execute); } } /** * 单次抓图 */ public void catchPicture() { if (Objects.equals(VIDEO_START, 0)) { log.warn("++++++++++++++++ stop catch picture running, place check the nacos config the value of video.start +++++++++++"); return; } log.info("+++++++++++++++++ start catch picture +++++++++++++++++"); String token = getToken(); if (StringUtils.isEmpty(token)) { log.error("========== catch picture interface, get token error ======"); return; } String COMPLETE_CATCH_PICTURE = VIDEO_ADDRESS + String.format(CATCH_PICTURE, VIDEO_USERNAME, token, DateUtils.getTimeStamp(), UUID.randomUUID()); // log.info("============!!!!!!!!========= catch picture interface url is :{}", COMPLETE_CATCH_PICTURE); //获取所有的设备列表 List equipmentList = tEquipmentMapper.getAllEquipmentList(); if (CollUtil.isEmpty(equipmentList)) { log.info("============= there is no equipmentList in dataBase ========"); return; } log.info("============ equipmentList number is :{} ========", equipmentList.size()); //for (TEquipment equipment : equipmentList) { for (int i = 0; i < 3; i++) { TEquipment equipment = equipmentList.get(i); //taskExecutor.execute(() -> { String equipCode = equipment.getEquipCode(); Integer status = equipment.getStatus(); if (1 != status) { //log.info("=========== equipment off line the code is:{},do not execution =========", equipCode); return; } log.info("============== equipment on the line, the code is :{}, execute catch picture ==========", equipCode); Map body = new HashMap<>(16); body.put("sessionId", UUID.randomUUID()); body.put("code", equipCode); log.info("============!!!!!!!!========= catch picture interface url is :{}", COMPLETE_CATCH_PICTURE); log.info("============!!!!!!!!========= catch picture interface query body is :{}", JSON.toJSONString(body)); HttpResponse execute = HttpUtil.createPost(COMPLETE_CATCH_PICTURE).body(JSON.toJSONString(body)).execute(); boolean ok = execute.isOk(); log.info("================= equipment code:{}, response header from catch picture :{}", equipCode, JSON.toJSONString(execute.headers())); log.info("================= equipment code:{}, response body from catch picture :{}", equipCode, JSON.toJSONString(execute.body())); log.info("================= equipment code:{}, response status from catch picture :{}", equipCode, JSON.toJSONString(execute.getStatus())); if (ok) { String responseBody = execute.body(); CommonResp commonResp = JSON.parseObject(responseBody, CommonResp.class); if (Objects.equals("true", commonResp.successful)) { log.info("============= equipment code:{}, result by catch picture is :{}", equipCode, "success!!!"); Map resultValue = commonResp.resultValue; String fileUrl = (String) resultValue.get("fileUrl"); String[] split = fileUrl.split("="); String fileId = split[1]; //更新抓取的图片信息 TEquipment updateEquip = new TEquipment(); updateEquip.setId(equipment.getId()); updateEquip.setFileUrl(fileUrl); updateEquip.setFileId(fileId); updateEquip.setCatchTime(new Date()); tEquipmentMapper.update(updateEquip); } else { log.info("============= equipment code:{}, result by catch picture is :{}", equipCode, "error!!!"); } } //}); } log.info("+++++++++++++++++ end catch picture +++++++++++++++++"); } public String toStr(Object obj) { if (null == obj) { return null; } return String.valueOf(obj); } /** * 同步统一视频中心设备列表 */ public void asyncDeviceList() { if (Objects.equals(0, 0)) { log.warn("++++++++++++++++未启用人工智能平台相关功能之同步设备+++++++++++"); return; } log.info("++++++++启用人工智能平台之同步设备++++++++++++"); String token = getToken(); if (StringUtils.isEmpty(token)) { log.error("==========同步设备,获取统一视频平台token异常======"); return; } // String COMPLETE_DEVICE_LIST = String.format(DEVICE_LIST, VIDEO_USERNAME, token, DateUtils.getTimeStamp(), UUID.randomUUID()); String COMPLETE_DEVICE_LIST = VIDEO_ADDRESS + String.format(DEVICE_LIST, VIDEO_USERNAME, token, DateUtils.getTimeStamp(), UUID.randomUUID()); DeviceQueryVo deviceQueryVo = new DeviceQueryVo(); /*todo 其他参数未知*/ List list = new ArrayList<>(); list.add("01"); deviceQueryVo.setDevType(list); deviceQueryVo.setPageNo(1); deviceQueryVo.setPageSize(10); log.info("================第一次请求统一视频同步设备接口参数:{}", JSON.toJSONString(deviceQueryVo)); log.info("================第一次请求统一视频同步设备接口地址为:{}", COMPLETE_DEVICE_LIST); HttpResponse execute = HttpUtil.createPost(COMPLETE_DEVICE_LIST).body(JSON.toJSONString(deviceQueryVo)).execute(); boolean ok = execute.isOk(); log.info("第一次请求统一视频平台获取设备列表接口结果是否成功:{}", ok ? "成功" : "失败"); log.info("===========第一次请求统一视屏平台获取设备列表接口结果是否成功:{}", ok ? "成功" : "失败"); if (ok) { String responseBody = execute.body(); log.info("第一次请求统一视频平台返回结果:{}", responseBody); log.info("========获取统一视频设备列表,第一次请求统一视频平台返回结果:{}", responseBody); CommonResp commonResp = JSON.parseObject(responseBody, CommonResp.class); if (Objects.equals("true", commonResp.successful)) { List thirdEquipmentList = new ArrayList<>(); Map resultValue = commonResp.getResultValue(); Integer total = (Integer) resultValue.get("total"); //每页5000条 double value = NumberUtil.div(String.valueOf(total), "5000").doubleValue(); int pageNum = (int) Math.ceil(value); //查询本地是否有重复数据 List allEquipmentIdList = tEquipmentMapper.getEquipmentIdList(); //查询的总数量 int totalCount = 0; //新增的总数量 int insertCount = 0; //删除的总数量 int deleteCount = 0; for (int i = 1; i <= pageNum; i++) { List insertEquipmentList = new ArrayList<>(); DeviceQueryVo deviceQueryBody = new DeviceQueryVo(); /*todo 其他参数未知*/ deviceQueryBody.setDevType(list); deviceQueryBody.setPageNo(pageNum); deviceQueryBody.setPageSize(5000); HttpResponse afterExecute = HttpUtil.createPost(COMPLETE_DEVICE_LIST).body(JSON.toJSONString(deviceQueryBody)).execute(); boolean executeOk = afterExecute.isOk(); log.info("第{}次请求统一视屏平台获取设备列表接口结果是否成功:{}", i + 1, executeOk ? "成功" : "失败"); if (executeOk) { CommonResp resp = JSON.parseObject(afterExecute.body(), CommonResp.class); Map respResultValue = resp.getResultValue(); List> devList = (List>) respResultValue.get("devList"); TEquipment equipment; for (Map map : devList) { totalCount++; //如果没有则新增 String equipId = toStr(map.get("id")); if (!allEquipmentIdList.contains(equipId)) { equipment = new TEquipment(); equipment.setEquipCode(toStr(map.get("devCode"))); equipment.setEquipId(equipId); equipment.setEquipType(toStr(map.get("devType"))); equipment.setEquipName(toStr(map.get("devName"))); equipment.setEquipShortName(toStr(map.get("devShortName"))); equipment.setNodeCode(toStr(map.get("nodeCode"))); equipment.setStatus((Integer) map.get("status")); equipment.setDecoderTag(toStr(map.get("decoderTag"))); equipment.setLongitude(toStr(map.get("longLtude"))); equipment.setLatitude(toStr(map.get("latLtude"))); equipment.setCreateTime(DateUtils.parseDate(toStr(map.get("createTime")))); equipment.setUpdateTime(DateUtils.parseDate(toStr(map.get("updateTime")))); equipment.setScore((Integer) map.get("socre")); insertEquipmentList.add(equipment); } //第三方的所有数据 thirdEquipmentList.add(equipId); } } //批量新增 List> split = CollUtil.split(insertEquipmentList, 500); for (List equipmentList : split) { int rows = tEquipmentMapper.insertBatch(equipmentList); insertCount += rows; } } log.info("查询统一视频平台所有的数据量为:{}条", totalCount); log.info("新增入数据库数据量为:{}", insertCount); //移除多余的设备 /*List collect = allEquipmentIdList.stream().filter(it -> !thirdEquipmentList.contains(it)).collect(Collectors.toList()); tEquipmentMapper.deleteByIds(StringUtils.join(collect, ","));*/ } } } /** * 统一视频平台登录获取token * * @return */ private String getToken() { String token = redisService.getCacheObject(getTokenKey(VIDEO_USERNAME)); if (StringUtils.isNotEmpty(token)) { return token; } else { log.info("=========获取新的token========="); Map body = new HashMap<>(16); body.put("ak", VIDEO_USERNAME); body.put("sk", Base64.getEncoder().encodeToString(VIDEO_PASSWORD.getBytes())); HttpResponse execute = HttpUtil.createPost(VIDEO_ADDRESS + LOGIN_URL).body(JSON.toJSONString(body)).execute(); log.info("=======获取token接口参数为:{}", JSON.toJSONString(body)); String COMPLETE_AUTH_URL = VIDEO_ADDRESS + LOGIN_URL; log.info("=======获取token接口请求地址为:{}", COMPLETE_AUTH_URL); // HttpResponse execute = HttpUtil.createPost(COMPLETE_AUTH_URL).body(JSON.toJSONString(body)).execute(); boolean ok = execute.isOk(); log.info("请求统一视屏平台登录接口结果是否成功:{}", ok ? "成功" : "失败"); if (ok) { log.info("===========请求统一视频平台接口通畅========"); String responseBody = execute.body(); log.info("统一视屏平台登录返回结果:{}", responseBody); AuthResultDto authResultDto = JSON.parseObject(responseBody, AuthResultDto.class); if (Objects.equals("true", authResultDto.getSuccessful())) { token = authResultDto.getResultValue().getToken(); log.info("========获取的token成功======="); redisService.setCacheObject(getTokenKey(VIDEO_USERNAME), token, CacheConstants.VIDEO_TOKEN_KEY_EXPIRATION, TimeUnit.MINUTES); return token; } else { log.error("=============获取token失败============"); } } else { log.error("====获取token接口请求失败=======返回结果为:{}", execute); } return null; } } /** * 判断是否违章 * * @param imageDefect * @return */ private boolean hasIllegalBehavior(List imageDefect) { boolean illegal = true; for (String risk : RISK_CONSTANTS) { boolean contains = imageDefect.stream().map(ImageDefect::getClassName).collect(Collectors.toList()).contains(risk); if (contains) { illegal = false; break; } } return illegal; } /** * 是否为重复动作&& 是否违章 */ private boolean hasIllegalBehaviorAndRepeat(boolean illegal, String preClassName, String className) { boolean repeat = Objects.equals(preClassName, className); return illegal && !repeat; } @Data private static class responseData { private String resultCode; private String resultMsg; private List imageDefect; public String getResultCode() { return resultCode; } public void setResultCode(String resultCode) { this.resultCode = resultCode; } public String getResultMsg() { return resultMsg; } public void setResultMsg(String resultMsg) { this.resultMsg = resultMsg; } public List getImageDefect() { return imageDefect; } public void setImageDefect(List imageDefect) { this.imageDefect = imageDefect; } } @Data private static class ImageDefect { private String className; public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } } @Data private static class AuthResultDto { private String successful; private ResultValue resultValue; private String resultHint; @Data private static class ResultValue { private String ak; private String token; } } /** * 登录账户密码错误次数缓存键名 * * @param username 用户名 * @return 缓存键key */ private String getTokenKey(String username) { return CacheConstants.VIDEO_TOKEN_KEY + username; } @Data private static class DeviceQueryVo { /** * 设备标签集合 */ private List devDecoderTagList; /** * 设备名称 */ private List devName; /** * 设备名称 */ private List devSocreList; /** * 设备状态集合 */ private List devStatusList; /** * 设备评级集合 */ private List devType; private int pageNo; private int pageSize; } @Data public static class CommonResp { private String successful; private Map resultValue; private String resultHint; } }