feat: 触控交互评估

This commit is contained in:
stream 2026-03-12 09:47:20 +08:00
parent 8fce38f447
commit 69f74f6227
13 changed files with 282 additions and 8 deletions

View File

@ -71,6 +71,12 @@
<groupId>com.cmvr</groupId> <groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-ti</artifactId> <artifactId>cmvr-iot-ti</artifactId>
</dependency> </dependency>
<!-- AI评估-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-evaluation</artifactId>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
<env>dev</env> <env>dev</env>

View File

@ -84,4 +84,17 @@ public class TiProjectController extends BaseController {
public AjaxResult queryExecuteInstId(@PathVariable("projectId") String projectId) { public AjaxResult queryExecuteInstId(@PathVariable("projectId") String projectId) {
return AjaxResult.ok(tiProjectService.queryExecuteInstId(projectId)); return AjaxResult.ok(tiProjectService.queryExecuteInstId(projectId));
} }
@ApiOperation("临时执行项目评估")
@PostMapping("/evaluation")
public AjaxResult evaluation(@RequestBody List<Long> funcIds) {
tiProjectService.executeTiEvaluation(funcIds);
return AjaxResult.ok();
}
@ApiOperation("评估查询")
@GetMapping("/evaluation/{projectId}")
public AjaxResult queryEvaluation(@PathVariable("projectId") String projectId) {
return AjaxResult.ok(tiProjectService.queryEvaluation(projectId));
}
} }

View File

@ -123,7 +123,7 @@ api:
TOUCH_COORDINATES: # 意图识别 TOUCH_COORDINATES: # 意图识别
app-id: d5thge2cktmipk78h82g app-id: d5thge2cktmipk78h82g
app-key: d1ebtabnjkflk4gmhikg app-key: d1ebtabnjkflk4gmhikg
evaluation: http://192.168.0.18:8000/analyze evaluation: http://192.168.0.8:8000/analyze
flowise: flowise:
tts: 192.168.0.222:8080/tts/ tts: 192.168.0.222:8080/tts/

View File

@ -1,4 +1,4 @@
package com.cmvr.test.service.ex; package com.cmvr.evaluation.service;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
@ -6,4 +6,6 @@ public interface ExTiProjectService {
public JSONObject queryById(String id); public JSONObject queryById(String id);
public boolean updateProjectStatus(String projectId, Integer status);
} }

View File

@ -16,6 +16,8 @@ public interface IAeEvaluationService extends IService<AeEvaluation> {
List<AeEvaluation> queryEvaluation(String instId); List<AeEvaluation> queryEvaluation(String instId);
public List<AeEvaluation> queryEvaluationByProjectId(String projectId);
/** /**
* 判断当前项目是否已完成全部评估 * 判断当前项目是否已完成全部评估
*/ */

View File

@ -8,8 +8,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cmvr.common.exception.GlobalException; import com.cmvr.common.exception.GlobalException;
import com.cmvr.evaluation.model.domain.AeEvaluation; import com.cmvr.evaluation.model.domain.AeEvaluation;
import com.cmvr.evaluation.service.AeCallbackService; import com.cmvr.evaluation.service.AeCallbackService;
import com.cmvr.evaluation.service.ExTiProjectService;
import com.cmvr.evaluation.service.ExViProjectService; import com.cmvr.evaluation.service.ExViProjectService;
import com.cmvr.evaluation.service.IAeEvaluationService; import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.test.enums.RunModeEnum;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,6 +27,7 @@ public class AeCallbackServiceImpl implements AeCallbackService {
private final IAeEvaluationService aeEvaluationService; private final IAeEvaluationService aeEvaluationService;
private final ExViProjectService exViProjectService; private final ExViProjectService exViProjectService;
private final ExTiProjectService exTiProjectService;
@Override @Override
public void callback(AeEvaluation aeEvaluation) { public void callback(AeEvaluation aeEvaluation) {
@ -59,7 +62,13 @@ public class AeCallbackServiceImpl implements AeCallbackService {
// 判断是否是最后一次评估 更改项目状态 // 判断是否是最后一次评估 更改项目状态
boolean finished = aeEvaluationService.isAllEvaluationsFinished(byId.getInstId()); boolean finished = aeEvaluationService.isAllEvaluationsFinished(byId.getInstId());
if (finished) { if (!finished) {
return;
}
String aeType = aeEvaluation.getAeType();
if (RunModeEnum.TI_PROJECT.name().equals(aeType)) {
exTiProjectService.updateProjectStatus(byId.getTaskId(), 2);
} else {
exViProjectService.updateStatus(byId.getTaskId()); exViProjectService.updateStatus(byId.getTaskId());
} }
} }

View File

@ -194,7 +194,8 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} else if (aeType.equals(RunModeEnum.TI_PROJECT.name())) { } else if (aeType.equals(RunModeEnum.TI_PROJECT.name())) {
// 触控交互评估
} else { } else {
throw new GlobalException("错误的评估任务类型!仅支持语音交互和触控交互!"); throw new GlobalException("错误的评估任务类型!仅支持语音交互和触控交互!");
} }
@ -236,6 +237,13 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
return this.list(wrapper); return this.list(wrapper);
} }
@Override
public List<AeEvaluation> queryEvaluationByProjectId(String projectId) {
LambdaQueryWrapper<AeEvaluation> wrapper = Wrappers.lambdaQuery(AeEvaluation.class);
wrapper.eq(AeEvaluation::getTaskId, projectId);
return this.list(wrapper);
}
@Override @Override
public boolean isAllEvaluationsFinished(String instId) { public boolean isAllEvaluationsFinished(String instId) {
long total = this.count( long total = this.count(

View File

@ -30,8 +30,11 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(), metaObject); this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(), metaObject);
this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject); this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
this.setFieldValByName(DELETED, "0", metaObject); this.setFieldValByName(DELETED, "0", metaObject);
// this.setFieldValByName(STATUS, "1", metaObject);
if (getFieldValByName(STATUS, metaObject) == null) {
this.setFieldValByName(STATUS, "1", metaObject); this.setFieldValByName(STATUS, "1", metaObject);
} }
}
/** /**
* 更新时的填充策略 * 更新时的填充策略

View File

@ -28,6 +28,11 @@
<artifactId>cmvr-iot-test</artifactId> <artifactId>cmvr-iot-test</artifactId>
</dependency> </dependency>
<!-- AI评估-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-evaluation</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -74,7 +74,7 @@ public class TiProject extends BaseEntity {
@ApiModelProperty("送样日期") @ApiModelProperty("送样日期")
private Date sampleDate; private Date sampleDate;
@ApiModelProperty(value = "状态", notes = "状态0已执行 1未执行") @ApiModelProperty(value = "状态", notes = "状态0未执行 1执行中 2执行完成评估")
private String status; private String status;
@ApiModelProperty(value = "评价id") @ApiModelProperty(value = "评价id")

View File

@ -1,8 +1,8 @@
package com.cmvr.ti.service; package com.cmvr.ti.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.cmvr.evaluation.model.vo.AeViEvaluationVO;
import com.cmvr.test.model.domain.TeTaskInst; import com.cmvr.test.model.domain.TeTaskInst;
import com.cmvr.test.model.vo.TeQueryProjectOrchestraItemVO;
import com.cmvr.test.model.vo.TeQueryTaskOrchestraItemVO; import com.cmvr.test.model.vo.TeQueryTaskOrchestraItemVO;
import com.cmvr.test.model.vo.TeTaskExecuteProjectVO; import com.cmvr.test.model.vo.TeTaskExecuteProjectVO;
import com.cmvr.ti.model.domain.TiProject; import com.cmvr.ti.model.domain.TiProject;
@ -27,4 +27,10 @@ public interface ITiProjectService extends IService<TiProject> {
public TeTaskInst getTeTaskInst(String projectId); public TeTaskInst getTeTaskInst(String projectId);
public String queryExecuteInstId(String projectId); public String queryExecuteInstId(String projectId);
public boolean updateProjectStatus(String projectId, Integer status);
public void executeTiEvaluation(List<Long> funcIds);
public AeViEvaluationVO queryEvaluation(String projectId);
} }

View File

@ -1,7 +1,7 @@
package com.cmvr.ti.service.ex; package com.cmvr.ti.service.ex;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.cmvr.test.service.ex.ExTiProjectService; import com.cmvr.evaluation.service.ExTiProjectService;
import com.cmvr.ti.service.ITiProjectService; import com.cmvr.ti.service.ITiProjectService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -16,4 +16,9 @@ public class ExTiProjectServiceImpl implements ExTiProjectService {
public JSONObject queryById(String id) { public JSONObject queryById(String id) {
return JSONObject.from(tiProjectService.getById(id)); return JSONObject.from(tiProjectService.getById(id));
} }
@Override
public boolean updateProjectStatus(String projectId, Integer status) {
return tiProjectService.updateProjectStatus(projectId, status);
}
} }

View File

@ -1,13 +1,25 @@
package com.cmvr.ti.service.impl; package com.cmvr.ti.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmvr.common.core.domain.entity.SysDictData;
import com.cmvr.common.exception.GlobalException; import com.cmvr.common.exception.GlobalException;
import com.cmvr.evaluation.model.domain.AeEvaluation;
import com.cmvr.evaluation.model.domain.AeIndicatorEntity;
import com.cmvr.evaluation.model.dto.AeIResultDTO;
import com.cmvr.evaluation.model.vo.AeViEvaluationVO;
import com.cmvr.evaluation.service.AeIndicatorService;
import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.system.service.ISysDictTypeService;
import com.cmvr.test.enums.FlowSceneTypeEnum; import com.cmvr.test.enums.FlowSceneTypeEnum;
import com.cmvr.test.enums.RunModeEnum; import com.cmvr.test.enums.RunModeEnum;
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService; import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
@ -26,12 +38,19 @@ import com.cmvr.ti.model.domain.TiVehicleFunction;
import com.cmvr.ti.service.ITiProjectService; import com.cmvr.ti.service.ITiProjectService;
import com.cmvr.ti.service.ITiVehicleFunctionService; import com.cmvr.ti.service.ITiVehicleFunctionService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -42,6 +61,11 @@ public class TiProjectServiceImpl extends ServiceImpl<TiProjectMapper, TiProject
private final ITeTaskConfigInfoService taskConfigInfoService; private final ITeTaskConfigInfoService taskConfigInfoService;
private final FlowTaskRuntimeService flowTaskRuntimeService; private final FlowTaskRuntimeService flowTaskRuntimeService;
private final ITiVehicleFunctionService tiVehicleFunctionService; private final ITiVehicleFunctionService tiVehicleFunctionService;
private final ISysDictTypeService dictTypeService;
private final StringRedisTemplate redisTemplate;
private final IAeEvaluationService aeEvaluationService;
private final AeIndicatorService aeIndicatorService;
private final ITiVehicleFunctionService vehicleFunctionService;
@Override @Override
public TiProject selectTiProjectByProjectId(String projectId) { public TiProject selectTiProjectByProjectId(String projectId) {
@ -75,6 +99,7 @@ public class TiProjectServiceImpl extends ServiceImpl<TiProjectMapper, TiProject
throw new GlobalException("功能ID不属于同一车型配置"); throw new GlobalException("功能ID不属于同一车型配置");
} }
tiProject.setStatus("0");
int insert = this.baseMapper.insert(tiProject); int insert = this.baseMapper.insert(tiProject);
TeTaskConfigInfo taskConfigInfo = new TeTaskConfigInfo(); TeTaskConfigInfo taskConfigInfo = new TeTaskConfigInfo();
taskConfigInfo.setRunMode(RunModeEnum.TI_PROJECT.name()); taskConfigInfo.setRunMode(RunModeEnum.TI_PROJECT.name());
@ -132,4 +157,194 @@ public class TiProjectServiceImpl extends ServiceImpl<TiProjectMapper, TiProject
public String queryExecuteInstId(String projectId) { public String queryExecuteInstId(String projectId) {
return ""; return "";
} }
@Override
public boolean updateProjectStatus(String projectId, Integer status) {
LambdaUpdateWrapper<TiProject> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(TiProject::getProjectId, projectId)
.set(TiProject::getStatus, status);
return this.update(null, wrapper);
}
// 功能ID -> 音频地址
private final Map<String, String> AUDIO_PATH_MAP = new HashMap<String, String>() {{
put("8", "http://192.168.0.100:9000/cmvr-iot/AUDIO/20260310/1773108837127.wav"); // 播放音乐
put("12", "http://192.168.0.100:9000/cmvr-iot/AUDIO/20260310/1773108916488.wav"); // 打开导航
put("9", "http://192.168.0.100:9000/cmvr-iot/AUDIO/20260310/1773108933968.wav"); // 能量回收
}};
// 功能ID -> 视频地址
private final Map<String, String> VIDEO_PATH_MAP = new HashMap<String, String>() {{
put("8", "http://192.168.0.100:9000/cmvr-iot/VIDEO/20260310/1773108955700.mp4"); // 播放音乐
put("12", "http://192.168.0.100:9000/cmvr-iot/VIDEO/20260310/1773108967164.mp4"); // 打开导航
put("9", "http://192.168.0.100:9000/cmvr-iot/VIDEO/20260310/1773108978124.mp4"); // 能量回收
}};
@Override
public void executeTiEvaluation(List<Long> funcIds) {
AeEvaluation aeEvaluation = new AeEvaluation();
aeEvaluation.setAeType(RunModeEnum.TI_PROJECT.name());
aeEvaluation.setInstId(IdUtil.fastSimpleUUID());
aeEvaluation.setTaskId("aadb21a32e7990456b866e844a7d4a54");
aeEvaluation.setItemId(IdUtil.fastSimpleUUID());
// todo 触控交互评估
String taskId = aeEvaluation.getTaskId();
updateProjectStatus(taskId, 1); // 执行中
// 模拟流程运行
// try {
// Thread.sleep(30000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// 查字典
List<SysDictData> tiFunctionConfig = dictTypeService.selectDictDataByType("ti_function_config");
Map<String, String> functionMap = tiFunctionConfig.stream()
.collect(Collectors.toMap(
SysDictData::getDictValue,
SysDictData::getDictLabel
));
// 构建评估任务列表
List<AeEvaluation> evaluations = new LinkedList<>();
for (Long funcId : funcIds) {
TiVehicleFunction byId = vehicleFunctionService.getById(funcId);
String funcName = functionMap.get(byId.getFuncKey());
AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(aeEvaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0); // 待评估
eval.setAvContent(funcName);
eval.setAudioPath(AUDIO_PATH_MAP.get(byId.getFuncKey()));
eval.setVideoPath(VIDEO_PATH_MAP.get(byId.getFuncKey()));
evaluations.add(eval);
}
try {
// 入库
aeEvaluationService.saveBatch(evaluations);
// 提交评估
for (AeEvaluation e : evaluations) {
redisTemplate.opsForList()
.rightPush("ae:evaluation:queue", JSON.toJSONString(e));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public AeViEvaluationVO queryEvaluation(String projectId) {
// 1. 查询项目
TiProject project = getById(projectId);
// 2. 查询评估数据允许不完整
List<AeEvaluation> evaluations = aeEvaluationService.queryEvaluationByProjectId(projectId);
if (CollUtil.isEmpty(evaluations)) {
throw new GlobalException(StrUtil.format("暂无项目id为{}的数据", projectId));
}
// 3. 获取指标定义
List<AeIndicatorEntity> indicators =
aeIndicatorService.getChildrenByParentIdWithLevelLimit(
project.getIndicatorId(), 4, 1
);
List<AeViEvaluationVO.AeItemDetail> itemDetails = new ArrayList<>();
int failureCount = 0;
for (AeEvaluation evaluation : evaluations) {
AeViEvaluationVO.AeItemDetail itemDto = new AeViEvaluationVO.AeItemDetail();
itemDto.setAeId(evaluation.getAeId());
itemDto.setContent(evaluation.getAvContent());
AeIResultDTO dto = JSON.parseObject(evaluation.getResult(), AeIResultDTO.class);
itemDto.setItemResponseTime(dto.getResponseTime());
itemDto.setStatus(evaluation.getStatus());
boolean success = "成功".equals(dto.getOverallResult());
if (!success) {
itemDto.setFailureReason(dto.getFailureReason());
failureCount++;
}
itemDto.setVideoPath(dto.getVideoPath());
itemDto.setExecutionDetail(dto.getExecutionDetail());
itemDetails.add(itemDto);
}
// 计算成功率
Long successRate = (long) (((evaluations.size() - failureCount) * 100.0) / evaluations.size());
//成功率得分
Long score = calculateSuccessRateScore(successRate, indicators);
AeViEvaluationVO vo = new AeViEvaluationVO();
vo.setItemDetails(itemDetails);
vo.setSuccessRate(successRate);
vo.setSuccessRateScore(score);
return vo;
}
private Long calculateSuccessRateScore(Long successRate, List<AeIndicatorEntity> indicators) {
// 查找成功率指标
AeIndicatorEntity successRateIndicator = findIndicatorByName(indicators, "成功率");
if (successRateIndicator == null) {
return 0L; // 如果没有匹配的成功率指标返回 0
}
List<AeIndicatorEntity> children = successRateIndicator.getChildren();
long score = 0L;
for (AeIndicatorEntity child : children) {
// 子指标的比较值例如响应时间阈值和符号 <, <=, >, >=
BigDecimal compareValue1 = child.getCompareNum1();
BigDecimal compareValue2 = child.getCompareNum2();
String symbol = child.getSymbol();
// 4. 根据符号和阈值判断响应时间是否符合子指标的规则计算得分
if (compareRange(successRate, compareValue1, compareValue2, symbol)) {
score = child.getScore().longValue(); // 得分等于子指标的得分
break; // 找到符合条件的子指标后直接返回得分
}
}
return score;
}
private AeIndicatorEntity findIndicatorByName(List<AeIndicatorEntity> indicators, String indicatorName) {
for (AeIndicatorEntity indicator : indicators) {
if (indicator.getName().equals(indicatorName)) {
return indicator;
}
}
return null; // 如果找不到返回null
}
// 处理区间比较例如<=>=
private boolean compareRange(Long itemResponseTime, BigDecimal compareValue1, BigDecimal compareValue2, String symbol) {
// 如果 compareValue1 > compareValue2交换两者
if (compareValue1.compareTo(compareValue2) > 0) {
BigDecimal temp = compareValue1;
compareValue1 = compareValue2;
compareValue2 = temp;
}
switch (symbol) {
case "":
return itemResponseTime <= compareValue2.longValue() && itemResponseTime >= compareValue1.longValue();
case "<":
return itemResponseTime < compareValue2.longValue() && itemResponseTime >= compareValue1.longValue();
case ">":
return itemResponseTime > compareValue1.longValue() && itemResponseTime <= compareValue2.longValue();
case "":
return itemResponseTime >= compareValue1.longValue() && itemResponseTime <= compareValue2.longValue();
default:
return false;
}
}
} }