ソースを参照

暂存,图片上传接口制作

kindring 2 年 前
コミット
8a00954eb0

+ 13 - 1
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java

@@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
 import com.genersoft.iot.vmp.vmanager.bean.AiLib;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.github.pagehelper.PageInfo;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 
@@ -62,13 +63,24 @@ public interface IVideoManagerStorage {
 	 */
 	public List<AiConfig> queryAiConfigList(int arithmetic);
 
-	public int devUseAiConfig(String deviceId,int configId);
+	public int devUseAiConfig(String deviceId,int configId,int arithmetic);
 	/**
 	 * 获取数据库中所有的ai库
 	 * @return
 	 */
 	public List<AiLib> queryLibraryList();
 
+	/**
+	 * 添加数据库子项
+	 * @param libraryId
+	 * @param itemName
+	 * @param itemNo
+	 * @param card
+	 * @param file
+	 * @return
+	 */
+	public String addLibItem(int libraryId, String itemName, String itemNo, String card , MultipartFile file);
+
 	public int addAiConfig(String configName,
 						   int arithmetic,
 						   int triggerType,

+ 35 - 7
src/main/java/com/genersoft/iot/vmp/storager/dao/HfyDevAiMapper.java

@@ -21,6 +21,7 @@ public interface HfyDevAiMapper {
 
     @Insert("insert into ai_configs(" +
             "libraryId," +
+            "configName," +
             "arithmetic," +
             "triggerType," +
             "refreshTime," +
@@ -30,6 +31,7 @@ public interface HfyDevAiMapper {
             "pushUrl" +
             ") values(" +
             "#{libraryId}," +
+            "#{configName}," +
             "#{arithmetic}," +
             "#{triggerType}," +
             "#{refreshTime}," +
@@ -42,15 +44,32 @@ public interface HfyDevAiMapper {
 
     @Insert("insert into dev_ai_config(" +
             "deviceId," +
-            "configId"+
+            "configId,"+
+            "arithmetic"+
             ") values(" +
             "#{deviceId}," +
             "#{configId}," +
+            "#{arithmetic}" +
             ")")
     int devUseConfig(AiConfig aiConfig);
+
+    @Update(value = {"<script>" +
+            "update dev_ai_config " +
+            "set " +
+           "configId = ${configId} "+
+            "where  deviceId = #{deviceId} and arithmetic = #{arithmetic}" +
+            "</script>" })
+    int devChangeConfig(AiConfig aiConfig);
+
+    @Select("select * from dev_ai_config where deviceId = #{deviceId} and arithmetic = #{arithmetic}")
+    List<AiConfig> findDevConfig(AiConfig aiConfig);
+
     @Select("select * from ai_library ")
     List<AiLib> getAiLibraryList();
 
+    @Select("select * from ai_library where libraryId = #{libraryId}")
+    List<AiLib> getAiLibraryByLibId(int libraryId);
+
     @Select("select * from ai_library where libraryId = #{libraryId} and arithmetic = #{arithmetic}")
     List<AiLib> findLibByAiTypeAndLibraryId(int libraryId,int arithmetic);
 
@@ -81,14 +100,23 @@ public interface HfyDevAiMapper {
     @Insert("insert into lib_item(" +
             "libraryId," +
             "itemType," +
-            "textValue" +
-            "imageUrl" +
+            "imageUrl," +
+            "trait," +
+            "itemName,"+
+            "itemNo,"+
+            "idCard,"+
+            "carNo"+
             ") values (" +
-            "#{libraryName}," +
-            "#{version}," +
-            "#{arithmetic}" +
+            "#{libraryId}," +
+            "#{itemType}," +
+            "#{imageUrl}," +
+            "#{trait}," +
+            "#{itemName}," +
+            "#{itemNo}," +
+            "#{idCard}," +
+            "#{carNo}" +
             ")")
-    int addImg(AiConfig aiConfig);
+    int addLibItem(AiLib aiLib);
 
 
 

+ 62 - 2
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java

@@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.storager.dao.*;
 import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.AiLib;
+import com.genersoft.iot.vmp.vmanager.bean.UploadService;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -30,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
@@ -245,11 +247,25 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 	}
 
 
-	public int devUseAiConfig(String deviceId,int configId) {
+	public int devUseAiConfig(String deviceId,int configId,int arithmetic) {
 		AiConfig aiConfig = new AiConfig();
 		aiConfig.setConfigId(configId);
 		aiConfig.setDeviceId(deviceId);
-		return HfyDevAiMapper.devUseConfig(aiConfig);
+		aiConfig.setArithmetic(arithmetic);
+		if(configId<=0||arithmetic<=0){
+			logger.warn("configId 或者 算法类型为空");
+			return -1;
+		}
+		// 判断是否能找到对应的配置项
+		List <AiConfig> configList = HfyDevAiMapper.findDevConfig(aiConfig) ;
+		if(configList.isEmpty()){
+			// 创建
+			return HfyDevAiMapper.devUseConfig(aiConfig);
+		}else{
+			// 修改
+			return HfyDevAiMapper.devChangeConfig(aiConfig);
+		}
+
 	}
 
 	/**
@@ -260,6 +276,50 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		return HfyDevAiMapper.getAiLibraryList();
 	}
 
+	/**
+	 * 添加数据库子项
+	 * @param libraryId
+	 * @param itemName
+	 * @param itemNo
+	 * @param file
+	 * @return
+	 */
+	public String addLibItem(int libraryId, String itemName, String itemNo, String card, MultipartFile file){
+		// 获取library数据
+		List<AiLib> aiLibArr = HfyDevAiMapper.getAiLibraryByLibId(libraryId);
+		if(aiLibArr.isEmpty()){	logger.warn("无法找到lib库"); return "-1";}
+		AiLib libData = aiLibArr.stream().findFirst().get();
+		// 判断ai类型来检测是否合法
+		int arithmetic = libData.getArithmetic();
+		String fileName = "";
+		String idCard = "";
+		String carNo = "";
+		int itemType = 2;
+		AiLib aiLib = new AiLib();
+		if (arithmetic == 1 && !file.isEmpty()) {
+			// 人脸照片存储
+			UploadService uploadService = new UploadService();
+			fileName = uploadService.uploadLibImg(
+					String.valueOf(libData.getLibraryId()),
+					String.valueOf(libData.getTotal()),
+					file);
+			itemType = 1;
+			idCard = card;
+		}else if(arithmetic == 3 ){
+			carNo = card;
+		}
+		aiLib.setLibraryId(libraryId);
+		aiLib.setItemType(itemType);
+		aiLib.setImageUrl(fileName);
+		aiLib.setTrait("");
+		aiLib.setItemName(itemName);
+		aiLib.setItemNo(itemNo);
+		aiLib.setIdCard(idCard);
+		aiLib.setCarNo(carNo);
+		// 存储图像
+		HfyDevAiMapper.addLibItem(aiLib);
+		return fileName;
+	}
 	public int addAiConfig(String configName,
 						   int arithmetic,
 						   int triggerType,

+ 82 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/AiLib.java

@@ -18,6 +18,88 @@ public class AiLib {
     @Schema(description = "数量")
     private int total;
 
+    @Schema(description = "素材类型")
+    private int itemType;
+    @Schema(description = "图片的链接")
+    private String imageUrl;
+    @Schema(description = "用来匹配的图片的特征值")
+    private String trait;
+    @Schema(description = "用于匹配的值")
+    private String textValue;
+    @Schema(description = "名称,工人名字或者车辆名称")
+    private String itemName;
+    @Schema(description = "标记号,工人工号或者车牌")
+    private String itemNo;
+    @Schema(description = "身份证号")
+    private String idCard;
+    @Schema(description = "车牌号")
+    private String carNo;
+    public int getItemType() {
+        return itemType;
+    }
+
+    public void setItemType(int itemType) {
+        this.itemType = itemType;
+    }
+
+    public String getImageUrl() {
+        return imageUrl;
+    }
+
+    public void setImageUrl(String imageUrl) {
+        this.imageUrl = imageUrl;
+    }
+
+    public String getTrait() {
+        return trait;
+    }
+
+    public void setTrait(String trait) {
+        this.trait = trait;
+    }
+
+    public String getTextValue() {
+        return textValue;
+    }
+
+    public void setTextValue(String textValue) {
+        this.textValue = textValue;
+    }
+
+    public String getItemName() {
+        return itemName;
+    }
+
+    public void setItemName(String itemName) {
+        this.itemName = itemName;
+    }
+
+    public String getItemNo() {
+        return itemNo;
+    }
+
+    public void setItemNo(String itemNo) {
+        this.itemNo = itemNo;
+    }
+
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+
+    public String getCarNo() {
+        return carNo;
+    }
+
+    public void setCarNo(String carNo) {
+        this.carNo = carNo;
+    }
+
+
+
     public int getLibraryId() {
         return libraryId;
     }

+ 56 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/UploadService.java

@@ -0,0 +1,56 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class UploadService {
+    public String upload(String bId,
+                         String uId,
+                         MultipartFile file) {
+        //获得文件保存路径
+        String url = getNewFileName(bId, uId, file);
+        saveToLocal(file,url);
+        return url;
+    }
+    public String uploadLibImg(String libId,
+                               String uId,
+                               MultipartFile file){
+        String fileName = getNewFileName(libId, uId, file);
+        saveToLocal(file,fileName);
+        return fileName;
+    }
+
+    private String getNewFileName(String bId, String uId, MultipartFile file) {
+        // 获取文件后缀
+        String extension = "";
+        int i = file.getOriginalFilename().lastIndexOf('.');
+        if (i > 0) {
+            extension = file.getOriginalFilename().substring(i+1);
+        }
+        return "aiImg_"+bId+"_"+uId+"."+extension;
+    }
+
+    private void saveToLocal(MultipartFile file,String fileName){//上传到本地
+        try {
+            InputStream input = file.getInputStream();
+            OutputStream outputStream = new FileOutputStream("libImages/" + File.separator + fileName);
+            byte[] b = new byte[4096];
+            int count = input.read(b);
+            while (count != -1) {
+                for(int i = 0; i < count; i++){
+                    outputStream.write(b[i]);
+                }
+                count = input.read(b);
+            }
+            input.close();
+            outputStream.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 29 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java

@@ -9,6 +9,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device;
 
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.gb28181.bean.AiConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -109,6 +110,34 @@ public class DeviceConfig {
 		resultHolder.put(key, uuid, result);
 		return result;
 	}
+	@Operation(summary = "添加ai库配置文件")
+	@Parameter(name = "aiConfig", description = "配置数据", required = true)
+//	@Parameter(name = "configName", description = "配置名称", required = true)
+//	@Parameter(name = "arithmetic", description = "算法id")
+//	@Parameter(name = "triggerType", description = "触发类型")
+//	@Parameter(name = "refreshTime", description = "刷新时间")
+//	@Parameter(name = "score", description = "检测阈值",allowEmptyValue = true)
+//	@Parameter(name = "resourcePath", description = "资源数据更新获取地址",allowEmptyValue = true)
+//	@Parameter(name = "uploadUrl", description = "多媒体资源上传地址",allowEmptyValue = true)
+//	@Parameter(name = "pushUrl", description = "回调地址",allowEmptyValue = true)
+	@PostMapping("/addAiConfig")
+	public int addAiConfig(@RequestBody AiConfig aiConfig){
+		if (logger.isDebugEnabled()) {
+			logger.debug("创建ai配置");
+		}
+		return storager.addAiConfig(
+				aiConfig.getConfigName(),
+				aiConfig.getArithmetic(),
+				aiConfig.getTriggerType(),
+				aiConfig.getLibraryId(),
+				aiConfig.getRefreshTime(),
+				aiConfig.getScore(),
+				aiConfig.getResourcePath(),
+				aiConfig.getUploadUrl(),
+				aiConfig.getPushUrl());
+//		return 1;
+	}
+
 
 	/**
 	 * 设备配置查询请求API接口

+ 32 - 33
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java

@@ -14,10 +14,7 @@ import com.genersoft.iot.vmp.service.IDeviceChannelService;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
-import com.genersoft.iot.vmp.vmanager.bean.AiLib;
-import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
-import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import com.genersoft.iot.vmp.vmanager.bean.*;
 import com.github.pagehelper.PageInfo;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -32,6 +29,7 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.sip.InvalidArgumentException;
@@ -75,6 +73,7 @@ public class DeviceQuery {
 	@Autowired
 	private SubscribeHolder subscribeHolder;
 
+
 	/**
 	 * 使用ID查询国标设备
 	 * @param deviceId 国标ID
@@ -110,15 +109,41 @@ public class DeviceQuery {
 	@Operation(summary = "设备使用ai配置")
 	@Parameter(name = "deviceId", description = "设备国标编号", required = true)
 	@Parameter(name = "configId", description = "配置id", required = true)
+	@Parameter(name = "arithmetic", description = "算法标记", required = true)
 	@GetMapping("/useAi/{deviceId}/{configId}")
-	public int devUseConfig(@PathVariable String deviceId,@PathVariable int configId){
+	public int devUseConfig(@PathVariable String deviceId,@PathVariable int configId,@RequestParam int arithmetic){
 		if (logger.isDebugEnabled()) {
 			logger.debug("设备使用ai配置");
 		}
-		return storager.devUseAiConfig(deviceId,configId);
+		return storager.devUseAiConfig(deviceId,configId,arithmetic);
 	}
 
 
+	@Operation(summary = "添加lib元素")
+	@Parameter(name = "libraryId", description = "lib库id", required = true)
+	@Parameter(name = "itemName", description = "名称,用户名称或者车辆名称",required = true)
+	@Parameter(name = "itemNo", description = "标记号,用于车牌或者工号",required = true)
+	@Parameter(name = "img", description = "图像数据")
+	@Parameter(name = "idCard", description = "身份证号",required = false)
+	@Parameter(name = "carNo", description = "车牌号",required = false)
+	@PostMapping("/addLibItem/{libraryId}")
+	public String addLibItem(
+			@PathVariable int libraryId,
+			@RequestParam(value="img", required = false) MultipartFile file,
+			@RequestParam String itemName,
+			@RequestParam String itemNo,
+			@RequestParam(value="idCard", required = false)  String idCard,
+			@RequestParam(value="carNo", required = false)  String carNo
+			){
+		if (logger.isDebugEnabled()) {
+			logger.debug("新增算法库成员");
+		}
+		String card = "";
+		if(idCard != null){card = idCard;}
+		else if(carNo != null){card = carNo;}
+		return storager.addLibItem(libraryId,itemName,itemNo,card,file);
+	}
+
 	@Operation(summary = "ai数据库查询")
 	@GetMapping("/aiLibrary")
 	public List<AiLib> aiLibrary(){
@@ -138,33 +163,7 @@ public class DeviceQuery {
 	}
 
 	// allowEmptyValue
-	@Operation(summary = "添加ai库配置文件")
-	@Parameter(name = "aiConfig", description = "配置数据", required = true)
-//	@Parameter(name = "configName", description = "配置名称", required = true)
-//	@Parameter(name = "arithmetic", description = "算法id")
-//	@Parameter(name = "triggerType", description = "触发类型")
-//	@Parameter(name = "refreshTime", description = "刷新时间")
-//	@Parameter(name = "score", description = "检测阈值",allowEmptyValue = true)
-//	@Parameter(name = "resourcePath", description = "资源数据更新获取地址",allowEmptyValue = true)
-//	@Parameter(name = "uploadUrl", description = "多媒体资源上传地址",allowEmptyValue = true)
-//	@Parameter(name = "pushUrl", description = "回调地址",allowEmptyValue = true)
-	@PostMapping("/addAiConfig")
-	public int addAiConfig(@RequestBody AiConfig aiConfig){
-		if (logger.isDebugEnabled()) {
-			logger.debug("创建ai配置");
-		}
-		return storager.addAiConfig(
-				aiConfig.getConfigName(),
-				aiConfig.getArithmetic(),
-				aiConfig.getTriggerType(),
-				aiConfig.getLibraryId(),
-				aiConfig.getRefreshTime(),
-				aiConfig.getScore(),
-				aiConfig.getResourcePath(),
-				aiConfig.getUploadUrl(),
-				aiConfig.getPushUrl());
-//		return 1;
-	}
+
 
 	/**
 	 * 分页查询国标设备

+ 0 - 1
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java

@@ -60,7 +60,6 @@ public class ServerController {
     @Autowired
     private ThreadPoolTaskExecutor taskExecutor;
 
-
     @GetMapping(value = "/media_server/list")
     @ResponseBody
     @Operation(summary = "流媒体服务列表")

+ 1 - 1
src/main/resources/application.yml

@@ -121,7 +121,7 @@ media:
     # [必须修改] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId
     id: your_server_id
     # [必须修改] zlm服务器的内网IP
-    ip: szgpay.ticp.net
+    ip: 192.168.1.203
     # [可选] 返回流地址时的ip,置空使用 media.ip
     stream-ip: szgpay.ticp.net
     #stream-ip: 192.168.1.203

+ 18 - 3
web_src/src/components/aiConfig.vue

@@ -285,9 +285,24 @@ export default {
         });
       });
     },
-    async selectConfigHandle(configId){
-      console.log("-*----"+configId);
-
+    async selectConfigHandle(configId,arithmetic){
+      console.log("-*----"+configId + '---' + arithmetic);
+      this.isLoading = true;
+      let url  = `/api/device/query/useAi/${this.deviceId}/${configId}?arithmetic=${arithmetic}`
+      let [err,res] = await handle(this.$axios.get(url));
+      this.isLoading = false;
+      if(err){
+        console.error(err)
+        this.$message({
+          showClose: true,
+          message: err,
+          type: 'error'
+        });
+        return;
+      }
+      console.log(res);
+      this.$message.success("创建成功");
+      this.loadDeviceAi();
     },
     showEditAi(id){
       this.$router.push(`/devEditAi/${id}`);

+ 6 - 7
web_src/src/components/createConfig.vue

@@ -106,7 +106,7 @@
         <el-divider></el-divider>
         <el-button-group>
           <el-button @click="init">重置</el-button>
-          <el-button @click="submitData" type="primary">确认添加</el-button>
+          <el-button @click="submitData()" type="primary">确认添加</el-button>
         </el-button-group>
       </el-card>
     </el-container>
@@ -178,7 +178,7 @@ export default {
       let [err,res] = await handle(this.$axios({
         method: 'get',
         url: `/api/device/query/aiLibrary`
-      }))
+      }));
       this.isLoading = false;
       if (err){
         console.error(err)
@@ -215,6 +215,7 @@ export default {
     },
     // 构建数据结构体
     async submitData(){
+      console.log('hello world')
       if(!this.arithmetic){return this.$message.warning('未选择算法')}
       if(!this.triggerType){return this.$message.warning('未选择触发类型')}
       if(this.triggerType!==this.triggerTypes.unlimited && !this.libraryId){return this.$message.warning('未选择对应的数据库')}
@@ -227,12 +228,10 @@ export default {
       data.resourcePath = this.resourcePath;
       data.uploadUrl = this.uploadUrl;
       data.pushUrl = this.pushUrl;
+      console.log(data);
       this.isLoading = true;
-      let [err,res] = handle(this.$axios({
-        method: 'post',
-        url: '/api/device/query/addAiConfig',
-        data:data
-      }));
+      let [err,res] = await handle(this.$axios.post('/api/device/config/addAiConfig',data));
+      console.log('---------------------')
       this.isLoading = false;
       if(err){
         console.error(err)

+ 1 - 1
web_src/src/components/dialog/addArithmetic.vue

@@ -105,7 +105,7 @@ export default {
       if(!this.selectConfigId){
         return this.$message.warning("请选择配置文件")
       }
-      this.$emit('select',this.selectConfigId);
+      this.$emit('select',this.selectConfigId,this.arithmetic);
       this.$nextTick(()=>{
         this.showThisDialog = false;
       })

+ 19 - 12
参考文档/数据库扩展.md

@@ -12,17 +12,17 @@
 | total | int    | n | 图像数量 |
 
 ### 图像 lib_item
-| 字段    | 类型     | 可选值 | 备注  |
-|-------|--------| --- |-----|
-| libId | int    | pk | 项目id |
-| libraryId | int    | tk | 图像库id  |
-| itemType | int    | 1,2 | 数据类型,图片,文本 |
-| imageUrl | string | url | 图片的链接 |
-| trait | string | '' | 用来匹配的图片的特征值 |
-| textValue | string | '' | 用于匹配的值 |
-| personName | string | '' | 人员名称 |
-| workerNo | string | '' | 工号 |
-| idCard | string | '' | 身份证号 |
+| 字段        | 类型     | 可选值 | 备注            |
+|-----------|--------| --- |---------------|
+| itemId    | int    | pk | 项目id          |
+| libraryId | int    | tk | 图像库id         |
+| itemType  | int    | 1,2 | 数据类型,图片,文本    |
+| imageUrl  | string | url | 图片的链接         |
+| trait     | string | '' | 用来匹配的图片的特征值   |
+| itemName  | string | '' | 名称,用户名称或者车辆名称 |
+| itemNo    | string | '' | 标记号,用于车牌或者工号  |
+| idCard    | string | '' | 身份证号          |
+| carNo     | string | '' | 车牌号           |
 
 ## ai配置 aiConfigs
 | 字段    | 类型     | 可选值 | 备注  |
@@ -35,7 +35,7 @@
 | score | float  | 0.0-100.0 | 检测阈值 |
 | resourcePath | string | url | 资源数据更新获取地址 |
 | uploadUrl | string | url | 多媒体资源上传地址 |
-| pushUrl | string | url | 回调地址 | 
+| pushUrl | string | url | 回调地址 |
 
 
 资源获取地址 /api/device/lib?libId=xxxx
@@ -48,3 +48,10 @@
 | deviceId | int | tk | 设备id |
 | configId | int | tk | 配置id |
 | arithmetic | int | 1-3 | 对应的算法.人脸,火情,车牌, |
+
+### ai告警库 ai_alarm
+| 字段    | 类型  | 可选值 | 备注  |
+|-------|-----| --- |-----|
+
+
+