feat: 语音评估查询

This commit is contained in:
stream 2026-02-05 16:59:59 +08:00
parent 7ab5a64291
commit bf159ce7be
17 changed files with 550 additions and 153 deletions

View File

@ -3,8 +3,8 @@ package com.cmvr.web.controller.evaluation;
import com.cmvr.common.core.controller.BaseController; import com.cmvr.common.core.controller.BaseController;
import com.cmvr.common.core.domain.AjaxResult; import com.cmvr.common.core.domain.AjaxResult;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorCreateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorCreateDTO;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorUpdateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorUpdateDTO;
import com.cmvr.evaluation.service.AeIndicatorService; import com.cmvr.evaluation.service.AeIndicatorService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;

View File

@ -84,4 +84,10 @@ public class ViProjectController extends BaseController {
public AjaxResult queryExecuteInstId(@PathVariable("projectId") String projectId) { public AjaxResult queryExecuteInstId(@PathVariable("projectId") String projectId) {
return AjaxResult.ok(viProjectService.queryExecuteInstId(projectId)); return AjaxResult.ok(viProjectService.queryExecuteInstId(projectId));
} }
@ApiOperation("评估查询")
@GetMapping("/evaluation/{projectId}")
public AjaxResult queryEvaluation(@PathVariable("projectId") String projectId) {
return AjaxResult.ok(viProjectService.queryEvaluation(projectId));
}
} }

View File

@ -0,0 +1,31 @@
package com.cmvr.evaluation.model.dto;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("AI 评估结果明细")
public class AeIResultDTO {
@ApiModelProperty(value = "响应时间ms")
@JSONField(name = "response_time")
private Long responseTime;
@ApiModelProperty(value = "失败原因说明")
@JSONField(name = "failure_reason")
private String failureReason;
@ApiModelProperty(value = "整体评估结果(成功 / 失败)")
@JSONField(name = "overall_result")
private String overallResult;
@ApiModelProperty(value = "执行过程详情说明")
@JSONField(name = "execution_detail")
private String executionDetail;
@ApiModelProperty(value = "评估相关视频地址")
@JSONField(name = "videoPath")
private String videoPath;
}

View File

@ -1,4 +1,4 @@
package com.cmvr.evaluation.model.domain.dto; package com.cmvr.evaluation.model.dto;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package com.cmvr.evaluation.model.domain.dto; package com.cmvr.evaluation.model.dto;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@ -0,0 +1,15 @@
package com.cmvr.evaluation.model.dto;
import lombok.Data;
@Data
public class AeItemIndicatorResultDTO {
private String itemId;
/** 单 item 响应时间 */
private Long responseTime;
/** 单 item 是否成功 */
private Boolean success;
}

View File

@ -0,0 +1,65 @@
package com.cmvr.evaluation.model.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("语音交互评估")
public class AeViEvaluationVO {
@ApiModelProperty(value = "方案ID")
private String schemeId;
@ApiModelProperty(value = "方案名称")
private String schemeName;
@ApiModelProperty(value = "平均响应时间ms")
private Long responseTime;
@ApiModelProperty(value = "平均响应时间得分")
private Long responseTimeScore;
@ApiModelProperty(value = "成功率0-100")
private Long successRate;
@ApiModelProperty(value = "成功率得分")
private Long successRateScore;
@ApiModelProperty(value = "评估项详细列表")
private List<AeItemDetail> itemDetails;
/**
* 评估项详细信息
*/
@Data
@ApiModel("评估项详细")
public static class AeItemDetail {
@ApiModelProperty(value = "评估项ID")
private String aeId;
@ApiModelProperty(value = "文本")
private String content;
@ApiModelProperty(value = "评估项响应时间ms")
private Long itemResponseTime;
@ApiModelProperty(value = "是否成功true成功false失败")
private Boolean success;
@ApiModelProperty(value = "评估相关视频地址")
private String videoPath;
@ApiModelProperty(value = "失败原因说明")
private String failureReason;
@ApiModelProperty(value = "执行过程详情说明")
private String executionDetail;
}
}

View File

@ -2,8 +2,8 @@ package com.cmvr.evaluation.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.cmvr.evaluation.model.domain.AeIndicatorEntity; import com.cmvr.evaluation.model.domain.AeIndicatorEntity;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorCreateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorCreateDTO;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorUpdateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorUpdateDTO;
import java.util.List; import java.util.List;
@ -19,4 +19,6 @@ public interface AeIndicatorService extends IService<AeIndicatorEntity> {
boolean updateIndicator(AeIndicatorUpdateDTO dto); boolean updateIndicator(AeIndicatorUpdateDTO dto);
List<AeIndicatorEntity> getChildrenByParentIdWithLevelLimit(Long parentId, Integer maxLevel, Integer type); List<AeIndicatorEntity> getChildrenByParentIdWithLevelLimit(Long parentId, Integer maxLevel, Integer type);
List<AeIndicatorEntity> getChildrenByIndicatorIdWithLevel(Long indicatorId, Integer level, Integer type);
} }

View File

@ -3,6 +3,8 @@ package com.cmvr.evaluation.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.cmvr.evaluation.model.domain.AeEvaluation; import com.cmvr.evaluation.model.domain.AeEvaluation;
import java.util.List;
public interface IAeEvaluationService extends IService<AeEvaluation> { public interface IAeEvaluationService extends IService<AeEvaluation> {
/** /**
@ -14,4 +16,6 @@ public interface IAeEvaluationService extends IService<AeEvaluation> {
* 评估回调 * 评估回调
*/ */
void callback(AeEvaluation aeEvaluation); void callback(AeEvaluation aeEvaluation);
List<AeEvaluation> queryEvaluation(String instId);
} }

View File

@ -7,6 +7,7 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 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;
@ -26,6 +27,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -255,6 +257,13 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
runEvaluation(evaluation); runEvaluation(evaluation);
} }
@Override
public List<AeEvaluation> queryEvaluation(String instId) {
LambdaQueryWrapper<AeEvaluation> wrapper = Wrappers.lambdaQuery(AeEvaluation.class);
wrapper.eq(AeEvaluation::getInstId, instId);
return this.list(wrapper);
}
private Map<String, List<TeNodeInst>> buildSingleIterationMap(List<TeNodeInst> view) { private Map<String, List<TeNodeInst>> buildSingleIterationMap(List<TeNodeInst> view) {
return view.stream() return view.stream()
.filter(e -> StrUtil.isNotEmpty(e.getIteration())) .filter(e -> StrUtil.isNotEmpty(e.getIteration()))
@ -270,7 +279,6 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
)); ));
} }
private Map<String, List<TeNodeInst>> buildContinuousIterationMap(List<TeNodeInst> view) { private Map<String, List<TeNodeInst>> buildContinuousIterationMap(List<TeNodeInst> view) {
return view.stream() return view.stream()
@ -303,7 +311,6 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
return paramsOut.getJSONObject("audioUrl").getString("audioUrl"); return paramsOut.getJSONObject("audioUrl").getString("audioUrl");
} }
private String extractVideoUrl(List<TeNodeInst> nodeList) { private String extractVideoUrl(List<TeNodeInst> nodeList) {
TeNodeInst recordingInst = nodeList.stream() TeNodeInst recordingInst = nodeList.stream()
.filter(e -> ActionEnum.CAMERA_RECORDING_STOP.getAction().equals(e.getAction())) .filter(e -> ActionEnum.CAMERA_RECORDING_STOP.getAction().equals(e.getAction()))

View File

@ -1,13 +1,14 @@
package com.cmvr.evaluation.service.impl; package com.cmvr.evaluation.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 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.evaluation.mapper.AeIndicatorMapper; import com.cmvr.evaluation.mapper.AeIndicatorMapper;
import com.cmvr.evaluation.model.domain.AeIndicatorEntity; import com.cmvr.evaluation.model.domain.AeIndicatorEntity;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorCreateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorCreateDTO;
import com.cmvr.evaluation.model.domain.dto.AeIndicatorUpdateDTO; import com.cmvr.evaluation.model.dto.AeIndicatorUpdateDTO;
import com.cmvr.evaluation.service.AeIndicatorService; import com.cmvr.evaluation.service.AeIndicatorService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,8 +19,6 @@ import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@ -123,9 +122,19 @@ public class AeIndicatorServiceImpl extends ServiceImpl<AeIndicatorMapper, AeInd
return buildTree(parentId, currentLevel, maxLevel, type); return buildTree(parentId, currentLevel, maxLevel, type);
} }
@Override
public List<AeIndicatorEntity> getChildrenByIndicatorIdWithLevel(Long indicatorId, Integer level, Integer type) {
LambdaQueryWrapper<AeIndicatorEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(AeIndicatorEntity::getParentId, indicatorId)
.eq(AeIndicatorEntity::getLevel, level)
.eq(AeIndicatorEntity::getType, type);
return this.list(wrapper);
}
/** /**
* 私有工具方法递归查询指定ID的所有后代指标ID重孙无限级 * 私有工具方法递归查询指定ID的所有后代指标ID重孙无限级
* @param parentId /祖指标ID *
* @param parentId /祖指标ID
* @param childrenIds 用于收集所有后代ID的集合引用传递 * @param childrenIds 用于收集所有后代ID的集合引用传递
*/ */
private void findAllChildrenIds(Long parentId, List<Long> childrenIds) { private void findAllChildrenIds(Long parentId, List<Long> childrenIds) {
@ -218,10 +227,11 @@ public class AeIndicatorServiceImpl extends ServiceImpl<AeIndicatorMapper, AeInd
/** /**
* 私有递归辅助方法核心构建树形结构实现层级限制 * 私有递归辅助方法核心构建树形结构实现层级限制
* @param parentId 当前父节点ID *
* @param parentId 当前父节点ID
* @param currentLevel 当前要构建的节点层级 * @param currentLevel 当前要构建的节点层级
* @param maxLevel 允许的最大层级达到则停止递归 * @param maxLevel 允许的最大层级达到则停止递归
* @param type 指标类型 0-语音 1-触控 * @param type 指标类型 0-语音 1-触控
* @return 带children的树形节点列表 * @return 带children的树形节点列表
*/ */
private List<AeIndicatorEntity> buildTree(Long parentId, Integer currentLevel, Integer maxLevel, Integer type) { private List<AeIndicatorEntity> buildTree(Long parentId, Integer currentLevel, Integer maxLevel, Integer type) {

View File

@ -50,7 +50,7 @@ public class FlowTaskEngine {
message.setPendingItemCount(pendingItemCount); message.setPendingItemCount(pendingItemCount);
JSONObject jsonObject = runParams.getJSONObject(itemId); JSONObject jsonObject = runParams.getJSONObject(itemId);
if (runMode.equals(RunModeEnum.NORMAL)) { if (!runMode.equals(RunModeEnum.TRIAL)) {
context.setRunParams(jsonObject); context.setRunParams(jsonObject);
} }
flowTaskExecutor.executeGraph(message, item, latch::countDown); flowTaskExecutor.executeGraph(message, item, latch::countDown);

View File

@ -15,6 +15,8 @@ import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class EdgeCameraOperateService implements EdgeOperateService { public class EdgeCameraOperateService implements EdgeOperateService {
@ -28,6 +30,15 @@ public class EdgeCameraOperateService implements EdgeOperateService {
return action.name().startsWith("CAMERA_"); return action.name().startsWith("CAMERA_");
} }
private static final String[] VIDEO_URLS = {
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20260205/1770257486644.mp4", // 单次 东北话中的那疙瘩什么意思
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20260205/1770257510949.mp4",// 单次 打开视频
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20260205/1770257536282.mp4", // 连续 导航到解放碑
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20260205/1770257552050.mp4" // 连续 青花瓷
};
private AtomicInteger currentIndex = new AtomicInteger(0);
@Override @Override
public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message) { public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message) {
// try { // try {
@ -127,6 +138,8 @@ public class EdgeCameraOperateService implements EdgeOperateService {
// String videoUrl = videoInfo.getString("videoUrl"); // String videoUrl = videoInfo.getString("videoUrl");
// String url = sysFileService.uploadFile(new File(videoUrl), FileType.VIDEO.code()); // String url = sysFileService.uploadFile(new File(videoUrl), FileType.VIDEO.code());
// videoInfo.put("videoUrl", url); // videoInfo.put("videoUrl", url);
String videoUrl = VIDEO_URLS[currentIndex.getAndUpdate(i -> (i + 1) % VIDEO_URLS.length)];
videoInfo.put("videoUrl", videoUrl);
// 将视频路径数组保存到 output // 将视频路径数组保存到 output
output.put("videoUrl", videoInfo); output.put("videoUrl", videoInfo);
break; break;

View File

@ -1,6 +1,5 @@
package com.cmvr.test.flow.runtime.operator.edge; package com.cmvr.test.flow.runtime.operator.edge;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.enums.FileType; import com.cmvr.common.enums.FileType;
import com.cmvr.common.exception.GlobalException; import com.cmvr.common.exception.GlobalException;
@ -15,7 +14,7 @@ import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.File; import java.util.concurrent.atomic.AtomicInteger;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -30,6 +29,15 @@ public class EdgeMicrophoneOperateService implements EdgeOperateService {
return action.name().startsWith("MICROPHONE_"); return action.name().startsWith("MICROPHONE_");
} }
private static final String[] AUDIO_URLS = {
"http://192.168.0.100:9000/cmvr-iot/AUDIO/20260205/1770257444584.wav", // 单次 东北话中的那疙瘩什么意思
"http://192.168.0.100:9000/cmvr-iot/AUDIO/20260205/1770255964713.wav",// 单次 打开视频
"http://192.168.0.100:9000/cmvr-iot/AUDIO/20260205/1770257150877.wav", // 连续 导航到解放碑
"http://192.168.0.100:9000/cmvr-iot/AUDIO/20260205/1770257188864.wav" // 连续 青花瓷
};
private AtomicInteger currentIndex = new AtomicInteger(0);
@Override @Override
public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message) { public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message) {
String instId = message.getInstId(); String instId = message.getInstId();
@ -80,6 +88,8 @@ public class EdgeMicrophoneOperateService implements EdgeOperateService {
// String audioUrl = audioInfo.getString("audioUrl"); // String audioUrl = audioInfo.getString("audioUrl");
// String url = sysFileService.uploadFile(new File(audioUrl), FileType.AUDIO.code()); // String url = sysFileService.uploadFile(new File(audioUrl), FileType.AUDIO.code());
// audioInfo.put("audioUrl", url); // audioInfo.put("audioUrl", url);
String audioUrl = AUDIO_URLS[currentIndex.getAndUpdate(i -> (i + 1) % AUDIO_URLS.length)];
audioInfo.put("audioUrl", audioUrl);
// 将视频路径数组保存到 output // 将视频路径数组保存到 output
output.put("audioUrl", audioInfo); output.put("audioUrl", audioInfo);
break; break;

View File

@ -5,7 +5,6 @@ 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.exception.GlobalException; import com.cmvr.common.exception.GlobalException;
@ -116,11 +115,11 @@ public class TiProjectServiceImpl extends ServiceImpl<TiProjectMapper, TiProject
normalVO.setRunParams(taskExecuteProjectVO.getRunParams()); normalVO.setRunParams(taskExecuteProjectVO.getRunParams());
normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId()); normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId());
String instId = flowTaskRuntimeService.executeProjectTask(normalVO); String instId = flowTaskRuntimeService.executeProjectTask(normalVO);
this.update( // this.update(
new LambdaUpdateWrapper<TiProject>() // new LambdaUpdateWrapper<TiProject>()
.eq(TiProject::getProjectId, taskExecuteProjectVO.getProjectId()) // .eq(TiProject::getProjectId, taskExecuteProjectVO.getProjectId())
.set(TiProject::getStatus, "0") // .set(TiProject::getStatus, "0")
); // );
return instId; return instId;
} }

View File

@ -1,6 +1,7 @@
package com.cmvr.vi.service; package com.cmvr.vi.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.TeQueryProjectOrchestraItemVO;
import com.cmvr.test.model.vo.TeTaskExecuteProjectVO; import com.cmvr.test.model.vo.TeTaskExecuteProjectVO;
@ -71,5 +72,5 @@ public interface IViProjectService extends IService<ViProject> {
*/ */
public String queryExecuteInstId(String projectId); public String queryExecuteInstId(String projectId);
Object queryEvaluation(String projectId); public List<AeViEvaluationVO> queryEvaluation(String projectId);
} }

View File

@ -2,11 +2,16 @@ package com.cmvr.vi.service.impl;
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.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.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.vo.AeViEvaluationVO;
import com.cmvr.evaluation.model.dto.AeIResultDTO;
import com.cmvr.evaluation.service.AeIndicatorService;
import com.cmvr.evaluation.service.IAeEvaluationService; import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.test.enums.FlowSceneTypeEnum; import com.cmvr.test.enums.FlowSceneTypeEnum;
import com.cmvr.test.enums.RunModeEnum; import com.cmvr.test.enums.RunModeEnum;
@ -27,9 +32,13 @@ import com.cmvr.vi.service.IViSchemeService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* 语音交互-项目Service业务层处理 * 语音交互-项目Service业务层处理
@ -46,6 +55,7 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
private final ITeTaskConfigInfoService taskConfigInfoService; private final ITeTaskConfigInfoService taskConfigInfoService;
private final ITeTaskInstService taskInstService; private final ITeTaskInstService taskInstService;
private final IAeEvaluationService aeEvaluationService; private final IAeEvaluationService aeEvaluationService;
private final AeIndicatorService aeIndicatorService;
@Override @Override
public ViProject selectViProjectByProjectId(String projectId) { public ViProject selectViProjectByProjectId(String projectId) {
@ -124,11 +134,11 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
normalVO.setRunParams(taskExecuteProjectVO.getRunParams()); normalVO.setRunParams(taskExecuteProjectVO.getRunParams());
normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId()); normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId());
String instId = flowTaskRuntimeService.executeProjectTask(normalVO); String instId = flowTaskRuntimeService.executeProjectTask(normalVO);
this.update( // this.update(
new LambdaUpdateWrapper<ViProject>() // new LambdaUpdateWrapper<ViProject>()
.eq(ViProject::getProjectId, taskExecuteProjectVO.getProjectId()) // .eq(ViProject::getProjectId, taskExecuteProjectVO.getProjectId())
.set(ViProject::getStatus, "0") // .set(ViProject::getStatus, "0")
); // );
return instId; return instId;
} }
@ -141,8 +151,8 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
@Override @Override
public TeTaskInst getTeTaskInst(String projectId) { public TeTaskInst getTeTaskInst(String projectId) {
LambdaQueryWrapper<ViProject> wrapperProject = Wrappers.lambdaQuery(ViProject.class); LambdaQueryWrapper<ViProject> wrapperProject = Wrappers.lambdaQuery(ViProject.class);
wrapperProject.eq(ViProject::getProjectId, projectId) wrapperProject.eq(ViProject::getProjectId, projectId);
.eq(ViProject::getStatus, "0"); // .eq(ViProject::getStatus, "0");
ViProject project = this.getOne(wrapperProject); ViProject project = this.getOne(wrapperProject);
if (ObjUtil.isEmpty(project)) { if (ObjUtil.isEmpty(project)) {
throw new GlobalException("项目id为 [{}] 的任务不存在或未执行!", projectId); throw new GlobalException("项目id为 [{}] 的任务不存在或未执行!", projectId);
@ -156,19 +166,243 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
} }
@Override @Override
public Object queryEvaluation(String projectId) { public List<AeViEvaluationVO> queryEvaluation(String projectId) {
// 查询项目信息 // 1. 查询项目
ViProject project = getById(projectId); ViProject project = getById(projectId);
// 查询对应的实例id
// 2. 查询实例ID
String instId = queryExecuteInstId(projectId); String instId = queryExecuteInstId(projectId);
// 查询对应检测项信息
// 3. 查询检测项itemId -> schemeId
List<TeQueryProjectOrchestraItemVO> items = queryExecuteRunParams(projectId); List<TeQueryProjectOrchestraItemVO> items = queryExecuteRunParams(projectId);
Map<String, String> itemSchemeMap = items.stream()
.filter(i -> StrUtil.isNotBlank(i.getItemId()) && StrUtil.isNotBlank(i.getSchemeId()))
.collect(Collectors.toMap(
TeQueryProjectOrchestraItemVO::getItemId,
TeQueryProjectOrchestraItemVO::getSchemeId,
(a, b) -> a
));
// 查询对应评估信息 // 4. 查询评估数据
// aeEvaluationService List<AeEvaluation> evaluations = aeEvaluationService.queryEvaluation(instId);
return null; // 5. 获取指标定义
List<AeIndicatorEntity> indicators = aeIndicatorService.getChildrenByParentIdWithLevelLimit(project.getIndicatorId(), 4, 0);
// 6. schemeId 分组评估数据
Map<String, List<AeEvaluation>> schemaEvaluationMap = evaluations.stream()
.map(e -> new AbstractMap.SimpleEntry<>(itemSchemeMap.get(e.getItemId()), e))
.filter(entry -> StrUtil.isNotBlank(entry.getKey()))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
// 7. 计算每个 schemeId 的评估结果
List<AeViEvaluationVO> resultList = new ArrayList<>();
for (Map.Entry<String, List<AeEvaluation>> entry : schemaEvaluationMap.entrySet()) {
String schemeId = entry.getKey();
List<AeEvaluation> evalList = entry.getValue();
List<AeViEvaluationVO.AeItemDetail> itemDetails = new ArrayList<>();
long responseTimeSum = 0L;
long responseTimeCount = 0L;
long successCount = 0L;
// 8. 计算每个评估项的响应时间得分和成功率得分
for (AeEvaluation evaluation : evalList) {
AeIResultDTO dto = JSON.parseObject(evaluation.getResult(), AeIResultDTO.class);
// 创建评估项对象
AeViEvaluationVO.AeItemDetail itemDto = new AeViEvaluationVO.AeItemDetail();
itemDto.setAeId(evaluation.getAeId());
itemDto.setContent(evaluation.getAvContent());
itemDto.setItemResponseTime(dto.getResponseTime());
// 判断是否成功
boolean success = "成功".equals(dto.getOverallResult());
if (success) {
itemDto.setSuccess(success);
} else {
itemDto.setSuccess(false);
itemDto.setFailureReason(dto.getFailureReason());
}
itemDto.setVideoPath(dto.getVideoPath());
itemDto.setExecutionDetail(dto.getExecutionDetail());
// 汇总
itemDetails.add(itemDto);
// 汇总响应时间计算平均响应时间
if (dto.getResponseTime() != null) {
responseTimeSum += dto.getResponseTime();
responseTimeCount++;
}
// 汇总成功项用于计算成功率
if (success) {
successCount++;
}
}
// 计算方案的平均响应时间及得分
Long avgResponseTime = responseTimeCount == 0 ? 0L : responseTimeSum / responseTimeCount;
Long responseTimeScore = calculateResponseTimeScore(avgResponseTime, indicators);
// 计算方案的成功率及得分
Long successRate = evalList.isEmpty() ? 0L : (successCount * 100) / evalList.size();
Long successRateScore = calculateSuccessRateScore(successRate, indicators);
// 创建 AeViEvaluationVO 并设置字段
AeViEvaluationVO vo = new AeViEvaluationVO();
vo.setSchemeId(schemeId);
String schemeName = items.stream().filter(x -> x.getSchemeId().equals(schemeId)).findFirst().get().getSchemeName();
vo.setSchemeName(schemeName);
vo.setResponseTime(avgResponseTime);
vo.setResponseTimeScore(responseTimeScore);
vo.setSuccessRate(successRate);
vo.setSuccessRateScore(successRateScore);
vo.setItemDetails(itemDetails);
resultList.add(vo);
}
return resultList;
} }
// 计算响应时间得分
private Long calculateResponseTimeScore(Long itemResponseTime, List<AeIndicatorEntity> indicators) {
// 1. 查找"唤醒时间"指标
AeIndicatorEntity responseTimeIndicator = findIndicatorByName(indicators, "唤醒时间");
if (responseTimeIndicator == null) {
return 0L; // 如果没有找到指标返回 0
}
// 2. 获取响应时间指标的子指标可能存在多个子指标例如不同的响应时间区间
List<AeIndicatorEntity> children = responseTimeIndicator.getChildren();
long score = 0L;
// 3. 遍历子指标根据响应时间计算得分
for (AeIndicatorEntity child : children) {
// 子指标的比较值例如响应时间阈值和符号 <, <=, >, >=
BigDecimal compareValue1 = child.getCompareNum1();
BigDecimal compareValue2 = child.getCompareNum2();
String symbol = child.getSymbol();
// 4. 根据符号和阈值判断响应时间是否符合子指标的规则计算得分
if (compareResponseTime(itemResponseTime, compareValue1, compareValue2, symbol)) {
score = child.getScore().longValue(); // 得分等于子指标的得分
break; // 找到符合条件的子指标后直接返回得分
}
}
return score;
}
// 计算成功率得分
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 (compareResponseTime(successRate, compareValue1, compareValue2, symbol)) {
score = child.getScore().longValue(); // 得分等于子指标的得分
break; // 找到符合条件的子指标后直接返回得分
}
}
return score;
}
private boolean compareResponseTime(Long itemResponseTime, BigDecimal compareValue1, BigDecimal compareValue2, String symbol) {
// 如果只有一个阈值就执行单边判断
if (compareValue2 == null) {
return compareSingleSide(itemResponseTime, compareValue1, symbol);
} else {
// 如果有两个阈值执行区间判断
return compareRange(itemResponseTime, compareValue1, compareValue2, symbol);
}
}
// 处理单边比较例如<=><>=
private boolean compareSingleSide(Long itemResponseTime, BigDecimal compareValue1, String symbol) {
switch (symbol) {
case "<=":
return itemResponseTime <= compareValue1.longValue();
case "<":
return itemResponseTime < compareValue1.longValue();
case ">":
return itemResponseTime > compareValue1.longValue();
case ">=":
return itemResponseTime >= compareValue1.longValue();
default:
return false;
}
}
// 处理区间比较例如<=>=
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;
}
}
// 计算成功率得分
private Long calculateSuccessRateScore(String overallResult, List<AeIndicatorEntity> indicators) {
AeIndicatorEntity successRateIndicator = findIndicatorByName(indicators, "成功率");
if (successRateIndicator == null) {
return 0L; // 如果没有匹配的成功率指标
}
if ("成功".equals(overallResult)) {
return successRateIndicator.getScore().longValue(); // 满分
} else {
return 0L; // 失败 0
}
}
// 根据指标名称找到对应的指标
private AeIndicatorEntity findIndicatorByName(List<AeIndicatorEntity> indicators, String indicatorName) {
for (AeIndicatorEntity indicator : indicators) {
if (indicator.getName().equals(indicatorName)) {
return indicator;
}
}
return null; // 如果找不到返回null
}
} }