feat: 语音交互评估
This commit is contained in:
parent
8950f7cd06
commit
87a6cbfc6e
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传
|
* 文件上传
|
||||||
*
|
*
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -9,4 +9,9 @@ public interface IAeEvaluationService extends IService<AeEvaluation> {
|
|||||||
* 执行语音交互评估
|
* 执行语音交互评估
|
||||||
*/
|
*/
|
||||||
public void executeEvaluation(AeEvaluation evaluation);
|
public void executeEvaluation(AeEvaluation evaluation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评估回调
|
||||||
|
*/
|
||||||
|
void callback(AeEvaluation aeEvaluation);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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(); // 保持中断状态
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除节点
|
* 删除节点
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user