iailab-module-ai/iailab-module-ai-api/pom.xml
@@ -40,5 +40,15 @@ <artifactId>spring-boot-starter-validation</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-core</artifactId> </dependency> <dependency> <groupId>io.swagger.core.v3</groupId> <artifactId>swagger-annotations</artifactId> <version>2.2.25</version> <scope>compile</scope> </dependency> </dependencies> </project> iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/controller/admin/questiontemplate/QuestionTemplateController.java
@@ -1,5 +1,6 @@ package com.iailab.module.ai.controller.admin.questiontemplate; import com.iailab.module.ai.service.model.AiModelService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; @@ -13,6 +14,7 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.pojo.CommonResult; import com.iailab.framework.common.util.object.BeanUtils; import static com.iailab.framework.common.pojo.CommonResult.success; @@ -28,6 +30,9 @@ @Resource private QuestionTemplateService questionTemplateService; @Resource private AiModelService aiModelService; @PostMapping("/create") @Operation(summary = "创建大模型问题模板") @@ -67,6 +72,11 @@ @PreAuthorize("@ss.hasPermission('ai:question-template:query')") public CommonResult<PageResult<QuestionTemplateRespVO>> getQuestionTemplatePage(@Valid QuestionTemplatePageReqVO pageReqVO) { PageResult<QuestionTemplateDO> pageResult = questionTemplateService.getQuestionTemplatePage(pageReqVO); pageResult.getList().forEach(questionTemplateDO -> questionTemplateDO.setModelName( aiModelService.getModel(Long.valueOf((questionTemplateDO.getModelId()))).getName() ) ); return success(BeanUtils.toBean(pageResult, QuestionTemplateRespVO.class)); } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/controller/admin/questiontemplate/vo/QuestionTemplateRespVO.java
@@ -1,8 +1,11 @@ package com.iailab.module.ai.controller.admin.questiontemplate.vo; import com.baomidou.mybatisplus.annotation.TableField; import com.iailab.module.ai.controller.admin.questionparamsetting.vo.QuestionParamSettingRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.time.LocalDateTime; import java.util.List; @Schema(description = "管理后台 - 大模型问题模板 Response VO") @Data @@ -13,6 +16,9 @@ @Schema(description = "模型id", requiredMode = Schema.RequiredMode.REQUIRED, example = "11609") private String modelId; @Schema(description = "模型名称") public String modelName; @Schema(description = "问题编号", requiredMode = Schema.RequiredMode.REQUIRED) private String questionCode; @@ -35,4 +41,5 @@ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; private List<QuestionParamSettingRespVO> settingList; } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/controller/admin/questiontemplate/vo/QuestionTemplateSaveReqVO.java
@@ -1,9 +1,11 @@ package com.iailab.module.ai.controller.admin.questiontemplate.vo; import com.iailab.module.ai.controller.admin.questionparamsetting.vo.QuestionParamSettingSaveReqVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import javax.validation.constraints.*; import java.time.LocalDateTime; import java.util.List; @Schema(description = "管理后台 - 大模型问题模板新增/修改 Request VO") @Data @@ -35,4 +37,6 @@ @Schema(description = "备注", example = "随便") private String remark; @Schema(description = "问题模版列表") private List<QuestionParamSettingSaveReqVO> settingList; } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/dal/dataobject/questionparamsetting/QuestionParamSettingDO.java
@@ -23,7 +23,7 @@ /** * id */ @TableId(type = IdType.INPUT) @TableId(type = IdType.ASSIGN_ID) private String id; /** * 问题模板id iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/dal/dataobject/questiontemplate/QuestionTemplateDO.java
@@ -1,8 +1,13 @@ package com.iailab.module.ai.dal.dataobject.questiontemplate; import com.iailab.module.ai.controller.admin.questionparamsetting.vo.QuestionParamSettingRespVO; import com.iailab.module.ai.controller.admin.questiontemplate.vo.QuestionTemplateSaveReqVO; import com.iailab.module.ai.dal.dataobject.model.AiModelDO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.time.LocalDateTime; import java.util.List; import com.baomidou.mybatisplus.annotation.*; import com.iailab.framework.mybatis.core.dataobject.BaseDO; @@ -56,4 +61,9 @@ */ private String remark; @TableField(exist = false) private List<QuestionParamSettingRespVO> settingList; @TableField(exist = false) public String modelName; } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/dal/mysql/questionparamsetting/QuestionParamSettingMapper.java
@@ -1,5 +1,7 @@ package com.iailab.module.ai.dal.mysql.questionparamsetting; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; import com.iailab.framework.mybatis.core.mapper.BaseMapperX; @@ -25,4 +27,7 @@ .orderByDesc(QuestionParamSettingDO::getId)); } default int deleteByTemplateId(String templateId) { return delete("template_id",templateId); } } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/service/questiontemplate/QuestionTemplateService.java
@@ -4,6 +4,9 @@ import com.iailab.module.ai.controller.admin.questiontemplate.vo.*; import com.iailab.module.ai.dal.dataobject.questiontemplate.QuestionTemplateDO; import com.iailab.framework.common.pojo.PageResult; import org.apache.ibatis.annotations.Param; import java.util.List; /** * 大模型问题模板 Service 接口 @@ -50,4 +53,12 @@ */ PageResult<QuestionTemplateDO> getQuestionTemplatePage(QuestionTemplatePageReqVO pageReqVO); /** * 根据模型id获得大模型问题模板列表 * * @param modelId 模型id * @return 大模型问题模板列表 */ List<QuestionTemplateDO> getQuestionTemplateList(@Param("modelId") Long modelId ); } iailab-module-ai/iailab-module-ai-biz/src/main/java/com/iailab/module/ai/service/questiontemplate/QuestionTemplateServiceImpl.java
@@ -1,5 +1,8 @@ package com.iailab.module.ai.service.questiontemplate; import com.iailab.module.ai.controller.admin.questionparamsetting.vo.QuestionParamSettingRespVO; import com.iailab.module.ai.dal.dataobject.questionparamsetting.QuestionParamSettingDO; import com.iailab.module.ai.dal.mysql.questionparamsetting.QuestionParamSettingMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -10,6 +13,9 @@ import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.module.ai.dal.mysql.questiontemplate.QuestionTemplateMapper; import java.util.List; import java.util.UUID; import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.iailab.module.ai.enums.ErrorCodeConstants.*; @@ -26,10 +32,20 @@ @Resource private QuestionTemplateMapper questionTemplateMapper; @Resource private QuestionParamSettingMapper questionParamSettingMapper; @Override public String createQuestionTemplate(QuestionTemplateSaveReqVO createReqVO) { // 插入 QuestionTemplateDO questionTemplate = BeanUtils.toBean(createReqVO, QuestionTemplateDO.class); String id = UUID.randomUUID().toString(); questionTemplate.setId(id); // 插入设置列表 createReqVO.getSettingList().forEach(setting -> { setting.setTemplateId(id); questionParamSettingMapper.insert(BeanUtils.toBean(setting, QuestionParamSettingDO.class)); }); questionTemplateMapper.insert(questionTemplate); // 返回 return questionTemplate.getId(); @@ -41,6 +57,14 @@ validateQuestionTemplateExists(updateReqVO.getId()); // 更新 QuestionTemplateDO updateObj = BeanUtils.toBean(updateReqVO, QuestionTemplateDO.class); // 删除设置列表 questionParamSettingMapper.deleteByTemplateId(updateReqVO.getId()); // 更新设置列表 updateReqVO.getSettingList().forEach(setting -> { setting.setTemplateId(updateReqVO.getId()); setting.setId(null); questionParamSettingMapper.insert(BeanUtils.toBean(setting, QuestionParamSettingDO.class)); }); questionTemplateMapper.updateById(updateObj); } @@ -50,6 +74,8 @@ validateQuestionTemplateExists(id); // 删除 questionTemplateMapper.deleteById(id); // 删除设置列表 questionParamSettingMapper.deleteByTemplateId(id); } private void validateQuestionTemplateExists(String id) { @@ -60,7 +86,9 @@ @Override public QuestionTemplateDO getQuestionTemplate(String id) { return questionTemplateMapper.selectById(id); QuestionTemplateDO questionTemplateDO = questionTemplateMapper.selectById(id); questionTemplateDO.setSettingList(BeanUtils.toBean(questionParamSettingMapper.selectList("template_id",id), QuestionParamSettingRespVO.class)); return questionTemplateDO; } @Override @@ -68,4 +96,13 @@ return questionTemplateMapper.selectPage(pageReqVO); } @Override public List<QuestionTemplateDO> getQuestionTemplateList(Long modelId) { List<QuestionTemplateDO> questionTemplateDOList = questionTemplateMapper.selectList("model_id",modelId); questionTemplateDOList.forEach(DO -> { BeanUtils.toBean(questionParamSettingMapper.selectList("template_id",DO.getId()), QuestionParamSettingRespVO.class); }); return questionTemplateDOList; } } iailab-module-ai/iailab-module-ai-biz/src/main/resources/application.yaml
@@ -220,5 +220,7 @@ ignore-tables: - ai_api_key - ai_model - ai_question_template - ai_question_param_setting debug: true iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java
@@ -1,6 +1,7 @@ package com.iailab.module.data.point.collection.handler; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.iailab.framework.common.util.string.StrUtils; import com.iailab.module.data.common.enums.CommonConstant; import com.iailab.module.data.common.enums.DataTypeEnum; @@ -16,6 +17,7 @@ import org.apache.commons.lang3.StringUtils; import javax.annotation.Resource; import javax.validation.constraints.Max; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -24,6 +26,7 @@ import java.math.BigDecimal; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; /** @@ -58,7 +61,13 @@ @Autowired private RedisTemplate<String, Object> redisTemplate; public static final String regex = "[+\\-\\*/()\\&\\|\\>\\<]"; public final static String regex = "[+\\-\\*/()\\&\\|\\>\\<]"; private final static String POINT_PREFIX = "C"; private final static String PENDING_FLAG = "pending"; private final static int MAX_RECURSION = 10; public List<InfluxPointValuePOJO> handle(Date collectTime, List<DaPointDTO> dtos, Map<String, Object> dataMap, List<String> listGood, List<String> listBad) { List<InfluxPointValuePOJO> result = new ArrayList<>(); @@ -67,33 +76,83 @@ if (CollectionUtils.isEmpty(dtos)) { return result; } Map<String, DaPointDTO> pendingMap = new HashMap<>(); log.info(JSON.toJSONString(listBad)); dtos.forEach(dto -> { try { Object rawValue = singleCompute(dto, dataMap, listGood, listBad); BigDecimal coefficient = dto.getUnittransfactor() == null ? BigDecimal.ONE : dto.getUnittransfactor(); BigDecimal calValue = new BigDecimal(rawValue.toString()).multiply(coefficient); if (dto.getMaxValue() != null && calValue.compareTo(dto.getMaxValue()) > 0) { calValue = dto.getMaxValue(); } else if (dto.getMinValue() != null && calValue.compareTo(dto.getMinValue()) < 0) { calValue = dto.getMinValue(); if (PENDING_FLAG.equals(rawValue.toString())) { pendingMap.put(dto.getPointNo(), dto); } else { BigDecimal coefficient = dto.getUnittransfactor() == null ? BigDecimal.ONE : dto.getUnittransfactor(); BigDecimal calValue = new BigDecimal(rawValue.toString()).multiply(coefficient); if (dto.getMaxValue() != null && calValue.compareTo(dto.getMaxValue()) > 0) { calValue = dto.getMaxValue(); } else if (dto.getMinValue() != null && calValue.compareTo(dto.getMinValue()) < 0) { calValue = dto.getMinValue(); } dataMap.put(dto.getPointNo(), calValue); InfluxPointValuePOJO pojo = GenInfluxPointValueUtils.getByPoint(dto, calValue); pojo.setTimestamp(GenInfluxPointValueUtils.getByMin(collectTime, DataPointFreqEnum.getEumByCode(dto.getMinfreqid()))); result.add(pojo); } InfluxPointValuePOJO pojo = GenInfluxPointValueUtils.getByPoint(dto, calValue); pojo.setTimestamp(GenInfluxPointValueUtils.getByMin(collectTime, DataPointFreqEnum.getEumByCode(dto.getMinfreqid()))); result.add(pojo); } catch (Exception ex) { ex.printStackTrace(); log.info("计算点异常!PointNo=" + dto.getPointNo()); } }); log.info("计算点处理结束"); Map<DaPointDTO, Object> valueResult = new HashMap<>(); handPending(pendingMap, dataMap, listGood, listBad, valueResult, 1); log.info("valueResult size=" + valueResult.size()); valueResult.forEach((key, value) -> { InfluxPointValuePOJO pojo = GenInfluxPointValueUtils.getByPoint(key, value); pojo.setTimestamp(GenInfluxPointValueUtils.getByMin(collectTime, DataPointFreqEnum.getEumByCode(key.getMinfreqid()))); result.add(pojo); }); log.info("计算点处理结束"); } catch (Exception ex) { ex.printStackTrace(); log.info("计算点处理异常!"); } return result; } private void handPending(Map<String, DaPointDTO> pendingMap, Map<String, Object> dataMap, List<String> listGood, List<String> listBad, Map<DaPointDTO, Object> valueResult, int count) { Map<String, DaPointDTO> tempMap = new HashMap<>(); if (CollectionUtils.isEmpty(pendingMap)) { log.info("pendingMap is empty"); return; } log.info("处理包含计算点的"); log.info("handPending count=" + count); if (count > MAX_RECURSION) { log.info("最多递归10次"); return; } count = count + 1; for(String key : pendingMap.keySet()) { DaPointDTO dto = pendingMap.get(key); Object rawValue = singleCompute(dto, dataMap, listGood, listBad); if (PENDING_FLAG.equals(rawValue.toString())) { tempMap.put(key, dto); } else { BigDecimal coefficient = dto.getUnittransfactor() == null ? BigDecimal.ONE : dto.getUnittransfactor(); BigDecimal calValue = new BigDecimal(rawValue.toString()).multiply(coefficient); if (dto.getMaxValue() != null && calValue.compareTo(dto.getMaxValue()) > 0) { calValue = dto.getMaxValue(); } else if (dto.getMinValue() != null && calValue.compareTo(dto.getMinValue()) < 0) { calValue = dto.getMinValue(); } dataMap.put(dto.getPointNo(), calValue); valueResult.put(dto, calValue); } } if (!CollectionUtils.isEmpty(tempMap)) { this.handPending(tempMap, dataMap, listGood, listBad, valueResult, count); } } private Object singleCompute(DaPointDTO dto, Map<String, Object> dataMap, List<String> listGood, List<String> listBad) { @@ -103,17 +162,25 @@ // 去掉arr中的空格 arr = Stream.of(arr).filter(StringUtils::isNotBlank).toArray(String[]::new); // 判断arr都在dataMap中包含 if (!Arrays.stream(arr).allMatch(dataMap::containsKey)) { /*if (!Arrays.stream(arr).allMatch(dataMap::containsKey)) { log.info("dataMap not contains key"); listBad.add(dto.getPointNo()); return CommonConstant.BAD_VALUE; } }*/ for (int i = 0; i < arr.length; i++) { String s = arr[i]; if (StringUtils.isNotBlank(s) && dataMap.containsKey(s)) { // 对每个数加(),否则负值报错 expression = expression.replace(s, "(" + dataMap.get(s).toString() + ")"); } else if(StringUtils.isNotBlank(s) && s.trim().startsWith(POINT_PREFIX)) { log.info("包含计算点,先挂起"); log.info("dataMap=" + JSONObject.toJSONString(dataMap)); return PENDING_FLAG; } else if(StringUtils.isNotBlank(s) && !dataMap.containsKey(s)) { log.info("dataMap not contains key " + s); listBad.add(dto.getPointNo()); return CommonConstant.BAD_VALUE; } } expression = expression.replace("&", "&&"); @@ -121,6 +188,7 @@ expression = expression.replace("False", "false"); expression = expression.replace("True", "true"); log.info("PointNo=" + dto.getPointNo() + ";expression=" + expression); String result = javaScriptHandler.eval(expression); log.info("result=" + result); if (result == null || result.contains(JsErrorCode.Infinity.name()) || result.contains(JsErrorCode.NaN.name())) { @@ -154,7 +222,7 @@ if (redisTemplate.hasKey(PointCollector.PV + item.getPointNo())) { value = redisTemplate.opsForValue().get(PointCollector.PV + item.getPointNo()); } else { Object rawValue = singleCompute(item); Object rawValue = singleCompute(item, 1); BigDecimal coefficient = item.getUnittransfactor() == null ? BigDecimal.ONE : item.getUnittransfactor(); value = new BigDecimal(rawValue.toString()).multiply(coefficient); } @@ -163,7 +231,7 @@ return data; } private Object singleCompute(DaPointDTO dto) { private Object singleCompute(DaPointDTO dto, int count) { String result = CommonConstant.BAD_VALUE.toString(); Map<String, Object> dataMap = new HashMap<>(); String expression = dto.getExpression(); @@ -179,6 +247,20 @@ dataMap.putAll(constantHandle.getCurrent(pointNos)); dataMap.putAll(cumulateHandle.getCurrent(pointNos)); dataMap.putAll(extremalHandle.getCurrent(pointNos)); if (s.trim().startsWith(POINT_PREFIX)) { log.info("计算点递归查询"); List<DaPointDTO> pointMathList = daPointService.getMathPoint(pointNos); if (CollectionUtils.isEmpty(pointMathList)) { return result; } log.info("count = " + count); if (count > MAX_RECURSION) { return result; } Object v = this.singleCompute(pointMathList.get(0), count); dataMap.put(s, v); count = count + 1; } if (dataMap.get(s) == null) { log.info("计算点数据异常"); log.info("pointNo=" + dto.getPointNo() + ";dataMap.key=" + s);