feat: 语音交互评估

This commit is contained in:
stream 2026-02-03 10:58:38 +08:00
parent 8950f7cd06
commit 87a6cbfc6e
19 changed files with 388 additions and 195 deletions

View File

@ -4,10 +4,13 @@ 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.AeEvaluation; import com.cmvr.evaluation.model.domain.AeEvaluation;
import com.cmvr.evaluation.service.IAeEvaluationService; import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.test.model.domain.TeAiEvaluation;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -20,13 +23,20 @@ public class AeEvaluationController extends BaseController {
private final IAeEvaluationService aeEvaluationService; private final IAeEvaluationService aeEvaluationService;
// @ApiOperation("回调AI评估")
// @GetMapping("/test")
// public AjaxResult execute() {
// AeEvaluation aeEvaluation = new AeEvaluation();
// aeEvaluation.setInstId("1336caf1e80b2d23b706ad1cd05d78bd");
// aeEvaluation.setItemId("18483d62ccec13c0a336d1d605e9b06c");
// aeEvaluationService.executeEvaluation(aeEvaluation);
// return AjaxResult.ok();
// }
@ApiOperation("回调AI评估") @ApiOperation("回调AI评估")
@GetMapping("/test") @PostMapping("/callback")
public AjaxResult execute() { public AjaxResult list(@RequestBody AeEvaluation aeEvaluation) {
AeEvaluation aeEvaluation = new AeEvaluation(); aeEvaluationService.callback(aeEvaluation);
aeEvaluation.setInstId("1336caf1e80b2d23b706ad1cd05d78bd");
aeEvaluation.setItemId("18483d62ccec13c0a336d1d605e9b06c");
aeEvaluationService.executeEvaluation(aeEvaluation);
return AjaxResult.ok(); return AjaxResult.ok();
} }
} }

View File

@ -64,7 +64,7 @@ public class EdgeMicrophoneServiceImpl implements EdgeMicrophoneService {
try { try {
// 获取gRPC客户端存根 // 获取gRPC客户端存根
MicPhoneServiceGrpc.MicPhoneServiceBlockingStub stub = grpcServiceManager.getGrpcClient(edgeCommonVO.getTerminalId(), MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class); MicPhoneServiceGrpc.MicPhoneServiceBlockingStub stub = grpcServiceManager.getGrpcClient(edgeCommonVO.getTerminalId(), MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class);
String filePath = StrUtil.format("{}/{}_{}.mp4", "/home/share/assets/video", deviceId, System.currentTimeMillis()); String filePath = StrUtil.format("{}/{}_{}.wav", "/home/share/assets/video", deviceId, System.currentTimeMillis());
// 构建请求消息 // 构建请求消息
MicrophoneCommand.StartMicRecordingCommand.Request request = MicrophoneCommand.StartMicRecordingCommand.Request.newBuilder() MicrophoneCommand.StartMicRecordingCommand.Request request = MicrophoneCommand.StartMicRecordingCommand.Request.newBuilder()

View File

@ -2,7 +2,14 @@ package com.cmvr.common.core.minio;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import io.minio.*; import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.SetBucketPolicyArgs;
import io.minio.StatObjectArgs;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -10,10 +17,10 @@ import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files;
import java.util.Date; import java.util.Date;
@Slf4j @Slf4j
@ -104,6 +111,40 @@ public class MinioService {
return objectName; return objectName;
} }
public String upload(String bucketName, String path, File file) {
String originalFilename = file.getName();
if (StringUtils.isBlank(originalFilename)) {
throw new RuntimeException("文件名为空");
}
// 生成文件名使用当前时间戳
String fileName = System.currentTimeMillis() + "";
if (originalFilename.lastIndexOf(".") >= 0) {
fileName += originalFilename.substring(originalFilename.lastIndexOf("."));
}
// 构建文件在 MinIO 中的路径
String objectName = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + "/" + fileName;
try (InputStream stream = Files.newInputStream(file.toPath())) {
PutObjectArgs objectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(path + "/" + objectName)
.stream(stream, file.length(), -1) // 传入文件流
.contentType("application/octet-stream") // 可以根据需要修改文件类型
.build();
// 上传文件到 MinIO
minioClient.putObject(objectArgs);
} catch (Exception e) {
log.error("文件上传失败,", e);
return null;
}
return objectName;
}
/** /**
* 文件上传 * 文件上传
* *

View File

@ -19,7 +19,7 @@ public class AeEvaluation implements Serializable {
@TableId(value = "ae_id", type = IdType.ASSIGN_UUID) @TableId(value = "ae_id", type = IdType.ASSIGN_UUID)
private String aeId; private String aeId;
@ApiModelProperty("评估类型VOICE:语音TOUCH:触控)") @ApiModelProperty("评估类型VI_PROJECT:语音TI_PROJECT:触控)")
private String aeType; private String aeType;
@ApiModelProperty("流程实例ID") @ApiModelProperty("流程实例ID")

View File

@ -9,4 +9,9 @@ public interface IAeEvaluationService extends IService<AeEvaluation> {
* 执行语音交互评估 * 执行语音交互评估
*/ */
public void executeEvaluation(AeEvaluation evaluation); public void executeEvaluation(AeEvaluation evaluation);
/**
* 评估回调
*/
void callback(AeEvaluation aeEvaluation);
} }

View File

@ -4,20 +4,25 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.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.update.LambdaUpdateWrapper;
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.utils.http.CallAPIUtil; import com.cmvr.common.utils.http.CallAPIUtil;
import com.cmvr.evaluation.mapper.AeEvaluationMapper; import com.cmvr.evaluation.mapper.AeEvaluationMapper;
import com.cmvr.evaluation.model.domain.AeEvaluation; import com.cmvr.evaluation.model.domain.AeEvaluation;
import com.cmvr.evaluation.service.IAeEvaluationService; import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.llm.config.APIProperties; import com.cmvr.llm.config.APIProperties;
import com.cmvr.test.enums.ActionEnum; import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.enums.RunModeEnum;
import com.cmvr.test.model.domain.TeNodeInst; import com.cmvr.test.model.domain.TeNodeInst;
import com.cmvr.test.model.vo.TeFlowViewVO; import com.cmvr.test.model.vo.TeFlowViewVO;
import com.cmvr.test.service.ITeNodeInstService; import com.cmvr.test.service.ITeNodeInstService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
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;
@ -30,6 +35,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeEvaluation> implements IAeEvaluationService { public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeEvaluation> implements IAeEvaluationService {
@ -38,154 +44,215 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
private final APIProperties apiProperties; private final APIProperties apiProperties;
private final StringRedisTemplate redisTemplate; private final StringRedisTemplate redisTemplate;
@Override
public void executeEvaluation(AeEvaluation evaluation) { public void executeEvaluation(AeEvaluation evaluation) {
String aeType = evaluation.getAeType();
if (aeType.equals(RunModeEnum.VI_PROJECT.name())) {
// 语音交互评估
// 查询流程执行记录
TeFlowViewVO teFlowViewVO = new TeFlowViewVO();
teFlowViewVO.setInstId(evaluation.getInstId());
teFlowViewVO.setItemId(evaluation.getItemId());
// 查询流程执行记录 List<TeNodeInst> view = teNodeInstService.view(teFlowViewVO);
TeFlowViewVO teFlowViewVO = new TeFlowViewVO();
teFlowViewVO.setInstId(evaluation.getInstId());
teFlowViewVO.setItemId(evaluation.getItemId());
List<TeNodeInst> view = teNodeInstService.view(teFlowViewVO); // 解析 VI_SCHEME 参数
TeNodeInst viSchemeInst = view.stream()
.filter(e -> ActionEnum.VI_SCHEME.getAction().equals(e.getAction()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("未找到 VI_SCHEME 节点"));
// 解析 VI_SCHEME 参数 JSONObject paramsOut = JSONObject.parseObject(viSchemeInst.getParamsOut());
TeNodeInst viSchemeInst = view.stream()
.filter(e -> ActionEnum.VI_SCHEME.getAction().equals(e.getAction()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("未找到 VI_SCHEME 节点"));
JSONObject paramsOut = JSONObject.parseObject(viSchemeInst.getParamsOut()); Integer sceneType = paramsOut.getInteger("sceneType");
Integer sceneType = paramsOut.getInteger("sceneType"); // 唤醒语料
JSONObject wakeCorpus = paramsOut.getJSONObject("wakeCorpus");
String wakeContent = wakeCorpus != null ? wakeCorpus.getString("textContent") : null;
// 唤醒语料 // 测试语料
JSONObject wakeCorpus = paramsOut.getJSONObject("wakeCorpus"); JSONArray testCorpusArray = paramsOut.getJSONArray("testCorpus");
String wakeContent = wakeCorpus != null ? wakeCorpus.getString("textContent") : null;
// 测试语料 // 构建评估任务列表
JSONArray testCorpusArray = paramsOut.getJSONArray("testCorpus"); List<AeEvaluation> evaluations = new LinkedList<>();
// 构建评估任务列表 switch (sceneType) {
List<AeEvaluation> evaluations = new LinkedList<>();
switch (sceneType) {
// 场景 1唤醒
case 1: {
AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(evaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0); // 待评估
eval.setAvContent(wakeContent);
evaluations.add(eval);
break;
}
// 场景 2单次对话一层循环
case 2: {
Map<String, List<TeNodeInst>> iterationMap = buildSingleIterationMap(view);
for (Map.Entry<String, List<TeNodeInst>> entry : iterationMap.entrySet()) {
String iterationKey = entry.getKey(); // "1" / "2" / ...
List<TeNodeInst> nodeList = entry.getValue();
int index = Integer.parseInt(iterationKey) - 1;
JSONObject corpus = testCorpusArray.getJSONObject(index);
String content = StrUtil.join(", ",
wakeContent,
corpus.getString("textContent")
);
String audioUrl = extractAudioUrl(nodeList);
String videoUrl = extractVideoUrl(nodeList);
// 场景 1唤醒
case 1: {
String audioUrl = extractAudioUrl(view);
String videoUrl = extractVideoUrl(view);
AeEvaluation eval = new AeEvaluation(); AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(evaluation, eval); BeanUtil.copyProperties(evaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID()); eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0); eval.setStatus(0); // 待评估
eval.setAvContent(content); eval.setAvContent(wakeContent);
eval.setAudioPath(audioUrl); eval.setAudioPath(audioUrl);
eval.setVideoPath(videoUrl); eval.setVideoPath(videoUrl);
evaluations.add(eval); evaluations.add(eval);
break;
} }
break;
}
// 场景 3连续对话嵌套循环 // 场景 2单次对话一层循环
case 3: { case 2: {
Map<String, List<TeNodeInst>> ContinuousIterationMap = buildContinuousIterationMap(view); view.stream()
for (Map.Entry<String, List<TeNodeInst>> entry : ContinuousIterationMap.entrySet()) { .filter(e -> e.getAction().equals(ActionEnum.CAMERA_RECORDING_STOP.getAction()))
.map(x->JSONObject.parseObject(x.getParamsOut()).getJSONObject("videoUrl").getString("videoUrl"))
.collect(Collectors.toList())
.forEach(System.out::println);
String key = entry.getKey(); Map<String, List<TeNodeInst>> iterationMap = buildSingleIterationMap(view);
List<TeNodeInst> value = entry.getValue();
// 每一个 outer iteration 代表一次完整连续对话 for (Map.Entry<String, List<TeNodeInst>> entry : iterationMap.entrySet()) {
StringBuilder contentBuilder = new StringBuilder(wakeContent);
String iterationKey = entry.getKey(); // "1" / "2" / ...
List<TeNodeInst> nodeList = entry.getValue();
int corpusIndex = Integer.parseInt(key) - 1; int index = Integer.parseInt(iterationKey) - 1;
JSONArray corpus = testCorpusArray.getJSONArray(corpusIndex); JSONObject corpus = testCorpusArray.getJSONObject(index);
String corpusText = corpus.stream() String content = StrUtil.join(", ",
.filter(Objects::nonNull) wakeContent,
.map(obj -> ((JSONObject) obj).getString("textContent")) corpus.getString("textContent")
.filter(StrUtil::isNotEmpty) );
.collect(Collectors.joining(", "));
if (StrUtil.isNotEmpty(corpusText)) { String audioUrl = extractAudioUrl(nodeList);
contentBuilder.append(", ").append(corpusText); String videoUrl = extractVideoUrl(nodeList);
AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(evaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0);
eval.setAvContent(content);
eval.setAudioPath(audioUrl);
eval.setVideoPath(videoUrl);
evaluations.add(eval);
} }
break;
String audioUrl = extractAudioUrl(value);
String videoUrl = extractVideoUrl(value);
AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(evaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0);
eval.setAvContent(contentBuilder.toString());
eval.setAudioPath(audioUrl);
eval.setVideoPath(videoUrl);
evaluations.add(eval);
} }
break;
// 场景 3连续对话嵌套循环
case 3: {
Map<String, List<TeNodeInst>> ContinuousIterationMap = buildContinuousIterationMap(view);
for (Map.Entry<String, List<TeNodeInst>> entry : ContinuousIterationMap.entrySet()) {
String key = entry.getKey();
List<TeNodeInst> value = entry.getValue();
// 每一个 outer iteration 代表一次完整连续对话
StringBuilder contentBuilder = new StringBuilder(wakeContent);
int corpusIndex = Integer.parseInt(key) - 1;
JSONArray corpus = testCorpusArray.getJSONArray(corpusIndex);
String corpusText = corpus.stream()
.filter(Objects::nonNull)
.map(obj -> ((JSONObject) obj).getString("textContent"))
.filter(StrUtil::isNotEmpty)
.collect(Collectors.joining(", "));
if (StrUtil.isNotEmpty(corpusText)) {
contentBuilder.append(", ").append(corpusText);
}
String audioUrl = extractAudioUrl(value);
String videoUrl = extractVideoUrl(value);
AeEvaluation eval = new AeEvaluation();
BeanUtil.copyProperties(evaluation, eval);
eval.setAeId(IdUtil.fastSimpleUUID());
eval.setStatus(0);
eval.setAvContent(contentBuilder.toString());
eval.setAudioPath(audioUrl);
eval.setVideoPath(videoUrl);
evaluations.add(eval);
}
break;
}
default:
throw new IllegalArgumentException("未知 sceneType" + sceneType);
} }
default: try {
throw new IllegalArgumentException("未知 sceneType" + sceneType); // 入库
} this.saveBatch(evaluations);
try { // 提取第一个对象出来
// 入库 AeEvaluation first = CollUtil.getFirst(evaluations);
this.saveBatch(evaluations); List<AeEvaluation> rest = CollUtil.sub(evaluations, 1, evaluations.size());
// 剩下的先入队列
for (AeEvaluation e : rest) {
redisTemplate.opsForList().rightPush("ae:evaluation:queue", JSON.toJSONString(e));
}
// 提取第一个对象出来 runEvaluation(first);
AeEvaluation first = CollUtil.getFirst(evaluations); } catch (Exception e) {
List<AeEvaluation> rest = CollUtil.sub(evaluations, 1, evaluations.size()); throw new RuntimeException(e);
// 剩下的先入队列
for (AeEvaluation e : rest) {
redisTemplate.opsForList().rightPush("ae:evaluation:queue", JSON.toJSONString(e));
} }
} else if (aeType.equals(RunModeEnum.TI_PROJECT.name())) {
// 构建评估请求 // 触控交互评估
Map<String, String> body = new HashMap<>(); } else {
body.put("aeId", first.getAeId()); throw new GlobalException("错误的评估任务类型!仅支持语音交互和触控交互!");
body.put("audioPath", first.getAudioPath());
body.put("videoPath", first.getVideoPath());
body.put("content", first.getAvContent());
body.put("aeType", first.getAeType());
CallAPIUtil.doPostJson(apiProperties.getEvaluation(), null, body);
first.setStatus(1);
this.updateById(first);
} catch (Exception e) {
throw new RuntimeException(e);
} }
}
private void runEvaluation(AeEvaluation first) {
// 构建评估请求
Map<String, String> body = new HashMap<>();
body.put("aeId", first.getAeId());
body.put("audioPath", first.getAudioPath());
body.put("videoPath", first.getVideoPath());
body.put("content", first.getAvContent());
body.put("aeType", first.getAeType());
CallAPIUtil.doPostJson(apiProperties.getEvaluation(), null, body);
first.setStatus(1);
this.updateById(first);
}
@Override
public void callback(AeEvaluation aeEvaluation) {
String aeId = aeEvaluation.getAeId();
if (StrUtil.isEmpty(aeId)) {
throw new GlobalException("AI评估ID不能为空!");
}
String result = aeEvaluation.getResult();
if (StrUtil.isEmpty(result)) {
throw new GlobalException("AI评估结果不能为空!");
}
AeEvaluation byId = this.getById(aeId);
if (Objects.isNull(byId)) {
log.error("ID为 {} 的评估对象不存在!",aeId);
}
JSONObject jsonObject = JSON.parseObject(result);
String overallResult = jsonObject.getString("overall_result");
int status;
if (StrUtil.isNotEmpty(overallResult) && overallResult.equals("成功")) {
status = 3;
} else {
status = 4;
}
LambdaUpdateWrapper<AeEvaluation> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(AeEvaluation::getAeId, aeId)
.set(AeEvaluation::getResult, result)
.set(AeEvaluation::getStatus, status); // 评估完成/失败
this.update(wrapper);
// 继续下一个评估
String str = redisTemplate.opsForList().leftPop("ae:evaluation:queue");
if (StrUtil.isEmpty(str)) {
return;
}
AeEvaluation evaluation = JSON.parseObject(str, AeEvaluation.class);
runEvaluation(evaluation);
} }
private Map<String, List<TeNodeInst>> buildSingleIterationMap(List<TeNodeInst> view) { private Map<String, List<TeNodeInst>> buildSingleIterationMap(List<TeNodeInst> view) {
@ -224,7 +291,7 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
private String extractAudioUrl(List<TeNodeInst> nodeList) { private String extractAudioUrl(List<TeNodeInst> nodeList) {
TeNodeInst microPhoneInst = nodeList.stream() TeNodeInst microPhoneInst = nodeList.stream()
.filter(e -> ActionEnum.MICROPHONE_START.getAction().equals(e.getAction())) .filter(e -> ActionEnum.MICROPHONE_STOP.getAction().equals(e.getAction()))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@ -233,13 +300,13 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
} }
JSONObject paramsOut = JSONObject.parseObject(microPhoneInst.getParamsOut()); JSONObject paramsOut = JSONObject.parseObject(microPhoneInst.getParamsOut());
return paramsOut.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_START.getAction().equals(e.getAction())) .filter(e -> ActionEnum.CAMERA_RECORDING_STOP.getAction().equals(e.getAction()))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@ -248,6 +315,6 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
} }
JSONObject paramsOut = JSONObject.parseObject(recordingInst.getParamsOut()); JSONObject paramsOut = JSONObject.parseObject(recordingInst.getParamsOut());
return paramsOut.getString("videoUrl"); return paramsOut.getJSONObject("videoUrl").getString("videoUrl");
} }
} }

View File

@ -114,7 +114,7 @@ public class SecurityConfig
requests.antMatchers("/login", "/register", "/captchaImage").permitAll() requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
// 静态资源可匿名访问 // 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/test/evaluation/callback","/flow/**","/flowise/**","/kws/**","/ws/**","/api/grpc/**","/show/**","/node-red/**","/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() .antMatchers("/system/file/upload","/evaluation/callback","/flow/**","/flowise/**","/kws/**","/ws/**","/api/grpc/**","/show/**","/node-red/**","/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证 // 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated(); .anyRequest().authenticated();
}) })

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.cmvr.common.core.domain.entity.SysFileInfo; import com.cmvr.common.core.domain.entity.SysFileInfo;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.List; import java.util.List;
public interface ISysFileService extends IService<SysFileInfo> { public interface ISysFileService extends IService<SysFileInfo> {
@ -12,5 +13,7 @@ public interface ISysFileService extends IService<SysFileInfo> {
public String uploadFile(MultipartFile file, Integer fileType); public String uploadFile(MultipartFile file, Integer fileType);
public String uploadFile(File file, Integer fileType);
public int deleteFileByIds(Long[] fileIds); public int deleteFileByIds(Long[] fileIds);
} }

View File

@ -18,7 +18,9 @@ import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -75,7 +77,7 @@ public class ISysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileInfo>
} }
String url = generUrl(type, fileName); String url = generUrl(type, fileName);
// 保存文件 // 保存文件
saveFileInfo(file, md5, url, fileType); saveFileInfo(file.getOriginalFilename(),file.getSize(), md5, url, fileType);
log.info("文件上传成功,url:{}", url); log.info("文件上传成功,url:{}", url);
return url; return url;
} catch (IOException e) { } catch (IOException e) {
@ -84,6 +86,40 @@ public class ISysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileInfo>
} }
} }
@Override
public String uploadFile(File file, Integer fileType) {
try {
// 计算文件的 MD5 校验码
String md5 = DigestUtils.md5DigestAsHex(Files.newInputStream(file.toPath()));
SysFileInfo fileInfo = findByMd5(md5);
if (!Objects.isNull(fileInfo)) {
this.updateById(fileInfo);
// 如果文件已存在直接返回已上传文件的 URL
return fileInfo.getFilePath();
}
// 上传文件到 MinIO
FileType type = FileType.getByCode(fileType);
String fileName = minioService.upload(minioProps.getBucketName(), type.toString(), file);
if (StringUtils.isEmpty(fileName)) {
throw new RuntimeException("文件上传失败");
}
// 生成文件的 URL
String url = generUrl(type, fileName);
// 将文件信息保存到数据库
saveFileInfo(file.getName(),file.length(), md5, url, fileType);
log.info("文件上传成功url: {}", url);
return url;
} catch (IOException e) {
log.error("文件上传失败,{}", e.getMessage(), e);
throw new RuntimeException("文件上传失败");
}
}
@Override @Override
public int deleteFileByIds(Long[] fileIds) { public int deleteFileByIds(Long[] fileIds) {
return this.baseMapper.deleteBatchIds(Arrays.asList(fileIds)); return this.baseMapper.deleteBatchIds(Arrays.asList(fileIds));
@ -99,10 +135,10 @@ public class ISysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileInfo>
return getOne(wrapper); return getOne(wrapper);
} }
private void saveFileInfo(MultipartFile file, String md5, String filePath, Integer fileType) throws IOException { private void saveFileInfo(String filename,Long size, String md5, String filePath, Integer fileType) throws IOException {
SysFileInfo fileInfo = new SysFileInfo(); SysFileInfo fileInfo = new SysFileInfo();
fileInfo.setFileName(file.getOriginalFilename()); fileInfo.setFileName(filename);
fileInfo.setFileSize(file.getSize()); fileInfo.setFileSize(size);
fileInfo.setFileType(fileType); fileInfo.setFileType(fileType);
fileInfo.setFilePath(filePath); fileInfo.setFilePath(filePath);
fileInfo.setMd5(md5); fileInfo.setMd5(md5);

View File

@ -47,8 +47,8 @@ public class TaskInstHolder {
} }
public void markSuccess(String instId, String itemId, String nodeId, int pendingItemCount, String nodeType, public void markSuccess(String instId, String itemId, String nodeId, int pendingItemCount, String nodeType,
String paramsOut, String message) { String paramsOut, String message, List<Integer> iterations) {
nodeInstService.logSuccess(instId, itemId, nodeId, paramsOut, message); nodeInstService.logSuccess(instId, itemId, nodeId, paramsOut, message,iterations);
syncStatus(instId, TaskStatusEnum.SUCCESS); syncStatus(instId, TaskStatusEnum.SUCCESS);
// 如果没有下一个检测项要执行 且是end节点 注销任务上下文 // 如果没有下一个检测项要执行 且是end节点 注销任务上下文
if (pendingItemCount == 0 && nodeType.equalsIgnoreCase(NodeTypeEnum.END.getCode())) { if (pendingItemCount == 0 && nodeType.equalsIgnoreCase(NodeTypeEnum.END.getCode())) {
@ -58,8 +58,8 @@ public class TaskInstHolder {
public void markFailed(String instId, String taskId, String itemId, public void markFailed(String instId, String taskId, String itemId,
String nodeId, String nodeType, String operate, String nodeId, String nodeType, String operate,
String action, String params, String message) { String action, String params, String message, List<Integer> iterations) {
nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message); nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message,iterations);
syncStatus(instId, TaskStatusEnum.FAILED); syncStatus(instId, TaskStatusEnum.FAILED);
taskContextManager.unregister(instId); taskContextManager.unregister(instId);

View File

@ -31,20 +31,24 @@ public class FlowEndNodeHandler implements FlowNodeTypeHandler {
String itemId = message.getItemId(); String itemId = message.getItemId();
TaskContext context = taskInstHolder.getContext(instId); TaskContext context = taskInstHolder.getContext(instId);
RunModeEnum runMode = context.getRunMode(); RunModeEnum runMode = context.getRunMode();
// if (runMode.equals(RunModeEnum.NORMAL) || runMode.equals(RunModeEnum.TRIAL)) {
// // 仅语音交互和触控交互进行评估
// return TaskNodeExecuteResult.success();
// }
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("instId", instId); jsonObject.put("instId", instId);
jsonObject.put("itemId", itemId); jsonObject.put("itemId", itemId);
jsonObject.put("aeType", "VOICE"); jsonObject.put("aeType", RunModeEnum.VI_PROJECT.name());
executor.submit(() -> { executor.submit(() -> {
Thread.currentThread().setName("evaluation-thread-" + Thread.currentThread().getId()); Thread.currentThread().setName("evaluation-thread-" + Thread.currentThread().getId());
try { try {
// log.info("异步任务开始执行threadName={}, instId={}, taskId={}", Thread.currentThread().getName(), instId, taskId); log.info("异步评估任务开始执行threadName={}, instId={}, itemId={}", Thread.currentThread().getName(), instId, itemId);
exAeEvaluationService.executeEvaluation(jsonObject); exAeEvaluationService.executeEvaluation(jsonObject);
// log.info("异步任务执行结束threadName={}, instId={}, taskId={}", Thread.currentThread().getName(), instId, taskId); log.info("异步评估任务执行结束threadName={}, instId={}, itemId={}", Thread.currentThread().getName(), instId, itemId);
} catch (Exception e) { } catch (Exception e) {
// log.error("任务执行异常threadName={}, instId={}, taskId={}, 错误={}", Thread.currentThread().getName(), instId, taskId, e.getMessage(), e); log.error("评估任务执行异常threadName={}, instId={}, itemId={}, 错误={}", Thread.currentThread().getName(), instId, itemId, e.getMessage(), e);
Thread.currentThread().interrupt(); // 保持中断状态 Thread.currentThread().interrupt(); // 保持中断状态
} }
}); });

View File

@ -100,8 +100,8 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
null, null, null, null,
ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(), ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
JSON.toJSONString(taskExecuteTrailVO), JSON.toJSONString(taskExecuteTrailVO),
"试运行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480) "试运行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
); null);
throw new GlobalException("试运行异常:" + e.getMessage()); throw new GlobalException("试运行异常:" + e.getMessage());
} }
} }
@ -149,8 +149,8 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
instId, taskId, null, null, null, instId, taskId, null, null, null,
ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(), ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
JSON.toJSONString(originalVO), JSON.toJSONString(originalVO),
"任务执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480) "任务执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
); null);
throw new GlobalException("任务执行异常:" + e.getMessage()); throw new GlobalException("任务执行异常:" + e.getMessage());
} }
} }

View File

@ -40,7 +40,8 @@ public class FlowExceptionInterceptor implements FlowMsgPreInterceptor {
message.getNodeType(), message.getNodeType(),
message.getAction().getOperate(), message.getAction().getOperate(), message.getAction().getOperate(), message.getAction().getOperate(),
ObjUtil.isEmpty(message.getInputParams()) ? null : message.getInputParams().toJSONString(), ObjUtil.isEmpty(message.getInputParams()) ? null : message.getInputParams().toJSONString(),
"执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480) "执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
message.getIterations()
); );
log.error("节点执行异常instId={}, nodeId={}, action={}", log.error("节点执行异常instId={}, nodeId={}, action={}",
message.getInstId(), message.getNodeId(), message.getAction(), e); message.getInstId(), message.getNodeId(), message.getAction(), e);

View File

@ -45,7 +45,7 @@ public class FlowLoggingInterceptor implements FlowMsgPreInterceptor {
} }
taskInstHolder.markSuccess(message.getInstId(), message.getItemId(), message.getNodeId(), message.getPendingItemCount(), message.getNodeType(), taskInstHolder.markSuccess(message.getInstId(), message.getItemId(), message.getNodeId(), message.getPendingItemCount(), message.getNodeType(),
result.getOutputParams().toJSONString(), StrUtil.format("[{}] 执行成功", message.getAction())); result.getOutputParams().toJSONString(), StrUtil.format("[{}] 执行成功", message.getAction()), message.getIterations());
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
log.info("[ {} ]节点执行结束, 参数[ {} ], 循环次数[ {} ], 耗时[ {} ]", message.getAction(), message.getInputParams(), message.getLoopNum(), end - start); log.info("[ {} ]节点执行结束, 参数[ {} ], 循环次数[ {} ], 耗时[ {} ]", message.getAction(), message.getInputParams(), message.getLoopNum(), end - start);

View File

@ -1,13 +1,12 @@
package com.cmvr.test.flow.runtime.operator.edge; package com.cmvr.test.flow.runtime.operator.edge;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
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;
import com.cmvr.edge.client.model.EdgeCommonVO; import com.cmvr.edge.client.model.EdgeCommonVO;
import com.cmvr.edge.client.service.EdgeCameraService; import com.cmvr.edge.client.service.EdgeCameraService;
import com.cmvr.system.service.ISysFileService;
import com.cmvr.test.enums.ActionEnum; import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.flow.builder.FlowNodeWrapper; import com.cmvr.test.flow.builder.FlowNodeWrapper;
import com.cmvr.test.flow.context.TaskInstHolder; import com.cmvr.test.flow.context.TaskInstHolder;
@ -16,7 +15,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.util.List; import java.io.File;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -24,6 +23,7 @@ public class EdgeCameraOperateService implements EdgeOperateService {
private final EdgeCameraService edgeCameraService; private final EdgeCameraService edgeCameraService;
private final TaskInstHolder taskInstHolder; private final TaskInstHolder taskInstHolder;
private final ISysFileService sysFileService;
@Override @Override
public boolean supports(ActionEnum action) { public boolean supports(ActionEnum action) {
@ -94,32 +94,18 @@ public class EdgeCameraOperateService implements EdgeOperateService {
} }
case CAMERA_RECORDING_START: { case CAMERA_RECORDING_START: {
// 生成视频路径
// String videoUrl = edgeCameraService.startRecording(edgeCommonVO); // String videoUrl = edgeCameraService.startRecording(edgeCommonVO);
// videoUrl = StrUtil.format("{}/{}", "http://10.148.108.162/system/video", StrUtil.subAfter(videoUrl, "/", true)); // String videoUrl = StrUtil.format("{}/{}_{}.mp4", "/home/share/assets/video", deviceId, System.currentTimeMillis());
List<String> videoList = CollUtil.newArrayList( String videoUrl = "/home/xtkuang/Projects/models/assets/video/IMG_0524_silent.mp4";
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477538765.mp4", // 创建一个新的 JSONObject 来保存视频路径和其他信息
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477608318.mp4", JSONObject videoInfo = new JSONObject();
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477631974.mp4", videoInfo.put("videoUrl", videoUrl);
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766478299920.mp4", videoInfo.put("isPlay", false); // 初始状态为不可播放
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477777557.mp4" videoInfo.put("type", FileType.VIDEO.code()); // 文件类型为视频
);
Integer index = CollUtil.getLast(message.getIterations());
String videoUrl = videoList.get(index -1);
// String videoUrl = "http://10.148.108.162/system/video/cam4_1752225205349.mp4";
// JSONArray videoUrls = new JSONArray();
// if (ObjUtil.isNotEmpty(upstreamOutput)) {
// JSONArray upstream = upstreamOutput.getJSONArray("videoUrl");
// if (ObjUtil.isNotEmpty(upstream)) {
// videoUrls.addAll(upstream);
// }
// }
//
// videoUrls.add(videoUrl);
output.put("videoUrl", videoUrl);
output.put("isPlay", false);
output.put("type", FileType.VIDEO.code());
// 将视频路径数组保存到 output
output.put("videoInfo", videoInfo);
break; break;
} }
@ -136,11 +122,15 @@ public class EdgeCameraOperateService implements EdgeOperateService {
.orElseThrow(() -> new IllegalStateException("未找到视频录制开始节点")); .orElseThrow(() -> new IllegalStateException("未找到视频录制开始节点"));
// 从上下文获取上游节点存储的参数 获取视频地址 // 从上下文获取上游节点存储的参数 获取视频地址
JSONObject pre = taskInstHolder.getNodeOutParams(instId, startRecordNode.getNodeId(),message.getIterations()); JSONObject preStart = taskInstHolder.getNodeOutParams(instId, startRecordNode.getNodeId(), message.getIterations());
JSONArray videoUrl = pre.getJSONArray("videoUrl");
output.put("videoUrl", videoUrl); JSONObject videoInfo = preStart.getJSONObject("videoInfo");
output.put("isPlay", true); videoInfo.put("isPlay", true);
output.put("type", FileType.VIDEO.code()); // String videoUrl = videoInfo.getString("videoUrl");
// String url = sysFileService.uploadFile(new File(videoUrl), FileType.VIDEO.code());
// videoInfo.put("videoUrl", url);
// 将视频路径数组保存到 output
output.put("videoUrl", videoInfo);
break; break;
} }
default: default:

View File

@ -1,20 +1,29 @@
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.exception.GlobalException; import com.cmvr.common.exception.GlobalException;
import com.cmvr.edge.client.model.EdgeCommonVO; import com.cmvr.edge.client.model.EdgeCommonVO;
import com.cmvr.edge.client.service.EdgeMicrophoneService; import com.cmvr.edge.client.service.EdgeMicrophoneService;
import com.cmvr.system.service.ISysFileService;
import com.cmvr.test.enums.ActionEnum; import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.flow.builder.FlowNodeWrapper;
import com.cmvr.test.flow.context.TaskInstHolder;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult; 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;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class EdgeMicrophoneOperateService implements EdgeOperateService { public class EdgeMicrophoneOperateService implements EdgeOperateService {
private final EdgeMicrophoneService edgeMicrophoneService; private final EdgeMicrophoneService edgeMicrophoneService;
private final TaskInstHolder taskInstHolder;
private final ISysFileService sysFileService;
@Override @Override
public boolean supports(ActionEnum action) { public boolean supports(ActionEnum action) {
@ -37,13 +46,42 @@ public class EdgeMicrophoneOperateService implements EdgeOperateService {
switch (action) { switch (action) {
case MICROPHONE_START: { case MICROPHONE_START: {
// String audioPath = edgeMicrophoneService.startRecord(edgeCommonVO); // String audioPath = edgeMicrophoneService.startRecord(edgeCommonVO);
String audioPath = "xxx";
// String audioPath = StrUtil.format("{}/{}_{}.wav", "/home/share/assets/audio", deviceId, System.currentTimeMillis());
String audioPath = "/home/xtkuang/Projects/models/assets/video/IMG_0524_audio.wav";
output.put("audioUrl", audioPath); output.put("audioUrl", audioPath);
// 创建一个新的 JSONObject 来保存音频路径和其他信息
JSONObject audioInfo = new JSONObject();
audioInfo.put("audioUrl", audioPath);
audioInfo.put("isPlay", false); // 初始状态为不可播放
audioInfo.put("type", FileType.AUDIO.code());
output.put("audioInfo", audioInfo);
break; break;
} }
case MICROPHONE_STOP: { case MICROPHONE_STOP: {
// edgeMicrophoneService.stopRecord(edgeCommonVO); // edgeMicrophoneService.stopRecord(edgeCommonVO);
// 获取视频录制开始节点的id
FlowNodeWrapper startRecordNode = message.getGraph()
.getNodeMap()
.values()
.stream()
.filter(node -> ActionEnum.MICROPHONE_START.equals(node.getAction()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("未找到音频录制开始节点"));
// 从上下文获取上游节点存储的参数 获取音频地址
JSONObject preStart = taskInstHolder.getNodeOutParams(instId, startRecordNode.getNodeId(), message.getIterations());
JSONObject audioInfo = preStart.getJSONObject("audioInfo");
audioInfo.put("isPlay", true);
// String audioUrl = audioInfo.getString("audioUrl");
// String url = sysFileService.uploadFile(new File(audioUrl), FileType.AUDIO.code());
// audioInfo.put("audioUrl", url);
// 将视频路径数组保存到 output
output.put("audioUrl", audioInfo);
break; break;
} }

View File

@ -41,14 +41,14 @@ public interface ITeNodeInstService extends IService<TeNodeInst> {
* 节点执行后更新输出参数等信息/记录节点成功完成 * 节点执行后更新输出参数等信息/记录节点成功完成
*/ */
void logSuccess(String instId, String itemId, String nodeId, void logSuccess(String instId, String itemId, String nodeId,
String paramsOut, String message); String paramsOut, String message, List<Integer> iterations);
/** /**
* 记录节点执行失败 * 记录节点执行失败
*/ */
void logFailed(String instId, String taskId, String itemId, void logFailed(String instId, String taskId, String itemId,
String nodeId, String nodeType, String nodeId, String nodeType,
String operate, String action, String params, String message); String operate, String action, String params, String message, List<Integer> iterations);
/** /**
* 删除节点 * 删除节点

View File

@ -1,5 +1,6 @@
package com.cmvr.test.service.impl; package com.cmvr.test.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
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.conditions.update.LambdaUpdateWrapper;
@ -55,11 +56,12 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
@Override @Override
public void logSuccess(String instId, String itemId, String nodeId, public void logSuccess(String instId, String itemId, String nodeId,
String paramsOut, String message) { String paramsOut, String message, List<Integer> iterations) {
LambdaUpdateWrapper<TeNodeInst> update = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<TeNodeInst> update = new LambdaUpdateWrapper<>();
update.eq(TeNodeInst::getInstId, instId) update.eq(TeNodeInst::getInstId, instId)
.eq(TeNodeInst::getItemId, itemId) .eq(TeNodeInst::getItemId, itemId)
.eq(TeNodeInst::getNodeId, nodeId) .eq(TeNodeInst::getNodeId, nodeId)
.eq(TeNodeInst::getIteration, getIteration(iterations))
.set(TeNodeInst::getParamsOut, paramsOut) .set(TeNodeInst::getParamsOut, paramsOut)
.set(TeNodeInst::getStatus, TaskStatusEnum.SUCCESS.name()) .set(TeNodeInst::getStatus, TaskStatusEnum.SUCCESS.name())
.set(TeNodeInst::getMessage, message) .set(TeNodeInst::getMessage, message)
@ -71,12 +73,13 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
@Override @Override
public void logFailed(String instId, String taskId, String itemId, public void logFailed(String instId, String taskId, String itemId,
String nodeId, String nodeType, String nodeId, String nodeType,
String operate, String action, String params, String message) { String operate, String action, String params, String message, List<Integer> iterations) {
LambdaQueryWrapper<TeNodeInst> query = Wrappers.lambdaQuery(); LambdaQueryWrapper<TeNodeInst> query = Wrappers.lambdaQuery();
query.eq(TeNodeInst::getInstId, instId) query.eq(TeNodeInst::getInstId, instId)
.eq(TeNodeInst::getItemId, itemId) .eq(TeNodeInst::getItemId, itemId)
.eq(TeNodeInst::getNodeId, nodeId); .eq(TeNodeInst::getNodeId, nodeId)
.eq(CollUtil.isNotEmpty(iterations), TeNodeInst::getIteration, getIteration(iterations));
TeNodeInst existing = this.getOne(query, false); TeNodeInst existing = this.getOne(query, false);

View File

@ -7,7 +7,6 @@ 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.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;
@ -15,7 +14,6 @@ import com.cmvr.test.model.domain.TeDetectionItem;
import com.cmvr.test.model.domain.TeTaskConfigInfo; import com.cmvr.test.model.domain.TeTaskConfigInfo;
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.TeTaskExecuteNormalVO;
import com.cmvr.test.model.vo.TeTaskExecuteProjectVO; import com.cmvr.test.model.vo.TeTaskExecuteProjectVO;
import com.cmvr.test.service.ITeDetectionItemService; import com.cmvr.test.service.ITeDetectionItemService;
import com.cmvr.test.service.ITeTaskConfigInfoService; import com.cmvr.test.service.ITeTaskConfigInfoService;
@ -119,19 +117,16 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
@Override @Override
public String executeProject(TeTaskExecuteProjectVO taskExecuteProjectVO) { public String executeProject(TeTaskExecuteProjectVO taskExecuteProjectVO) {
TeTaskExecuteNormalVO normalVO = new TeTaskExecuteNormalVO(); TeTaskExecuteProjectVO normalVO = new TeTaskExecuteProjectVO();
normalVO.setTaskId(taskExecuteProjectVO.getProjectId()); normalVO.setProjectId(taskExecuteProjectVO.getProjectId());
normalVO.setRunParams(taskExecuteProjectVO.getRunParams()); normalVO.setRunParams(taskExecuteProjectVO.getRunParams());
normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId()); normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId());
String instId = flowTaskRuntimeService.executeTask(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")
); );
// 异步执行评估
AeEvaluation aeEvaluation = new AeEvaluation();
aeEvaluation.setInstId(instId);
return instId; return instId;
} }