Kaynağa Gözat

1、去掉部分中心侧、边缘侧的区分配置,当前不分中心侧和边缘测;
2、新增摄像头上传文件通知算法;
3、完善算法调用接口的记录情况;

pc147123 5 ay önce
ebeveyn
işleme
d1ec7bee0e
24 değiştirilmiş dosya ile 442 ekleme ve 166 silme
  1. 10 3
      pom.xml
  2. 1 1
      src/main/java/com/example/unusualsounds/UnusualSoundsApplication.java
  3. 44 0
      src/main/java/com/example/unusualsounds/common/utils/VoiceAnalysisUtils.java
  4. 12 1
      src/main/java/com/example/unusualsounds/framework/minio/MinioUtil.java
  5. 2 2
      src/main/java/com/example/unusualsounds/project/device/service/impl/DeviceVoiceServiceImpl.java
  6. 10 16
      src/main/java/com/example/unusualsounds/project/device/service/impl/DevicesSoundSensorsServiceImpl.java
  7. 15 27
      src/main/java/com/example/unusualsounds/project/vox/config/VideoTaskManager.java
  8. 30 16
      src/main/java/com/example/unusualsounds/project/vox/controller/CheckVoxController.java
  9. 1 0
      src/main/java/com/example/unusualsounds/project/vox/entity/Alarms.java
  10. 5 0
      src/main/java/com/example/unusualsounds/project/vox/service/VideoService.java
  11. 1 1
      src/main/java/com/example/unusualsounds/project/vox/service/VoiceTicketLogsService.java
  12. 1 1
      src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmsServiceImpl.java
  13. 10 15
      src/main/java/com/example/unusualsounds/project/vox/service/impl/EdgeOrganizationServiceImpl.java
  14. 22 8
      src/main/java/com/example/unusualsounds/project/vox/service/impl/SkillsServiceImpl.java
  15. 66 2
      src/main/java/com/example/unusualsounds/project/vox/service/impl/VideoServiceImpl.java
  16. 2 1
      src/main/java/com/example/unusualsounds/project/vox/service/impl/VoiceTicketLogsServiceImpl.java
  17. 7 16
      src/main/java/com/example/unusualsounds/project/vox/service/impl/VoxServiceImpl.java
  18. 74 10
      src/main/java/com/example/unusualsounds/project/vox/task/TicketsTask.java
  19. 25 5
      src/main/resources/application-dev.yml
  20. 29 7
      src/main/resources/application-prod.yml
  21. 2 32
      src/main/resources/application.yml
  22. 22 0
      src/main/resources/banner.txt
  23. 2 2
      src/main/resources/logback.xml
  24. 49 0
      src/test/java/com/example/unusualsounds/UnusualSoundsApplicationTests.java

+ 10 - 3
pom.xml

@@ -7,7 +7,7 @@
     <version>0.0.1-SNAPSHOT</version>
     <name>unusualSounds</name>
     <description>unusualSounds</description>
-
+    <packaging>jar</packaging>
     <properties>
         <java.version>17</java.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -23,10 +23,17 @@
         <dynamic.version>3.6.1</dynamic.version>
         <fastjson.version>2.0.28</fastjson.version>
         <mybatis-plus-extension>3.3.0</mybatis-plus-extension>
+        <hutool.version>5.8.16</hutool.version>
     </properties>
     <dependencies>
 
-<!--        <dependency>-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+
+        <!--        <dependency>-->
 <!--            <groupId>com.baomidou</groupId>-->
 <!--            <artifactId>mybatis-plus-extension</artifactId>-->
 <!--            <version>${mybatis-plus-extension}</version>-->
@@ -210,7 +217,7 @@
                 <version>${spring-boot.version}</version>
                 <configuration>
                     <mainClass>com.example.unusualsounds.UnusualSoundsApplication</mainClass>
-                    <skip>true</skip>
+                    <skip>false</skip>
                 </configuration>
                 <executions>
                     <execution>

+ 1 - 1
src/main/java/com/example/unusualsounds/UnusualSoundsApplication.java

@@ -17,7 +17,7 @@ public class UnusualSoundsApplication {
     @Autowired
     //RestTemplateBuilder
     private RestTemplateBuilder builder;
-    // 使用RestTemplateBuilder来实例化RestTemplate对象,spring默认已经注入了RestTemplateBuilder实例
+    // spring默认已经注入了RestTemplateBuilder实例
     @Bean
     public RestTemplate restTemplate() {
         return builder.build();

+ 44 - 0
src/main/java/com/example/unusualsounds/common/utils/VoiceAnalysisUtils.java

@@ -0,0 +1,44 @@
+package com.example.unusualsounds.common.utils;
+
+import jakarta.annotation.Resource;
+import lombok.extern.java.Log;
+import org.hibernate.validator.constraints.Length;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * 音频算法分析类
+ */
+@Log
+@Component
+public final class VoiceAnalysisUtils {
+
+    private static RestTemplate restTemplateStatic;
+    @Autowired
+    public void setRestTemplate(RestTemplate restTemplate) {
+        VoiceAnalysisUtils.restTemplateStatic = restTemplate;
+    }
+
+    public static String postVoxAnalysis(Map<String,Object> maps,String postAnalysisUrl){
+
+        HttpHeaders httpHeaders = new HttpHeaders();
+        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<Map<String, Object>> mapHttpEntity = new HttpEntity<>(maps, httpHeaders);
+        try {
+            ResponseEntity<String> stringResponseEntity = restTemplateStatic.postForEntity(postAnalysisUrl, mapHttpEntity, String.class);
+            if (stringResponseEntity.getStatusCode() == HttpStatus.OK){
+                return "通知算法成功";
+            }
+            return "通知算法失败";
+        }catch (Exception e){
+            return "发送失败:"+e.getMessage();
+        }
+
+    }
+
+}

+ 12 - 1
src/main/java/com/example/unusualsounds/framework/minio/MinioUtil.java

@@ -3,6 +3,7 @@ package com.example.unusualsounds.framework.minio;
 import com.example.unusualsounds.common.utils.DateUtils;
 import com.example.unusualsounds.common.utils.UUID;
 import io.minio.*;
+import io.minio.errors.*;
 import io.minio.http.Method;
 import io.minio.messages.Bucket;
 import io.minio.messages.Item;
@@ -16,6 +17,13 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.FastByteArrayOutputStream;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -160,7 +168,7 @@ public class MinioUtil {
                 byte[] bytes = os.toByteArray();
                 res.setCharacterEncoding("utf-8");
                 // 设置强制下载不打开
-                // res.setContentType("application/force-download");
+                res.setContentType("application/force-download");
                 res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                 try (ServletOutputStream stream = res.getOutputStream()){
                     stream.write(bytes);
@@ -172,6 +180,9 @@ public class MinioUtil {
         }
     }
 
+
+
+
     /**
      * 查看文件对象
      * @return 存储bucket内文件对象信息

+ 2 - 2
src/main/java/com/example/unusualsounds/project/device/service/impl/DeviceVoiceServiceImpl.java

@@ -11,13 +11,13 @@ import java.util.List;
 public class DeviceVoiceServiceImpl implements DeviceVoiceService {
 
 
-    private static final List<String> SUPPORTED_AUDIO_FORMATS = Arrays.asList("mp4",".mp3", ".wma", ".wav", ".aac", ".flac");
+    private static final List<String> SUPPORTED_AUDIO_FORMATS = Arrays.asList("mp4","mp3", "wma", "wav", "aac", "flac");
 
 
     @Override
     public boolean checkVoiceFile(String fileName, Long fileSize) {
 
-        if(fileSize > 1024 * 1024*50){
+        if(fileSize > 1024*1024*50){
             return false;
         }
         String s = fileName.split("\\.")[1].toLowerCase();

+ 10 - 16
src/main/java/com/example/unusualsounds/project/device/service/impl/DevicesSoundSensorsServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.example.unusualsounds.common.utils.BaiDuUtils;
 import com.example.unusualsounds.common.utils.RedisUtils;
 import com.example.unusualsounds.common.utils.UUID;
+import com.example.unusualsounds.common.utils.VoiceAnalysisUtils;
 import com.example.unusualsounds.project.device.entity.DevicesSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.RegisterSoundSensors;
 import com.example.unusualsounds.project.device.entity.vo.SoundSensorsQueryVo;
@@ -95,6 +96,7 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
 
         if("file".equals(soundSensors.getSoundSensorType())){
             Object o = RedisUtils.get(soundSensors.getSoundFileUUid());
+
             devicesSoundSensors.setStreamUrl(o.toString());
             devicesSoundSensors.setSrcUrl(o.toString());
             devicesSoundSensors.setStatus("online");
@@ -127,8 +129,6 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
             this.analysisSoundFile(devicesSoundSensors.getSrcUrl(),skills.getName(), devicesSoundSensors.getUuid(),
                     devicesSoundSensors.getName(),soundSensors.getSkillUuid());
         }
-
-
         if (insert > 0){
             return true;
         }else {
@@ -228,20 +228,14 @@ public class DevicesSoundSensorsServiceImpl extends ServiceImpl<DevicesSoundSens
         CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
             log.info("通知算法解析用户自定义上传文件");
 
-            HashMap<String, Object> hashMap = new HashMap<>();
-            hashMap.put("filePath",filePath);
-            hashMap.put("skillName",skillName);
-            hashMap.put("streamId",streamId);
-            hashMap.put("deviceName",deviceName);
-            hashMap.put("skillId",skillId);
-
-            HttpHeaders httpHeaders = new HttpHeaders();
-            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
-            HttpEntity<Map<String, Object>> mapHttpEntity = new HttpEntity<Map<String, Object>>(hashMap, httpHeaders);
-            ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(postAnalysisUrl, mapHttpEntity, String.class);
-            if (stringResponseEntity.getStatusCode() == HttpStatus.OK){
-                log.info("通知算法成功");
-            }
+            Map<String, Object> map = new HashMap<>();
+            map.put("filePath",filePath);
+            map.put("skillName",skillName);
+            map.put("streamId",streamId);
+            map.put("deviceName",deviceName);
+            map.put("skillId",skillId);
+
+            log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
 
         },executorService);
         try {

+ 15 - 27
src/main/java/com/example/unusualsounds/project/vox/config/VideoTaskManager.java

@@ -2,6 +2,7 @@ package com.example.unusualsounds.project.vox.config;
 
 import com.example.unusualsounds.common.utils.FileToMultipartFile;
 import com.example.unusualsounds.common.utils.RedisUtils;
+import com.example.unusualsounds.common.utils.VoiceAnalysisUtils;
 import com.example.unusualsounds.framework.minio.MinioUtil;
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -39,8 +40,6 @@ public class VideoTaskManager {
     @Autowired
     private  MinioUtil minioUtil;
 
-    @Autowired
-    private RestTemplate restTemplate;
 
     private final ConcurrentMap<String, VideoTask> taskMap = new ConcurrentHashMap<>();
 
@@ -92,7 +91,6 @@ public class VideoTaskManager {
 
     @Data
     private class VideoTask {
-        //streamId = streamId+ skillName
         private final String streamId;
         private final String rtspUrl;
         private String skillName;
@@ -113,13 +111,14 @@ public class VideoTaskManager {
 
         void start() {
             List<String> command = Arrays.asList(
-                    "D:\\file\\ffmpeg\\ffmpeg.exe",
+//                    "D:\\file\\ffmpeg\\ffmpeg.exe",
+                    "ffmpeg",
                     "-rtsp_transport", "tcp",
                     "-i", rtspUrl,
                     "-vn",
                     "-c", "copy",
                     "-f", "segment",
-                    "-segment_time", "100",
+                    "-segment_time", "300", //100秒
                     "-segment_format", "mp4",
                     "-reset_timestamps", "1",
                     "-force_key_frames", "expr:gte(t,n_floor(t/100)*100)",
@@ -127,7 +126,6 @@ public class VideoTaskManager {
                     "-segment_atclocktime", "1",
                     "-strftime", "1",
                     videoDir+streamId+"-%Y-%m-%d_%H-%M-%S"+".mp4"
-//                    "D:\\tmp\\data\\vox\\"+streamId+".mp4"
             );
 
             ProcessBuilder pb = new ProcessBuilder(command)
@@ -225,7 +223,8 @@ public class VideoTaskManager {
                 while (true){
                 //检查文件是否完成
                     List<String> checkVoxFinish = Arrays.asList(
-                            "D:\\file\\ffmpeg\\ffmpeg.exe",
+//                            "D:\\file\\ffmpeg\\ffmpeg.exe",
+                            "ffmpeg",
                             "-v","error",
                             "-i", filePath,
                             "-f", "null",
@@ -244,8 +243,8 @@ public class VideoTaskManager {
                         log.error("checkVoxFinish:[{}]文件未完成",filePath);
                         //重置状态errorOutput状态
                         errorOutput.delete(0, errorOutput.length());
-                        //等待1分钟后再次检查
-                        Thread.sleep(60000);
+                        //等待2分钟后再次检查
+                        Thread.sleep(120000);
                     }else {
                         //上传文件
                         File file = new File(filePath);
@@ -255,22 +254,13 @@ public class VideoTaskManager {
                         log.info("上传文件:{}",upload);
 
                         //发送消息
-                        HashMap<String, Object> hashMap = new HashMap<>();
-                        hashMap.put("filePath",upload);
-                        hashMap.put("skillName",skillName);
-                        hashMap.put("streamId",streamId);
-                        hashMap.put("deviceName",deviceName);
-                        hashMap.put("skillId",skillId);
-
-
-                        HttpHeaders httpHeaders = new HttpHeaders();
-                        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
-                        HttpEntity<Map<String, Object>> mapHttpEntity = new HttpEntity<Map<String, Object>>(hashMap, httpHeaders);
-                        ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(postAnalysisUrl, mapHttpEntity, String.class);
-                        if (stringResponseEntity.getStatusCode() == HttpStatus.OK){
-                            log.info("通知算法成功");
-                        }
-
+                        Map<String, Object> map = new HashMap<>();
+                        map.put("filePath",upload);
+                        map.put("skillName",skillName);
+                        map.put("streamId",streamId);
+                        map.put("deviceName",deviceName);
+                        map.put("skillId",skillId);
+                        log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
                         break;
                     }
                 }
@@ -281,8 +271,6 @@ public class VideoTaskManager {
             }
         });
 
-
-
     }
 
 

+ 30 - 16
src/main/java/com/example/unusualsounds/project/vox/controller/CheckVoxController.java

@@ -47,43 +47,60 @@ public class CheckVoxController {
     public AjaxResult startStopVox(@RequestBody Device device) throws InterruptedException {
 
         String openUuid = UUID.generateUUIDWithoutHyphens();
-        //保存启停接口的设备信息到数据库,便于后续定时任务调用
-        voiceTicketLogsServiceImpl.saveStartStop(device,openUuid);
-
-
         //校验设备是否开启(包含传感器、摄像头),当前只做摄像头校验
         CameraDTO camera  = voxServiceImpl.checkDevice(device.getDeviceId());
-
         //-----测试(云环境的是mp4文件,不是rtsp流)
-        camera.setSrcURL("rtsp://192.168.1.120:8554/video");
+//        camera.setSrcURL("rtsp://192.168.1.112:8554/video");
+//        camera.setVideoType("");
         //-----测试
-
-
         if(camera == null || "offline".equals(camera.getStatus()) || "error".equals(camera.getStatus())){
+            //保存启停接口的设备信息到数据库,便于后续定时任务调用
+            voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"设备离线或出错");
             return AjaxResult.error("设备离线或出错");
+        }
+
+        System.out.println("摄像头查询:"+camera.toString());
+
+        Skill skill = device.getSkills().get(0);
+        boolean  skillOpen = device.getSkills().get(0).isOpen();
+        //设备为上传的文件,不需要
+        if("file".equals(camera.getVideoType())){
+            if(skillOpen){
+                videoServiceImpl.handlesVideoFile(camera.getSrcURL(),skill.getName(),camera.getId(),camera.getName(),skill.getId());
+                //保存启停接口的设备信息到数据库,便于后续定时任务调用
+                voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"算法已启动(源文件解析)");
+                return AjaxResult.success("算法已启动");
+            }else {
+                //保存启停接口的设备信息到数据库,便于后续定时任务调用
+                voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"算法已关闭(源文件解析)");
+                return AjaxResult.success("算法已关闭");
+            }
         }else{
-            Skill skill = device.getSkills().get(0);
-            boolean  skillOpen = device.getSkills().get(0).isOpen();
             if(skillOpen){
-
                 //添加校验视频流地址是否有效,无效则不启动算法
                 boolean checkStream = videoServiceImpl.checkStream(camera);
                 log.info("视频流地址校验结果:{}",checkStream);
                 if(!checkStream){
+                    //保存启停接口的设备信息到数据库,便于后续定时任务调用
+                    voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"视频流地址无效");
                     return AjaxResult.error("视频流地址无效");
                 }
-
                 //开启处理视频流和接入算法
                 videoServiceImpl.handlesStream(device.getDeviceId(),camera.getSrcURL(),skill,camera.getName(),openUuid);
+                //保存启停接口的设备信息到数据库,便于后续定时任务调用
+                voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"算法已启动(视频流解析)");
                 return AjaxResult.success("算法已启动");
             }else{
-                //关闭处理视频流和接入算法
+                //关闭处理视频流和接入算法 (使用定时任务的方式清理视频分片)
                 videoTaskManager.stopTask(device.getDeviceId()+"_"+skill.getName());
+                //保存启停接口的设备信息到数据库,便于后续定时任务调用
+                voiceTicketLogsServiceImpl.saveStartStop(device,openUuid,"算法已关闭(视频流解析)");
                 return AjaxResult.success("算法已关闭");
             }
 
         }
 
+
     }
 
 
@@ -104,7 +121,4 @@ public class CheckVoxController {
     }
 
 
-
-
-
 }

+ 1 - 0
src/main/java/com/example/unusualsounds/project/vox/entity/Alarms.java

@@ -439,6 +439,7 @@ public class Alarms implements Serializable {
         private String roisUuid = "";
         private String trackUuid = "";
         private String figures = "";
+//        private String type = "camera";
         private String type = "voice";
         private String triggerType = "auto";
         private String robotUuid = "";

+ 5 - 0
src/main/java/com/example/unusualsounds/project/vox/service/VideoService.java

@@ -33,4 +33,9 @@ public interface VideoService {
      * @return
      */
     boolean checkStream(CameraDTO camera);
+
+    /**
+     * 处理视频文件
+     */
+    void handlesVideoFile(String filePath,String skillName,String streamId,String deviceName,String skillId);
 }

+ 1 - 1
src/main/java/com/example/unusualsounds/project/vox/service/VoiceTicketLogsService.java

@@ -18,7 +18,7 @@ public interface VoiceTicketLogsService extends IService<VoiceTicketLogs> {
      * 一见调用算法时,保存发送的时间
      * @param device
      */
-    void saveStartStop(Device device,String openUuid);
+    void saveStartStop(Device device,String openUuid,String remark);
 
     /**
      * 获取正在运行的任务和表里的任务对比,返回超时的任务map<uuid,skillName>

+ 1 - 1
src/main/java/com/example/unusualsounds/project/vox/service/impl/AlarmsServiceImpl.java

@@ -31,7 +31,7 @@ public class AlarmsServiceImpl extends ServiceImpl<AlarmsMapper, Alarms>
 
 
     @Override
-    public boolean saveResultAnalysis(HashMap<String, String> resultAnalysis) {
+    public boolean  saveResultAnalysis(HashMap<String, String> resultAnalysis) {
 
         String deviceId = resultAnalysis.get("deviceId");
         String deviceName = resultAnalysis.get("deviceName");

+ 10 - 15
src/main/java/com/example/unusualsounds/project/vox/service/impl/EdgeOrganizationServiceImpl.java

@@ -33,22 +33,17 @@ public class EdgeOrganizationServiceImpl extends ServiceImpl<EdgeOrganizationMap
     @Value("${yijian-interface.organizations}")
     private String getOrganizations;
 
-    @Value("${yijian-interface.organizations-directors}")
-    private String getOrganizationDirectors;
-
     @Value("${yijian-interface.uri-path-prefix}")
     private String uriPathPrefix;
 
-    @Value("${yijian-interface.edge-ends.ak}")
-    private String edgeEndsAk;
-
-    @Value("${yijian-interface.edge-ends.sk}")
-    private String edgeEndsSk;
-
-    @Value("${yijian-interface.edge-ends.endpoint}")
-    private String edgeEndsEndpoint;
+    @Value("${yijian-interface.center.ak}")
+    private String ak;
 
+    @Value("${yijian-interface.center.sk}")
+    private String sk;
 
+    @Value("${yijian-interface.center.endpoint}")
+    private String endpoint;
 
 
     @Override
@@ -58,8 +53,8 @@ public class EdgeOrganizationServiceImpl extends ServiceImpl<EdgeOrganizationMap
 
         try {
             ResponseEntity<String> response = BaiDuUtils.sendRequest(getOrganizations, HttpMethodName.GET,
-                    null, null, String.class, edgeEndsAk, edgeEndsSk,
-                    edgeEndsEndpoint, uriPathPrefix);
+                    null, null, String.class, ak, sk,
+                    endpoint, uriPathPrefix);
             if (response.getStatusCode().is2xxSuccessful()) {
 
                 JSONArray objects = JSONArray.parseArray(response.getBody());
@@ -90,8 +85,8 @@ public class EdgeOrganizationServiceImpl extends ServiceImpl<EdgeOrganizationMap
     public String getOrganizationObj() {
 
         ResponseEntity<String> response = BaiDuUtils.sendRequest(getOrganizations, HttpMethodName.GET,
-                null, null, String.class, edgeEndsAk, edgeEndsSk,
-                edgeEndsEndpoint, uriPathPrefix);
+                null, null, String.class, ak, sk,
+                endpoint, uriPathPrefix);
         if (response.getStatusCode().is2xxSuccessful()) {
             return response.getBody();
         }else {

+ 22 - 8
src/main/java/com/example/unusualsounds/project/vox/service/impl/SkillsServiceImpl.java

@@ -7,6 +7,7 @@ import com.example.unusualsounds.project.vox.service.SkillsService;
 import com.example.unusualsounds.project.vox.mapper.SkillsMapper;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -36,14 +37,27 @@ public class SkillsServiceImpl extends ServiceImpl<SkillsMapper, Skills>
 
     @Override
     public List<Skills> getSkillByName(List<String> skillsName) {
-        QueryWrapper<Skills> queryWrapper = new QueryWrapper<Skills>();
-        if(skillsName.isEmpty()||skillsName.size()<1){
-            skillsName.add("人声呼救测试");
-            skillsName.add("设备异音测试");
-        }
-        queryWrapper.in("name", skillsName);
-        List<Skills> skills = baseMapper.selectList(queryWrapper);
-        return skills;
+//        QueryWrapper<Skills> queryWrapper = new QueryWrapper<Skills>();
+//        if(skillsName.isEmpty()||skillsName.size()<1){
+//            skillsName.add("人声呼救");
+//            skillsName.add("设备异音");
+//        }
+//        queryWrapper.in("name", skillsName);
+//        List<Skills> skills = baseMapper.selectList(queryWrapper);
+//        return skills;
+
+        //应现场要求,不进行动态获取查询,硬编码返回
+        List<Skills> skillsList = new ArrayList<>();
+        Skills skill1 = new Skills();
+        skill1.setName("人声呼救");
+        skill1.setUuid("172595901cda42ccbb18e2b8175bd6b5");
+        skillsList.add(skill1);
+        Skills skill2 = new Skills();
+        skill2.setName("设备异音");
+        skill2.setUuid("62b25f6697c4458084f51d45d8cc6cb5");
+        skillsList.add(skill2);
+        return skillsList;
+
     }
 }
 

+ 66 - 2
src/main/java/com/example/unusualsounds/project/vox/service/impl/VideoServiceImpl.java

@@ -1,22 +1,37 @@
 package com.example.unusualsounds.project.vox.service.impl;
 
+import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson2.JSON;
 import com.example.unusualsounds.common.utils.RedisUtils;
+import com.example.unusualsounds.common.utils.VoiceAnalysisUtils;
+import com.example.unusualsounds.framework.minio.MinioUtil;
 import com.example.unusualsounds.project.vox.config.VideoTaskManager;
 import com.example.unusualsounds.project.vox.entity.Alarms;
 import com.example.unusualsounds.project.vox.service.VideoService;
 import com.example.unusualsounds.web.jsonobj.CameraDTO;
 import com.example.unusualsounds.web.jsonobj.Skill;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
 
 import java.io.BufferedReader;
+import java.io.File;
 import java.io.InputStreamReader;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @Service
+@Slf4j
 public class VideoServiceImpl implements VideoService {
 
     @Autowired
@@ -28,6 +43,22 @@ public class VideoServiceImpl implements VideoService {
     @Autowired
     private SkillsServiceImpl skillsService;
 
+    @Value("${vox.video-dir}")
+    private String videoDir;
+
+    @Value("${minio.source-dir}")
+    private String sourceDir;
+
+    @Value("${vox.post-analysis-url}")
+    private String postAnalysisUrl;
+
+    @Autowired
+    private  MinioUtil minioUtil;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+
 
     @Override
     @Async("videoTaskExecutor")
@@ -76,7 +107,8 @@ public class VideoServiceImpl implements VideoService {
         Process process = null;
         try {
             ProcessBuilder processBuilder = new ProcessBuilder(
-                    "D:\\file\\ffmpeg\\ffprobe.exe",
+//                    "D:\\file\\ffmpeg\\ffprobe.exe",
+                    "ffprobe",
                     "-v", "error",
                     "-rtsp_transport", "tcp",
                     "-timeout", "15000000", // 单位:微秒
@@ -94,7 +126,7 @@ public class VideoServiceImpl implements VideoService {
                 if (errorReader.ready()) { // 检查是否有数据可读
                     line = errorReader.readLine();
                     if (line != null) {
-                        System.out.println("FFPROBE Error: " + line);
+                        log.info("FFPROBE Error: " + line);
                         hasError = true;
                         process.destroyForcibly();
                         break; // 发现错误立即退出
@@ -130,4 +162,36 @@ public class VideoServiceImpl implements VideoService {
         }
     }
 
+    @Override
+    public void handlesVideoFile(String filePath,String skillName,String streamId,String deviceName,String skillId) {
+        //同时支持20个用户上传文件解析
+        ExecutorService executorService = Executors.newFixedThreadPool(20);
+
+        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+            log.info("通知算法解析用户自定义上传文件");
+
+            Map<String, Object> map = new HashMap<>();
+            map.put("filePath",filePath);
+            map.put("skillName",skillName);
+            map.put("streamId",streamId);
+            map.put("deviceName",deviceName);
+            map.put("skillId",skillId);
+
+            log.info(VoiceAnalysisUtils.postVoxAnalysis(map, postAnalysisUrl));
+
+        },executorService);
+        try {
+            future.get();
+
+            executorService.shutdown();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+
+
 }

+ 2 - 1
src/main/java/com/example/unusualsounds/project/vox/service/impl/VoiceTicketLogsServiceImpl.java

@@ -27,7 +27,7 @@ public class VoiceTicketLogsServiceImpl extends ServiceImpl<VoiceTicketLogsMappe
     implements VoiceTicketLogsService{
 
     @Override
-    public void saveStartStop(Device device,String openUuid) {
+    public void saveStartStop(Device device,String openUuid,String remark) {
 
         VoiceTicketLogs voiceTicketLogs = new VoiceTicketLogs();
         voiceTicketLogs.setDeviceUuid(device.getDeviceId());
@@ -37,6 +37,7 @@ public class VoiceTicketLogsServiceImpl extends ServiceImpl<VoiceTicketLogsMappe
         voiceTicketLogs.setEndTimes(DateUtils.parseDate(device.getSkills().get(0).getTimes().get(0).getEnd()));
         voiceTicketLogs.setOpen(device.getSkills().get(0).isOpen() ? 1 : 0);
         voiceTicketLogs.setOpenUuid(openUuid);
+        voiceTicketLogs.setRemark(remark);
         boolean save = save(voiceTicketLogs);
     }
 

+ 7 - 16
src/main/java/com/example/unusualsounds/project/vox/service/impl/VoxServiceImpl.java

@@ -29,24 +29,15 @@ public class VoxServiceImpl implements VoxService {
 
 
     @Value("${yijian-interface.center.ak}")
-    private String centerAk;
+    private String ak;
 
     @Value("${yijian-interface.center.sk}")
-    private String centerSk;
+    private String sk;
 
     @Value("${yijian-interface.center.endpoint}")
-    private String centerEndpoint;
+    private String endpoint;
 
 
-    @Value("${yijian-interface.edge-ends.ak}")
-    private String edgeEndsAk;
-
-    @Value("${yijian-interface.edge-ends.sk}")
-    private String edgeEndsSk;
-
-    @Value("${yijian-interface.edge-ends.endpoint}")
-    private String edgeEndsEndpoint;
-
 
 
     @Override
@@ -55,8 +46,8 @@ public class VoxServiceImpl implements VoxService {
         try {
             String url = getDeviceInfoUrl.replace("{deviceID}", device_id);
             ResponseEntity<CameraDTO> response = BaiDuUtils.sendRequest(url, HttpMethodName.GET,
-                    null, null, CameraDTO.class, edgeEndsAk, edgeEndsSk,
-                    edgeEndsEndpoint, uriPathPrefix);
+                    null, null, CameraDTO.class, ak, sk,
+                    endpoint, uriPathPrefix);
 
             if (response.getStatusCode().is2xxSuccessful()) {
                 return response.getBody();
@@ -74,8 +65,8 @@ public class VoxServiceImpl implements VoxService {
     public String getGetOrganization(){
         try {
             ResponseEntity<String> response = BaiDuUtils.sendRequest(getOrganizations, HttpMethodName.GET,
-                    null, null, String.class, edgeEndsAk, edgeEndsSk,
-                    edgeEndsEndpoint, uriPathPrefix);
+                    null, null, String.class, ak, sk,
+                    endpoint, uriPathPrefix);
             if (response.getStatusCode().is2xxSuccessful()) {
                 return response.getBody();
             } else {

+ 74 - 10
src/main/java/com/example/unusualsounds/project/vox/task/TicketsTask.java

@@ -11,6 +11,10 @@ import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -23,6 +27,10 @@ import java.util.stream.Collectors;
  * 3. 只添加算法停接口因网络问题未收到停止的请求
  * 4. 忽略因网络问题未收到启动的请求,所以定时查询是自己表内已经插入的数据
  *
+ * 视频切片定时任务
+ * ---
+ * 用于回收已经解析完成的视频切片
+ *
  */
 @Component
 @Slf4j
@@ -38,14 +46,33 @@ public class TicketsTask {
     private String videoDir;
 
 
+    /**
+     * 每十分钟检查一次
+     */
     @Scheduled(cron = "0 */10 * * * ?")
     public void checkStopTickets() {
 
-        List<String> strings = this.stopTickets();
-        if (strings != null && strings.size() > 0) {
-            strings.forEach(s -> {
+        List<VoiceTicketLogs> voiceTicketLogs = this.stopTickets();
+        if (voiceTicketLogs != null && voiceTicketLogs.size() > 0) {
+
+            List<String> collect = voiceTicketLogs.stream().map(
+                            task -> {
+                                return task.getDeviceUuid() + "_" + task.getSkillName();
+                            })
+                    .distinct().collect(Collectors.toList());
+            collect.forEach(s -> {
                 try {
                     videoTaskManager.stopTask(s);
+                    //记录自动关闭
+                    voiceTicketLogs.forEach(
+                            ticketLog ->{
+                                if(s.equals(ticketLog.getDeviceUuid()+"_"+ticketLog.getSkillName())){
+                                    ticketLog.setId(null);
+                                    ticketLog.setRemark("算法已关闭(超时关闭)");
+                                    voiceTicketLogsServiceImpl.save(ticketLog);
+                                }
+                            }
+                    );
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
@@ -55,11 +82,48 @@ public class TicketsTask {
         }
     }
 
+
+    /**
+     * 每两小时检查一次
+     * @throws IOException
+     */
+    @Scheduled(cron = "0 2 * * * ?")
+    public void delVideoFile() throws IOException {
+        Path path = Paths.get(videoDir);
+        if(!Files.exists(path)) {
+            log.info("定时删除视频文件:{}路径不存在",videoDir);
+        };
+        List<VideoTaskManager.TaskStatus> taskStatuses = videoTaskManager.listTasks();
+        if(taskStatuses == null || taskStatuses.size() == 0) {
+            //没有工单任务执行,进行删除文件
+            Files.walkFileTree(path,new SimpleFileVisitor<>(){
+
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    if(file.getFileName().toString().toLowerCase().endsWith(".mp4")){
+                        Files.delete(file);
+                        log.info("定时删除视频切片:{}",file);
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+                @Override
+                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+                    log.error("定时删除视频文件:{}文件失败,失败原因{}",file,exc.getMessage());
+                    return super.visitFileFailed(file, exc);
+                }
+            });
+        }
+    }
+
+
+
+
+
     /**
      * 停止到时间未停止的工单
      * @return
      */
-    public List<String> stopTickets() {
+    public List<VoiceTicketLogs> stopTickets() {
         List<VideoTaskManager.TaskStatus> taskStatuses = videoTaskManager.listTasks();
         if(taskStatuses == null || taskStatuses.size() == 0) return  null;
         //openUuid,streamId
@@ -74,12 +138,12 @@ public class TicketsTask {
         delTasks.forEach(str -> {
             log.info("需要停止的工单:{}",str);
         });
-        List<String> collect = delTasks.stream().map(
-                task -> {
-                    return task.getDeviceUuid() + "_" + task.getSkillName();
-                })
-                .distinct().collect(Collectors.toList());
-        return collect;
+//        List<String> collect = delTasks.stream().map(
+//                task -> {
+//                    return task.getDeviceUuid() + "_" + task.getSkillName();
+//                })
+//                .distinct().collect(Collectors.toList());
+        return delTasks;
     }
 
 

+ 25 - 5
src/main/resources/application-dev.yml

@@ -8,8 +8,6 @@ knife4j:
 
 
 minio:
-#  中心测
-#  endpoint: http://10.68.204.52:8077
 #  边缘测
   endpoint: http://10.68.208.94:8077
   ak: AKIAIOSFODNN7EXAMPLE
@@ -27,9 +25,9 @@ spring:
         master:
           type: com.alibaba.druid.pool.DruidDataSource
           driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://10.68.208.94:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+          url: jdbc:mysql://10.68.204.52:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
-          password: 123456
+          password: fbLfJZ1sFMAw
         #边缘测
         slave:
           type: com.alibaba.druid.pool.DruidDataSource
@@ -49,5 +47,27 @@ spring:
       minEvictableIdleTimeMillis: 60000
       # 配置一个连接在池中最大生存的时间,单位是毫秒
       maxEvictableIdleTimeMillis: 900000
-      access-to-underlying-connection-allowed:
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  data:
+    redis:
+      host: 192.168.1.112
+      port: 6390
+      password:
+      database: 0
+      timeout: 6000ms
+      lettuce:
+        pool:
+          min-idle: 5
+          max-idle: 10
+          max-wait: -1ms
+          max-active: 1000
 
+#异音算法接口
+vox:
+  #vox服务地址
+  post-analysis-url: http://192.168.1.188:8899/audio
+  #视频流切片保存地址
+  video-dir: D:\tmp\data\vox\

+ 29 - 7
src/main/resources/application-prod.yml

@@ -8,7 +8,8 @@ knife4j:
 
 
 minio:
-#  endpoint: http://192.168.10.135:9000
+  #  中心测
+  endpoint: http://minio-idaas-0.middleware.svc.cluster.local:8077
   ak: AKIAIOSFODNN7EXAMPLE
   sk: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKE
   bucket: windmill
@@ -18,20 +19,20 @@ minio:
 spring:
   datasource:
     dynamic:
-      primary: slave
+      primary: master
       datasource:
         #中心测
         master:
           type: com.alibaba.druid.pool.DruidDataSource
           driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://10.68.208.94:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+          url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
-          password: 123456
+          password: fbLfJZ1sFMAw
         #边缘测
         slave:
           type: com.alibaba.druid.pool.DruidDataSource
           driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://10.68.208.94:8639/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+          url: jdbc:mysql://xdbmysql57-leader.middleware.svc.cluster.local:8436/iip_api_service?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
           username: root
           password: fbLfJZ1sFMAw
     druid:
@@ -46,6 +47,27 @@ spring:
       minEvictableIdleTimeMillis: 60000
       # 配置一个连接在池中最大生存的时间,单位是毫秒
       maxEvictableIdleTimeMillis: 900000
-      access-to-underlying-connection-allowed:
-
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  data:
+    redis:
+      host: redis-single.middleware.svc.cluster.local
+      port: 8485
+      password: MTJmYkxmSloxYTNG
+      database: 0
+      timeout: 6000ms
+      lettuce:
+        pool:
+          min-idle: 5
+          max-idle: 10
+          max-wait: -1ms
+          max-active: 1000
 
+#异音算法接口
+vox:
+  #vox服务地址
+  post-analysis-url: http://vox-model-service.vox-services.svc.cluster.local:8899/audio
+  #视频流切片保存地址
+  video-dir: /tmp

+ 2 - 32
src/main/resources/application.yml

@@ -1,24 +1,6 @@
 spring:
-  servlet:
-    multipart:
-      max-file-size: 100MB
-      max-request-size: 100MB
-
   profiles:
-    active: dev
-  data:
-    redis:
-      host: 192.168.1.120
-      port: 6390
-      password:
-      database: 0
-      timeout: 6000ms
-      lettuce:
-        pool:
-          min-idle: 5
-          max-idle: 10
-          max-wait: -1ms
-          max-active: 1000
+    active: prod
 
 
 
@@ -78,11 +60,6 @@ yijian-interface:
     ak: fd01ec4de8724d71bb764190f202929c
     sk: f44a391cadcc42f98167e7e42086514f
     endpoint: http://10.68.204.52:8412
-  #边缘节点配置信息
-  edge-ends:
-    ak: a440a816330a4e558ec33d50aaad379d
-    sk: d9068f8ff3604a45a83b81c987de673a
-    endpoint: http://10.68.208.94:8412
 
   #接口地址前缀配置
   uri-path-prefix: /api/spi
@@ -90,13 +67,6 @@ yijian-interface:
   device-info: /v1/devices/{deviceID}
   #组织树接口地址 GET /v1/organizations
   organizations: /v1/organizations
-  #责任人请求 /v1/organizations/directors?deptID=452b784fe34d42b1b3700b6aeb648e1e
-  organizations-directors: /v1/organizations/directors?deptID={deptId}
 
-#异音算法接口
-vox:
-  #vox服务地址
-  post-analysis-url: http://192.168.1.188:8899/audio
-  #视频流切片保存地址
-  video-dir: D:\tmp\data\vox\
+
 

+ 22 - 0
src/main/resources/banner.txt

@@ -0,0 +1,22 @@
+
+#
+#
+#                                                              iiii
+#                                                             i::::i
+#                                                              iiii
+#
+#  vvvvvvv           vvvvvvv ooooooooooo xxxxxxx      xxxxxxxiiiiiii     cccccccccccccccc    eeeeeeeeeeee
+#   v:::::v         v:::::voo:::::::::::oox:::::x    x:::::x i:::::i   cc:::::::::::::::c  ee::::::::::::ee
+#    v:::::v       v:::::vo:::::::::::::::ox:::::x  x:::::x   i::::i  c:::::::::::::::::c e::::::eeeee:::::ee
+#     v:::::v     v:::::v o:::::ooooo:::::o x:::::xx:::::x    i::::i c:::::::cccccc:::::ce::::::e     e:::::e
+#      v:::::v   v:::::v  o::::o     o::::o  x::::::::::x     i::::i c::::::c     ccccccce:::::::eeeee::::::e
+#       v:::::v v:::::v   o::::o     o::::o   x::::::::x      i::::i c:::::c             e:::::::::::::::::e
+#        v:::::v:::::v    o::::o     o::::o   x::::::::x      i::::i c:::::c             e::::::eeeeeeeeeee
+#         v:::::::::v     o::::o     o::::o  x::::::::::x     i::::i c::::::c     ccccccce:::::::e
+#          v:::::::v      o:::::ooooo:::::o x:::::xx:::::x   i::::::ic:::::::cccccc:::::ce::::::::e
+#           v:::::v       o:::::::::::::::ox:::::x  x:::::x  i::::::i c:::::::::::::::::c e::::::::eeeeeeee
+#            v:::v         oo:::::::::::oox:::::x    x:::::x i::::::i  cc:::::::::::::::c  ee:::::::::::::e
+#             vvv            ooooooooooo xxxxxxx      xxxxxxxiiiiiiii    cccccccccccccccc    eeeeeeeeeeeeee
+#
+#
+

+ 2 - 2
src/main/resources/logback.xml

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
     <!-- 日志存放路径 -->
-	<property name="log.path" value="D:\\tmp\\logs\\vox" />
-<!--    <property name="log.path" value="/logs" />-->
+<!--	<property name="log.path" value="D:\\tmp\\logs\\vox" />-->
+    <property name="log.path" value="/tmp/logs" />
     <!-- 日志输出格式 -->
 	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
 

+ 49 - 0
src/test/java/com/example/unusualsounds/UnusualSoundsApplicationTests.java

@@ -2,18 +2,21 @@ package com.example.unusualsounds;
 
 import static com.baidubce.auth.SignOptions.DEFAULT;
 
+import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson2.JSON;
 import com.baidubce.http.HttpMethodName;
 import com.example.unusualsounds.common.utils.BaiDuUtils;
 import com.example.unusualsounds.common.utils.DateUtils;
 import com.example.unusualsounds.common.utils.RedisUtils;
 import com.example.unusualsounds.common.utils.UUID;
+import com.example.unusualsounds.framework.minio.MinioUtil;
 import com.example.unusualsounds.project.device.entity.vo.SoundSensorsQueryVo;
 import com.example.unusualsounds.project.vox.entity.AlarmReports;
 import com.example.unusualsounds.project.vox.entity.Alarms;
 import com.example.unusualsounds.project.vox.entity.VoiceTicketLogs;
 import com.example.unusualsounds.project.vox.service.impl.*;
 import com.example.unusualsounds.web.jsonobj.CameraDTO;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
@@ -21,7 +24,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.ResponseEntity;
 
+import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
@@ -240,4 +246,47 @@ class UnusualSoundsApplicationTests {
 
     }
 
+
+    /**
+     *
+     */
+    @Test
+    void TestAlarmsPost(){
+
+        String uri = "/v1/alarms/list";
+
+        String body = "{\"pageSize\":40,\"pageNo\":1,\"isRobotAlarm\":false,\"type\":\"camera|voice\",\"skillID\":[],\"status\":[\"pending\",\"processed\"],\"startTimestamp\":1740585600,\"endTimestamp\":1741190399,\"deptID\":\"452b784fe34d42b1b3700b6aeb648e1e\"}";
+        ResponseEntity<String> response = BaiDuUtils.sendRequest(uri,HttpMethodName.POST,JSON.parse(body),null,String.class, ak, sk, endpoint, uriPathPrefix);
+        System.out.println(response.getStatusCode());
+        System.out.println(response.getBody());
+
+    }
+
+    @Autowired
+    private MinioUtil minioUtil;
+    @Test
+    void testMinioDownload(){
+
+
+        String url = "http://10.68.208.94:8412/spi/minio/windmill/store/video-stream/2025-02-21/6DbTa7S709testVideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20250305%2Fbj%2Fs3%2Faws4_request&X-Amz-Date=20250305T055218Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=0199c107bd76e1aab9c54ab3083a7d9216df28a196c12abcedf3e91a8f4f7d84";
+        String save = "D:\\tmp\\6DbTa7S709testVideo.mp4";
+        String regex = "^.*/([^/?]+)(?:\\\\?.*)?$";
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(url);
+        if (matcher.find()) {
+            System.out.println(matcher.group(1));
+        }
+
+
+//        File file = HttpUtil.downloadFileFromUrl(url, new File(save));
+//        if(file.exists()){
+//            System.out.println("下载成功");
+//        }else {
+//            System.out.println("下载失败");
+//        }
+
+
+    }
+
+
 }