增加智眸AI接口封装
This commit is contained in:
parent
ab47d75ca3
commit
55273df8d7
|
|
@ -8,6 +8,7 @@ package com.multictrl.common.constant;
|
|||
*/
|
||||
public interface BusinessConstant {
|
||||
|
||||
String ZHIMOU_AI_CALLBACK_TOPIC = "thing/product/zhimou_ai_callback";
|
||||
String WEB_EVENT_TOPIC = "thing/product/%s/web_event";
|
||||
String NOFLY_ZONE_METHOD = "nofly_zone";
|
||||
|
||||
|
|
@ -90,6 +91,7 @@ public interface BusinessConstant {
|
|||
String DOCK_NOFLY_ZONE = "dock_nofly_zone_";
|
||||
String DOCK_NOFLY_ZONE_TRIGGER_SIGN = "dock_nofly_zone_trigger_sign_";
|
||||
String ZHIMOU_TOKEN = "zhiMou_token";
|
||||
String DOCK_ZHIMOU_TASK_ID = "dock_zhiMou_task_id_";
|
||||
|
||||
//********************************* other *********************************//
|
||||
String HTTP_PROTOCOL = "http://";
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ package com.multictrl.common.constant;
|
|||
public interface SysParamsKey {
|
||||
|
||||
//********************************* zhimou *********************************//
|
||||
String ZHIMOU_AI_URL = "zhi_mou_ai_url";
|
||||
String ZHIMOU_AI_APP_KEY = "zhi_mou_ai_app_key";
|
||||
String ZHIMOU_AI_APP_SECRET = "zhi_mou_ai_app_secret";
|
||||
String ZHIMOU_AI_URL = "zhimou_ai_url";
|
||||
String ZHIMOU_AI_APP_KEY = "zhimou_ai_app_key";
|
||||
String ZHIMOU_AI_APP_SECRET = "zhimou_ai_app_secret";
|
||||
|
||||
//********************************* sys component *********************************//
|
||||
String SRS_RTMP_MAP_URL = "srs_rtmp_map_url";
|
||||
String EMQX_MAP_URL = "emqx_map_url";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import cn.hutool.core.util.StrUtil;
|
|||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.filter.NameFilter;
|
||||
import com.drew.imaging.jpeg.JpegMetadataReader;
|
||||
import com.drew.imaging.jpeg.JpegProcessingException;
|
||||
import com.drew.imaging.mp4.Mp4MetadataReader;
|
||||
|
|
@ -75,6 +77,15 @@ public class Utils {
|
|||
return snakeJson;
|
||||
}
|
||||
|
||||
/*
|
||||
* 阿里FastJson2驼峰转下划线
|
||||
*/
|
||||
public static com.alibaba.fastjson2.JSONObject beanToSnakeJsonFastJson(Object o) {
|
||||
NameFilter snakeCaseFilter = (object, name, value)
|
||||
-> name.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
|
||||
return com.alibaba.fastjson2.JSONObject.parseObject(JSON.toJSONString(o, snakeCaseFilter));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后两个字符
|
||||
* "a/b/c/d" "c/d"
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@ package com.multictrl.modules.business.controller;
|
|||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.multictrl.common.annotation.ApiOrder;
|
||||
import com.multictrl.common.annotation.LogOperation;
|
||||
import com.multictrl.common.utils.Result;
|
||||
import com.multictrl.common.validator.ValidatorUtils;
|
||||
import com.multictrl.modules.business.dto.zhimou.ZhiMouAiStart;
|
||||
import com.multictrl.modules.business.service.ZhiMouService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 智眸AI接口封装
|
||||
|
|
@ -33,4 +34,23 @@ public class ZhiMouController {
|
|||
JSONObject data = zhiMouService.getApp();
|
||||
return zhiMouService.resultHandle(data);
|
||||
}
|
||||
|
||||
@Operation(summary = "开始AI检测任务")
|
||||
@LogOperation("开始AI检测任务")
|
||||
@PostMapping("/startByWeb")
|
||||
@RequiresPermissions("bus:zhimou:startByWeb")
|
||||
public Result<Object> startByWeb(@RequestBody ZhiMouAiStart zhiMouAiStart) {
|
||||
ValidatorUtils.validateEntity(zhiMouAiStart);
|
||||
JSONObject data = zhiMouService.startByWeb(zhiMouAiStart);
|
||||
return zhiMouService.resultHandle(data);
|
||||
}
|
||||
|
||||
@Operation(summary = "停止AI检测任务")
|
||||
@LogOperation("停止AI检测任务")
|
||||
@PostMapping("/stopByWeb")
|
||||
@RequiresPermissions("bus:zhimou:stopByWeb")
|
||||
public Result<Object> stopByWeb(@RequestParam String dockSn) {
|
||||
JSONObject data = zhiMouService.stopByWeb(dockSn);
|
||||
return zhiMouService.resultHandle(data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.multictrl.modules.business.dto.zhimou;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开始AI检测参数
|
||||
*
|
||||
* @author Sdy
|
||||
* @since 1.0.0 2026/6/10
|
||||
*/
|
||||
@Schema(name = "开始AI检测参数")
|
||||
@Data
|
||||
public class ZhiMouAiStart {
|
||||
@NotBlank(message = "设备编号不能为空")
|
||||
@Schema(description = "设备编号")
|
||||
private String dockSn;
|
||||
|
||||
@NotBlank(message = "应用编号不能为空")
|
||||
@Schema(description = "应用编号")
|
||||
private String appId;
|
||||
|
||||
@Schema(description = "指定开启应用下规则列表,不指定则开启所有规则")
|
||||
private List<String> rules;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public class ZhiMouTask {
|
|||
* 应用唯一ID
|
||||
*/
|
||||
@JsonProperty("app_id")
|
||||
private String appID;
|
||||
private String appId;
|
||||
/**
|
||||
* 输出视频比特率
|
||||
*/
|
||||
|
|
@ -26,7 +26,7 @@ public class ZhiMouTask {
|
|||
* 三方业务ID
|
||||
*/
|
||||
@JsonProperty("business_id")
|
||||
private String businessID;
|
||||
private String businessId;
|
||||
/**
|
||||
* 设备号
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ public interface SrsService {
|
|||
//获取飞机推流地址
|
||||
String getUavPushLiveUrl(String dockSn);
|
||||
|
||||
//获取飞机AI推流地址
|
||||
String getUavAiPushLiveUrl(String dockSn);
|
||||
|
||||
//获取dao
|
||||
SrsRecordDao getDao();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.multictrl.modules.business.service;
|
|||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.multictrl.common.utils.Result;
|
||||
import com.multictrl.modules.business.dto.zhimou.ZhiMouAiStart;
|
||||
import com.multictrl.modules.business.dto.zhimou.ZhiMouInfo;
|
||||
|
||||
/**
|
||||
|
|
@ -20,4 +21,10 @@ public interface ZhiMouService {
|
|||
|
||||
//获取应用列表
|
||||
JSONObject getApp();
|
||||
|
||||
//开始AI检测任务
|
||||
JSONObject startByWeb(ZhiMouAiStart zhiMouAiStart);
|
||||
|
||||
//停止AI检测任务
|
||||
JSONObject stopByWeb(String dockSn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,12 @@ public class SrsServiceImpl implements SrsService {
|
|||
return RTMP_PROTOCOL + srsConfig.getIp() + ":" + srsConfig.getRtmpPort() + "/" + dockSn + "/uav?token=" + srsConfig.getRtmpToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUavAiPushLiveUrl(String dockSn) {
|
||||
|
||||
return RTMP_PROTOCOL + srsConfig.getIp() + ":" + srsConfig.getRtmpPort() + "/" + dockSn + "/uav_ai?token=" + srsConfig.getRtmpToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SrsRecordDao getDao() {
|
||||
return srsRecordDao;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
package com.multictrl.modules.business.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.Method;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.multictrl.common.config.MqttConfig;
|
||||
import com.multictrl.common.constant.BusinessConstant;
|
||||
import com.multictrl.common.constant.SysParamsKey;
|
||||
import com.multictrl.common.exception.ErrorCode;
|
||||
import com.multictrl.common.exception.RenException;
|
||||
import com.multictrl.common.utils.CacheUtils;
|
||||
import com.multictrl.common.utils.Result;
|
||||
import com.multictrl.modules.business.dto.zhimou.ZhiMouInfo;
|
||||
import com.multictrl.common.utils.Utils;
|
||||
import com.multictrl.modules.business.dto.zhimou.*;
|
||||
import com.multictrl.modules.business.service.SrsService;
|
||||
import com.multictrl.modules.business.service.ZhiMouService;
|
||||
import com.multictrl.modules.sys.dao.SysParamsDao;
|
||||
import com.multictrl.modules.sys.entity.SysParamsEntity;
|
||||
|
|
@ -24,6 +29,8 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 智眸AI接口封装
|
||||
|
|
@ -36,6 +43,8 @@ import java.util.Map;
|
|||
@RequiredArgsConstructor
|
||||
public class ZhiMouServiceImpl implements ZhiMouService {
|
||||
private final SysParamsDao paramsDao;
|
||||
private final SrsService srsService;
|
||||
private final MqttConfig mqttConfig;
|
||||
private static final String APP_KEY = "appkey";
|
||||
private static final String APP_SECRET = "appsecret";
|
||||
private static final String AUTHORIZATION = "Authorization";
|
||||
|
|
@ -95,6 +104,7 @@ public class ZhiMouServiceImpl implements ZhiMouService {
|
|||
}
|
||||
}
|
||||
}
|
||||
log.error("invoke zhiMou resultHandle result: {}", result);
|
||||
return new Result<>().error(ErrorCode.ZHIMOU_REQUEST_ERROR);
|
||||
}
|
||||
|
||||
|
|
@ -181,4 +191,105 @@ public class ZhiMouServiceImpl implements ZhiMouService {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject startByWeb(ZhiMouAiStart zhiMouAiStart) {
|
||||
String dockSn = zhiMouAiStart.getDockSn();
|
||||
ZhiMouTask zhiMouTask = new ZhiMouTask();
|
||||
zhiMouTask.setMode("video");
|
||||
zhiMouTask.setAppId(zhiMouAiStart.getAppId());
|
||||
zhiMouTask.setDevice(dockSn);
|
||||
zhiMouTask.setBusinessId((String) CacheUtils.get(BusinessConstant.IN_FLIGHT_WORKING_TASK_ID + dockSn));
|
||||
zhiMouTask.setRules(zhiMouAiStart.getRules());
|
||||
zhiMouTask.setInput(srsService.getUavPushLiveUrl(dockSn));
|
||||
zhiMouTask.setOutput(srsService.getUavAiPushLiveUrl(dockSn));
|
||||
//内网部署的服务,想要使用公网的知眸服务,需要把srs-rtmp的1935映射到公网,这样知眸才能拉到视频流处理并推流
|
||||
SysParamsEntity rtmpMapUrl = paramsDao.selectOne(new QueryWrapper<SysParamsEntity>()
|
||||
.eq("param_code", SysParamsKey.SRS_RTMP_MAP_URL));
|
||||
if (rtmpMapUrl != null) {
|
||||
String paramValue = rtmpMapUrl.getParamValue();
|
||||
if (StrUtil.isNotBlank(paramValue) && paramValue.contains(":")) {
|
||||
//替换掉input中的ip和端口
|
||||
zhiMouTask.setInput(replaceRtmpIpPort(zhiMouTask.getInput(), paramValue.split(":")[0],
|
||||
paramValue.split(":")[1]));
|
||||
zhiMouTask.setOutput(replaceRtmpIpPort(zhiMouTask.getOutput(), paramValue.split(":")[0],
|
||||
paramValue.split(":")[1]));
|
||||
}
|
||||
}
|
||||
zhiMouTask.setOsd(new Osd());
|
||||
Report report = new Report();
|
||||
ReportMqtt mqtt = new ReportMqtt();
|
||||
MqttConfig.Client client1 = mqttConfig.getClient1();
|
||||
String hostUrl = client1.getUrl().replaceAll(BusinessConstant.TCP_PROTOCOL, "");
|
||||
mqtt.setBrokerHost(hostUrl.split(":")[0]);
|
||||
mqtt.setBrokerPort(Long.parseLong(hostUrl.split(":")[1]));
|
||||
//内网部署的服务,想要使用公网的知眸服务,需要把emqx的1883映射到公网,这样知眸才能通知系统检测结果
|
||||
SysParamsEntity emqxMapUrl = paramsDao.selectOne(new QueryWrapper<SysParamsEntity>()
|
||||
.eq("param_code", SysParamsKey.EMQX_MAP_URL));
|
||||
if (emqxMapUrl != null) {
|
||||
String paramValue = emqxMapUrl.getParamValue();
|
||||
if (StrUtil.isNotBlank(paramValue) && paramValue.contains(":")) {
|
||||
mqtt.setBrokerHost(paramValue.split(":")[0]);
|
||||
mqtt.setBrokerPort(Long.parseLong(paramValue.split(":")[1]));
|
||||
}
|
||||
}
|
||||
mqtt.setSsl(false);
|
||||
mqtt.setClientID("zhi_mou_ai_" + IdUtil.getSnowflakeNextIdStr());
|
||||
mqtt.setUsername(client1.getUsername());
|
||||
mqtt.setPassword(client1.getPassword());
|
||||
mqtt.setTopic(BusinessConstant.ZHIMOU_AI_CALLBACK_TOPIC);
|
||||
mqtt.setQos(0L);
|
||||
report.setMqtt(mqtt);
|
||||
zhiMouTask.setReport(report);
|
||||
JSONObject jsonObject = Utils.beanToSnakeJsonFastJson(zhiMouTask);
|
||||
//执行命令
|
||||
ZhiMouInfo zhiMouInfo = getToken();
|
||||
String result = HttpUtil.createPost(zhiMouInfo.getUrl() + TASK)
|
||||
.body(jsonObject.toJSONString())
|
||||
.header(AUTHORIZATION, BEARER + zhiMouInfo.getToken())
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("invoke zhiMou start request: {},result: {}", jsonObject, result);
|
||||
if (StrUtil.isNotBlank(result)) {
|
||||
JSONObject parse = JSONObject.parse(result);
|
||||
if (parse.containsKey("code") && parse.getInteger("code") == 0) {
|
||||
String taskId = parse.getJSONObject("data").getString("task_id");
|
||||
CacheUtils.set(BusinessConstant.DOCK_ZHIMOU_TASK_ID + dockSn, taskId);
|
||||
}
|
||||
return parse;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject stopByWeb(String dockSn) {
|
||||
String taskId = (String) CacheUtils.get(BusinessConstant.DOCK_ZHIMOU_TASK_ID + dockSn);
|
||||
if (StrUtil.isBlank(taskId)) {
|
||||
throw new RenException(ErrorCode.ZHIMOU_TASK_NOT_EXIST);
|
||||
}
|
||||
ZhiMouInfo zhiMouInfo = getToken();
|
||||
String result = HttpUtil.createRequest(Method.DELETE, zhiMouInfo.getUrl() + TASK + "/" + taskId)
|
||||
.header(AUTHORIZATION, BEARER + zhiMouInfo.getToken())
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("invoke zhiMou stop taskId: {},result: {}", taskId, result);
|
||||
if (StrUtil.isNotBlank(result)) {
|
||||
return JSONObject.parse(result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String replaceRtmpIpPort(String originalUrl, String newIp, String newPort) {
|
||||
// 定义RTMP URL的正则表达式模式
|
||||
Pattern pattern = Pattern.compile("^rtmp://([^/:]+):([^/]+)(/.*)$");
|
||||
Matcher matcher = pattern.matcher(originalUrl);
|
||||
|
||||
if (matcher.matches()) {
|
||||
// 构建新的URL
|
||||
return "rtmp://" + newIp + ":" + newPort + matcher.group(3);
|
||||
} else {
|
||||
// 如果URL格式不符合预期,返回原始URL或抛出异常
|
||||
return originalUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,4 +71,5 @@ public interface ErrorCode {
|
|||
int DELETE_FAIL = 20030;
|
||||
int ZHIMOU_NO_CONFIG = 20031;
|
||||
int ZHIMOU_REQUEST_ERROR = 20032;
|
||||
int ZHIMOU_TASK_NOT_EXIST = 20033;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,3 +60,4 @@
|
|||
20030=\u5220\u9664{0}\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
|
||||
20031=AI\u56FE\u50CF\u68C0\u6D4B\u7B97\u6CD5\u4FE1\u606F\u672A\u914D\u7F6E
|
||||
20032=AI\u56FE\u50CF\u68C0\u6D4B\u7B97\u6CD5\u8BF7\u6C42\u51FA\u9519
|
||||
20033=AI\u4EFB\u52A1\u672A\u5F00\u542F
|
||||
|
|
@ -41,7 +41,7 @@ minio:
|
|||
|
||||
mqtt:
|
||||
client1:
|
||||
url: tcp://dj-multictrl-emqx:1883
|
||||
url: tcp://${host.ip}:61627
|
||||
username: dock
|
||||
password: Dock@2023
|
||||
subClientId: dj-one-sub
|
||||
|
|
|
|||
Loading…
Reference in New Issue