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.evaluation.model.domain.AeEvaluation;
|
||||
import com.cmvr.evaluation.service.IAeEvaluationService;
|
||||
import com.cmvr.test.model.domain.TeAiEvaluation;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RestController;
|
||||
|
||||
@ -20,13 +23,20 @@ public class AeEvaluationController extends BaseController {
|
||||
|
||||
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评估")
|
||||
@GetMapping("/test")
|
||||
public AjaxResult execute() {
|
||||
AeEvaluation aeEvaluation = new AeEvaluation();
|
||||
aeEvaluation.setInstId("1336caf1e80b2d23b706ad1cd05d78bd");
|
||||
aeEvaluation.setItemId("18483d62ccec13c0a336d1d605e9b06c");
|
||||
aeEvaluationService.executeEvaluation(aeEvaluation);
|
||||
@PostMapping("/callback")
|
||||
public AjaxResult list(@RequestBody AeEvaluation aeEvaluation) {
|
||||
aeEvaluationService.callback(aeEvaluation);
|
||||
return AjaxResult.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ public class EdgeMicrophoneServiceImpl implements EdgeMicrophoneService {
|
||||
try {
|
||||
// 获取gRPC客户端存根
|
||||
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()
|
||||
|
||||
@ -2,7 +2,14 @@ package com.cmvr.common.core.minio;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
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.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -10,10 +17,10 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@ -104,6 +111,40 @@ public class MinioService {
|
||||
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)
|
||||
private String aeId;
|
||||
|
||||
@ApiModelProperty("评估类型(VOICE:语音,TOUCH:触控)")
|
||||
@ApiModelProperty("评估类型(VI_PROJECT:语音,TI_PROJECT:触控)")
|
||||
private String aeType;
|
||||
|
||||
@ApiModelProperty("流程实例ID")
|
||||
|
||||
@ -9,4 +9,9 @@ public interface IAeEvaluationService extends IService<AeEvaluation> {
|
||||
* 执行语音交互评估
|
||||
*/
|
||||
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.util.IdUtil;
|
||||
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.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.cmvr.common.exception.GlobalException;
|
||||
import com.cmvr.common.utils.http.CallAPIUtil;
|
||||
import com.cmvr.evaluation.mapper.AeEvaluationMapper;
|
||||
import com.cmvr.evaluation.model.domain.AeEvaluation;
|
||||
import com.cmvr.evaluation.service.IAeEvaluationService;
|
||||
import com.cmvr.llm.config.APIProperties;
|
||||
import com.cmvr.test.enums.ActionEnum;
|
||||
import com.cmvr.test.enums.RunModeEnum;
|
||||
import com.cmvr.test.model.domain.TeNodeInst;
|
||||
import com.cmvr.test.model.vo.TeFlowViewVO;
|
||||
import com.cmvr.test.service.ITeNodeInstService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -30,6 +35,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeEvaluation> implements IAeEvaluationService {
|
||||
@ -38,8 +44,11 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
private final APIProperties apiProperties;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public void executeEvaluation(AeEvaluation evaluation) {
|
||||
|
||||
String aeType = evaluation.getAeType();
|
||||
if (aeType.equals(RunModeEnum.VI_PROJECT.name())) {
|
||||
// 语音交互评估
|
||||
// 查询流程执行记录
|
||||
TeFlowViewVO teFlowViewVO = new TeFlowViewVO();
|
||||
teFlowViewVO.setInstId(evaluation.getInstId());
|
||||
@ -71,11 +80,15 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
|
||||
// 场景 1:唤醒
|
||||
case 1: {
|
||||
String audioUrl = extractAudioUrl(view);
|
||||
String videoUrl = extractVideoUrl(view);
|
||||
AeEvaluation eval = new AeEvaluation();
|
||||
BeanUtil.copyProperties(evaluation, eval);
|
||||
eval.setAeId(IdUtil.fastSimpleUUID());
|
||||
eval.setStatus(0); // 待评估
|
||||
eval.setAvContent(wakeContent);
|
||||
eval.setAudioPath(audioUrl);
|
||||
eval.setVideoPath(videoUrl);
|
||||
evaluations.add(eval);
|
||||
break;
|
||||
}
|
||||
@ -83,6 +96,12 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
// 场景 2:单次对话(一层循环)
|
||||
case 2: {
|
||||
|
||||
view.stream()
|
||||
.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);
|
||||
|
||||
Map<String, List<TeNodeInst>> iterationMap = buildSingleIterationMap(view);
|
||||
|
||||
for (Map.Entry<String, List<TeNodeInst>> entry : iterationMap.entrySet()) {
|
||||
@ -172,6 +191,19 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
redisTemplate.opsForList().rightPush("ae:evaluation:queue", JSON.toJSONString(e));
|
||||
}
|
||||
|
||||
runEvaluation(first);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (aeType.equals(RunModeEnum.TI_PROJECT.name())) {
|
||||
// 触控交互评估
|
||||
} else {
|
||||
throw new GlobalException("错误的评估任务类型!仅支持语音交互和触控交互!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void runEvaluation(AeEvaluation first) {
|
||||
// 构建评估请求
|
||||
Map<String, String> body = new HashMap<>();
|
||||
body.put("aeId", first.getAeId());
|
||||
@ -183,9 +215,44 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
|
||||
first.setStatus(1);
|
||||
this.updateById(first);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@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) {
|
||||
@ -224,7 +291,7 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
|
||||
private String extractAudioUrl(List<TeNodeInst> nodeList) {
|
||||
TeNodeInst microPhoneInst = nodeList.stream()
|
||||
.filter(e -> ActionEnum.MICROPHONE_START.getAction().equals(e.getAction()))
|
||||
.filter(e -> ActionEnum.MICROPHONE_STOP.getAction().equals(e.getAction()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
@ -233,13 +300,13 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
}
|
||||
|
||||
JSONObject paramsOut = JSONObject.parseObject(microPhoneInst.getParamsOut());
|
||||
return paramsOut.getString("audioUrl");
|
||||
return paramsOut.getJSONObject("audioUrl").getString("audioUrl");
|
||||
}
|
||||
|
||||
|
||||
private String extractVideoUrl(List<TeNodeInst> nodeList) {
|
||||
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()
|
||||
.orElse(null);
|
||||
|
||||
@ -248,6 +315,6 @@ public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeE
|
||||
}
|
||||
|
||||
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()
|
||||
// 静态资源,可匿名访问
|
||||
.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();
|
||||
})
|
||||
|
||||
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.cmvr.common.core.domain.entity.SysFileInfo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
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(File file, Integer fileType);
|
||||
|
||||
public int deleteFileByIds(Long[] fileIds);
|
||||
}
|
||||
|
||||
@ -18,7 +18,9 @@ import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -75,7 +77,7 @@ public class ISysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileInfo>
|
||||
}
|
||||
String url = generUrl(type, fileName);
|
||||
// 保存文件
|
||||
saveFileInfo(file, md5, url, fileType);
|
||||
saveFileInfo(file.getOriginalFilename(),file.getSize(), md5, url, fileType);
|
||||
log.info("文件上传成功,url:{}", url);
|
||||
return url;
|
||||
} 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
|
||||
public int deleteFileByIds(Long[] fileIds) {
|
||||
return this.baseMapper.deleteBatchIds(Arrays.asList(fileIds));
|
||||
@ -99,10 +135,10 @@ public class ISysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileInfo>
|
||||
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();
|
||||
fileInfo.setFileName(file.getOriginalFilename());
|
||||
fileInfo.setFileSize(file.getSize());
|
||||
fileInfo.setFileName(filename);
|
||||
fileInfo.setFileSize(size);
|
||||
fileInfo.setFileType(fileType);
|
||||
fileInfo.setFilePath(filePath);
|
||||
fileInfo.setMd5(md5);
|
||||
|
||||
@ -47,8 +47,8 @@ public class TaskInstHolder {
|
||||
}
|
||||
|
||||
public void markSuccess(String instId, String itemId, String nodeId, int pendingItemCount, String nodeType,
|
||||
String paramsOut, String message) {
|
||||
nodeInstService.logSuccess(instId, itemId, nodeId, paramsOut, message);
|
||||
String paramsOut, String message, List<Integer> iterations) {
|
||||
nodeInstService.logSuccess(instId, itemId, nodeId, paramsOut, message,iterations);
|
||||
syncStatus(instId, TaskStatusEnum.SUCCESS);
|
||||
// 如果没有下一个检测项要执行 且是end节点 注销任务上下文
|
||||
if (pendingItemCount == 0 && nodeType.equalsIgnoreCase(NodeTypeEnum.END.getCode())) {
|
||||
@ -58,8 +58,8 @@ public class TaskInstHolder {
|
||||
|
||||
public void markFailed(String instId, String taskId, String itemId,
|
||||
String nodeId, String nodeType, String operate,
|
||||
String action, String params, String message) {
|
||||
nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message);
|
||||
String action, String params, String message, List<Integer> iterations) {
|
||||
nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message,iterations);
|
||||
|
||||
syncStatus(instId, TaskStatusEnum.FAILED);
|
||||
taskContextManager.unregister(instId);
|
||||
|
||||
@ -31,20 +31,24 @@ public class FlowEndNodeHandler implements FlowNodeTypeHandler {
|
||||
String itemId = message.getItemId();
|
||||
TaskContext context = taskInstHolder.getContext(instId);
|
||||
RunModeEnum runMode = context.getRunMode();
|
||||
// if (runMode.equals(RunModeEnum.NORMAL) || runMode.equals(RunModeEnum.TRIAL)) {
|
||||
// // 仅语音交互和触控交互进行评估
|
||||
// return TaskNodeExecuteResult.success();
|
||||
// }
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("instId", instId);
|
||||
jsonObject.put("itemId", itemId);
|
||||
jsonObject.put("aeType", "VOICE");
|
||||
jsonObject.put("aeType", RunModeEnum.VI_PROJECT.name());
|
||||
|
||||
executor.submit(() -> {
|
||||
Thread.currentThread().setName("evaluation-thread-" + Thread.currentThread().getId());
|
||||
try {
|
||||
// log.info("异步任务开始执行:threadName={}, instId={}, taskId={}", Thread.currentThread().getName(), instId, taskId);
|
||||
log.info("异步评估任务开始执行:threadName={}, instId={}, itemId={}", Thread.currentThread().getName(), instId, itemId);
|
||||
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) {
|
||||
// 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(); // 保持中断状态
|
||||
}
|
||||
});
|
||||
|
||||
@ -100,8 +100,8 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
|
||||
null, null,
|
||||
ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
|
||||
JSON.toJSONString(taskExecuteTrailVO),
|
||||
"试运行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480)
|
||||
);
|
||||
"试运行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
|
||||
null);
|
||||
throw new GlobalException("试运行异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
@ -149,8 +149,8 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
|
||||
instId, taskId, null, null, null,
|
||||
ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
|
||||
JSON.toJSONString(originalVO),
|
||||
"任务执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480)
|
||||
);
|
||||
"任务执行异常:" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
|
||||
null);
|
||||
throw new GlobalException("任务执行异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ public class FlowExceptionInterceptor implements FlowMsgPreInterceptor {
|
||||
message.getNodeType(),
|
||||
message.getAction().getOperate(), message.getAction().getOperate(),
|
||||
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={}",
|
||||
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(),
|
||||
result.getOutputParams().toJSONString(), StrUtil.format("[{}] 执行成功", message.getAction()));
|
||||
result.getOutputParams().toJSONString(), StrUtil.format("[{}] 执行成功", message.getAction()), message.getIterations());
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("[ {} ]节点执行结束, 参数[ {} ], 循环次数[ {} ], 耗时[ {} ]", message.getAction(), message.getInputParams(), message.getLoopNum(), end - start);
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
package com.cmvr.test.flow.runtime.operator.edge;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.cmvr.common.enums.FileType;
|
||||
import com.cmvr.common.exception.GlobalException;
|
||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||
import com.cmvr.edge.client.service.EdgeCameraService;
|
||||
import com.cmvr.system.service.ISysFileService;
|
||||
import com.cmvr.test.enums.ActionEnum;
|
||||
import com.cmvr.test.flow.builder.FlowNodeWrapper;
|
||||
import com.cmvr.test.flow.context.TaskInstHolder;
|
||||
@ -16,7 +15,7 @@ import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ -24,6 +23,7 @@ public class EdgeCameraOperateService implements EdgeOperateService {
|
||||
|
||||
private final EdgeCameraService edgeCameraService;
|
||||
private final TaskInstHolder taskInstHolder;
|
||||
private final ISysFileService sysFileService;
|
||||
|
||||
@Override
|
||||
public boolean supports(ActionEnum action) {
|
||||
@ -94,32 +94,18 @@ public class EdgeCameraOperateService implements EdgeOperateService {
|
||||
}
|
||||
|
||||
case CAMERA_RECORDING_START: {
|
||||
|
||||
// 生成视频路径
|
||||
// String videoUrl = edgeCameraService.startRecording(edgeCommonVO);
|
||||
// videoUrl = StrUtil.format("{}/{}", "http://10.148.108.162/system/video", StrUtil.subAfter(videoUrl, "/", true));
|
||||
List<String> videoList = CollUtil.newArrayList(
|
||||
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477538765.mp4",
|
||||
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477608318.mp4",
|
||||
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477631974.mp4",
|
||||
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766478299920.mp4",
|
||||
"http://192.168.0.100:9000/cmvr-iot/VIDEO/20251223/1766477777557.mp4"
|
||||
);
|
||||
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());
|
||||
// String videoUrl = StrUtil.format("{}/{}_{}.mp4", "/home/share/assets/video", deviceId, System.currentTimeMillis());
|
||||
String videoUrl = "/home/xtkuang/Projects/models/assets/video/IMG_0524_silent.mp4";
|
||||
// 创建一个新的 JSONObject 来保存视频路径和其他信息
|
||||
JSONObject videoInfo = new JSONObject();
|
||||
videoInfo.put("videoUrl", videoUrl);
|
||||
videoInfo.put("isPlay", false); // 初始状态为不可播放
|
||||
videoInfo.put("type", FileType.VIDEO.code()); // 文件类型为视频
|
||||
|
||||
// 将视频路径数组保存到 output 中
|
||||
output.put("videoInfo", videoInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -136,11 +122,15 @@ public class EdgeCameraOperateService implements EdgeOperateService {
|
||||
.orElseThrow(() -> new IllegalStateException("未找到视频录制开始节点"));
|
||||
|
||||
// 从上下文获取上游节点存储的参数 获取视频地址
|
||||
JSONObject pre = taskInstHolder.getNodeOutParams(instId, startRecordNode.getNodeId(),message.getIterations());
|
||||
JSONArray videoUrl = pre.getJSONArray("videoUrl");
|
||||
output.put("videoUrl", videoUrl);
|
||||
output.put("isPlay", true);
|
||||
output.put("type", FileType.VIDEO.code());
|
||||
JSONObject preStart = taskInstHolder.getNodeOutParams(instId, startRecordNode.getNodeId(), message.getIterations());
|
||||
|
||||
JSONObject videoInfo = preStart.getJSONObject("videoInfo");
|
||||
videoInfo.put("isPlay", true);
|
||||
// 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;
|
||||
}
|
||||
default:
|
||||
|
||||
@ -1,20 +1,29 @@
|
||||
package com.cmvr.test.flow.runtime.operator.edge;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.cmvr.common.enums.FileType;
|
||||
import com.cmvr.common.exception.GlobalException;
|
||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||
import com.cmvr.edge.client.service.EdgeMicrophoneService;
|
||||
import com.cmvr.system.service.ISysFileService;
|
||||
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.TaskNodeExecuteResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EdgeMicrophoneOperateService implements EdgeOperateService {
|
||||
|
||||
private final EdgeMicrophoneService edgeMicrophoneService;
|
||||
private final TaskInstHolder taskInstHolder;
|
||||
private final ISysFileService sysFileService;
|
||||
|
||||
@Override
|
||||
public boolean supports(ActionEnum action) {
|
||||
@ -37,13 +46,42 @@ public class EdgeMicrophoneOperateService implements EdgeOperateService {
|
||||
switch (action) {
|
||||
case MICROPHONE_START: {
|
||||
// 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);
|
||||
|
||||
// 创建一个新的 JSONObject 来保存音频路径和其他信息
|
||||
JSONObject audioInfo = new JSONObject();
|
||||
audioInfo.put("audioUrl", audioPath);
|
||||
audioInfo.put("isPlay", false); // 初始状态为不可播放
|
||||
audioInfo.put("type", FileType.AUDIO.code());
|
||||
|
||||
output.put("audioInfo", audioInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
case MICROPHONE_STOP: {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@ -41,14 +41,14 @@ public interface ITeNodeInstService extends IService<TeNodeInst> {
|
||||
* 节点执行后更新输出参数等信息/记录节点成功完成
|
||||
*/
|
||||
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,
|
||||
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;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
@ -55,11 +56,12 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
|
||||
|
||||
@Override
|
||||
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<>();
|
||||
update.eq(TeNodeInst::getInstId, instId)
|
||||
.eq(TeNodeInst::getItemId, itemId)
|
||||
.eq(TeNodeInst::getNodeId, nodeId)
|
||||
.eq(TeNodeInst::getIteration, getIteration(iterations))
|
||||
.set(TeNodeInst::getParamsOut, paramsOut)
|
||||
.set(TeNodeInst::getStatus, TaskStatusEnum.SUCCESS.name())
|
||||
.set(TeNodeInst::getMessage, message)
|
||||
@ -71,12 +73,13 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
|
||||
@Override
|
||||
public void logFailed(String instId, String taskId, String itemId,
|
||||
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();
|
||||
query.eq(TeNodeInst::getInstId, instId)
|
||||
.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);
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ 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.cmvr.common.exception.GlobalException;
|
||||
import com.cmvr.evaluation.model.domain.AeEvaluation;
|
||||
import com.cmvr.test.enums.FlowSceneTypeEnum;
|
||||
import com.cmvr.test.enums.RunModeEnum;
|
||||
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.TeTaskInst;
|
||||
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.service.ITeDetectionItemService;
|
||||
import com.cmvr.test.service.ITeTaskConfigInfoService;
|
||||
@ -119,19 +117,16 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
|
||||
|
||||
@Override
|
||||
public String executeProject(TeTaskExecuteProjectVO taskExecuteProjectVO) {
|
||||
TeTaskExecuteNormalVO normalVO = new TeTaskExecuteNormalVO();
|
||||
normalVO.setTaskId(taskExecuteProjectVO.getProjectId());
|
||||
TeTaskExecuteProjectVO normalVO = new TeTaskExecuteProjectVO();
|
||||
normalVO.setProjectId(taskExecuteProjectVO.getProjectId());
|
||||
normalVO.setRunParams(taskExecuteProjectVO.getRunParams());
|
||||
normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId());
|
||||
String instId = flowTaskRuntimeService.executeTask(normalVO);
|
||||
String instId = flowTaskRuntimeService.executeProjectTask(normalVO);
|
||||
this.update(
|
||||
new LambdaUpdateWrapper<ViProject>()
|
||||
.eq(ViProject::getProjectId, taskExecuteProjectVO.getProjectId())
|
||||
.set(ViProject::getStatus, "0")
|
||||
);
|
||||
// 异步执行评估
|
||||
AeEvaluation aeEvaluation = new AeEvaluation();
|
||||
aeEvaluation.setInstId(instId);
|
||||
return instId;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user