Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
fa63a8e039
@ -4,11 +4,14 @@ import com.cmvr.common.core.controller.BaseController;
|
|||||||
import com.cmvr.common.core.domain.AjaxResult;
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
import com.cmvr.common.core.page.TableDataInfo;
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
import com.cmvr.vi.model.domain.ViCorpus;
|
import com.cmvr.vi.model.domain.ViCorpus;
|
||||||
|
import com.cmvr.vi.model.vo.ViContinuousCorpusVO;
|
||||||
|
import com.cmvr.vi.model.vo.ViCorpusVO;
|
||||||
import com.cmvr.vi.service.IViCorpusService;
|
import com.cmvr.vi.service.IViCorpusService;
|
||||||
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.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -20,11 +23,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语料库Controller
|
|
||||||
*
|
|
||||||
* @author cmvr-iot
|
|
||||||
*/
|
|
||||||
@Api(tags = "语音交互--语料库")
|
@Api(tags = "语音交互--语料库")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/vi/corpus")
|
@RequestMapping("/vi/corpus")
|
||||||
@ -33,67 +31,97 @@ public class ViCorpusController extends BaseController {
|
|||||||
|
|
||||||
private final IViCorpusService viCorpusService;
|
private final IViCorpusService viCorpusService;
|
||||||
|
|
||||||
/**
|
@ApiOperation("根据id获取语料详细信息")
|
||||||
* 查询语料库列表
|
|
||||||
*/
|
|
||||||
@ApiOperation("查询语料库列表")
|
|
||||||
@PreAuthorize("@ss.hasPermi('vi:corpus:list')")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo list(ViCorpus viCorpus) {
|
|
||||||
startPage();
|
|
||||||
List<ViCorpus> list = viCorpusService.selectViCorpusList(viCorpus);
|
|
||||||
return getDataTable(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 导出语料库列表
|
|
||||||
// */
|
|
||||||
// @ApiOperation("查询语料库列表")
|
|
||||||
// @PreAuthorize("@ss.hasPermi('vi:corpus:export')")
|
|
||||||
// @PostMapping("/export")
|
|
||||||
// public void export(HttpServletResponse response, ViCorpus viCorpus) {
|
|
||||||
// List<ViCorpus> list = viCorpusService.selectViCorpusList(viCorpus);
|
|
||||||
// ExcelUtil<ViCorpus> util = new ExcelUtil<ViCorpus>(ViCorpus.class);
|
|
||||||
// util.exportExcel(response, list, "语料库数据");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取语料库详细信息
|
|
||||||
*/
|
|
||||||
@ApiOperation("根据id获取语料库详细信息")
|
|
||||||
@PreAuthorize("@ss.hasPermi('vi:corpus:query')")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:query')")
|
||||||
@GetMapping(value = "/{corpusId}")
|
@GetMapping(value = "/{corpusId}")
|
||||||
public AjaxResult getInfo(@PathVariable("corpusId") Long corpusId) {
|
public AjaxResult getInfo(@PathVariable("corpusId") Long corpusId) {
|
||||||
return success(viCorpusService.selectViCorpusByCorpusId(corpusId));
|
return success(viCorpusService.selectViCorpusByCorpusId(corpusId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ----------------------- 单次对话语料/唤醒语料 --------------------------
|
||||||
* 新增语料库
|
|
||||||
*/
|
@ApiOperation(value = "查询单次对话语料/唤醒语料列表")
|
||||||
@ApiOperation("新增语料库")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:list')")
|
||||||
|
@PostMapping("/single/list")
|
||||||
|
public TableDataInfo list(@Validated @RequestBody ViCorpusVO viCorpusVO) {
|
||||||
|
startPage();
|
||||||
|
List<ViCorpus> list = viCorpusService.selectViCorpusList(viCorpusVO);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增单次对话语料/唤醒语料")
|
||||||
@PreAuthorize("@ss.hasPermi('vi:corpus:add')")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:add')")
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@RequestBody ViCorpus viCorpus) {
|
public AjaxResult add(@RequestBody ViCorpus viCorpus) {
|
||||||
return toAjax(viCorpusService.insertViCorpus(viCorpus));
|
return toAjax(viCorpusService.insertViCorpus(viCorpus));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@ApiOperation("批量新增单次对话语料/唤醒语料")
|
||||||
* 修改语料库
|
@PreAuthorize("@ss.hasPermi('vi:corpus:add')")
|
||||||
*/
|
@PostMapping("/insertBatch")
|
||||||
@ApiOperation("修改语料库")
|
public AjaxResult insertBatch(@RequestBody List<ViCorpus> data) {
|
||||||
|
return toAjax(viCorpusService.insertBatch(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除单次对话语料/唤醒语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:corpus:remove')")
|
||||||
|
@DeleteMapping("/{corpusIds}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] corpusIds) {
|
||||||
|
return toAjax(viCorpusService.deleteViCorpusByCorpusIds(corpusIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改单次对话语料/唤醒语料")
|
||||||
@PreAuthorize("@ss.hasPermi('vi:corpus:edit')")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:edit')")
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestBody ViCorpus viCorpus) {
|
public AjaxResult edit(@RequestBody ViCorpus viCorpus) {
|
||||||
return toAjax(viCorpusService.updateViCorpus(viCorpus));
|
return toAjax(viCorpusService.updateViCorpus(viCorpus));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ----------------------- 连续对话 --------------------------
|
||||||
* 删除语料库
|
|
||||||
*/
|
@ApiOperation("查询连续对话列表")
|
||||||
@ApiOperation("删除语料库")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:list')")
|
||||||
|
@PostMapping("/continuous/list")
|
||||||
|
public TableDataInfo continuousList(@Validated @RequestBody ViCorpusVO viCorpusVO) {
|
||||||
|
startPage();
|
||||||
|
List<ViContinuousCorpusVO> list = viCorpusService.selectContinuousList(viCorpusVO);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增连续对话")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:corpus:add')")
|
||||||
|
@PostMapping("/continuous/insert")
|
||||||
|
public AjaxResult add(@RequestBody ViContinuousCorpusVO viContinuousCorpusVO) {
|
||||||
|
return toAjax(viCorpusService.insertContinuousViCorpus(viContinuousCorpusVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改连续对话")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:corpus:edit')")
|
||||||
|
@PostMapping("/continuous/update")
|
||||||
|
public AjaxResult update(@RequestBody ViContinuousCorpusVO viContinuousCorpusVO) {
|
||||||
|
return toAjax(viCorpusService.updateContinuousViCorpus(viContinuousCorpusVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除连续对话")
|
||||||
@PreAuthorize("@ss.hasPermi('vi:corpus:remove')")
|
@PreAuthorize("@ss.hasPermi('vi:corpus:remove')")
|
||||||
@DeleteMapping("/{corpusIds}")
|
@DeleteMapping("/continuous")
|
||||||
public AjaxResult remove(@PathVariable Long[] corpusIds) {
|
public AjaxResult continuousRemove(@RequestBody String[] parentIds) {
|
||||||
return toAjax(viCorpusService.deleteViCorpusByCorpusIds(corpusIds));
|
return toAjax(viCorpusService.deleteViCorpusByParentIds(parentIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @ApiOperation("批量修改")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:corpus:edit')")
|
||||||
|
@PostMapping("/updateBatch")
|
||||||
|
public AjaxResult updateBatch(@RequestBody List<ViCorpus> data) {
|
||||||
|
return toAjax(viCorpusService.updateBatch(data));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* @ApiOperation("批量新增/修改")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:corpus:edit')")
|
||||||
|
@PostMapping("/insertOrUpdateBatch")
|
||||||
|
public AjaxResult insertOrUpdateBatch(@RequestBody List<ViCorpus> data) {
|
||||||
|
return toAjax(viCorpusService.insertOrUpdateBatch(data));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.cmvr.web.controller.vi;
|
||||||
|
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.vi.model.domain.ViProject;
|
||||||
|
import com.cmvr.vi.service.IViProjectService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "语音交互--项目管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/vi/project")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ViProjectController extends BaseController {
|
||||||
|
|
||||||
|
private final IViProjectService viProjectService;
|
||||||
|
|
||||||
|
@ApiOperation("获取项目列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:project:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(ViProject viProject) {
|
||||||
|
startPage();
|
||||||
|
List<ViProject> list = viProjectService.selectViProjectList(viProject);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据id获取项目信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:project:query')")
|
||||||
|
@GetMapping(value = "/{projectId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("projectId") String projectId) {
|
||||||
|
return success(viProjectService.selectViProjectByProjectId(projectId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("添加项目")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:project:add')")
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody ViProject viProject) {
|
||||||
|
return toAjax(viProjectService.insertViProject(viProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("编辑项目")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:project:edit')")
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody ViProject viProject) {
|
||||||
|
return toAjax(viProjectService.updateViProject(viProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除项目")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:project:remove')")
|
||||||
|
@DeleteMapping("/{projectIds}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] projectIds) {
|
||||||
|
return toAjax(viProjectService.deleteViProjectByProjectIds(projectIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ApiOperation("执行项目")
|
||||||
|
@PostMapping("/execute")
|
||||||
|
public AjaxResult execute(@RequestParam("projectId") String projectId) {
|
||||||
|
return AjaxResult.ok(viProjectService.execute(projectId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package com.cmvr.web.controller.vi;
|
||||||
|
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.vi.model.domain.ViScheme;
|
||||||
|
import com.cmvr.vi.service.IViSchemeService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "语音交互--方案")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/vi/scheme")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ViSchemeController extends BaseController {
|
||||||
|
private final IViSchemeService viSchemeService;
|
||||||
|
|
||||||
|
@ApiOperation("查询方案列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:scheme:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(ViScheme viScheme) {
|
||||||
|
startPage();
|
||||||
|
List<ViScheme> list = viSchemeService.selectViSchemeList(viScheme);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据ID查询方案详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:scheme:query')")
|
||||||
|
@GetMapping(value = "/{schemeId}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("schemeId") String schemeId) {
|
||||||
|
return success(viSchemeService.selectViSchemeBySchemeId(schemeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增方案")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:scheme:add')")
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody ViScheme viScheme) {
|
||||||
|
return toAjax(viSchemeService.insertViScheme(viScheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("修改方案")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:scheme:edit')")
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody ViScheme viScheme) {
|
||||||
|
return toAjax(viSchemeService.updateViScheme(viScheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除方案")
|
||||||
|
@PreAuthorize("@ss.hasPermi('vi:scheme:remove')")
|
||||||
|
@DeleteMapping("/{schemeIds}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] schemeIds) {
|
||||||
|
return toAjax(viSchemeService.deleteViSchemeBySchemeIds(schemeIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,7 +24,11 @@ import org.springframework.http.MediaType;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.imageio.IIOImage;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.stream.FileImageOutputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@ -42,6 +46,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@ -166,6 +171,7 @@ public class EdgeCameraServiceImpl implements EdgeCameraService, EdgeStreamServi
|
|||||||
throw new GlobalException("响应图片数据无效");
|
throw new GlobalException("响应图片数据无效");
|
||||||
}
|
}
|
||||||
String filePath = saveImage(frame.getData(), frame.getWidth(), frame.getHeight(), false);
|
String filePath = saveImage(frame.getData(), frame.getWidth(), frame.getHeight(), false);
|
||||||
|
log.info("彩色图片地址:{}", filePath);
|
||||||
// String deepFilePath = saveImage(depthFrame.getData(), depthFrame.getWidth(), depthFrame.getHeight(), true);
|
// String deepFilePath = saveImage(depthFrame.getData(), depthFrame.getWidth(), depthFrame.getHeight(), true);
|
||||||
// List<String> result = new ArrayList<>();
|
// List<String> result = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
@ -178,7 +184,7 @@ public class EdgeCameraServiceImpl implements EdgeCameraService, EdgeStreamServi
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new GlobalException("图片上传失败: " + e.getMessage());
|
throw new GlobalException("图片上传失败: " + e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
deleteTempFile(filePath);
|
// deleteTempFile(filePath);
|
||||||
// deleteTempFile(deepFilePath);
|
// deleteTempFile(deepFilePath);
|
||||||
// todo 暂时不关闭摄像头
|
// todo 暂时不关闭摄像头
|
||||||
// stop(terminalId, deviceId);
|
// stop(terminalId, deviceId);
|
||||||
@ -368,50 +374,50 @@ public class EdgeCameraServiceImpl implements EdgeCameraService, EdgeStreamServi
|
|||||||
|
|
||||||
String fileName = System.currentTimeMillis() + (isDepth ? "_depth" : "") + ".jpg";
|
String fileName = System.currentTimeMillis() + (isDepth ? "_depth" : "") + ".jpg";
|
||||||
String filePath = Paths.get(tempDir.getAbsolutePath(), fileName).toString();
|
String filePath = Paths.get(tempDir.getAbsolutePath(), fileName).toString();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] pixels = pixelData.toByteArray();
|
byte[] pixels = pixelData.toByteArray();
|
||||||
BufferedImage image;
|
BufferedImage image;
|
||||||
|
|
||||||
if (isDepth) {
|
if (isDepth) {
|
||||||
// 深度图:单通道(灰度)
|
// 灰度深度图
|
||||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||||
WritableRaster raster = Raster.createInterleavedRaster(
|
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, width, 1, new int[]{0}, null);
|
||||||
buffer, width, height, width, 1,
|
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false,
|
||||||
new int[]{0}, null
|
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||||
);
|
|
||||||
|
|
||||||
ColorModel cm = new ComponentColorModel(
|
|
||||||
ColorSpace.getInstance(ColorSpace.CS_GRAY),
|
|
||||||
false, false,
|
|
||||||
Transparency.OPAQUE,
|
|
||||||
DataBuffer.TYPE_BYTE
|
|
||||||
);
|
|
||||||
image = new BufferedImage(cm, raster, false, null);
|
image = new BufferedImage(cm, raster, false, null);
|
||||||
} else {
|
} else {
|
||||||
// 彩色图:RGB 三通道
|
// 彩色RGB
|
||||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||||
WritableRaster raster = Raster.createInterleavedRaster(
|
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, 3 * width, 3,
|
||||||
buffer, width, height, 3 * width, 3,
|
new int[]{1, 2, 0}, null);
|
||||||
new int[]{2, 1, 0}, null
|
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false,
|
||||||
);
|
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||||
|
|
||||||
ColorModel cm = new ComponentColorModel(
|
|
||||||
ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
|
||||||
false, false,
|
|
||||||
Transparency.OPAQUE,
|
|
||||||
DataBuffer.TYPE_BYTE
|
|
||||||
);
|
|
||||||
image = new BufferedImage(cm, raster, false, null);
|
image = new BufferedImage(cm, raster, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
File output = new File(filePath);
|
// 设置高质量JPEG压缩
|
||||||
ImageIO.write(image, "jpg", output);
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
|
||||||
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
|
try (FileImageOutputStream output = new FileImageOutputStream(new File(filePath))) {
|
||||||
|
writer.setOutput(output);
|
||||||
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
|
if (param.canWriteCompressed()) {
|
||||||
|
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||||
|
param.setCompressionQuality(0.95f); // 压缩质量/压缩比 95%
|
||||||
|
}
|
||||||
|
writer.write(null, new IIOImage(image, null, null), param);
|
||||||
|
}
|
||||||
|
writer.dispose();
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new GlobalException(e.getMessage());
|
throw new GlobalException(e.getMessage());
|
||||||
}
|
}
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将本地文件转换为 MultipartFile
|
* 将本地文件转换为 MultipartFile
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.cmvr.test.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程场景类型
|
||||||
|
*/
|
||||||
|
public enum FlowSceneTypeEnum {
|
||||||
|
NORMAL, // 普通
|
||||||
|
VI_WAKEUP_CORPUS, // 语音交互-唤醒场景
|
||||||
|
VI_SINGLE_CORPUS, // 语音交互-单次对话场景
|
||||||
|
VI_CONTINUOUS_CORPUS // 语音交互-连续对话场景
|
||||||
|
}
|
||||||
@ -174,7 +174,6 @@ public class FlowGraph {
|
|||||||
* 获取开始节点对象
|
* 获取开始节点对象
|
||||||
*/
|
*/
|
||||||
public FlowNodeWrapper getStartNode() {
|
public FlowNodeWrapper getStartNode() {
|
||||||
System.out.println("这是什么线程:" + Thread.currentThread().getName());
|
|
||||||
String id = findStartNodeId();
|
String id = findStartNodeId();
|
||||||
return getNode(id);
|
return getNode(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务实例状态协调器:负责同步日志记录、上下文状态、数据库状态
|
* 任务实例状态协调器:负责同步日志记录、上下文状态、数据库状态
|
||||||
*/
|
*/
|
||||||
@ -40,8 +42,8 @@ public class TaskInstHolder {
|
|||||||
|
|
||||||
public void markRunning(String instId, String taskId, String itemId,
|
public void markRunning(String instId, String taskId, String itemId,
|
||||||
String nodeId, String nodeType, String operate,
|
String nodeId, String nodeType, String operate,
|
||||||
String action, String paramsIn) {
|
String action, String paramsIn, List<Integer> iterations) {
|
||||||
nodeInstService.logRunning(instId, taskId, itemId, nodeId, nodeType, operate, action, paramsIn);
|
nodeInstService.logRunning(instId, taskId, itemId, nodeId, nodeType, operate, action, paramsIn, iterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.cmvr.test.flow.control;
|
package com.cmvr.test.flow.control;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.cmvr.common.exception.GlobalException;
|
import com.cmvr.common.exception.GlobalException;
|
||||||
import com.cmvr.test.enums.NodeTypeEnum;
|
import com.cmvr.test.enums.NodeTypeEnum;
|
||||||
import com.cmvr.test.enums.TaskStatusEnum;
|
import com.cmvr.test.enums.TaskStatusEnum;
|
||||||
@ -10,6 +11,7 @@ import com.cmvr.test.flow.context.TaskInstHolder;
|
|||||||
import com.cmvr.test.flow.context.TaskThreadRegistry;
|
import com.cmvr.test.flow.context.TaskThreadRegistry;
|
||||||
import com.cmvr.test.flow.runtime.engine.FlowItemExecutor;
|
import com.cmvr.test.flow.runtime.engine.FlowItemExecutor;
|
||||||
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteContext;
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteContext;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||||
import com.cmvr.test.service.ITeNodeInstService;
|
import com.cmvr.test.service.ITeNodeInstService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -17,6 +19,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -118,7 +121,7 @@ public class FlowControlService {
|
|||||||
nodeInstService.update(instId, nodeId, TaskStatusEnum.RUNNING);
|
nodeInstService.update(instId, nodeId, TaskStatusEnum.RUNNING);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
nodeInstService.delete(instId, nodeId);
|
nodeInstService.delete(instId, nodeId, pendingNode.getIterations());
|
||||||
}
|
}
|
||||||
if (graph.isSub()) {
|
if (graph.isSub()) {
|
||||||
// 找到子图对应的loop节点
|
// 找到子图对应的loop节点
|
||||||
@ -135,11 +138,21 @@ public class FlowControlService {
|
|||||||
// 子图中断点,先执行中断的子图节点
|
// 子图中断点,先执行中断的子图节点
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
CountDownLatch latch = taskThreadRegistry.getLatch(instId, loopCtx.getNode().getNodeId());
|
CountDownLatch latch = taskThreadRegistry.getLatch(instId, loopCtx.getNode().getNodeId());
|
||||||
|
|
||||||
|
// 恢复时构造新的 message,带上 loopNum 和 iterations
|
||||||
|
TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage();
|
||||||
|
BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage);
|
||||||
|
resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留中断时的循环次数
|
||||||
|
resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留中断时的路径
|
||||||
|
|
||||||
flowItemExecutor.executeNode(
|
flowItemExecutor.executeNode(
|
||||||
pendingNode.getGraph(), pendingNode.getNode(),
|
pendingNode.getGraph(),
|
||||||
pendingNode.getStartNodeId(), pendingNode.getStartInputDefs(),
|
pendingNode.getNode(),
|
||||||
pendingNode.getRootMessage(), latch::countDown,
|
pendingNode.getStartNodeId(),
|
||||||
pendingNode.getLoopIteration()
|
pendingNode.getStartInputDefs(),
|
||||||
|
resumeMessage,
|
||||||
|
latch::countDown,
|
||||||
|
pendingNode.getIterations()
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -152,11 +165,19 @@ public class FlowControlService {
|
|||||||
} else {
|
} else {
|
||||||
// 普通节点直接恢复
|
// 普通节点直接恢复
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
|
TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage();
|
||||||
|
BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage);
|
||||||
|
resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留循环次数
|
||||||
|
resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留路径
|
||||||
|
|
||||||
flowItemExecutor.executeNode(
|
flowItemExecutor.executeNode(
|
||||||
pendingNode.getGraph(), pendingNode.getNode(),
|
pendingNode.getGraph(),
|
||||||
pendingNode.getStartNodeId(), pendingNode.getStartInputDefs(),
|
pendingNode.getNode(),
|
||||||
pendingNode.getRootMessage(), pendingNode.getOnFinished(),
|
pendingNode.getStartNodeId(),
|
||||||
pendingNode.getLoopIteration()
|
pendingNode.getStartInputDefs(),
|
||||||
|
resumeMessage,
|
||||||
|
pendingNode.getOnFinished(),
|
||||||
|
pendingNode.getIterations()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.cmvr.test.flow.runtime.dispatcher;
|
package com.cmvr.test.flow.runtime.dispatcher;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.cmvr.common.utils.spring.SpringUtils;
|
import com.cmvr.common.utils.spring.SpringUtils;
|
||||||
import com.cmvr.test.flow.builder.FlowGraph;
|
import com.cmvr.test.flow.builder.FlowGraph;
|
||||||
import com.cmvr.test.flow.builder.FlowNodeWrapper;
|
import com.cmvr.test.flow.builder.FlowNodeWrapper;
|
||||||
@ -11,6 +12,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -25,7 +28,9 @@ public class FlowLoopNodeHandler implements FlowNodeTypeHandler {
|
|||||||
String instId = message.getInstId();
|
String instId = message.getInstId();
|
||||||
FlowGraph graph = message.getGraph();
|
FlowGraph graph = message.getGraph();
|
||||||
// 当前从第几次循环开始
|
// 当前从第几次循环开始
|
||||||
int loopNum = message.getLoopNum() < 0 ? 1 : message.getLoopNum();
|
int loopNum = Math.max(message.getLoopNum(), 1);
|
||||||
|
// 父级迭代路径
|
||||||
|
List<Integer> parentIterations = message.getIterations();
|
||||||
|
|
||||||
String nodeId = message.getNodeId();
|
String nodeId = message.getNodeId();
|
||||||
FlowNodeWrapper nodeWrapper = graph.getNode(nodeId);
|
FlowNodeWrapper nodeWrapper = graph.getNode(nodeId);
|
||||||
@ -50,7 +55,28 @@ public class FlowLoopNodeHandler implements FlowNodeTypeHandler {
|
|||||||
|
|
||||||
taskThreadRegistry.registerLatch(instId, nodeId, latch);
|
taskThreadRegistry.registerLatch(instId, nodeId, latch);
|
||||||
FlowItemExecutor flowItemExecutor = SpringUtils.getBean(FlowItemExecutor.class);
|
FlowItemExecutor flowItemExecutor = SpringUtils.getBean(FlowItemExecutor.class);
|
||||||
flowItemExecutor.executeSubGraph(subGraph, message, latch::countDown, i);
|
|
||||||
|
// 构造新的迭代路径
|
||||||
|
// List<Integer> newIterations = new ArrayList<>(parentIterations);
|
||||||
|
// newIterations.add(i);
|
||||||
|
//
|
||||||
|
// // 克隆 message,避免覆盖父级
|
||||||
|
// TaskNodeExecuteMessage subMessage = new TaskNodeExecuteMessage();
|
||||||
|
// BeanUtil.copyProperties(message, subMessage);
|
||||||
|
//// subMessage.setLoopNum(i); // 当前层循环次数
|
||||||
|
// subMessage.setIterations(newIterations); // 完整迭代路径
|
||||||
|
|
||||||
|
// 构造新的迭代路径
|
||||||
|
List<Integer> newIterations = new ArrayList<>(parentIterations);
|
||||||
|
newIterations.add(i);
|
||||||
|
|
||||||
|
// 克隆 message,并明确设置 loopNum
|
||||||
|
TaskNodeExecuteMessage subMessage = new TaskNodeExecuteMessage();
|
||||||
|
BeanUtil.copyProperties(message, subMessage);
|
||||||
|
// subMessage.setLoopNum(i); // 当前 loop 第 i 次
|
||||||
|
subMessage.setIterations(newIterations); // 完整路径
|
||||||
|
|
||||||
|
flowItemExecutor.executeSubGraph(subGraph, subMessage, latch::countDown, newIterations);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
latch.await(); // 等待子图执行完毕后再进行下一轮
|
latch.await(); // 等待子图执行完毕后再进行下一轮
|
||||||
|
|||||||
@ -53,12 +53,11 @@ public class FlowItemExecutor {
|
|||||||
String startNodeId = graph.findStartNodeId();
|
String startNodeId = graph.findStartNodeId();
|
||||||
List<FlowParamDef> startInputDefs = graph.getStartInputParamsDefs();
|
List<FlowParamDef> startInputDefs = graph.getStartInputParamsDefs();
|
||||||
|
|
||||||
|
|
||||||
NodeExecutor executor = node ->
|
|
||||||
executeNode(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, -1);
|
|
||||||
|
|
||||||
// 执行 start 节点(同步执行)
|
// 执行 start 节点(同步执行)
|
||||||
executeNode(graph, graph.getStartNode(), startNodeId, startInputDefs, rootMessage, onFinished, -1);
|
NodeExecutor executor = node ->
|
||||||
|
executeNode(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, new ArrayList<>());
|
||||||
|
|
||||||
|
executeNode(graph, graph.getStartNode(), startNodeId, startInputDefs, rootMessage, onFinished, new ArrayList<>());
|
||||||
|
|
||||||
// 调度后续节点(并发)
|
// 调度后续节点(并发)
|
||||||
flowTaskScheduler.start(graph, taskInstHolder.getContext(rootMessage.getInstId()), executor, onFinished);
|
flowTaskScheduler.start(graph, taskInstHolder.getContext(rootMessage.getInstId()), executor, onFinished);
|
||||||
@ -70,7 +69,7 @@ public class FlowItemExecutor {
|
|||||||
public void executeSubGraph(FlowGraph subGraph,
|
public void executeSubGraph(FlowGraph subGraph,
|
||||||
TaskNodeExecuteMessage rootMessage,
|
TaskNodeExecuteMessage rootMessage,
|
||||||
Runnable onFinished,
|
Runnable onFinished,
|
||||||
int loopIteration) {
|
List<Integer> iterations) {
|
||||||
|
|
||||||
// 主图中开始节点的 inputParams
|
// 主图中开始节点的 inputParams
|
||||||
List<FlowParamDef> startInputDefs = subGraph.getStartInputParamsDefs();
|
List<FlowParamDef> startInputDefs = subGraph.getStartInputParamsDefs();
|
||||||
@ -81,15 +80,16 @@ public class FlowItemExecutor {
|
|||||||
|
|
||||||
NodeExecutor executor = node -> executeNode(
|
NodeExecutor executor = node -> executeNode(
|
||||||
subGraph, node, subStartNodeId, startInputDefs,
|
subGraph, node, subStartNodeId, startInputDefs,
|
||||||
rootMessage, onFinished, loopIteration
|
rootMessage, onFinished, iterations
|
||||||
);
|
);
|
||||||
|
|
||||||
// 执行子图起始节点
|
// 执行子图起始节点
|
||||||
executeNode(subGraph, subStartNode, subStartNodeId, startInputDefs,
|
executeNode(subGraph, subStartNode, subStartNodeId, startInputDefs,
|
||||||
rootMessage, onFinished, loopIteration);
|
rootMessage, onFinished, iterations);
|
||||||
|
|
||||||
// 启动子图调度
|
// 启动子图调度
|
||||||
flowTaskScheduler.subStart(subGraph, taskInstHolder.getContext(rootMessage.getInstId()), executor, onFinished, loopIteration);
|
flowTaskScheduler.subStart(subGraph, taskInstHolder.getContext(rootMessage.getInstId()),
|
||||||
|
executor, onFinished, iterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,20 +101,22 @@ public class FlowItemExecutor {
|
|||||||
List<FlowParamDef> startInputDefs,
|
List<FlowParamDef> startInputDefs,
|
||||||
TaskNodeExecuteMessage rootMessage,
|
TaskNodeExecuteMessage rootMessage,
|
||||||
Runnable onFinished,
|
Runnable onFinished,
|
||||||
int loopIteration) {
|
List<Integer> iterations) {
|
||||||
|
|
||||||
String instId = rootMessage.getInstId();
|
String instId = rootMessage.getInstId();
|
||||||
String itemId = rootMessage.getItemId();
|
String itemId = rootMessage.getItemId();
|
||||||
String nodeId = node.getNodeId();
|
String nodeId = node.getNodeId();
|
||||||
|
log.info("当前执行的是 {} 节点,迭代路径={}", node.getNodeName(), iterations);
|
||||||
|
|
||||||
//注册当前线程
|
//注册当前线程
|
||||||
registerThread(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, loopIteration, instId, itemId, nodeId);
|
registerThread(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, iterations, instId, itemId, nodeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 准备输入参数
|
// 准备输入参数
|
||||||
JSONObject inputParams = paramPreparer.prepare(graph, node, startNodeId, startInputDefs, rootMessage);
|
JSONObject inputParams = paramPreparer.prepare(graph, node, startNodeId, startInputDefs, rootMessage);
|
||||||
|
|
||||||
// 创建带上下文的执行消息(关键:注入 graph)
|
// 创建带上下文的执行消息(关键:注入 graph + iterations)
|
||||||
TaskNodeExecuteMessage message = buildTaskNodeExecuteMsg(graph, node, rootMessage, nodeId, inputParams, loopIteration);
|
TaskNodeExecuteMessage message = buildTaskNodeExecuteMsg(graph, node, rootMessage, nodeId, inputParams, iterations);
|
||||||
|
|
||||||
// 执行责任链
|
// 执行责任链
|
||||||
TaskNodeExecuteResult result = chainBuilder.build(interceptors, dispatchNodeHandler).apply(message);
|
TaskNodeExecuteResult result = chainBuilder.build(interceptors, dispatchNodeHandler).apply(message);
|
||||||
@ -126,13 +128,14 @@ public class FlowItemExecutor {
|
|||||||
|
|
||||||
// 分支节点处理
|
// 分支节点处理
|
||||||
if (node.getNodeType() == NodeTypeEnum.BRANCH) {
|
if (node.getNodeType() == NodeTypeEnum.BRANCH) {
|
||||||
postHandleBranchNode(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, loopIteration, nodeId, inputParams, message);
|
postHandleBranchNode(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, iterations, nodeId, inputParams, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// END 节点 or 子图结束
|
// END 节点 or 子图结束
|
||||||
if (node.getNodeType() == NodeTypeEnum.END || node.getNodeType() == NodeTypeEnum.SUB_END) {
|
if (node.getNodeType() == NodeTypeEnum.END || node.getNodeType() == NodeTypeEnum.SUB_END) {
|
||||||
try {
|
try {
|
||||||
|
log.info("{} 节点执行,释放线程", node.getNodeType());
|
||||||
onFinished.run();
|
onFinished.run();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("onFinished 回调异常", e);
|
log.error("onFinished 回调异常", e);
|
||||||
@ -140,22 +143,24 @@ public class FlowItemExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 通知调度器继续调度后继节点
|
// 通知调度器继续调度后继节点
|
||||||
flowTaskScheduler.markCompleted(message.getInstId(), nodeId, graph, n ->
|
flowTaskScheduler.markCompleted(
|
||||||
executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, loopIteration), loopIteration);
|
message.getInstId(), nodeId, graph,
|
||||||
|
n -> executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, iterations),
|
||||||
|
iterations
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
// 如果不是暂停全中断
|
// 如果不是暂停全中断
|
||||||
TaskContext ctx = taskInstHolder.getContext(instId);
|
TaskContext ctx = taskInstHolder.getContext(instId);
|
||||||
if (ctx == null || !ctx.isPaused()) {
|
if (ctx == null || !ctx.isPaused()) {
|
||||||
taskThreadRegistry.unregisterNodeContext(instId, itemId, nodeId);
|
taskThreadRegistry.unregisterNodeContext(instId, itemId, nodeId);
|
||||||
if (node.getNodeType().equals(NodeTypeEnum.SUB_START)) {
|
|
||||||
log.info("subStart注銷了");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static TaskNodeExecuteMessage buildTaskNodeExecuteMsg(FlowGraph graph, FlowNodeWrapper node, TaskNodeExecuteMessage rootMessage, String nodeId, JSONObject inputParams, int loopIteration) {
|
private static TaskNodeExecuteMessage buildTaskNodeExecuteMsg(FlowGraph graph, FlowNodeWrapper node,
|
||||||
|
TaskNodeExecuteMessage rootMessage, String nodeId,
|
||||||
|
JSONObject inputParams, List<Integer> iterations) {
|
||||||
TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
|
TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
|
||||||
BeanUtil.copyProperties(rootMessage, message);
|
BeanUtil.copyProperties(rootMessage, message);
|
||||||
message.setNodeId(nodeId);
|
message.setNodeId(nodeId);
|
||||||
@ -163,11 +168,18 @@ public class FlowItemExecutor {
|
|||||||
message.setAction(node.getAction());
|
message.setAction(node.getAction());
|
||||||
message.setInputParams(inputParams);
|
message.setInputParams(inputParams);
|
||||||
message.setGraph(graph);
|
message.setGraph(graph);
|
||||||
message.setLoopNum(loopIteration);
|
// 只设置 iterations
|
||||||
|
message.setIterations(new ArrayList<>(iterations));
|
||||||
|
|
||||||
|
// loopNum 不在这里计算,而是由 FlowLoopNodeHandler / resume 显式写入
|
||||||
|
// 如果 rootMessage 里已经带了 loopNum,就沿用它
|
||||||
|
message.setLoopNum(rootMessage.getLoopNum());
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postHandleBranchNode(FlowGraph graph, FlowNodeWrapper node, String startNodeId, List<FlowParamDef> startInputDefs, TaskNodeExecuteMessage rootMessage, Runnable onFinished, int loopIteration, String nodeId, JSONObject inputParams, TaskNodeExecuteMessage message) {
|
private void postHandleBranchNode(FlowGraph graph, FlowNodeWrapper node, String startNodeId,
|
||||||
|
List<FlowParamDef> startInputDefs, TaskNodeExecuteMessage rootMessage, Runnable onFinished,
|
||||||
|
List<Integer> iterations, String nodeId, JSONObject inputParams, TaskNodeExecuteMessage message) {
|
||||||
String matchedAnchorId = FlowBranchEvaluator.evaluate(nodeId, node.getBranchConditions(), inputParams);
|
String matchedAnchorId = FlowBranchEvaluator.evaluate(nodeId, node.getBranchConditions(), inputParams);
|
||||||
FlowEdge matchedEdge = graph.getEdgeByFromAnchorId(matchedAnchorId);
|
FlowEdge matchedEdge = graph.getEdgeByFromAnchorId(matchedAnchorId);
|
||||||
|
|
||||||
@ -190,12 +202,13 @@ public class FlowItemExecutor {
|
|||||||
message.getInstId(),
|
message.getInstId(),
|
||||||
matchedEdge.getTo(),
|
matchedEdge.getTo(),
|
||||||
graph,
|
graph,
|
||||||
n -> executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, loopIteration),
|
n -> executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, iterations),
|
||||||
loopIteration
|
iterations
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerThread(FlowGraph graph, FlowNodeWrapper node, String startNodeId, List<FlowParamDef> startInputDefs, TaskNodeExecuteMessage rootMessage, Runnable onFinished, int loopIteration, String instId, String itemId, String nodeId) {
|
private void registerThread(FlowGraph graph, FlowNodeWrapper node, String startNodeId, List<FlowParamDef> startInputDefs,
|
||||||
|
TaskNodeExecuteMessage rootMessage, Runnable onFinished, List<Integer> iterations, String instId, String itemId, String nodeId) {
|
||||||
TaskNodeExecuteContext nodeExecuteContext = new TaskNodeExecuteContext();
|
TaskNodeExecuteContext nodeExecuteContext = new TaskNodeExecuteContext();
|
||||||
nodeExecuteContext.setThread(Thread.currentThread());
|
nodeExecuteContext.setThread(Thread.currentThread());
|
||||||
nodeExecuteContext.setGraph(graph);
|
nodeExecuteContext.setGraph(graph);
|
||||||
@ -204,7 +217,8 @@ public class FlowItemExecutor {
|
|||||||
nodeExecuteContext.setNode(node);
|
nodeExecuteContext.setNode(node);
|
||||||
nodeExecuteContext.setOnFinished(onFinished);
|
nodeExecuteContext.setOnFinished(onFinished);
|
||||||
nodeExecuteContext.setRootMessage(rootMessage);
|
nodeExecuteContext.setRootMessage(rootMessage);
|
||||||
nodeExecuteContext.setLoopIteration(loopIteration);
|
// nodeExecuteContext.setLoopIteration(loopIteration);
|
||||||
|
nodeExecuteContext.setIterations(new ArrayList<>(iterations));
|
||||||
taskThreadRegistry.registerNodeContext(instId, itemId, nodeId, nodeExecuteContext);
|
taskThreadRegistry.registerNodeContext(instId, itemId, nodeId, nodeExecuteContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -32,7 +33,6 @@ public class FlowTaskScheduler {
|
|||||||
TaskContext context,
|
TaskContext context,
|
||||||
FlowItemExecutor.NodeExecutor executorFunc,
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
Runnable onFinished) {
|
Runnable onFinished) {
|
||||||
|
|
||||||
String instId = context.getInstId();
|
String instId = context.getInstId();
|
||||||
String startNodeId = graph.findStartNodeId();
|
String startNodeId = graph.findStartNodeId();
|
||||||
List<String> nextNodes = graph.getNextNodes(startNodeId);
|
List<String> nextNodes = graph.getNextNodes(startNodeId);
|
||||||
@ -44,7 +44,7 @@ public class FlowTaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (String nextId : nextNodes) {
|
for (String nextId : nextNodes) {
|
||||||
scheduleNode(instId, nextId, graph, executorFunc, -1);
|
scheduleNode(instId, nextId, graph, executorFunc, new ArrayList<>()); // 空 iterations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +55,7 @@ public class FlowTaskScheduler {
|
|||||||
TaskContext context,
|
TaskContext context,
|
||||||
FlowItemExecutor.NodeExecutor executorFunc,
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
Runnable onFinished,
|
Runnable onFinished,
|
||||||
int loopIteration) {
|
List<Integer> iterations) {
|
||||||
|
|
||||||
String instId = context.getInstId();
|
String instId = context.getInstId();
|
||||||
FlowNodeWrapper startNode = graph.findSubStartNodeId();
|
FlowNodeWrapper startNode = graph.findSubStartNodeId();
|
||||||
List<String> nextNodes = graph.getNextNodes(startNode.getNodeId());
|
List<String> nextNodes = graph.getNextNodes(startNode.getNodeId());
|
||||||
@ -67,16 +66,15 @@ public class FlowTaskScheduler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 并发调度后继节点
|
|
||||||
for (String nextId : nextNodes) {
|
for (String nextId : nextNodes) {
|
||||||
scheduleNode(instId, nextId, graph, executorFunc, loopIteration);
|
scheduleNode(instId, nextId, graph, executorFunc, iterations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 某节点执行完成后,判断并调度其所有后继节点
|
* 某节点执行完成后,判断并调度其所有后继节点
|
||||||
*/
|
*/
|
||||||
public void markCompleted(String instId,
|
/* public void markCompleted(String instId,
|
||||||
String nodeId,
|
String nodeId,
|
||||||
FlowGraph graph,
|
FlowGraph graph,
|
||||||
FlowItemExecutor.NodeExecutor executorFunc,
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
@ -99,12 +97,38 @@ public class FlowTaskScheduler {
|
|||||||
scheduleNode(instId, nextId, graph, executorFunc, loopIteration);
|
scheduleNode(instId, nextId, graph, executorFunc, loopIteration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
/**
|
||||||
|
* 某节点执行完成后,判断并调度其所有后继节点
|
||||||
|
*/
|
||||||
|
public void markCompleted(String instId,
|
||||||
|
String nodeId,
|
||||||
|
FlowGraph graph,
|
||||||
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
|
List<Integer> iterations) {
|
||||||
|
List<String> nextNodes = graph.getNextNodes(nodeId);
|
||||||
|
|
||||||
|
for (String nextId : nextNodes) {
|
||||||
|
String key = FlowSchedulerCache.buildKey(instId, nextId, iterations);
|
||||||
|
|
||||||
|
// 使用 Set 来记录已完成的前驱节点
|
||||||
|
Set<String> completedPreNodes = schedulerCache.getOrInitCompletedPre(key);
|
||||||
|
// 添加当前节点作为已完成的前驱节点
|
||||||
|
completedPreNodes.add(nodeId);
|
||||||
|
|
||||||
|
int preCount = graph.getPredecessors().getOrDefault(nextId, Collections.emptyList()).size();
|
||||||
|
|
||||||
|
// 如果当前节点的所有前驱节点都已完成,则调度后继节点
|
||||||
|
if (completedPreNodes.size() == preCount) {
|
||||||
|
scheduleNode(instId, nextId, graph, executorFunc, iterations);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交节点执行任务(只调度一次)
|
* 提交节点执行任务(只调度一次)
|
||||||
*/
|
*/
|
||||||
private void scheduleNode(String instId,
|
/* private void scheduleNode(String instId,
|
||||||
String nodeId,
|
String nodeId,
|
||||||
FlowGraph graph,
|
FlowGraph graph,
|
||||||
FlowItemExecutor.NodeExecutor executorFunc,
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
@ -112,6 +136,31 @@ public class FlowTaskScheduler {
|
|||||||
|
|
||||||
String key = FlowSchedulerCache.buildKey(instId, nodeId, loopIteration);
|
String key = FlowSchedulerCache.buildKey(instId, nodeId, loopIteration);
|
||||||
|
|
||||||
|
// 如果已经调度过,则不再重复调度
|
||||||
|
if (schedulerCache.trySchedule(key)) {
|
||||||
|
executor.submit(() -> {
|
||||||
|
Thread.currentThread().setName("node-thread-" + nodeId);
|
||||||
|
try {
|
||||||
|
executorFunc.execute(graph.getNode(nodeId));
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (ExceptionUtil.getRootCause(e) instanceof InterruptedException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.error("节点执行异常:instId={}, nodeId={}, err={}", instId, nodeId, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
/**
|
||||||
|
* 提交节点执行任务(除循环只调度一次)
|
||||||
|
*/
|
||||||
|
private void scheduleNode(String instId,
|
||||||
|
String nodeId,
|
||||||
|
FlowGraph graph,
|
||||||
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
|
List<Integer> iterations) {
|
||||||
|
String key = FlowSchedulerCache.buildKey(instId, nodeId, iterations);
|
||||||
|
|
||||||
// 如果已经调度过,则不再重复调度
|
// 如果已经调度过,则不再重复调度
|
||||||
if (schedulerCache.trySchedule(key)) {
|
if (schedulerCache.trySchedule(key)) {
|
||||||
executor.submit(() -> {
|
executor.submit(() -> {
|
||||||
@ -132,9 +181,9 @@ public class FlowTaskScheduler {
|
|||||||
String nodeId,
|
String nodeId,
|
||||||
FlowGraph graph,
|
FlowGraph graph,
|
||||||
FlowItemExecutor.NodeExecutor executorFunc,
|
FlowItemExecutor.NodeExecutor executorFunc,
|
||||||
int loopIteration) {
|
List<Integer> iterations) {
|
||||||
|
|
||||||
String key = FlowSchedulerCache.buildKey(instId, nodeId, loopIteration);
|
String key = FlowSchedulerCache.buildKey(instId, nodeId, iterations);
|
||||||
if (schedulerCache.trySchedule(key)) {
|
if (schedulerCache.trySchedule(key)) {
|
||||||
executor.submit(() -> {
|
executor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.cmvr.test.flow.runtime.engine.support;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
@ -34,4 +35,12 @@ public class FlowSchedulerCache {
|
|||||||
? StrUtil.format("{}_{}_{}", instId, nodeId, loopIteration)
|
? StrUtil.format("{}_{}_{}", instId, nodeId, loopIteration)
|
||||||
: StrUtil.format("{}_{}", instId, nodeId);
|
: StrUtil.format("{}_{}", instId, nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String buildKey(String instId, String nodeId, List<Integer> iterations) {
|
||||||
|
StringBuilder sb = new StringBuilder(instId).append(":").append(nodeId);
|
||||||
|
for (int it : iterations) {
|
||||||
|
sb.append(":").append(it);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,8 @@ public class FlowLoggingInterceptor implements FlowMsgPreInterceptor {
|
|||||||
// todo 判断一下是否为LOOP重入
|
// todo 判断一下是否为LOOP重入
|
||||||
if (!(message.getNodeType().equalsIgnoreCase(NodeTypeEnum.LOOP.getCode()) && message.getLoopNum() > 0)) {
|
if (!(message.getNodeType().equalsIgnoreCase(NodeTypeEnum.LOOP.getCode()) && message.getLoopNum() > 0)) {
|
||||||
taskInstHolder.markRunning(message.getInstId(), message.getTaskId(), message.getItemId(), message.getNodeId(),
|
taskInstHolder.markRunning(message.getInstId(), message.getTaskId(), message.getItemId(), message.getNodeId(),
|
||||||
message.getNodeType(), message.getAction().getOperate(), message.getAction().getAction(), message.getInputParams().toJSONString());
|
message.getNodeType(), message.getAction().getOperate(), message.getAction().getAction(),
|
||||||
|
message.getInputParams().toJSONString(), message.getIterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskNodeExecuteResult result = next.apply(message);
|
TaskNodeExecuteResult result = next.apply(message);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.cmvr.test.flow.builder.FlowNodeWrapper;
|
|||||||
import com.cmvr.test.flow.builder.FlowParamDef;
|
import com.cmvr.test.flow.builder.FlowParamDef;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,4 +22,5 @@ public class TaskNodeExecuteContext {
|
|||||||
private TaskNodeExecuteMessage rootMessage;
|
private TaskNodeExecuteMessage rootMessage;
|
||||||
private Runnable onFinished;
|
private Runnable onFinished;
|
||||||
private int loopIteration;
|
private int loopIteration;
|
||||||
|
private List<Integer> iterations = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,25 +5,38 @@ import com.cmvr.test.enums.ActionEnum;
|
|||||||
import com.cmvr.test.flow.builder.FlowGraph;
|
import com.cmvr.test.flow.builder.FlowGraph;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单个节点的执行输入消息
|
* 单个节点的执行输入消息
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class TaskNodeExecuteMessage {
|
public class TaskNodeExecuteMessage {
|
||||||
|
|
||||||
/** 实例ID */
|
/**
|
||||||
|
* 实例ID
|
||||||
|
*/
|
||||||
private String instId;
|
private String instId;
|
||||||
|
|
||||||
/** 任务ID */
|
/**
|
||||||
|
* 任务ID
|
||||||
|
*/
|
||||||
private String taskId;
|
private String taskId;
|
||||||
|
|
||||||
/** 检测项ID(用于定位流程) */
|
/**
|
||||||
|
* 检测项ID(用于定位流程)
|
||||||
|
*/
|
||||||
private String itemId;
|
private String itemId;
|
||||||
|
|
||||||
/** 节点ID */
|
/**
|
||||||
|
* 节点ID
|
||||||
|
*/
|
||||||
private String nodeId;
|
private String nodeId;
|
||||||
|
|
||||||
/** 待执行检测项数 */
|
/**
|
||||||
|
* 待执行检测项数
|
||||||
|
*/
|
||||||
private int pendingItemCount;
|
private int pendingItemCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,25 +50,44 @@ public class TaskNodeExecuteMessage {
|
|||||||
*/
|
*/
|
||||||
private transient int loopNum = 0;
|
private transient int loopNum = 0;
|
||||||
|
|
||||||
/** 节点名称 */
|
/**
|
||||||
|
* 全局迭代路径(嵌套循环时用)
|
||||||
|
*/
|
||||||
|
private List<Integer> iterations = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点名称
|
||||||
|
*/
|
||||||
private String nodeName;
|
private String nodeName;
|
||||||
|
|
||||||
/** 节点类型(START、FUNCTION、END 等) */
|
/**
|
||||||
|
* 节点类型(START、FUNCTION、END 等)
|
||||||
|
*/
|
||||||
private String nodeType;
|
private String nodeType;
|
||||||
|
|
||||||
/** 节点行为(动作标识符) */
|
/**
|
||||||
|
* 节点行为(动作标识符)
|
||||||
|
*/
|
||||||
private ActionEnum action;
|
private ActionEnum action;
|
||||||
|
|
||||||
/** 是否试运行 */
|
/**
|
||||||
|
* 是否试运行
|
||||||
|
*/
|
||||||
private boolean trial;
|
private boolean trial;
|
||||||
|
|
||||||
/** 所属终端ID */
|
/**
|
||||||
|
* 所属终端ID
|
||||||
|
*/
|
||||||
private String terminalId;
|
private String terminalId;
|
||||||
|
|
||||||
/** 节点入参 */
|
/**
|
||||||
|
* 节点入参
|
||||||
|
*/
|
||||||
private JSONObject inputParams;
|
private JSONObject inputParams;
|
||||||
|
|
||||||
/** 上游输出参数(来自上一个节点的输出) */
|
/**
|
||||||
|
* 上游输出参数(来自上一个节点的输出)
|
||||||
|
*/
|
||||||
private JSONObject upStreamOutput;
|
private JSONObject upStreamOutput;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,8 +64,8 @@ public class EdgeCameraOperateService implements EdgeOperateService {
|
|||||||
// // 驾驶偏好
|
// // 驾驶偏好
|
||||||
// imageUrl = "http://192.168.1.100:9000/cmvr-iot/FILE/20250822/1755849654731.jpg";
|
// imageUrl = "http://192.168.1.100:9000/cmvr-iot/FILE/20250822/1755849654731.jpg";
|
||||||
// }
|
// }
|
||||||
// String imageUrl = "http://192.168.1.100:9000/cmvr-iot/IMAGE/20250901/1756718594725.jpg";
|
String imageUrl = "http://192.168.1.100:9000/cmvr-iot/IMAGE/20250901/1756718594725.jpg";
|
||||||
String imageUrl = edgeCameraService.getRGBDImages(terminalId, deviceId);
|
// String imageUrl = edgeCameraService.getRGBDImages(terminalId, deviceId);
|
||||||
|
|
||||||
JSONArray imageUrls = new JSONArray();
|
JSONArray imageUrls = new JSONArray();
|
||||||
if (ObjUtil.isNotEmpty(upstreamOutput)) {
|
if (ObjUtil.isNotEmpty(upstreamOutput)) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.cmvr.common.annotation.Excel;
|
import com.cmvr.common.annotation.Excel;
|
||||||
import com.cmvr.common.core.domain.BaseEntity;
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import com.cmvr.test.enums.LoopNodeTypeEnum;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -49,4 +50,10 @@ public class TeDetectionItem extends BaseEntity {
|
|||||||
|
|
||||||
@ApiModelProperty("检测项参数配置(JSON)")
|
@ApiModelProperty("检测项参数配置(JSON)")
|
||||||
private String config;
|
private String config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* #{@link LoopNodeTypeEnum}
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("场景标识,默认 NORMAL")
|
||||||
|
private String sceneCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,9 @@ public class TeNodeInst {
|
|||||||
@ApiModelProperty("执行日志/备注")
|
@ApiModelProperty("执行日志/备注")
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
|
@ApiModelProperty("循环节点的层级")
|
||||||
|
private String iteration;
|
||||||
|
|
||||||
@ApiModelProperty("开始时间戳(ms)")
|
@ApiModelProperty("开始时间戳(ms)")
|
||||||
private Long startTime;
|
private Long startTime;
|
||||||
|
|
||||||
|
|||||||
@ -70,4 +70,12 @@ public interface ITeDetectionItemService extends IService<TeDetectionItem> {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteTeDetectionItemById(String id);
|
public int deleteTeDetectionItemById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据场景类型查询检测项
|
||||||
|
*
|
||||||
|
* @param sceneType 场景类型
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public TeDetectionItem selectTeDetectionItemBySceneType(String sceneType);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,10 +31,11 @@ public interface ITeNodeInstService extends IService<TeNodeInst> {
|
|||||||
* @param operate 执行来源
|
* @param operate 执行来源
|
||||||
* @param action 动作类型
|
* @param action 动作类型
|
||||||
* @param paramsIn 输入参数(已序列化为 JSON 字符串)
|
* @param paramsIn 输入参数(已序列化为 JSON 字符串)
|
||||||
|
* @param iterations 迭代次数
|
||||||
*/
|
*/
|
||||||
void logRunning(String instId, String taskId, String itemId,
|
void logRunning(String instId, String taskId, String itemId,
|
||||||
String nodeId, String nodeType,
|
String nodeId, String nodeType,
|
||||||
String operate, String action, String paramsIn);
|
String operate, String action, String paramsIn, List<Integer> iterations);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 节点执行后更新输出参数等信息/记录节点成功完成
|
* 节点执行后更新输出参数等信息/记录节点成功完成
|
||||||
@ -52,7 +53,7 @@ public interface ITeNodeInstService extends IService<TeNodeInst> {
|
|||||||
/**
|
/**
|
||||||
* 删除节点
|
* 删除节点
|
||||||
*/
|
*/
|
||||||
void delete(String instId, String nodeId);
|
void delete(String instId, String nodeId, List<Integer> iterations);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新节点
|
* 更新节点
|
||||||
|
|||||||
@ -12,6 +12,7 @@ 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 lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -33,7 +34,7 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
|
|||||||
@Override
|
@Override
|
||||||
public void logRunning(String instId, String taskId, String itemId,
|
public void logRunning(String instId, String taskId, String itemId,
|
||||||
String nodeId, String nodeType,
|
String nodeId, String nodeType,
|
||||||
String operate, String action, String paramsIn) {
|
String operate, String action, String paramsIn, List<Integer> iterations) {
|
||||||
|
|
||||||
TeNodeInst record = new TeNodeInst();
|
TeNodeInst record = new TeNodeInst();
|
||||||
record.setInstId(instId);
|
record.setInstId(instId);
|
||||||
@ -47,6 +48,7 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
|
|||||||
record.setParamsIn(paramsIn);
|
record.setParamsIn(paramsIn);
|
||||||
record.setParamsOut("{}");
|
record.setParamsOut("{}");
|
||||||
record.setStartTime(System.currentTimeMillis());
|
record.setStartTime(System.currentTimeMillis());
|
||||||
|
record.setIteration(getIteration(iterations));
|
||||||
|
|
||||||
this.save(record);
|
this.save(record);
|
||||||
}
|
}
|
||||||
@ -113,13 +115,20 @@ public class ITeNodeInstServiceImpl extends ServiceImpl<TeNodeInstMapper, TeNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String instId, String nodeId) {
|
public void delete(String instId, String nodeId, List<Integer> iterations) {
|
||||||
|
String iteration = getIteration(iterations);
|
||||||
LambdaQueryWrapper<TeNodeInst> wrapper = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<TeNodeInst> wrapper = Wrappers.lambdaQuery();
|
||||||
wrapper.eq(TeNodeInst::getInstId, instId)
|
wrapper.eq(TeNodeInst::getInstId, instId)
|
||||||
.eq(TeNodeInst::getNodeId, nodeId);
|
.eq(TeNodeInst::getNodeId, nodeId)
|
||||||
|
.eq(TeNodeInst::getIteration, iteration);
|
||||||
this.baseMapper.delete(wrapper);
|
this.baseMapper.delete(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String getIteration(List<Integer> iterations) {
|
||||||
|
return StrUtil.join(StrUtil.DASHED, iterations);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(String instId, String nodeId, TaskStatusEnum nodeStatus) {
|
public void update(String instId, String nodeId, TaskStatusEnum nodeStatus) {
|
||||||
LambdaUpdateWrapper<TeNodeInst> wrapper = Wrappers.lambdaUpdate();
|
LambdaUpdateWrapper<TeNodeInst> wrapper = Wrappers.lambdaUpdate();
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
package com.cmvr.test.service.impl;
|
package com.cmvr.test.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.cmvr.common.core.domain.entity.SysGroup;
|
import com.cmvr.common.core.domain.entity.SysGroup;
|
||||||
import com.cmvr.common.utils.StringUtils;
|
|
||||||
import com.cmvr.test.enums.NodeTypeEnum;
|
import com.cmvr.test.enums.NodeTypeEnum;
|
||||||
import com.cmvr.test.mapper.TeDetectionItemMapper;
|
import com.cmvr.test.mapper.TeDetectionItemMapper;
|
||||||
import com.cmvr.test.model.domain.TeDetectionItem;
|
import com.cmvr.test.model.domain.TeDetectionItem;
|
||||||
@ -56,11 +57,13 @@ public class TeDetectionItemServiceImpl extends ServiceImpl<TeDetectionItemMappe
|
|||||||
.select(SysGroup::getGroupId)
|
.select(SysGroup::getGroupId)
|
||||||
.select(SysGroup::getGroupName)
|
.select(SysGroup::getGroupName)
|
||||||
.leftJoin(SysGroup.class, SysGroup::getGroupId, TeDetectionItem::getGroupId)
|
.leftJoin(SysGroup.class, SysGroup::getGroupId, TeDetectionItem::getGroupId)
|
||||||
.like(StringUtils.isNotBlank(teDetectionItem.getDetectName()), TeDetectionItem::getDetectName, teDetectionItem.getDetectName())
|
.eq(StrUtil.isNotBlank(teDetectionItem.getSceneCode()), TeDetectionItem::getSceneCode, teDetectionItem.getSceneCode())
|
||||||
.like(StringUtils.isNotBlank(teDetectionItem.getDetectDesc()), TeDetectionItem::getDetectDesc, teDetectionItem.getDetectDesc())
|
.like(StrUtil.isNotBlank(teDetectionItem.getDetectName()), TeDetectionItem::getDetectName, teDetectionItem.getDetectName())
|
||||||
.eq(StringUtils.isNotBlank(teDetectionItem.getStatus()), TeDetectionItem::getStatus, teDetectionItem.getStatus())
|
.like(StrUtil.isNotBlank(teDetectionItem.getDetectDesc()), TeDetectionItem::getDetectDesc, teDetectionItem.getDetectDesc())
|
||||||
.eq(StringUtils.isNotBlank(teDetectionItem.getIsDeploy()), TeDetectionItem::getIsDeploy, teDetectionItem.getIsDeploy())
|
.eq(StrUtil.isNotBlank(teDetectionItem.getStatus()), TeDetectionItem::getStatus, teDetectionItem.getStatus())
|
||||||
.eq(StringUtils.isNotBlank(teDetectionItem.getDetectVersion()), TeDetectionItem::getDetectVersion, teDetectionItem.getDetectVersion());
|
.eq(StrUtil.isNotBlank(teDetectionItem.getIsDeploy()), TeDetectionItem::getIsDeploy, teDetectionItem.getIsDeploy())
|
||||||
|
.eq(StrUtil.isNotBlank(teDetectionItem.getDetectVersion()), TeDetectionItem::getDetectVersion, teDetectionItem.getDetectVersion())
|
||||||
|
.orderByDesc(TeDetectionItem::getCreateTime);
|
||||||
|
|
||||||
// 执行查询并返回结果
|
// 执行查询并返回结果
|
||||||
return this.baseMapper.selectJoinList(TeDetectionItemVO.class, queryWrapper);
|
return this.baseMapper.selectJoinList(TeDetectionItemVO.class, queryWrapper);
|
||||||
@ -180,4 +183,11 @@ public class TeDetectionItemServiceImpl extends ServiceImpl<TeDetectionItemMappe
|
|||||||
public int deleteTeDetectionItemById(String id) {
|
public int deleteTeDetectionItemById(String id) {
|
||||||
return this.baseMapper.deleteById(id);
|
return this.baseMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TeDetectionItem selectTeDetectionItemBySceneType(String sceneType) {
|
||||||
|
LambdaQueryWrapper<TeDetectionItem> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(TeDetectionItem::getSceneCode, sceneType);
|
||||||
|
return this.getOne(queryWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,12 @@
|
|||||||
<artifactId>cmvr-iot-common</artifactId>
|
<artifactId>cmvr-iot-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 测试流程-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package com.cmvr.vi.enums;
|
||||||
|
|
||||||
|
public enum ViCorpusEnum {
|
||||||
|
WAKEUP, //唤醒
|
||||||
|
TEST //测试
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.cmvr.vi.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.vi.model.domain.ViProject;
|
||||||
|
import com.github.yulichang.base.MPJBaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-项目Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
public interface ViProjectMapper extends MPJBaseMapper<ViProject> {
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.cmvr.vi.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.vi.model.domain.ViScheme;
|
||||||
|
import com.github.yulichang.base.MPJBaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-方案Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
public interface ViSchemeMapper extends MPJBaseMapper<ViScheme> {
|
||||||
|
}
|
||||||
@ -8,83 +8,55 @@ import io.swagger.annotations.ApiModel;
|
|||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语料库对象 vi_corpus
|
|
||||||
*
|
|
||||||
* @author cmvr-iot
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
@ApiModel("语料库对象")
|
@ApiModel("语音交互--语料库")
|
||||||
public class ViCorpus extends BaseEntity {
|
public class ViCorpus extends BaseEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语料ID
|
|
||||||
*/
|
|
||||||
@ApiModelProperty("语料ID")
|
@ApiModelProperty("语料ID")
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
private Long corpusId;
|
private Long corpusId;
|
||||||
|
|
||||||
/**
|
@ApiModelProperty("测试语料-连续对话的父ID")
|
||||||
* 语料名称
|
private String parentId;
|
||||||
*/
|
|
||||||
@Excel(name = "语料名称")
|
@Excel(name = "语料名称")
|
||||||
@ApiModelProperty("语料名称")
|
@ApiModelProperty("语料名称")
|
||||||
private String corpusName;
|
private String corpusName;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语料类型(WAKEUP唤醒 / TEST测试)
|
|
||||||
*/
|
|
||||||
@Excel(name = "语料类型", readConverterExp = "WAKEUP唤醒,TEST测试")
|
@Excel(name = "语料类型", readConverterExp = "WAKEUP唤醒,TEST测试")
|
||||||
@ApiModelProperty("语料类型")
|
@ApiModelProperty("语料类型")
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语音对应的文本
|
|
||||||
*/
|
|
||||||
@Excel(name = "语音对应的文本")
|
@Excel(name = "语音对应的文本")
|
||||||
@ApiModelProperty("语音对应的文本")
|
@ApiModelProperty("语音对应的文本")
|
||||||
private String textContent;
|
private String textContent;
|
||||||
|
|
||||||
/**
|
|
||||||
* 语音文件存放路径
|
|
||||||
*/
|
|
||||||
@Excel(name = "语音文件存放路径")
|
@Excel(name = "语音文件存放路径")
|
||||||
@ApiModelProperty("语音文件存放路径")
|
@ApiModelProperty("语音文件存放路径")
|
||||||
private String audioPath;
|
private String audioPath;
|
||||||
|
|
||||||
/**
|
|
||||||
* 音色
|
|
||||||
*/
|
|
||||||
@Excel(name = "音色")
|
@Excel(name = "音色")
|
||||||
@ApiModelProperty("音色")
|
@ApiModelProperty("音色")
|
||||||
private String voiceType;
|
private String voiceType;
|
||||||
|
|
||||||
/**
|
|
||||||
* 方言
|
|
||||||
*/
|
|
||||||
@Excel(name = "方言")
|
@Excel(name = "方言")
|
||||||
@ApiModelProperty("方言")
|
@ApiModelProperty("方言")
|
||||||
private String dialect;
|
private String dialect;
|
||||||
|
|
||||||
/**
|
|
||||||
* 预期结果(预留)
|
|
||||||
*/
|
|
||||||
// @Excel(name = "预期结果(预留)")
|
// @Excel(name = "预期结果(预留)")
|
||||||
@ApiModelProperty("预期结果(预留)")
|
@ApiModelProperty("预期结果(预留)")
|
||||||
private String expectedResult;
|
private String expectedResult;
|
||||||
|
|
||||||
/**
|
|
||||||
* 同一父语料下的顺序
|
|
||||||
*/
|
|
||||||
@Excel(name = "同一父语料下的顺序")
|
@Excel(name = "同一父语料下的顺序")
|
||||||
@ApiModelProperty("同一父语料下的顺序")
|
@ApiModelProperty("同一父语料下的顺序")
|
||||||
private Integer sortOrder;
|
private Integer sortOrder;
|
||||||
|
|
||||||
/**
|
@Excel(name = "是否连续(0连续 1单次)")
|
||||||
* 状态(0正常 1停用)
|
@ApiModelProperty("是否连续(0连续 1单次),测试语料时使用")
|
||||||
*/
|
private Integer continuous = 1;
|
||||||
|
|
||||||
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
||||||
@ApiModelProperty(value = "状态", notes = "0=正常,1=停用")
|
@ApiModelProperty(value = "状态", notes = "0=正常,1=停用")
|
||||||
private String status;
|
private String status;
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
package com.cmvr.vi.model.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("语音交互--项目表")
|
||||||
|
public class ViProject extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("项目ID")
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String projectId;
|
||||||
|
|
||||||
|
@Excel(name = "项目名称")
|
||||||
|
@ApiModelProperty("项目名称")
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
@Excel(name = "测试人员")
|
||||||
|
@ApiModelProperty("测试人员")
|
||||||
|
private String tester;
|
||||||
|
|
||||||
|
@Excel(name = "计划测试开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("计划测试开始时间")
|
||||||
|
private Date planStart;
|
||||||
|
|
||||||
|
@Excel(name = "计划测试结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("计划测试结束时间")
|
||||||
|
private Date planEnd;
|
||||||
|
|
||||||
|
@Excel(name = "项目描述")
|
||||||
|
@ApiModelProperty("项目描述")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Excel(name = "样品名称")
|
||||||
|
@ApiModelProperty("样品名称")
|
||||||
|
private String sampleName;
|
||||||
|
|
||||||
|
@Excel(name = "商标")
|
||||||
|
@ApiModelProperty("商标")
|
||||||
|
private String trademark;
|
||||||
|
|
||||||
|
@Excel(name = "型号规格")
|
||||||
|
@ApiModelProperty("型号规格")
|
||||||
|
private String modelSpec;
|
||||||
|
|
||||||
|
@Excel(name = "数量")
|
||||||
|
@ApiModelProperty("数量")
|
||||||
|
private Integer quantity;
|
||||||
|
|
||||||
|
@Excel(name = "委托单位")
|
||||||
|
@ApiModelProperty("委托单位")
|
||||||
|
private String entrustUnit;
|
||||||
|
|
||||||
|
@Excel(name = "生产单位")
|
||||||
|
@ApiModelProperty("生产单位")
|
||||||
|
private String productionUnit;
|
||||||
|
|
||||||
|
@Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
@ApiModelProperty("生产日期")
|
||||||
|
private Date productionDate;
|
||||||
|
|
||||||
|
@Excel(name = "送样日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
@ApiModelProperty("送样日期")
|
||||||
|
private Date sampleDate;
|
||||||
|
|
||||||
|
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
||||||
|
@ApiModelProperty(value = "状态", notes = "0=正常,1=停用")
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.cmvr.vi.model.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("语音交互--方案表")
|
||||||
|
public class ViScheme extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("方案ID")
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
private String schemeId;
|
||||||
|
|
||||||
|
@Excel(name = "所属项目ID")
|
||||||
|
@ApiModelProperty("所属项目ID")
|
||||||
|
private String projectId;
|
||||||
|
|
||||||
|
@Excel(name = "方案名称")
|
||||||
|
@ApiModelProperty("方案名称")
|
||||||
|
private String schemeName;
|
||||||
|
|
||||||
|
@ApiModelProperty("场景类型 1:唤醒场景 2: 单次对话场景 3:连续对话场景")
|
||||||
|
private Integer sceneType;
|
||||||
|
|
||||||
|
@ApiModelProperty("唤醒语料parent_id")
|
||||||
|
private String wakeId;
|
||||||
|
|
||||||
|
@ApiModelProperty("排序")
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
@Excel(name = "语料ID列表")
|
||||||
|
@ApiModelProperty(value = "语料parent_id列表,逗号分隔",notes = "单次和唤醒的parent_id和id一致,连续语料的parent_id下有多条子语料")
|
||||||
|
private String corpusIds;
|
||||||
|
|
||||||
|
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
||||||
|
@ApiModelProperty(value = "状态", notes = "0=正常,1=停用")
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.cmvr.vi.model.vo;
|
||||||
|
|
||||||
|
import com.cmvr.vi.model.domain.ViCorpus;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("连续对话分组VO")
|
||||||
|
public class ViContinuousCorpusVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("测试语料-连续对话的父ID")
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
@ApiModelProperty("语料名称")
|
||||||
|
private String corpusName;
|
||||||
|
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voiceType;
|
||||||
|
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
@ApiModelProperty("子语料列表")
|
||||||
|
private List<ViCorpus> children;
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package com.cmvr.vi.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("查询单次对话语料/唤醒语料VO")
|
||||||
|
public class ViCorpusVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("测试语料-连续对话的父ID")
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
@ApiModelProperty("测试语料-连续对话的父ID列表")
|
||||||
|
private List<String> parentIds;
|
||||||
|
|
||||||
|
@ApiModelProperty("语料名称")
|
||||||
|
private String corpusName;
|
||||||
|
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voiceType;
|
||||||
|
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
@ApiModelProperty("语音对应的文本")
|
||||||
|
private String textContent;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态", notes = "0=正常,1=停用")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@NotEmpty(message = "语料类型不能为空")
|
||||||
|
@ApiModelProperty(value = "语料类型", required = true, notes = "WAKEUP 唤醒,TEST 单次对话测试")
|
||||||
|
private String type;
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@ package com.cmvr.vi.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.cmvr.vi.model.domain.ViCorpus;
|
import com.cmvr.vi.model.domain.ViCorpus;
|
||||||
|
import com.cmvr.vi.model.vo.ViContinuousCorpusVO;
|
||||||
|
import com.cmvr.vi.model.vo.ViCorpusVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -22,10 +24,18 @@ public interface IViCorpusService extends IService<ViCorpus> {
|
|||||||
/**
|
/**
|
||||||
* 查询语料库列表
|
* 查询语料库列表
|
||||||
*
|
*
|
||||||
* @param viCorpus 语料库
|
* @param viCorpusVO 语料库
|
||||||
* @return 语料库集合
|
* @return 语料库集合
|
||||||
*/
|
*/
|
||||||
public List<ViCorpus> selectViCorpusList(ViCorpus viCorpus);
|
public List<ViCorpus> selectViCorpusList(ViCorpusVO viCorpusVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询连续对话列表
|
||||||
|
*
|
||||||
|
* @param viCorpusVO 语料库
|
||||||
|
* @return 语料库集合
|
||||||
|
*/
|
||||||
|
public List<ViContinuousCorpusVO> selectContinuousList(ViCorpusVO viCorpusVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增语料库
|
* 新增语料库
|
||||||
@ -35,6 +45,14 @@ public interface IViCorpusService extends IService<ViCorpus> {
|
|||||||
*/
|
*/
|
||||||
public int insertViCorpus(ViCorpus viCorpus);
|
public int insertViCorpus(ViCorpus viCorpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增语料库
|
||||||
|
*
|
||||||
|
* @param viCorpus 语料库
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public boolean insertBatch(List<ViCorpus> viCorpus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改语料库
|
* 修改语料库
|
||||||
*
|
*
|
||||||
@ -51,4 +69,20 @@ public interface IViCorpusService extends IService<ViCorpus> {
|
|||||||
*/
|
*/
|
||||||
public int deleteViCorpusByCorpusIds(Long[] corpusIds);
|
public int deleteViCorpusByCorpusIds(Long[] corpusIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增/修改语料库
|
||||||
|
*/
|
||||||
|
int insertOrUpdateBatch(List<ViCorpus> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增连续对话
|
||||||
|
*/
|
||||||
|
boolean insertContinuousViCorpus(ViContinuousCorpusVO viContinuousCorpusVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改连续对话
|
||||||
|
*/
|
||||||
|
int updateContinuousViCorpus(ViContinuousCorpusVO viContinuousCorpusVO);
|
||||||
|
|
||||||
|
int deleteViCorpusByParentIds(String[] parentIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.cmvr.vi.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.cmvr.vi.model.domain.ViProject;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-项目Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
public interface IViProjectService extends IService<ViProject> {
|
||||||
|
/**
|
||||||
|
* 查询语音交互-项目
|
||||||
|
*
|
||||||
|
* @param projectId 语音交互-项目主键
|
||||||
|
* @return 语音交互-项目
|
||||||
|
*/
|
||||||
|
public ViProject selectViProjectByProjectId(String projectId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语音交互-项目列表
|
||||||
|
*
|
||||||
|
* @param viProject 语音交互-项目
|
||||||
|
* @return 语音交互-项目集合
|
||||||
|
*/
|
||||||
|
public List<ViProject> selectViProjectList(ViProject viProject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语音交互-项目
|
||||||
|
*
|
||||||
|
* @param viProject 语音交互-项目
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertViProject(ViProject viProject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语音交互-项目
|
||||||
|
*
|
||||||
|
* @param viProject 语音交互-项目
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateViProject(ViProject viProject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除语音交互-项目
|
||||||
|
*
|
||||||
|
* @param projectIds 需要删除的语音交互-项目主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteViProjectByProjectIds(String[] projectIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行项目
|
||||||
|
*/
|
||||||
|
public String execute(String projectId);
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package com.cmvr.vi.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.cmvr.vi.model.domain.ViScheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-方案Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
public interface IViSchemeService extends IService<ViScheme> {
|
||||||
|
/**
|
||||||
|
* 查询语音交互-方案
|
||||||
|
*
|
||||||
|
* @param schemeId 语音交互-方案主键
|
||||||
|
* @return 语音交互-方案
|
||||||
|
*/
|
||||||
|
public ViScheme selectViSchemeBySchemeId(String schemeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语音交互-方案列表
|
||||||
|
*
|
||||||
|
* @param viScheme 语音交互-方案
|
||||||
|
* @return 语音交互-方案集合
|
||||||
|
*/
|
||||||
|
public List<ViScheme> selectViSchemeList(ViScheme viScheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语音交互-方案
|
||||||
|
*
|
||||||
|
* @param viScheme 语音交互-方案
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertViScheme(ViScheme viScheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语音交互-方案
|
||||||
|
*
|
||||||
|
* @param viScheme 语音交互-方案
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateViScheme(ViScheme viScheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除语音交互-方案
|
||||||
|
*
|
||||||
|
* @param schemeIds 需要删除的语音交互-方案主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteViSchemeBySchemeIds(String[] schemeIds);
|
||||||
|
}
|
||||||
@ -1,15 +1,27 @@
|
|||||||
package com.cmvr.vi.service.impl;
|
package com.cmvr.vi.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
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.utils.uuid.IdUtils;
|
||||||
|
import com.cmvr.vi.enums.ViCorpusEnum;
|
||||||
import com.cmvr.vi.mapper.ViCorpusMapper;
|
import com.cmvr.vi.mapper.ViCorpusMapper;
|
||||||
import com.cmvr.vi.model.domain.ViCorpus;
|
import com.cmvr.vi.model.domain.ViCorpus;
|
||||||
|
import com.cmvr.vi.model.vo.ViContinuousCorpusVO;
|
||||||
|
import com.cmvr.vi.model.vo.ViCorpusVO;
|
||||||
import com.cmvr.vi.service.IViCorpusService;
|
import com.cmvr.vi.service.IViCorpusService;
|
||||||
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语料库Service业务层处理
|
* 语料库Service业务层处理
|
||||||
@ -19,61 +31,193 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
public class IViCorpusServiceImpl extends ServiceImpl<ViCorpusMapper, ViCorpus> implements IViCorpusService {
|
public class IViCorpusServiceImpl extends ServiceImpl<ViCorpusMapper, ViCorpus> implements IViCorpusService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询语料库
|
|
||||||
*
|
|
||||||
* @param corpusId 语料库主键
|
|
||||||
* @return 语料库
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ViCorpus selectViCorpusByCorpusId(Long corpusId) {
|
public ViCorpus selectViCorpusByCorpusId(Long corpusId) {
|
||||||
return this.getById(corpusId);
|
return this.getById(corpusId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询语料库列表
|
|
||||||
*
|
|
||||||
* @param viCorpus 语料库
|
|
||||||
* @return 语料库
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<ViCorpus> selectViCorpusList(ViCorpus viCorpus) {
|
public List<ViCorpus> selectViCorpusList(ViCorpusVO viCorpusVO) {
|
||||||
LambdaQueryWrapper<ViCorpus> wrapper = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<ViCorpus> wrapper = Wrappers.lambdaQuery();
|
||||||
wrapper.eq(ViCorpus::getType, viCorpus.getType());
|
|
||||||
|
// 如果是唤醒语料
|
||||||
|
if (ViCorpusEnum.WAKEUP.name().equalsIgnoreCase(viCorpusVO.getType())) {
|
||||||
|
wrapper.eq(ViCorpus::getType, ViCorpusEnum.WAKEUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是单次对话
|
||||||
|
if (ViCorpusEnum.TEST.name().equalsIgnoreCase(viCorpusVO.getType())) {
|
||||||
|
wrapper.eq(ViCorpus::getType, ViCorpusEnum.TEST)
|
||||||
|
.eq(ViCorpus::getContinuous, 1); // 只查单次
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共条件
|
||||||
|
wrapper.like(ObjUtil.isNotEmpty(viCorpusVO.getVoiceType()), ViCorpus::getVoiceType, viCorpusVO.getVoiceType())
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getDialect()), ViCorpus::getDialect, viCorpusVO.getDialect())
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getCorpusName()), ViCorpus::getCorpusName, viCorpusVO.getCorpusName())
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getTextContent()), ViCorpus::getTextContent, viCorpusVO.getTextContent())
|
||||||
|
.eq(ObjUtil.isNotEmpty(viCorpusVO.getStatus()), ViCorpus::getStatus, viCorpusVO.getStatus())
|
||||||
|
.in(CollUtil.isNotEmpty(viCorpusVO.getParentIds()), ViCorpus::getParentId, viCorpusVO.getParentIds())
|
||||||
|
.orderByAsc(ViCorpus::getSortOrder)
|
||||||
|
.orderByDesc(ViCorpus::getUpdateTime);
|
||||||
|
|
||||||
return this.list(wrapper);
|
return this.list(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增语料库
|
@Override
|
||||||
*
|
public List<ViContinuousCorpusVO> selectContinuousList(ViCorpusVO viCorpusVO) {
|
||||||
* @param viCorpus 语料库
|
// 查询父级
|
||||||
* @return 结果
|
MPJLambdaWrapper<ViCorpus> wrapper = new MPJLambdaWrapper<>();
|
||||||
*/
|
wrapper.select(ViCorpus::getParentId)
|
||||||
|
.select(ViCorpus::getCorpusName)
|
||||||
|
.select(ViCorpus::getVoiceType)
|
||||||
|
.select(ViCorpus::getDialect)
|
||||||
|
.eq(ViCorpus::getType, ViCorpusEnum.TEST)
|
||||||
|
.eq(ViCorpus::getContinuous, 0)
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getVoiceType()), ViCorpus::getVoiceType, viCorpusVO.getVoiceType())
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getDialect()), ViCorpus::getDialect, viCorpusVO.getDialect())
|
||||||
|
.like(ObjUtil.isNotEmpty(viCorpusVO.getCorpusName()), ViCorpus::getCorpusName, viCorpusVO.getCorpusName())
|
||||||
|
.in(CollUtil.isNotEmpty(viCorpusVO.getParentIds()), ViCorpus::getParentId, viCorpusVO.getParentIds())
|
||||||
|
.groupBy(ViCorpus::getParentId, ViCorpus::getVoiceType, ViCorpus::getDialect, ViCorpus::getCorpusName);
|
||||||
|
|
||||||
|
List<ViContinuousCorpusVO> list = this.baseMapper.selectJoinList(ViContinuousCorpusVO.class, wrapper);
|
||||||
|
|
||||||
|
// 查询 children 用 parentId 关联
|
||||||
|
for (ViContinuousCorpusVO vo : list) {
|
||||||
|
List<ViCorpus> children = this.list(
|
||||||
|
Wrappers.lambdaQuery(ViCorpus.class)
|
||||||
|
.eq(ViCorpus::getParentId, vo.getParentId())
|
||||||
|
.eq(ViCorpus::getContinuous, 0)
|
||||||
|
.eq(ViCorpus::getType, ViCorpusEnum.TEST)
|
||||||
|
.orderByAsc(ViCorpus::getSortOrder)
|
||||||
|
);
|
||||||
|
vo.setChildren(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int insertViCorpus(ViCorpus viCorpus) {
|
public int insertViCorpus(ViCorpus viCorpus) {
|
||||||
|
viCorpus.setParentId(IdUtils.fastSimpleUUID());
|
||||||
return this.baseMapper.insert(viCorpus);
|
return this.baseMapper.insert(viCorpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 修改语料库
|
public boolean insertBatch(List<ViCorpus> data) {
|
||||||
*
|
data.forEach(v -> v.setParentId(IdUtils.fastSimpleUUID()));
|
||||||
* @param viCorpus 语料库
|
return this.saveBatch(data);
|
||||||
* @return 结果
|
}
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int updateViCorpus(ViCorpus viCorpus) {
|
public int updateViCorpus(ViCorpus viCorpus) {
|
||||||
return this.baseMapper.updateById(viCorpus);
|
return this.baseMapper.updateById(viCorpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除语料库
|
|
||||||
*
|
|
||||||
* @param corpusIds 需要删除的语料库主键
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int deleteViCorpusByCorpusIds(Long[] corpusIds) {
|
public int deleteViCorpusByCorpusIds(Long[] corpusIds) {
|
||||||
return this.baseMapper.deleteBatchIds(Arrays.asList(corpusIds));
|
return this.baseMapper.deleteBatchIds(Arrays.asList(corpusIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertOrUpdateBatch(List<ViCorpus> data) {
|
||||||
|
if (CollUtil.isEmpty(data)) {
|
||||||
|
throw new IllegalArgumentException("data must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非空 id → 更新
|
||||||
|
List<ViCorpus> updateList = data.stream()
|
||||||
|
.filter(item -> item.getCorpusId() != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 空 id → 新增
|
||||||
|
List<ViCorpus> insertList = data.stream()
|
||||||
|
.filter(item -> item.getCorpusId() == null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (!insertList.isEmpty()) {
|
||||||
|
this.saveBatch(insertList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新(自定义 XML,返回影响行数)
|
||||||
|
if (!updateList.isEmpty()) {
|
||||||
|
for (ViCorpus viCorpus : updateList) {
|
||||||
|
this.updateById(viCorpus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean insertContinuousViCorpus(ViContinuousCorpusVO viContinuousCorpusVO) {
|
||||||
|
String parentId = IdUtils.fastSimpleUUID();
|
||||||
|
List<ViCorpus> children = viContinuousCorpusVO.getChildren();
|
||||||
|
children.forEach(v -> v.setParentId(parentId));
|
||||||
|
return this.insertBatch(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int updateContinuousViCorpus(ViContinuousCorpusVO viContinuousCorpusVO) {
|
||||||
|
String parentId = viContinuousCorpusVO.getParentId();
|
||||||
|
|
||||||
|
// parentId 下现有 corpusId
|
||||||
|
List<Long> dbIds = this.list(new LambdaQueryWrapper<ViCorpus>()
|
||||||
|
.select(ViCorpus::getCorpusId)
|
||||||
|
.eq(ViCorpus::getParentId, parentId))
|
||||||
|
.stream()
|
||||||
|
.map(ViCorpus::getCorpusId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<ViCorpus> children = viContinuousCorpusVO.getChildren();
|
||||||
|
|
||||||
|
// 新增、更新、保留
|
||||||
|
List<ViCorpus> addList = new ArrayList<>();
|
||||||
|
List<ViCorpus> updateList = new ArrayList<>();
|
||||||
|
Set<Long> keepIds = new HashSet<>();
|
||||||
|
|
||||||
|
for (ViCorpus child : children) {
|
||||||
|
if (ObjUtil.isEmpty(child.getCorpusId())) {
|
||||||
|
// 新增
|
||||||
|
child.setParentId(parentId);
|
||||||
|
addList.add(child);
|
||||||
|
} else {
|
||||||
|
// 更新
|
||||||
|
updateList.add(child);
|
||||||
|
keepIds.add(child.getCorpusId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 要删除的
|
||||||
|
List<Long> removeIds = dbIds.stream()
|
||||||
|
.filter(id -> !keepIds.contains(id))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (!addList.isEmpty()) {
|
||||||
|
this.saveBatch(addList);
|
||||||
|
}
|
||||||
|
if (!updateList.isEmpty()) {
|
||||||
|
this.updateBatchById(updateList);
|
||||||
|
}
|
||||||
|
if (!removeIds.isEmpty()) {
|
||||||
|
this.removeByIds(removeIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addList.size() + updateList.size() + removeIds.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int deleteViCorpusByParentIds(String[] parentIds) {
|
||||||
|
if (parentIds == null || parentIds.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this.baseMapper.delete(
|
||||||
|
new LambdaQueryWrapper<ViCorpus>()
|
||||||
|
.in(ViCorpus::getParentId, Arrays.asList(parentIds))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
package com.cmvr.vi.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.cmvr.vi.mapper.ViProjectMapper;
|
||||||
|
import com.cmvr.vi.model.domain.ViProject;
|
||||||
|
import com.cmvr.vi.service.IViProjectService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-项目Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject> implements IViProjectService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViProject selectViProjectByProjectId(String projectId) {
|
||||||
|
return this.getById(projectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ViProject> selectViProjectList(ViProject viProject) {
|
||||||
|
LambdaQueryWrapper<ViProject> wrapper = Wrappers.lambdaQuery();
|
||||||
|
wrapper.eq(ObjUtil.isNotEmpty(viProject.getProjectName()), ViProject::getProjectName, viProject.getProjectName())
|
||||||
|
.eq(ObjUtil.isNotEmpty(viProject.getStatus()), ViProject::getStatus, viProject.getStatus());
|
||||||
|
return this.list(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertViProject(ViProject viProject) {
|
||||||
|
return this.baseMapper.insert(viProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateViProject(ViProject viProject) {
|
||||||
|
return this.baseMapper.updateById(viProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteViProjectByProjectIds(String[] projectIds) {
|
||||||
|
return this.baseMapper.deleteBatchIds(Arrays.asList(projectIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(String projectId) {
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
package com.cmvr.vi.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.cmvr.common.exception.GlobalException;
|
||||||
|
import com.cmvr.test.enums.FlowSceneTypeEnum;
|
||||||
|
import com.cmvr.test.model.domain.TeDetectionItem;
|
||||||
|
import com.cmvr.test.model.vo.TeQueryTaskOrchestraItemVO;
|
||||||
|
import com.cmvr.test.model.vo.TeTaskOrchestraVO;
|
||||||
|
import com.cmvr.test.service.ITeDetectionItemService;
|
||||||
|
import com.cmvr.test.service.ITeTaskOrchestrationService;
|
||||||
|
import com.cmvr.vi.mapper.ViSchemeMapper;
|
||||||
|
import com.cmvr.vi.model.domain.ViScheme;
|
||||||
|
import com.cmvr.vi.service.IViSchemeService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音交互-方案Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr-iot
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ViSchemeServiceImpl extends ServiceImpl<ViSchemeMapper, ViScheme> implements IViSchemeService {
|
||||||
|
|
||||||
|
private final ITeTaskOrchestrationService teTaskOrchestrationService;
|
||||||
|
private final ITeDetectionItemService detectionItemService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViScheme selectViSchemeBySchemeId(String schemeId) {
|
||||||
|
return this.getById(schemeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ViScheme> selectViSchemeList(ViScheme viScheme) {
|
||||||
|
LambdaQueryWrapper<ViScheme> wrapper = Wrappers.lambdaQuery();
|
||||||
|
wrapper.eq(ViScheme::getProjectId, viScheme.getProjectId())
|
||||||
|
.eq(ObjUtil.isNotEmpty(viScheme.getSchemeName()), ViScheme::getSchemeName, viScheme.getSchemeName())
|
||||||
|
.eq(ObjUtil.isNotEmpty(viScheme.getStatus()), ViScheme::getStatus, viScheme.getStatus())
|
||||||
|
.orderByAsc(ViScheme::getSort);
|
||||||
|
return this.list(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertViScheme(ViScheme viScheme) {
|
||||||
|
// 先插方案
|
||||||
|
int insert = this.baseMapper.insert(viScheme);
|
||||||
|
|
||||||
|
String taskId = viScheme.getProjectId();
|
||||||
|
Integer sort = viScheme.getSort();
|
||||||
|
|
||||||
|
// 获取对应场景流程id
|
||||||
|
Integer sceneType = viScheme.getSceneType(); // 1:唤醒 2:单次对话 3:连续对话
|
||||||
|
String key;
|
||||||
|
switch (sceneType) {
|
||||||
|
case 1: key = FlowSceneTypeEnum.VI_WAKEUP_CORPUS.name(); break;
|
||||||
|
case 2: key = FlowSceneTypeEnum.VI_SINGLE_CORPUS.name(); break;
|
||||||
|
case 3: key = FlowSceneTypeEnum.VI_CONTINUOUS_CORPUS.name(); break;
|
||||||
|
default: throw new GlobalException("场景类型参数错误!");
|
||||||
|
}
|
||||||
|
TeDetectionItem item = detectionItemService.selectTeDetectionItemBySceneType(key);
|
||||||
|
String itemId = item.getId();
|
||||||
|
|
||||||
|
// 查询已有编排项
|
||||||
|
List<TeQueryTaskOrchestraItemVO> items = teTaskOrchestrationService.queryByTaskId(taskId);
|
||||||
|
|
||||||
|
// 插入新编排项
|
||||||
|
TeQueryTaskOrchestraItemVO itemVO = new TeQueryTaskOrchestraItemVO();
|
||||||
|
itemVO.setItemId(itemId);
|
||||||
|
itemVO.setOrderNum(sort);
|
||||||
|
items.add(itemVO);
|
||||||
|
|
||||||
|
// 落库并归一化
|
||||||
|
normalizeTaskItems(taskId);
|
||||||
|
|
||||||
|
return insert;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateViScheme(ViScheme viScheme) {
|
||||||
|
int update = this.baseMapper.updateById(viScheme);
|
||||||
|
|
||||||
|
String taskId = viScheme.getProjectId();
|
||||||
|
|
||||||
|
// 这里不管 sort 是否改动,都做一次归一化,避免乱序
|
||||||
|
normalizeTaskItems(taskId);
|
||||||
|
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteViSchemeBySchemeIds(String[] schemeIds) {
|
||||||
|
List<String> schemeIdList = Arrays.asList(schemeIds);
|
||||||
|
|
||||||
|
// 查要删除的方案,获取对应 taskId 和流程 itemId
|
||||||
|
List<ViScheme> schemes = this.baseMapper.selectBatchIds(schemeIdList);
|
||||||
|
int delete = this.baseMapper.deleteBatchIds(schemeIdList);
|
||||||
|
|
||||||
|
// 每个 taskId 单独归一化一次
|
||||||
|
Map<String, List<ViScheme>> taskSchemeMap = schemes.stream()
|
||||||
|
.collect(Collectors.groupingBy(ViScheme::getProjectId));
|
||||||
|
|
||||||
|
for (String taskId : taskSchemeMap.keySet()) {
|
||||||
|
List<TeQueryTaskOrchestraItemVO> items = teTaskOrchestrationService.queryByTaskId(taskId);
|
||||||
|
|
||||||
|
if (items != null && !items.isEmpty()) {
|
||||||
|
// 找出要删的流程 itemId
|
||||||
|
List<String> deleteItemIds = taskSchemeMap.get(taskId).stream()
|
||||||
|
.map(s -> {
|
||||||
|
String key;
|
||||||
|
switch (s.getSceneType()) {
|
||||||
|
case 1: key = FlowSceneTypeEnum.VI_WAKEUP_CORPUS.name(); break;
|
||||||
|
case 2: key = FlowSceneTypeEnum.VI_SINGLE_CORPUS.name(); break;
|
||||||
|
case 3: key = FlowSceneTypeEnum.VI_CONTINUOUS_CORPUS.name(); break;
|
||||||
|
default: throw new GlobalException("场景类型参数错误!");
|
||||||
|
}
|
||||||
|
return detectionItemService.selectTeDetectionItemBySceneType(key).getId();
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 移除这些 item
|
||||||
|
items.removeIf(i -> deleteItemIds.contains(i.getItemId()));
|
||||||
|
|
||||||
|
// 覆盖保存并归一化
|
||||||
|
normalizeTaskItems(taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 taskId 对编排表的检测项重新排序(1..N)
|
||||||
|
*/
|
||||||
|
private void normalizeTaskItems(String taskId) {
|
||||||
|
List<TeQueryTaskOrchestraItemVO> items = teTaskOrchestrationService.queryByTaskId(taskId);
|
||||||
|
if (items == null || items.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按顺序排序
|
||||||
|
items.sort(Comparator.comparing(TeQueryTaskOrchestraItemVO::getOrderNum));
|
||||||
|
|
||||||
|
// 重新归一化 1..N
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
items.get(i).setOrderNum(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 落库
|
||||||
|
List<String> itemIds = items.stream()
|
||||||
|
.map(TeQueryTaskOrchestraItemVO::getItemId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
TeTaskOrchestraVO orchestraVO = new TeTaskOrchestraVO();
|
||||||
|
orchestraVO.setTaskId(taskId);
|
||||||
|
orchestraVO.setItemIds(itemIds);
|
||||||
|
|
||||||
|
teTaskOrchestrationService.insertTeTaskOrchestration(orchestraVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user