feat(inspection): 增加巡检点位语料配置功能
- 在 inspection_waypoint 表中新增 chinese_corpus 和 english_corpus 字段存储中英文语料 - 创建 InspectionWaypointCorpusConfigVO 用于巡检点位语料查询节点参数 - 实现 InspectionWaypointCorpusMapper 提供按检测项ID查询语料的数据库操作 - 开发 InspectionWaypointCorpusOperateService 处理语料类型识别和语料获取逻辑 - 添加语料类型支持包括中文/英文、zh-CN/en-US、zh/en或0/1等多种格式 - 实现语料验证机制确保巡检点位配置了相应语言语料 - 编写单元测试验证中英文语料获取和类型解析功能 - 为 VisionLocateOperateService 增加完整的测试用例覆盖安全方向校准和平面定位功能
This commit is contained in:
parent
356999547c
commit
9cd3e4a5d6
@ -0,0 +1,87 @@
|
|||||||
|
package com.cmvr.test.flow.runtime.operator.llm;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.common.exception.GlobalException;
|
||||||
|
import com.cmvr.test.enums.ActionEnum;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
|
||||||
|
import com.cmvr.test.mapper.InspectionWaypointCorpusMapper;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusConfigVO;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/** 根据检测项和语料类型读取巡检点位配置的播放语料。 */
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class InspectionWaypointCorpusOperateService implements LLMOperateService
|
||||||
|
{
|
||||||
|
private final InspectionWaypointCorpusMapper inspectionWaypointCorpusMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(ActionEnum action)
|
||||||
|
{
|
||||||
|
return ActionEnum.INSPECTION_WAYPOINT_CORPUS.equals(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message)
|
||||||
|
{
|
||||||
|
JSONObject input = message.getInputParams() == null ? new JSONObject() : message.getInputParams();
|
||||||
|
InspectionWaypointCorpusConfigVO config = input.to(InspectionWaypointCorpusConfigVO.class);
|
||||||
|
String detectItemId = StringUtils.trimToNull(config.getDetectItemId());
|
||||||
|
String type = StringUtils.trimToNull(config.getType());
|
||||||
|
if (detectItemId == null)
|
||||||
|
{
|
||||||
|
throw new GlobalException("检测项ID不能为空");
|
||||||
|
}
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
throw new GlobalException("语料类型不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
InspectionWaypointCorpusVO waypoint =
|
||||||
|
inspectionWaypointCorpusMapper.selectByDetectItemId(detectItemId);
|
||||||
|
if (waypoint == null)
|
||||||
|
{
|
||||||
|
throw new GlobalException("未找到检测项对应的巡检点位: " + detectItemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
String corpus = resolveCorpus(waypoint, type);
|
||||||
|
if (StringUtils.isBlank(corpus))
|
||||||
|
{
|
||||||
|
throw new GlobalException("巡检点位未配置" + languageName(type) + "语料");
|
||||||
|
}
|
||||||
|
|
||||||
|
return TaskNodeExecuteResult.success(new JSONObject().fluentPut("corpus", corpus));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCorpus(InspectionWaypointCorpusVO waypoint, String type)
|
||||||
|
{
|
||||||
|
return isChinese(type) ? waypoint.getChineseCorpus() : waypoint.getEnglishCorpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String languageName(String type)
|
||||||
|
{
|
||||||
|
return isChinese(type) ? "中文" : "英文";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isChinese(String type)
|
||||||
|
{
|
||||||
|
String normalized = type.trim().toLowerCase(Locale.ROOT).replace('_', '-');
|
||||||
|
if ("0".equals(normalized) || "cn".equals(normalized) || "chinese".equals(normalized)
|
||||||
|
|| "中文".equals(normalized) || normalized.startsWith("zh"))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ("1".equals(normalized) || "english".equals(normalized) || "英文".equals(normalized)
|
||||||
|
|| normalized.startsWith("en"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw new GlobalException("不支持的语料类型: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.cmvr.test.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
/** 巡检点位语料查询Mapper。 */
|
||||||
|
public interface InspectionWaypointCorpusMapper
|
||||||
|
{
|
||||||
|
@Select("select chinese_corpus as chineseCorpus, english_corpus as englishCorpus "
|
||||||
|
+ "from inspection_waypoint where detect_item_id = #{detectItemId} limit 1")
|
||||||
|
InspectionWaypointCorpusVO selectByDetectItemId(@Param("detectItemId") String detectItemId);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.cmvr.test.model.vo.inspection;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 巡检点位语料查询工作流节点参数。 */
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "InspectionWaypointCorpusConfigVO",
|
||||||
|
description = "INSPECTION_WAYPOINT_CORPUS节点参数")
|
||||||
|
public class InspectionWaypointCorpusConfigVO
|
||||||
|
{
|
||||||
|
@ApiModelProperty(value = "点位关联的检测项ID", required = true)
|
||||||
|
private String detectItemId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "语料类型,支持中文/英文、zh-CN/en-US、zh/en或0/1",
|
||||||
|
required = true, example = "zh-CN")
|
||||||
|
private String type;
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.cmvr.test.model.vo.inspection;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 巡检点位中英文语料查询结果。 */
|
||||||
|
@Data
|
||||||
|
public class InspectionWaypointCorpusVO
|
||||||
|
{
|
||||||
|
private String chineseCorpus;
|
||||||
|
|
||||||
|
private String englishCorpus;
|
||||||
|
}
|
||||||
@ -0,0 +1,258 @@
|
|||||||
|
package com.cmvr.test.flow.runtime.operator.edge;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.llm.analysis.MediaAnalysisClient;
|
||||||
|
import com.cmvr.test.enums.ActionEnum;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||||
|
import com.cmvr.test.flow.runtime.operator.llm.LLMMediaAnalysisOperateService;
|
||||||
|
import com.cmvr.test.vision.domain.VisionCalibrationProfile;
|
||||||
|
import com.cmvr.test.vision.math.VisionCalibrationMath;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class VisionLocateOperateServiceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calibratedSafeDirectionKeepsTheFinalFlangeOrientationStable() {
|
||||||
|
VisionLocateOperateService service = new VisionLocateOperateService(
|
||||||
|
null, null, null, null);
|
||||||
|
double[][] currentFlange = VisionCalibrationMath.fromCartesianPose(
|
||||||
|
cmvr.api.ArmCommand.CartesianPose.newBuilder()
|
||||||
|
.setRx(0.45).setRy(-0.3).setRz(0.7).build());
|
||||||
|
double[][] flangeToTcp = VisionCalibrationMath.fromCartesianPose(
|
||||||
|
cmvr.api.ArmCommand.CartesianPose.newBuilder()
|
||||||
|
.setX(0.07).setZ(0.01)
|
||||||
|
.setRx(0.08).setRy(-0.04).setRz(0.12).build());
|
||||||
|
double[][] currentTcp = VisionGeometry.multiply(currentFlange, flangeToTcp);
|
||||||
|
double[][] safeFlange = VisionCalibrationMath.fromCartesianPose(
|
||||||
|
cmvr.api.ArmCommand.CartesianPose.newBuilder()
|
||||||
|
.setRx(Math.PI).setRy(0.04).setRz(-0.2).build());
|
||||||
|
VisionCalibrationProfile toolProfile = new VisionCalibrationProfile();
|
||||||
|
toolProfile.setId("tool-profile-1");
|
||||||
|
toolProfile.setMetadataJson(new JSONObject()
|
||||||
|
.fluentPut("safeDirectionPose", matrixArray(safeFlange))
|
||||||
|
.toJSONString());
|
||||||
|
|
||||||
|
VisionLocateOperateService.StableToolOrientation orientation =
|
||||||
|
service.stableToolOrientation(currentTcp, flangeToTcp, toolProfile);
|
||||||
|
double[][] finalFlange = VisionGeometry.multiply(
|
||||||
|
orientation.tcpPose(), VisionGeometry.rigidInverse(flangeToTcp));
|
||||||
|
|
||||||
|
assertEquals("TOOL_CALIBRATION_SAFE_DIRECTION", orientation.source());
|
||||||
|
assertRotationEquals(safeFlange, finalFlange, 1e-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void missingSafeDirectionPreservesCurrentTcpOrientation() {
|
||||||
|
VisionLocateOperateService service = new VisionLocateOperateService(
|
||||||
|
null, null, null, null);
|
||||||
|
double[][] currentTcp = VisionCalibrationMath.fromCartesianPose(
|
||||||
|
cmvr.api.ArmCommand.CartesianPose.newBuilder()
|
||||||
|
.setRx(0.2).setRy(0.4).setRz(-0.6).build());
|
||||||
|
double[][] identity = VisionCalibrationMath.identity();
|
||||||
|
|
||||||
|
VisionLocateOperateService.StableToolOrientation orientation =
|
||||||
|
service.stableToolOrientation(currentTcp, identity, null);
|
||||||
|
|
||||||
|
assertEquals("CURRENT_TCP", orientation.source());
|
||||||
|
assertRotationEquals(currentTcp, orientation.tcpPose(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calibratedPlaneMakesTargetZIndependentFromRgbdDepthNoise() {
|
||||||
|
VisionLocateOperateService service = new VisionLocateOperateService(
|
||||||
|
null, null, null, null);
|
||||||
|
double[][] identity = VisionCalibrationMath.identity();
|
||||||
|
double[][] safeFlange = VisionCalibrationMath.identity();
|
||||||
|
safeFlange[2][3] = 0.5;
|
||||||
|
VisionCalibrationProfile toolProfile = new VisionCalibrationProfile();
|
||||||
|
toolProfile.setId("tool-profile-plane");
|
||||||
|
toolProfile.setMetadataJson(new JSONObject()
|
||||||
|
.fluentPut("safeDirectionPose", matrixArray(safeFlange))
|
||||||
|
.fluentPut("planeNormalBase", new JSONArray()
|
||||||
|
.fluentAdd(0.0).fluentAdd(0.0).fluentAdd(1.0))
|
||||||
|
.toJSONString());
|
||||||
|
VisionLocateOperateService.StableToolOrientation orientation =
|
||||||
|
service.stableToolOrientation(identity, identity, toolProfile);
|
||||||
|
com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot snapshot =
|
||||||
|
com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot.builder()
|
||||||
|
.width(640).height(480)
|
||||||
|
.fx(600).fy(600).cx(320).cy(240)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
VisionLocateOperateService.TargetPosition first = service.targetPosition(
|
||||||
|
identity, snapshot, 380, 240, new double[]{0.056, 0, 0.56},
|
||||||
|
List.of(), orientation, 0.0D);
|
||||||
|
VisionLocateOperateService.TargetPosition second = service.targetPosition(
|
||||||
|
identity, snapshot, 380, 240, new double[]{0.062, 0, 0.62},
|
||||||
|
List.of(), orientation, 0.0D);
|
||||||
|
|
||||||
|
assertEquals("TOOL_CALIBRATION_PLANE_OFFSET", first.source());
|
||||||
|
assertEquals(0.05, first.point()[0], 1e-12);
|
||||||
|
assertEquals(0.5, first.point()[2], 1e-12);
|
||||||
|
assertEquals(first.point()[2], second.point()[2], 0.0);
|
||||||
|
assertEquals(60.0, first.depthResidualMm(), 1e-9);
|
||||||
|
assertEquals(120.0, second.depthResidualMm(), 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dynamicParallelPlaneTracksHeightButRejectsDepthOutliers() {
|
||||||
|
VisionLocateOperateService service = new VisionLocateOperateService(
|
||||||
|
null, null, null, null);
|
||||||
|
double[][] identity = VisionCalibrationMath.identity();
|
||||||
|
VisionLocateOperateService.StableToolOrientation orientation =
|
||||||
|
new VisionLocateOperateService.StableToolOrientation(
|
||||||
|
identity, "TEST", new double[]{0, 0, 0.5}, new double[]{0, 0, 1});
|
||||||
|
com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot snapshot =
|
||||||
|
com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot.builder()
|
||||||
|
.width(640).height(480)
|
||||||
|
.fx(600).fy(600).cx(320).cy(240)
|
||||||
|
.build();
|
||||||
|
List<double[]> lowerSamples = List.of(
|
||||||
|
pointAtDepth(0.619), pointAtDepth(0.620), pointAtDepth(0.621),
|
||||||
|
pointAtDepth(0.620), pointAtDepth(0.619), pointAtDepth(0.621),
|
||||||
|
pointAtDepth(0.620), pointAtDepth(0.620), pointAtDepth(0.619),
|
||||||
|
pointAtDepth(0.621), pointAtDepth(0.800));
|
||||||
|
List<double[]> higherSamples = List.of(
|
||||||
|
pointAtDepth(0.679), pointAtDepth(0.680), pointAtDepth(0.681),
|
||||||
|
pointAtDepth(0.680), pointAtDepth(0.679), pointAtDepth(0.681),
|
||||||
|
pointAtDepth(0.680), pointAtDepth(0.680), pointAtDepth(0.679),
|
||||||
|
pointAtDepth(0.681), pointAtDepth(0.900));
|
||||||
|
|
||||||
|
VisionLocateOperateService.TargetPosition lower = service.targetPosition(
|
||||||
|
identity, snapshot, 380, 240, new double[]{0.09, 0, 0.90},
|
||||||
|
lowerSamples, orientation, null);
|
||||||
|
VisionLocateOperateService.TargetPosition higher = service.targetPosition(
|
||||||
|
identity, snapshot, 380, 240, new double[]{0.05, 0, 0.50},
|
||||||
|
higherSamples, orientation, null);
|
||||||
|
|
||||||
|
assertEquals("RGBD_PARALLEL_PLANE", lower.source());
|
||||||
|
assertEquals(0.620, lower.point()[2], 1e-12);
|
||||||
|
assertEquals(0.680, higher.point()[2], 1e-12);
|
||||||
|
assertEquals(0.062, lower.point()[0], 1e-12);
|
||||||
|
assertEquals(0.068, higher.point()[0], 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void preciseLocateUsesTheSameImageAnalysisRequestAsGenericPreciseMatch() {
|
||||||
|
AtomicReference<JSONObject> captured = new AtomicReference<>();
|
||||||
|
MediaAnalysisClient client = (MediaAnalysisClient) Proxy.newProxyInstance(
|
||||||
|
MediaAnalysisClient.class.getClassLoader(),
|
||||||
|
new Class<?>[]{MediaAnalysisClient.class},
|
||||||
|
(proxy, method, args) -> {
|
||||||
|
if (!"analyze".equals(method.getName())) {
|
||||||
|
throw new UnsupportedOperationException(method.getName());
|
||||||
|
}
|
||||||
|
JSONObject request = (JSONObject) args[0];
|
||||||
|
captured.set(request);
|
||||||
|
return new JSONObject()
|
||||||
|
.fluentPut("status", "SUCCEEDED")
|
||||||
|
.fluentPut("analysisType", "IMAGE_ANALYSIS")
|
||||||
|
.fluentPut("profileCode", "common.image_analysis.v1")
|
||||||
|
.fluentPut("result", new JSONObject()
|
||||||
|
.fluentPut("matched", true)
|
||||||
|
.fluentPut("center", new JSONArray().fluentAdd(610).fluentAdd(238))
|
||||||
|
.fluentPut("matchScore", 0.8D));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
LLMMediaAnalysisOperateService imageAnalysis =
|
||||||
|
new LLMMediaAnalysisOperateService(client, null);
|
||||||
|
|
||||||
|
imageAnalysis.execute(imageMessage(genericPreciseMatchInput()));
|
||||||
|
JSONObject genericRequest = captured.get();
|
||||||
|
|
||||||
|
VisionLocateOperateService visionLocate = new VisionLocateOperateService(
|
||||||
|
null, null, imageAnalysis, null);
|
||||||
|
visionLocate.analyze(visionMessage(), "https://files.example/scene.jpg",
|
||||||
|
"common.image_analysis.v1", "定位目标中心点", visualLocateInput(),
|
||||||
|
"REFERENCE_MATCH");
|
||||||
|
JSONObject visualRequest = captured.get();
|
||||||
|
|
||||||
|
assertEquals(genericRequest.getString("analysisType"), visualRequest.getString("analysisType"));
|
||||||
|
assertEquals(genericRequest.getString("profileCode"), visualRequest.getString("profileCode"));
|
||||||
|
assertEquals(genericRequest.getString("mediaUrl"), visualRequest.getString("mediaUrl"));
|
||||||
|
assertEquals(genericRequest.getJSONArray("mediaUrls"), visualRequest.getJSONArray("mediaUrls"));
|
||||||
|
assertEquals(genericRequest.getJSONObject("options"), visualRequest.getJSONObject("options"));
|
||||||
|
assertEquals(genericRequest.getJSONObject("context"), visualRequest.getJSONObject("context"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject genericPreciseMatchInput() {
|
||||||
|
return new JSONObject()
|
||||||
|
.fluentPut("profileCode", "common.image_analysis.v1")
|
||||||
|
.fluentPut("imageUrl", new JSONArray().fluentAdd("https://files.example/scene.jpg"))
|
||||||
|
.fluentPut("referenceImageUrl", "https://files.example/reference.png")
|
||||||
|
.fluentPut("prompt", "在大图中查找小图,返回原图像素坐标 [x1,y1,x2,y2]")
|
||||||
|
.fluentPut("analysisMethod", "REFERENCE_MATCH")
|
||||||
|
.fluentPut("analysisMode", "FAST")
|
||||||
|
.fluentPut("asynchronous", false)
|
||||||
|
.fluentPut("analysisTuning", new JSONObject()
|
||||||
|
.fluentPut("maxWidth", 896)
|
||||||
|
.fluentPut("maxImages", 12)
|
||||||
|
.fluentPut("maxOutputTokens", 384)
|
||||||
|
.fluentPut("matchThreshold", 0.48D)
|
||||||
|
.fluentPut("matchSelector", "BEST")
|
||||||
|
.fluentPut("matchIndex", 1)
|
||||||
|
.fluentPut("matchSort", "ROW_MAJOR")
|
||||||
|
.fluentPut("locateConfidenceThreshold", 0.45D));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject visualLocateInput() {
|
||||||
|
return new JSONObject()
|
||||||
|
.fluentPut("referenceImageUrl", "https://files.example/reference.png")
|
||||||
|
.fluentPut("analysisMode", "ACCURATE")
|
||||||
|
.fluentPut("matchSelector", "BEST")
|
||||||
|
.fluentPut("matchIndex", "1")
|
||||||
|
.fluentPut("matchSort", "ROW_MAJOR")
|
||||||
|
.fluentPut("confidenceThreshold", "0.45");
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskNodeExecuteMessage imageMessage(JSONObject input) {
|
||||||
|
TaskNodeExecuteMessage message = baseMessage();
|
||||||
|
message.setAction(ActionEnum.IMAGE_ANALYZE);
|
||||||
|
message.setInputParams(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskNodeExecuteMessage visionMessage() {
|
||||||
|
TaskNodeExecuteMessage message = baseMessage();
|
||||||
|
message.setAction(ActionEnum.VISION_LOCATE_TARGET);
|
||||||
|
message.setInputParams(visualLocateInput());
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskNodeExecuteMessage baseMessage() {
|
||||||
|
TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
|
||||||
|
message.setInstId("inst-1");
|
||||||
|
message.setTaskId("task-1");
|
||||||
|
message.setItemId("item-1");
|
||||||
|
message.setNodeId("node-1");
|
||||||
|
message.setTrial(true);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONArray matrixArray(double[][] matrix) {
|
||||||
|
JSONArray values = new JSONArray();
|
||||||
|
for (double[] row : matrix) {
|
||||||
|
for (double value : row) values.add(value);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double[] pointAtDepth(double depth) {
|
||||||
|
return new double[]{0, 0, depth};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertRotationEquals(double[][] expected, double[][] actual, double tolerance) {
|
||||||
|
for (int row = 0; row < 3; row++) {
|
||||||
|
for (int column = 0; column < 3; column++) {
|
||||||
|
assertEquals(expected[row][column], actual[row][column], tolerance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.cmvr.test.flow.runtime.operator.llm;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.common.exception.GlobalException;
|
||||||
|
import com.cmvr.test.enums.ActionEnum;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||||
|
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
|
||||||
|
import com.cmvr.test.mapper.InspectionWaypointCorpusMapper;
|
||||||
|
import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class InspectionWaypointCorpusOperateServiceTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void returnsChineseCorpus()
|
||||||
|
{
|
||||||
|
InspectionWaypointCorpusOperateService service = service("开始巡检", "Start inspection");
|
||||||
|
|
||||||
|
TaskNodeExecuteResult result = service.execute(message("zh-CN"));
|
||||||
|
|
||||||
|
assertTrue(result.isSuccess());
|
||||||
|
assertEquals("开始巡检", result.getOutputParams().getString("corpus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void returnsEnglishCorpusForNumericType()
|
||||||
|
{
|
||||||
|
InspectionWaypointCorpusOperateService service = service("开始巡检", "Start inspection");
|
||||||
|
|
||||||
|
TaskNodeExecuteResult result = service.execute(message(1));
|
||||||
|
|
||||||
|
assertEquals("Start inspection", result.getOutputParams().getString("corpus"));
|
||||||
|
assertTrue(service.supports(ActionEnum.INSPECTION_WAYPOINT_CORPUS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = GlobalException.class)
|
||||||
|
public void rejectsUnsupportedCorpusType()
|
||||||
|
{
|
||||||
|
service("开始巡检", "Start inspection").execute(message("fr-FR"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private InspectionWaypointCorpusOperateService service(String chineseCorpus, String englishCorpus)
|
||||||
|
{
|
||||||
|
InspectionWaypointCorpusVO waypoint = new InspectionWaypointCorpusVO();
|
||||||
|
waypoint.setChineseCorpus(chineseCorpus);
|
||||||
|
waypoint.setEnglishCorpus(englishCorpus);
|
||||||
|
InspectionWaypointCorpusMapper mapper = (InspectionWaypointCorpusMapper) Proxy.newProxyInstance(
|
||||||
|
InspectionWaypointCorpusMapper.class.getClassLoader(),
|
||||||
|
new Class<?>[]{InspectionWaypointCorpusMapper.class},
|
||||||
|
(proxy, method, args) -> {
|
||||||
|
if ("selectByDetectItemId".equals(method.getName()))
|
||||||
|
{
|
||||||
|
assertEquals("detect-item-1", args[0]);
|
||||||
|
return waypoint;
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException(method.getName());
|
||||||
|
});
|
||||||
|
return new InspectionWaypointCorpusOperateService(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskNodeExecuteMessage message(Object type)
|
||||||
|
{
|
||||||
|
TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
|
||||||
|
message.setAction(ActionEnum.INSPECTION_WAYPOINT_CORPUS);
|
||||||
|
message.setInputParams(new JSONObject()
|
||||||
|
.fluentPut("detectItemId", "detect-item-1")
|
||||||
|
.fluentPut("type", type));
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
sql/inspection_waypoint_corpus.sql
Normal file
4
sql/inspection_waypoint_corpus.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
-- 巡检点位增加中英文可播放语料。
|
||||||
|
ALTER TABLE `inspection_waypoint`
|
||||||
|
ADD COLUMN `chinese_corpus` text DEFAULT NULL COMMENT '该点位可播放的中文语料' AFTER `detect_item_id`,
|
||||||
|
ADD COLUMN `english_corpus` text DEFAULT NULL COMMENT '该点位可播放的英文语料' AFTER `chinese_corpus`;
|
||||||
Loading…
Reference in New Issue
Block a user