feat(agv): 添加AGV协议定义和重构命令接口
- 新增agv.proto文件定义AGV相关消息结构包括位姿、速度、电池状态等 - 新增统一2D/3D地图格式定义支持栅格、点云、体素等多种地图类型 - 重构agv_command.proto将原有命令接口替换为新的运行状态查询接口 - 添加导航控制、速度设置、地图管理等标准化命令接口 - 整合站点管理、路径规划、任务状态等AGV核心功能协议 - 引入运动约束选项和适配器参数扩展支持不同厂商设备特性
This commit is contained in:
parent
46fb4fecde
commit
736c510270
@ -89,6 +89,12 @@
|
|||||||
<groupId>com.cmvr</groupId>
|
<groupId>com.cmvr</groupId>
|
||||||
<artifactId>cmvr-iot-aima</artifactId>
|
<artifactId>cmvr-iot-aima</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 智能座舱语音语料采集-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-tts</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<properties>
|
<properties>
|
||||||
<env>dev</env>
|
<env>dev</env>
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package com.cmvr.web.controller.api;
|
package com.cmvr.web.controller.api;
|
||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.msgs.*;
|
||||||
import com.cmvr.common.core.domain.AjaxResult;
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
import com.cmvr.edge.client.model.agv.*;
|
|
||||||
import com.cmvr.edge.client.service.EdgeAgvService;
|
import com.cmvr.edge.client.service.EdgeAgvService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
@ -14,11 +13,13 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边缘系统AGV控制器
|
* 边缘系统AGV控制器
|
||||||
*
|
*
|
||||||
* @author cmvr-iot
|
* @author cmvr-iot
|
||||||
* @since 2026-07-01
|
* @since 2026-07-02
|
||||||
*/
|
*/
|
||||||
@Api(tags = "边缘--AGV")
|
@Api(tags = "边缘--AGV")
|
||||||
@RestController
|
@RestController
|
||||||
@ -28,139 +29,225 @@ public class EdgeAgvController {
|
|||||||
|
|
||||||
private final EdgeAgvService edgeAgvService;
|
private final EdgeAgvService edgeAgvService;
|
||||||
|
|
||||||
@ApiOperation("获取AGV状态信息")
|
@ApiOperation("获取AGV运行时状态")
|
||||||
@GetMapping("/getStatusInfo")
|
@GetMapping("/getRuntimeState")
|
||||||
public AjaxResult getStatusInfo(EdgeCommonVO vo) {
|
public AjaxResult getRuntimeState(EdgeCommonVO vo) {
|
||||||
AgvCommand.AgvStatusInfo statusInfo = edgeAgvService.getStatusInfo(vo);
|
Agv.AgvRuntimeState state = edgeAgvService.getRuntimeState(vo);
|
||||||
// 直接返回对象,Jackson会自动序列化
|
// 转换为Map返回
|
||||||
return AjaxResult.ok(statusInfo);
|
java.util.Map<String, Object> resultMap = new java.util.HashMap<>();
|
||||||
|
resultMap.put("timestamp", state.getTimestamp());
|
||||||
|
resultMap.put("mode", state.getMode());
|
||||||
|
resultMap.put("connected", state.getConnected());
|
||||||
|
resultMap.put("localized", state.getLocalized());
|
||||||
|
resultMap.put("moving", state.getMoving());
|
||||||
|
resultMap.put("fault", state.getFault());
|
||||||
|
resultMap.put("emergencyStopped", state.getEmergencyStopped());
|
||||||
|
|
||||||
|
// 位置信息
|
||||||
|
if (state.hasPose()) {
|
||||||
|
java.util.Map<String, Object> poseMap = new java.util.HashMap<>();
|
||||||
|
poseMap.put("x", state.getPose().getX());
|
||||||
|
poseMap.put("y", state.getPose().getY());
|
||||||
|
poseMap.put("theta", state.getPose().getTheta());
|
||||||
|
resultMap.put("pose", poseMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("获取机器人位置")
|
// 速度信息
|
||||||
@GetMapping("/getRobotLocation")
|
if (state.hasVelocity()) {
|
||||||
public AjaxResult getRobotLocation(EdgeCommonVO vo) {
|
java.util.Map<String, Object> velocityMap = new java.util.HashMap<>();
|
||||||
AgvCommand.AgvRobotLocation location = edgeAgvService.getRobotLocation(vo);
|
velocityMap.put("vx", state.getVelocity().getVx());
|
||||||
return AjaxResult.ok(location);
|
velocityMap.put("vy", state.getVelocity().getVy());
|
||||||
|
velocityMap.put("wz", state.getVelocity().getWz());
|
||||||
|
resultMap.put("velocity", velocityMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("获取地图状态")
|
// 电池信息
|
||||||
@GetMapping("/getMapStatus")
|
if (state.hasBattery()) {
|
||||||
public AjaxResult getMapStatus(EdgeCommonVO vo) {
|
java.util.Map<String, Object> batteryMap = new java.util.HashMap<>();
|
||||||
AgvCommand.AgvMapStatus mapStatus = edgeAgvService.getMapStatus(vo);
|
batteryMap.put("percentage", state.getBattery().getPercentage());
|
||||||
return AjaxResult.ok(mapStatus);
|
batteryMap.put("voltage", state.getBattery().getVoltage());
|
||||||
|
batteryMap.put("current", state.getBattery().getCurrent());
|
||||||
|
batteryMap.put("temperature", state.getBattery().getTemperature());
|
||||||
|
batteryMap.put("charging", state.getBattery().getCharging());
|
||||||
|
resultMap.put("battery", batteryMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap.put("currentMap", state.getCurrentMap());
|
||||||
|
resultMap.put("currentStation", state.getCurrentStation());
|
||||||
|
resultMap.put("lastError", state.getLastError());
|
||||||
|
|
||||||
|
return AjaxResult.ok(resultMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取导航状态")
|
||||||
|
@GetMapping("/getNavigationStatus")
|
||||||
|
public AjaxResult getNavigationStatus(EdgeCommonVO vo) {
|
||||||
|
Agv.AgvNavigationStatus status = edgeAgvService.getNavigationStatus(vo);
|
||||||
|
// 转换为Map返回
|
||||||
|
java.util.Map<String, Object> resultMap = new java.util.HashMap<>();
|
||||||
|
resultMap.put("state", status.getState());
|
||||||
|
resultMap.put("type", status.getType());
|
||||||
|
resultMap.put("progress", status.getProgress());
|
||||||
|
resultMap.put("message", status.getMessage());
|
||||||
|
return AjaxResult.ok(resultMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("紧急停止")
|
||||||
|
@GetMapping("/emergencyStop")
|
||||||
|
public AjaxResult emergencyStop(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.emergencyStop(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("清除故障")
|
||||||
|
@GetMapping("/clearFault")
|
||||||
|
public AjaxResult clearFault(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.clearFault(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导航到指定位置")
|
||||||
|
@PostMapping("/navigateToPose")
|
||||||
|
public AjaxResult navigateToPose(EdgeCommonVO vo,
|
||||||
|
@ApiParam("X坐标") double x,
|
||||||
|
@ApiParam("Y坐标") double y,
|
||||||
|
@ApiParam("角度") double theta) {
|
||||||
|
Agv.AgvPose2d pose = Agv.AgvPose2d.newBuilder()
|
||||||
|
.setX(x)
|
||||||
|
.setY(y)
|
||||||
|
.setTheta(theta)
|
||||||
|
.build();
|
||||||
|
edgeAgvService.navigateToPose(vo, pose);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("导航到站点")
|
||||||
|
@GetMapping("/navigateToStation")
|
||||||
|
public AjaxResult navigateToStation(EdgeCommonVO vo,
|
||||||
|
@ApiParam("站点ID") String stationId) {
|
||||||
|
edgeAgvService.navigateToStation(vo, stationId);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("暂停导航")
|
||||||
|
@GetMapping("/pauseNavigation")
|
||||||
|
public AjaxResult pauseNavigation(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.pauseNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("恢复导航")
|
||||||
|
@GetMapping("/resumeNavigation")
|
||||||
|
public AjaxResult resumeNavigation(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.resumeNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("取消导航")
|
||||||
|
@GetMapping("/cancelNavigation")
|
||||||
|
public AjaxResult cancelNavigation(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.cancelNavigation(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("设置速度")
|
||||||
|
@PostMapping("/setVelocity")
|
||||||
|
public AjaxResult setVelocity(EdgeCommonVO vo,
|
||||||
|
@ApiParam("线速度X") double vx,
|
||||||
|
@ApiParam("线速度Y") double vy,
|
||||||
|
@ApiParam("角速度") double wz) {
|
||||||
|
Agv.AgvVelocity velocity = Agv.AgvVelocity.newBuilder()
|
||||||
|
.setVx(vx)
|
||||||
|
.setVy(vy)
|
||||||
|
.setWz(wz)
|
||||||
|
.build();
|
||||||
|
edgeAgvService.setVelocity(vo, velocity);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("停止速度控制")
|
||||||
|
@GetMapping("/stopVelocityControl")
|
||||||
|
public AjaxResult stopVelocityControl(EdgeCommonVO vo) {
|
||||||
|
edgeAgvService.stopVelocityControl(vo);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("列出所有地图")
|
||||||
|
@GetMapping("/listMaps")
|
||||||
|
public AjaxResult listMaps(EdgeCommonVO vo) {
|
||||||
|
List<String> maps = edgeAgvService.listMaps(vo);
|
||||||
|
return AjaxResult.ok(maps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("列出所有站点")
|
||||||
|
@GetMapping("/listStations")
|
||||||
|
public AjaxResult listStations(EdgeCommonVO vo) {
|
||||||
|
List<Agv.AgvStation> stations = edgeAgvService.listStations(vo);
|
||||||
|
// 转换为List<Map>返回
|
||||||
|
List<java.util.Map<String, Object>> stationList = new java.util.ArrayList<>();
|
||||||
|
for (Agv.AgvStation station : stations) {
|
||||||
|
java.util.Map<String, Object> stationMap = new java.util.HashMap<>();
|
||||||
|
stationMap.put("id", station.getId());
|
||||||
|
stationMap.put("type", station.getType());
|
||||||
|
stationMap.put("description", station.getDescription());
|
||||||
|
|
||||||
|
if (station.hasPose()) {
|
||||||
|
java.util.Map<String, Object> poseMap = new java.util.HashMap<>();
|
||||||
|
poseMap.put("x", station.getPose().getX());
|
||||||
|
poseMap.put("y", station.getPose().getY());
|
||||||
|
poseMap.put("theta", station.getPose().getTheta());
|
||||||
|
stationMap.put("pose", poseMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
stationList.add(stationMap);
|
||||||
|
}
|
||||||
|
return AjaxResult.ok(stationList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("切换地图")
|
||||||
|
@GetMapping("/switchMap")
|
||||||
|
public AjaxResult switchMap(EdgeCommonVO vo,
|
||||||
|
@ApiParam("地图名称") String mapName) {
|
||||||
|
edgeAgvService.switchMap(vo, mapName);
|
||||||
|
return AjaxResult.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("上传地图")
|
||||||
|
@PostMapping("/uploadMap")
|
||||||
|
public AjaxResult uploadMap(EdgeCommonVO vo,
|
||||||
|
@ApiParam("地图名称") String mapName,
|
||||||
|
@ApiParam("地图内容") String content) {
|
||||||
|
edgeAgvService.uploadMap(vo, mapName, content);
|
||||||
|
return AjaxResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("下载地图")
|
@ApiOperation("下载地图")
|
||||||
@GetMapping("/downloadMap")
|
@GetMapping("/downloadMap")
|
||||||
public AjaxResult downloadMap(EdgeCommonVO vo,
|
public AjaxResult downloadMap(EdgeCommonVO vo,
|
||||||
@ApiParam("地图名称") String mapName) {
|
@ApiParam("地图名称") String mapName) {
|
||||||
AgvCommand.AgvDownloadMapResult result = edgeAgvService.robotConfigDownloadMap(vo, mapName);
|
String content = edgeAgvService.downloadMap(vo, mapName);
|
||||||
|
return AjaxResult.ok(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("开始建图")
|
||||||
|
@PostMapping("/startMapping")
|
||||||
|
public AjaxResult startMapping(EdgeCommonVO vo,
|
||||||
|
@ApiParam("建图维度(0:未指定 1:2D 2:3D 3:2D+3D)") int dimension,
|
||||||
|
@ApiParam("地图名称(可选)") String mapName,
|
||||||
|
@ApiParam("是否实时建图") boolean realTime) {
|
||||||
|
Agv.AgvMapDimension mapDimension = Agv.AgvMapDimension.forNumber(dimension);
|
||||||
|
String sessionId = edgeAgvService.startMapping(vo, mapDimension, mapName, realTime);
|
||||||
|
java.util.Map<String, Object> result = new java.util.HashMap<>();
|
||||||
|
result.put("sessionId", sessionId);
|
||||||
return AjaxResult.ok(result);
|
return AjaxResult.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("上传地图")
|
@ApiOperation("停止建图")
|
||||||
@PostMapping("/uploadMap")
|
@GetMapping("/stopMapping")
|
||||||
public AjaxResult uploadMap(EdgeCommonVO vo,
|
public AjaxResult stopMapping(EdgeCommonVO vo) {
|
||||||
@ApiParam("地图内容") String mapContent) {
|
edgeAgvService.stopMapping(vo);
|
||||||
AgvCommand.AgvUploadMapResult result = edgeAgvService.robotConfigUploadMap(vo, mapContent);
|
|
||||||
java.util.Map<String, Object> resultMap = new java.util.HashMap<>();
|
|
||||||
resultMap.put("retCode", result.getRetCode());
|
|
||||||
resultMap.put("errMsg", result.getErrMsg());
|
|
||||||
return AjaxResult.ok(resultMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("获取电池状态")
|
|
||||||
@GetMapping("/getBatteryStatus")
|
|
||||||
public AjaxResult getBatteryStatus(EdgeCommonVO vo) {
|
|
||||||
AgvCommand.AgvBatteryStatus batteryStatus = edgeAgvService.getBatteryStatus(vo);
|
|
||||||
return AjaxResult.ok(batteryStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("导航到指定站点")
|
|
||||||
@GetMapping("/goToStation")
|
|
||||||
public AjaxResult goToStation(EdgeCommonVO vo,
|
|
||||||
@ApiParam("起始站点ID") String sourceId,
|
|
||||||
@ApiParam("目标站点ID") String targetId,
|
|
||||||
@ApiParam("任务ID") String taskId,
|
|
||||||
@ApiParam("操作类型") String operation,
|
|
||||||
@ApiParam("顶升高度") Double jackHeight) {
|
|
||||||
AgvCommand.RobotGoTargetResData result = edgeAgvService.robotGoTarget(
|
|
||||||
vo, sourceId, targetId, taskId, operation, jackHeight
|
|
||||||
);
|
|
||||||
return AjaxResult.ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("自由导航到坐标点")
|
|
||||||
@GetMapping("/freeGo")
|
|
||||||
public AjaxResult freeGo(EdgeCommonVO vo,
|
|
||||||
@ApiParam("X坐标") double x,
|
|
||||||
@ApiParam("Y坐标") double y,
|
|
||||||
@ApiParam("角度") double theta,
|
|
||||||
@ApiParam("任务ID") String taskId) {
|
|
||||||
// 构建自由导航点
|
|
||||||
AgvCommand.FreeGoPoint freeGoPoint = AgvCommand.FreeGoPoint.newBuilder()
|
|
||||||
.setX(x)
|
|
||||||
.setY(y)
|
|
||||||
.setTheta(theta)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
AgvCommand.RobotGoTargetResData result = edgeAgvService.robotGoTargetWithFreeGo(
|
|
||||||
vo, freeGoPoint, taskId
|
|
||||||
);
|
|
||||||
return AjaxResult.ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("暂停导航任务")
|
|
||||||
@GetMapping("/pauseTask")
|
|
||||||
public AjaxResult pauseTask(EdgeCommonVO vo) {
|
|
||||||
edgeAgvService.robotTaskPause(vo);
|
|
||||||
return AjaxResult.ok();
|
return AjaxResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("继续导航任务")
|
|
||||||
@GetMapping("/resumeTask")
|
|
||||||
public AjaxResult resumeTask(EdgeCommonVO vo) {
|
|
||||||
edgeAgvService.robotTaskResume(vo);
|
|
||||||
return AjaxResult.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("取消导航任务")
|
|
||||||
@GetMapping("/cancelTask")
|
|
||||||
public AjaxResult cancelTask(EdgeCommonVO vo) {
|
|
||||||
edgeAgvService.robotTaskCancel(vo);
|
|
||||||
return AjaxResult.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("查询当前导航状态")
|
|
||||||
@GetMapping("/getTaskStatus")
|
|
||||||
public AjaxResult getTaskStatus(EdgeCommonVO vo,
|
|
||||||
@ApiParam("是否简化返回") boolean simple) {
|
|
||||||
AgvCommand.RobotStatusTaskResData taskData = edgeAgvService.getRobotStatusTaskCurrent(vo, simple);
|
|
||||||
return AjaxResult.ok(taskData);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("查询站点列表")
|
|
||||||
@GetMapping("/getStationList")
|
|
||||||
public AjaxResult getStationList(EdgeCommonVO vo) {
|
|
||||||
AgvCommand.QueryStationListResult result = edgeAgvService.queryStationList(vo);
|
|
||||||
return AjaxResult.ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("切换地图")
|
|
||||||
@GetMapping("/loadMap")
|
|
||||||
public AjaxResult loadMap(EdgeCommonVO vo,
|
|
||||||
@ApiParam("地图名称") String mapName) {
|
|
||||||
AgvCommand.RobotLoadMapResult result = edgeAgvService.robotLoadMap(vo, mapName);
|
|
||||||
java.util.Map<String, Object> resultMap = new java.util.HashMap<>();
|
|
||||||
resultMap.put("retCode", result.getRetCode());
|
|
||||||
resultMap.put("errMsg", result.getErrMsg());
|
|
||||||
return AjaxResult.ok(resultMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("查询地图加载状态")
|
|
||||||
@GetMapping("/getLoadMapStatus")
|
|
||||||
public AjaxResult getLoadMapStatus(EdgeCommonVO vo) {
|
|
||||||
AgvCommand.RobotQueryLoadMapStatusResult result = edgeAgvService.queryLoadMapStatus(vo);
|
|
||||||
return AjaxResult.ok(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package com.cmvr.web.controller.inspection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.msgs.Agv;
|
||||||
import com.cmvr.inspection.domain.vo.InspectionRobotVo;
|
import com.cmvr.inspection.domain.vo.InspectionRobotVo;
|
||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@ -114,8 +114,8 @@ public class InspectionRobotController extends BaseController
|
|||||||
@GetMapping("/{robotId}/maps")
|
@GetMapping("/{robotId}/maps")
|
||||||
public AjaxResult getRobotMapList(@PathVariable String robotId)
|
public AjaxResult getRobotMapList(@PathVariable String robotId)
|
||||||
{
|
{
|
||||||
AgvCommand.AgvMapStatus robotMapList = inspectionRobotService.getRobotMapList(robotId);
|
List<String> robotMapList = inspectionRobotService.getRobotMapList(robotId);
|
||||||
return success(robotMapList.getMapsList());
|
return success(robotMapList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,7 +180,7 @@ public class InspectionRobotController extends BaseController
|
|||||||
@GetMapping("/{robotId}/location")
|
@GetMapping("/{robotId}/location")
|
||||||
public AjaxResult getRobotRealtimeLocation(@PathVariable String robotId)
|
public AjaxResult getRobotRealtimeLocation(@PathVariable String robotId)
|
||||||
{
|
{
|
||||||
AgvCommand.AgvRobotLocation location = inspectionRobotService.getRobotRealtimeLocation(robotId);
|
Agv.AgvPose2d location = inspectionRobotService.getRobotRealtimeLocation(robotId);
|
||||||
return success(location);
|
return success(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,15 +195,47 @@ public class InspectionRobotController extends BaseController
|
|||||||
@PathVariable @ApiParam("机器人ID") String robotId,
|
@PathVariable @ApiParam("机器人ID") String robotId,
|
||||||
@RequestParam @ApiParam("X坐标(米)") Double x,
|
@RequestParam @ApiParam("X坐标(米)") Double x,
|
||||||
@RequestParam @ApiParam("Y坐标(米)") Double y,
|
@RequestParam @ApiParam("Y坐标(米)") Double y,
|
||||||
@RequestParam(required = false) @ApiParam("朝向角(弧度)") Double theta,
|
@RequestParam(required = false) @ApiParam("朝向角(弧度)") Double theta
|
||||||
@RequestParam(required = false) @ApiParam("任务ID") String taskId
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AgvCommand.RobotGoTargetResData result = inspectionRobotService.navigateToPosition(
|
inspectionRobotService.navigateToPosition(
|
||||||
robotId, x, y, theta, taskId
|
robotId, x, y, theta
|
||||||
);
|
);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始建图
|
||||||
|
*/
|
||||||
|
@ApiOperation("开始建图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "开始建图", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/start-mapping")
|
||||||
|
public AjaxResult startMapping(
|
||||||
|
@PathVariable @ApiParam("机器人ID") String robotId,
|
||||||
|
@RequestParam @ApiParam("建图维度(0:未指定 1:2D 2:3D 3:2D+3D)") int dimension,
|
||||||
|
@RequestParam(required = false) @ApiParam("地图名称(可选)") String mapName,
|
||||||
|
@RequestParam(defaultValue = "true") @ApiParam("是否实时建图") boolean realTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
String sessionId = inspectionRobotService.startMapping(robotId, dimension, mapName, realTime);
|
||||||
|
java.util.Map<String, Object> result = new java.util.HashMap<>();
|
||||||
|
result.put("sessionId", sessionId);
|
||||||
return success(result);
|
return success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止建图
|
||||||
|
*/
|
||||||
|
@ApiOperation("停止建图")
|
||||||
|
@PreAuthorize("@ss.hasPermi('inspection:robot:edit')")
|
||||||
|
@Log(title = "停止建图", businessType = BusinessType.OTHER)
|
||||||
|
@PostMapping("/{robotId}/stop-mapping")
|
||||||
|
public AjaxResult stopMapping(@PathVariable @ApiParam("机器人ID") String robotId)
|
||||||
|
{
|
||||||
|
inspectionRobotService.stopMapping(robotId);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
package com.cmvr.web.controller.tts;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.tts.domain.CorpusCategory;
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.service.ICorpusInfoService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据Controller
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tts/corpus")
|
||||||
|
@Api(tags = "智能座舱-车载语料管理")
|
||||||
|
public class CorpusInfoController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ICorpusInfoService corpusInfoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询语料列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(CorpusInfo corpus) {
|
||||||
|
startPage();
|
||||||
|
return corpusInfoService.selectCorpusList(corpus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取语料详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取语料详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(corpusInfoService.selectCorpusById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:add')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody CorpusInfo corpus) {
|
||||||
|
return toAjax(corpusInfoService.insertCorpus(corpus));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody CorpusInfo corpus) {
|
||||||
|
return toAjax(corpusInfoService.updateCorpus(corpus));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:remove')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(corpusInfoService.deleteCorpusByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频流
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取音频流")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/audio/{id}")
|
||||||
|
public void getAudio(@PathVariable String id, HttpServletResponse response) {
|
||||||
|
corpusInfoService.getAudioStream(id, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传语料音频
|
||||||
|
*/
|
||||||
|
@ApiOperation("上传语料音频")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/audio/upload/{id}")
|
||||||
|
public AjaxResult uploadAudio(@PathVariable String id, @RequestParam("file") MultipartFile file) {
|
||||||
|
String path = corpusInfoService.uploadCorpusAudio(id, file);
|
||||||
|
return success(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入语料
|
||||||
|
*/
|
||||||
|
@ApiOperation("批量导入语料")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:import')")
|
||||||
|
@Log(title = "车载语料", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/import")
|
||||||
|
public AjaxResult importData(@RequestParam("file") MultipartFile file) {
|
||||||
|
Map<String, Object> result = corpusInfoService.importCorpus(file);
|
||||||
|
return success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询看板统计数据")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/dashboard/stats")
|
||||||
|
public AjaxResult getDashboardStats() {
|
||||||
|
return success(corpusInfoService.getDashboardStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按语种统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/language")
|
||||||
|
public AjaxResult getStatsByLanguage() {
|
||||||
|
return success(corpusInfoService.getStatsByLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按方言统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按方言统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/dialect")
|
||||||
|
public AjaxResult getStatsByDialect() {
|
||||||
|
return success(corpusInfoService.getStatsByDialect());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按情绪统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/emotion")
|
||||||
|
public AjaxResult getStatsByEmotion() {
|
||||||
|
return success(corpusInfoService.getStatsByEmotion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按分类统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按分类统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/stats/category")
|
||||||
|
public AjaxResult getStatsByCategory() {
|
||||||
|
return success(corpusInfoService.getStatsByCategory());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分类树
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询分类树")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:query')")
|
||||||
|
@GetMapping("/category/tree")
|
||||||
|
public AjaxResult getCategoryTree() {
|
||||||
|
return success(corpusInfoService.getCategoryTree());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:add')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/category")
|
||||||
|
public AjaxResult addCategory(@RequestBody CorpusCategory category) {
|
||||||
|
return toAjax(corpusInfoService.insertCategory(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:edit')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/category")
|
||||||
|
public AjaxResult editCategory(@RequestBody CorpusCategory category) {
|
||||||
|
return toAjax(corpusInfoService.updateCategory(category));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除分类
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除分类")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:corpus:remove')")
|
||||||
|
@Log(title = "语料分类", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/category/{id}")
|
||||||
|
public AjaxResult removeCategory(@PathVariable String id) {
|
||||||
|
return toAjax(corpusInfoService.deleteCategoryById(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,253 @@
|
|||||||
|
package com.cmvr.web.controller.tts;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.cmvr.common.annotation.Log;
|
||||||
|
import com.cmvr.common.core.controller.BaseController;
|
||||||
|
import com.cmvr.common.core.domain.AjaxResult;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.enums.BusinessType;
|
||||||
|
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
||||||
|
import com.cmvr.tts.domain.TtsSynthesizeTask;
|
||||||
|
import com.cmvr.tts.domain.vo.LlmQueryVo;
|
||||||
|
import com.cmvr.tts.service.ITtsSynthesizeTaskService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务Controller
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tts/task")
|
||||||
|
@Api(tags = "智能座舱-TTS合成任务管理")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TtsSynthesizeTaskController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITtsSynthesizeTaskService ttsTaskService;
|
||||||
|
|
||||||
|
private final LLMAiAgentPlatformService llmAiAgentPlatformService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务列表
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询TTS合成任务列表")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(TtsSynthesizeTask task) {
|
||||||
|
startPage();
|
||||||
|
return ttsTaskService.selectTtsTaskList(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取TTS合成任务详细信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取TTS合成任务详细信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||||
|
return success(ttsTaskService.selectTtsTaskById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("新增TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:add')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody TtsSynthesizeTask task) {
|
||||||
|
return success(ttsTaskService.insertTtsTask(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("批量新增TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:add')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public AjaxResult batchAdd(@RequestBody List<TtsSynthesizeTask> tasks) {
|
||||||
|
return toAjax(ttsTaskService.batchInsertTtsTask(tasks));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("修改TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody TtsSynthesizeTask task) {
|
||||||
|
return toAjax(ttsTaskService.updateTtsTask(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS合成任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("删除TTS合成任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:remove')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable String[] ids) {
|
||||||
|
return toAjax(ttsTaskService.deleteTtsTaskByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重生成TTS任务
|
||||||
|
*/
|
||||||
|
@ApiOperation("重生成TTS任务")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/regenerate/{id}")
|
||||||
|
public AjaxResult regenerate(@PathVariable String id) {
|
||||||
|
return toAjax(ttsTaskService.regenerateTask(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频文件流
|
||||||
|
*/
|
||||||
|
@ApiOperation("获取音频文件流")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/audio/{id}")
|
||||||
|
public void getAudio(@PathVariable String id, HttpServletResponse response) {
|
||||||
|
ttsTaskService.getAudioStream(id, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询看板统计数据")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/dashboard/stats")
|
||||||
|
public AjaxResult getDashboardStats() {
|
||||||
|
return success(ttsTaskService.getDashboardStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按语种统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/language")
|
||||||
|
public AjaxResult getStatsByLanguage() {
|
||||||
|
return success(ttsTaskService.getStatsByLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按音色统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按音色统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/voice")
|
||||||
|
public AjaxResult getStatsByVoice() {
|
||||||
|
return success(ttsTaskService.getStatsByVoice());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@ApiOperation("按情绪统计")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/emotion")
|
||||||
|
public AjaxResult getStatsByEmotion() {
|
||||||
|
return success(ttsTaskService.getStatsByEmotion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近7日趋势
|
||||||
|
*/
|
||||||
|
@ApiOperation("近7日趋势")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@GetMapping("/stats/trend")
|
||||||
|
public AjaxResult getLast7DaysTrend() {
|
||||||
|
return success(ttsTaskService.getLast7DaysTrend());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本泛化
|
||||||
|
*/
|
||||||
|
@ApiOperation("文本泛化")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:query')")
|
||||||
|
@PostMapping("/llm/query")
|
||||||
|
public AjaxResult llmQuery(@RequestBody LlmQueryVo request) {
|
||||||
|
// 闲聊key d9672ql4shh4136opsfg
|
||||||
|
// 泛化key d966pq54shh4nveh8d20
|
||||||
|
JSONObject result = llmAiAgentPlatformService.query(
|
||||||
|
null,
|
||||||
|
request.getLanguage() + "," + request.getCount() + "," + request.getText(),
|
||||||
|
"d96ammd4shh4nvehb6mg",
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
// 解析LLM返回的结果,提取JSON数组
|
||||||
|
String resultStr = result.getString("result");
|
||||||
|
if (resultStr != null && !resultStr.isEmpty()) {
|
||||||
|
// 尝试多种格式解析
|
||||||
|
JSONArray jsonArray = parseJsonArray(resultStr);
|
||||||
|
return success(jsonArray);
|
||||||
|
}
|
||||||
|
return success(new JSONArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析JSON数组,兼容多种格式
|
||||||
|
*/
|
||||||
|
private JSONArray parseJsonArray(String text) {
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
return new JSONArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 直接尝试解析为JSON数组
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(text);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2. 移除markdown代码块标记
|
||||||
|
String cleaned = text.replace("```json", "").replace("```", "").trim();
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(cleaned);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 尝试从文本中提取JSON数组(匹配 [...] 格式)
|
||||||
|
int startIdx = text.indexOf("[");
|
||||||
|
int endIdx = text.lastIndexOf("]");
|
||||||
|
if (startIdx != -1 && endIdx != -1 && endIdx > startIdx) {
|
||||||
|
String jsonStr = text.substring(startIdx, endIdx + 1);
|
||||||
|
try {
|
||||||
|
return JSONArray.parseArray(jsonStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 继续尝试其他格式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果都失败,返回包含原始文本的数组
|
||||||
|
return new JSONArray().fluentAdd(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务到语料库
|
||||||
|
*/
|
||||||
|
@ApiOperation("保存任务到语料库")
|
||||||
|
@PreAuthorize("@ss.hasPermi('tts:task:edit')")
|
||||||
|
@Log(title = "TTS合成任务", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/Nsave-to-corpus/{taskId}/{categoryId}")
|
||||||
|
public AjaxResult saveToCorpus(@PathVariable String taskId, @PathVariable String categoryId) {
|
||||||
|
return toAjax(ttsTaskService.saveToCorpus(taskId, categoryId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -132,3 +132,8 @@ flowise:
|
|||||||
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/
|
||||||
query: http://192.168.0.108:3000/api/v1/executions/
|
query: http://192.168.0.108:3000/api/v1/executions/
|
||||||
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg
|
||||||
|
|
||||||
|
# TTS外部接口配置
|
||||||
|
tts:
|
||||||
|
external-api:
|
||||||
|
url: http://192.168.0.102:9003/generate_advanced_audio
|
||||||
@ -1,162 +1,167 @@
|
|||||||
package com.cmvr.edge.client.service;
|
package com.cmvr.edge.client.service;
|
||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.msgs.Agv;
|
||||||
|
import cmvr.msgs.Agv.AgvRuntimeState;
|
||||||
|
|
||||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边缘系统AGV服务
|
* 边缘系统AGV服务
|
||||||
*
|
*
|
||||||
* @author cmvr-iot
|
* @author cmvr-iot
|
||||||
* @since 2026-06-11
|
* @since 2026-07-02
|
||||||
*/
|
*/
|
||||||
public interface EdgeAgvService {
|
public interface EdgeAgvService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取AGV状态信息
|
* 获取AGV运行时状态
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @return AGV状态信息
|
* @return AGV运行时状态
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvStatusInfo getStatusInfo(EdgeCommonVO edgeCommonVO);
|
AgvRuntimeState getRuntimeState(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取机器人位置
|
* 获取导航状态
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @return 机器人位置
|
* @return 导航状态
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvRobotLocation getRobotLocation(EdgeCommonVO edgeCommonVO);
|
Agv.AgvNavigationStatus getNavigationStatus(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取地图状态(地图列表)
|
* 紧急停止
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @return 地图状态
|
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvMapStatus getMapStatus(EdgeCommonVO edgeCommonVO);
|
void emergencyStop(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载地图(从机器人下载地图到服务器)
|
* 清除故障
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
*/
|
||||||
|
void clearFault(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航到指定位置
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @param pose 目标位姿
|
||||||
|
*/
|
||||||
|
void navigateToPose(EdgeCommonVO edgeCommonVO, Agv.AgvPose2d pose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航到站点
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @param stationId 站点ID
|
||||||
|
*/
|
||||||
|
void navigateToStation(EdgeCommonVO edgeCommonVO, String stationId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟随路径
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @param pathSegments 路径段列表
|
||||||
|
*/
|
||||||
|
void followPath(EdgeCommonVO edgeCommonVO, List<Agv.AgvPathSegment> pathSegments);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停导航
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
*/
|
||||||
|
void pauseNavigation(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复导航
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
*/
|
||||||
|
void resumeNavigation(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消导航
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
*/
|
||||||
|
void cancelNavigation(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置速度
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @param velocity 速度
|
||||||
|
*/
|
||||||
|
void setVelocity(EdgeCommonVO edgeCommonVO, Agv.AgvVelocity velocity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止速度控制
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
*/
|
||||||
|
void stopVelocityControl(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有地图
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @return 地图列表
|
||||||
|
*/
|
||||||
|
List<String> listMaps(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有站点
|
||||||
|
*
|
||||||
|
* @param edgeCommonVO 边缘通用参数
|
||||||
|
* @return 站点列表
|
||||||
|
*/
|
||||||
|
List<Agv.AgvStation> listStations(EdgeCommonVO edgeCommonVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换地图
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @param mapName 地图名称
|
* @param mapName 地图名称
|
||||||
* @return 下载结果(包含地图内容)
|
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvDownloadMapResult robotConfigDownloadMap(EdgeCommonVO edgeCommonVO, String mapName);
|
void switchMap(EdgeCommonVO edgeCommonVO, String mapName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传地图(从服务器上传地图到机器人)
|
* 上传地图
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @param mapContent 地图内容
|
* @param mapName 地图名称
|
||||||
* @return 上传结果
|
* @param content 地图内容
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvUploadMapResult robotConfigUploadMap(EdgeCommonVO edgeCommonVO, String mapContent);
|
void uploadMap(EdgeCommonVO edgeCommonVO, String mapName, String content);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取电池状态
|
* 下载地图
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @return 电池状态
|
* @param mapName 地图名称
|
||||||
|
* @return 地图内容
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvBatteryStatus getBatteryStatus(EdgeCommonVO edgeCommonVO);
|
String downloadMap(EdgeCommonVO edgeCommonVO, String mapName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单点站点自动规划导航(命令码3051)
|
* 开始建图
|
||||||
* 从起始站点自动规划路径到目标站点,支持多种操作类型(顶升、货叉、滚筒等)
|
|
||||||
* 注意:此命令会取消当前正在执行的任务,严禁用于多车调度场景
|
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @param sourceId 起始站点ID("SELF_POSITION"表示当前位置)
|
* @param dimension 建图维度(2D/3D/两者)
|
||||||
* @param targetId 目标站点ID("SELF_POSITION"表示原地执行操作)
|
* @param mapName 地图名称(可选)
|
||||||
* @param taskId 任务ID(可选,建议提供)
|
* @param realTime 是否实时建图
|
||||||
* @param operation 操作类型(如"JackLoad"顶升装载、"ForkUnload"货叉卸载等,可选)
|
* @return 会话ID
|
||||||
* @param jackHeight 顶升高度(米,仅当operation为顶升相关时有效,可选)
|
|
||||||
* @return 导航任务下发结果
|
|
||||||
*/
|
*/
|
||||||
AgvCommand.RobotGoTargetResData robotGoTarget(EdgeCommonVO edgeCommonVO, String sourceId, String targetId,
|
String startMapping(EdgeCommonVO edgeCommonVO, Agv.AgvMapDimension dimension, String mapName, boolean realTime);
|
||||||
String taskId, String operation, Double jackHeight);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自由导航到指定坐标位置(命令码3051,使用freego参数)
|
* 停止建图
|
||||||
* 直接导航到指定的X、Y坐标和角度,不依赖站点
|
|
||||||
* 注意:此命令会取消当前正在执行的任务,仅支持双轮差速底盘
|
|
||||||
*
|
*
|
||||||
* @param edgeCommonVO 边缘通用参数
|
* @param edgeCommonVO 边缘通用参数
|
||||||
* @param freeGoPoint 自由导航目标点(包含x、y、theta)
|
|
||||||
* @param taskId 任务ID(可选,建议提供)
|
|
||||||
* @return 导航任务下发结果
|
|
||||||
*/
|
*/
|
||||||
AgvCommand.RobotGoTargetResData robotGoTargetWithFreeGo(EdgeCommonVO edgeCommonVO,
|
void stopMapping(EdgeCommonVO edgeCommonVO);
|
||||||
AgvCommand.FreeGoPoint freeGoPoint,
|
|
||||||
String taskId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 暂停当前导航任务(命令码3001)
|
|
||||||
* 暂停AGV当前正在执行的导航任务,AGV将减速停止
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @return 暂停结果
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotTaskPauseCommand.Feedback.Result robotTaskPause(EdgeCommonVO edgeCommonVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 继续当前导航任务(命令码3002)
|
|
||||||
* 恢复之前被暂停的导航任务,AGV将继续执行
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @return 继续结果
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotTaskResumeCommand.Feedback.Result robotTaskResume(EdgeCommonVO edgeCommonVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消当前导航任务(命令码3003)
|
|
||||||
* 完全取消当前正在执行或暂停的导航任务
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @return 取消结果
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotTaskCancelCommand.Feedback.Result robotTaskCancel(EdgeCommonVO edgeCommonVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询当前实时导航状态(命令码1020)
|
|
||||||
* 获取AGV当前导航任务的详细状态,包括任务进度、已经过站点、剩余站点等
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @param simple 是否仅返回任务状态(true=仅task_status,false=全量信息)
|
|
||||||
* @return 导航状态信息
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotStatusTaskResData getRobotStatusTaskCurrent(EdgeCommonVO edgeCommonVO, boolean simple);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询当前地图站点列表(命令码1301)
|
|
||||||
* 获取当前加载地图中的所有站点信息,包括站点坐标、类型、描述等
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @return 站点列表信息
|
|
||||||
*/
|
|
||||||
AgvCommand.QueryStationListResult queryStationList(EdgeCommonVO edgeCommonVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换载入地图(命令码2022)
|
|
||||||
* 将AGV切换到指定的地图,目标地图必须已存在于机器人中
|
|
||||||
* 切换后需要等待地图加载完成才能执行导航任务
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @param mapName 目标地图名称(必填,仅允许字母、数字、-、_)
|
|
||||||
* @return 切换地图结果
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotLoadMapResult robotLoadMap(EdgeCommonVO edgeCommonVO, String mapName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询地图载入状态(命令码1022)
|
|
||||||
* 查询当前地图加载的状态,可用于判断地图是否加载完成
|
|
||||||
* 状态值:0=失败,1=成功,2=加载中(加载中时禁止执行重定位操作)
|
|
||||||
*
|
|
||||||
* @param edgeCommonVO 边缘通用参数
|
|
||||||
* @return 地图加载状态
|
|
||||||
*/
|
|
||||||
AgvCommand.RobotQueryLoadMapStatusResult queryLoadMapStatus(EdgeCommonVO edgeCommonVO);
|
|
||||||
}
|
}
|
||||||
@ -2,6 +2,8 @@ package com.cmvr.edge.client.service.impl;
|
|||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.api.AgvCommand;
|
||||||
import cmvr.api.AgvServiceGrpc;
|
import cmvr.api.AgvServiceGrpc;
|
||||||
|
import cmvr.api.Common;
|
||||||
|
import cmvr.msgs.Agv;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.cmvr.common.exception.GlobalException;
|
import com.cmvr.common.exception.GlobalException;
|
||||||
import com.cmvr.edge.client.manage.GrpcServiceManager;
|
import com.cmvr.edge.client.manage.GrpcServiceManager;
|
||||||
@ -12,11 +14,13 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AGV服务实现类
|
* AGV服务实现类
|
||||||
*
|
*
|
||||||
* @author cmvr-iot
|
* @author cmvr-iot
|
||||||
* @since 2026-06-11
|
* @since 2026-07-02
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -26,281 +30,225 @@ public class EdgeAgvServiceImpl implements EdgeAgvService {
|
|||||||
private final GrpcServiceManager grpcServiceManager;
|
private final GrpcServiceManager grpcServiceManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvStatusInfo getStatusInfo(EdgeCommonVO edgeCommonVO) {
|
public Agv.AgvRuntimeState getRuntimeState(EdgeCommonVO edgeCommonVO) {
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
AgvCommand.GetAgvStatusInfoCommand.Request request = AgvCommand.GetAgvStatusInfoCommand.Request.newBuilder()
|
AgvCommand.AgvRuntimeStateCommand.Request request = AgvCommand.AgvRuntimeStateCommand.Request.newBuilder()
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.build();
|
.build();
|
||||||
return executeGrpcCall(() -> stub.getStatusInfo(request)).getStatus();
|
return executeGrpcCall(() -> stub.getRuntimeState(request)).getState();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.AgvRobotLocation getRobotLocation(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotStatusLocCommand.Request request = AgvCommand.RobotStatusLocCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.build();
|
|
||||||
return executeGrpcCall(() -> stub.getRobotLocation(request)).getStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvMapStatus getMapStatus(EdgeCommonVO edgeCommonVO) {
|
public Agv.AgvNavigationStatus getNavigationStatus(EdgeCommonVO edgeCommonVO) {
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
AgvCommand.RobotStatusMapCommand.Request request = AgvCommand.RobotStatusMapCommand.Request.newBuilder()
|
AgvCommand.AgvNavigationStatusCommand.Request request = AgvCommand.AgvNavigationStatusCommand.Request.newBuilder()
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.build();
|
.build();
|
||||||
return executeGrpcCall(() -> stub.getMapStatus(request)).getStatus();
|
return executeGrpcCall(() -> stub.getNavigationStatus(request)).getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvDownloadMapResult robotConfigDownloadMap(EdgeCommonVO edgeCommonVO, String mapName) {
|
public void emergencyStop(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.emergencyStop(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearFault(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.clearFault(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void navigateToPose(EdgeCommonVO edgeCommonVO, Agv.AgvPose2d pose) {
|
||||||
|
if (pose == null) {
|
||||||
|
throw new GlobalException("目标位姿不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvNavigateToPoseCommand.Request request = AgvCommand.AgvNavigateToPoseCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.setPose(pose)
|
||||||
|
.build();
|
||||||
|
executeGrpcCall(() -> stub.navigateToPose(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void navigateToStation(EdgeCommonVO edgeCommonVO, String stationId) {
|
||||||
|
if (StrUtil.isBlank(stationId)) {
|
||||||
|
throw new GlobalException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvNavigateToStationCommand.Request request = AgvCommand.AgvNavigateToStationCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.setStationId(stationId)
|
||||||
|
.build();
|
||||||
|
executeGrpcCall(() -> stub.navigateToStation(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void followPath(EdgeCommonVO edgeCommonVO, List<Agv.AgvPathSegment> pathSegments) {
|
||||||
|
if (pathSegments == null || pathSegments.isEmpty()) {
|
||||||
|
throw new GlobalException("路径段不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvFollowPathCommand.Request request = AgvCommand.AgvFollowPathCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.addAllPath(pathSegments)
|
||||||
|
.build();
|
||||||
|
executeGrpcCall(() -> stub.followPath(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pauseNavigation(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.pauseNavigation(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resumeNavigation(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.resumeNavigation(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelNavigation(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.cancelNavigation(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVelocity(EdgeCommonVO edgeCommonVO, Agv.AgvVelocity velocity) {
|
||||||
|
if (velocity == null) {
|
||||||
|
throw new GlobalException("速度不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvSetVelocityCommand.Request request = AgvCommand.AgvSetVelocityCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.setVelocity(velocity)
|
||||||
|
.build();
|
||||||
|
executeGrpcCall(() -> stub.setVelocity(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopVelocityControl(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.stopVelocityControl(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> listMaps(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvListMapsCommand.Request request = AgvCommand.AgvListMapsCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.build();
|
||||||
|
return executeGrpcCall(() -> stub.listMaps(request)).getMapsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Agv.AgvStation> listStations(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvListStationsCommand.Request request = AgvCommand.AgvListStationsCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
|
.build();
|
||||||
|
return executeGrpcCall(() -> stub.listStations(request)).getStationsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void switchMap(EdgeCommonVO edgeCommonVO, String mapName) {
|
||||||
if (StrUtil.isBlank(mapName)) {
|
if (StrUtil.isBlank(mapName)) {
|
||||||
throw new GlobalException("地图名称不能为空");
|
throw new GlobalException("地图名称不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
AgvCommand.RobotConfigDownloadMapRequestData requestData = AgvCommand.RobotConfigDownloadMapRequestData.newBuilder()
|
AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.setMapName(mapName)
|
.setMapName(mapName)
|
||||||
.build();
|
.build();
|
||||||
AgvCommand.RobotConfigDownloadMapCommand.Request request = AgvCommand.RobotConfigDownloadMapCommand.Request.newBuilder()
|
executeGrpcCall(() -> stub.switchMap(request));
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(requestData)
|
|
||||||
.build();
|
|
||||||
AgvCommand.AgvDownloadMapResult result = executeGrpcCall(() -> stub.robotConfigDownloadMap(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("下载地图失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvUploadMapResult robotConfigUploadMap(EdgeCommonVO edgeCommonVO, String mapContent) {
|
public void uploadMap(EdgeCommonVO edgeCommonVO, String mapName, String content) {
|
||||||
if (StrUtil.isBlank(mapContent)) {
|
if (StrUtil.isBlank(mapName)) {
|
||||||
|
throw new GlobalException("地图名称不能为空");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(content)) {
|
||||||
throw new GlobalException("地图内容不能为空");
|
throw new GlobalException("地图内容不能为空");
|
||||||
}
|
}
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotConfigUploadMapRequestData requestData = AgvCommand.RobotConfigUploadMapRequestData.newBuilder()
|
|
||||||
.setMapContent(mapContent)
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotConfigUploadMapCommand.Request request = AgvCommand.RobotConfigUploadMapCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(requestData)
|
|
||||||
.build();
|
|
||||||
AgvCommand.AgvUploadMapResult result = executeGrpcCall(() -> stub.robotConfigUploadMap(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("上传地图失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.AgvBatteryStatus getBatteryStatus(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotStatusBatteryRequestData requestData = AgvCommand.RobotStatusBatteryRequestData.newBuilder()
|
|
||||||
.setSimple(true)
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotStatusBatteryCommand.Request request = AgvCommand.RobotStatusBatteryCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(requestData)
|
|
||||||
.build();
|
|
||||||
return executeGrpcCall(() -> stub.getBatteryStatus(request)).getStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotGoTargetResData robotGoTarget(EdgeCommonVO edgeCommonVO, String sourceId, String targetId,
|
|
||||||
String taskId, String operation, Double jackHeight) {
|
|
||||||
if (StrUtil.isBlank(sourceId)) {
|
|
||||||
throw new GlobalException("起始站点ID不能为空");
|
|
||||||
}
|
|
||||||
if (StrUtil.isBlank(targetId)) {
|
|
||||||
throw new GlobalException("目标站点ID不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
|
||||||
// 构建请求数据
|
|
||||||
AgvCommand.RobotGoTargetReqData.Builder dataBuilder = AgvCommand.RobotGoTargetReqData.newBuilder()
|
|
||||||
.setSourceId(sourceId)
|
|
||||||
.setId(targetId);
|
|
||||||
|
|
||||||
// 设置可选参数
|
|
||||||
if (StrUtil.isNotBlank(taskId)) {
|
|
||||||
dataBuilder.setTaskId(taskId);
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(operation)) {
|
|
||||||
dataBuilder.setOperation(operation);
|
|
||||||
}
|
|
||||||
if (jackHeight != null) {
|
|
||||||
dataBuilder.setJackHeight(jackHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
AgvCommand.RobotGoTargetCommand.Request request = AgvCommand.RobotGoTargetCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.setData(dataBuilder.build())
|
.setMapName(mapName)
|
||||||
|
.setContent(content)
|
||||||
.build();
|
.build();
|
||||||
|
executeGrpcCall(() -> stub.uploadMap(request));
|
||||||
AgvCommand.RobotGoTargetResData result = executeGrpcCall(() -> stub.robotGoTarget(request)).getData();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("单点导航任务下发失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.RobotGoTargetResData robotGoTargetWithFreeGo(EdgeCommonVO edgeCommonVO,
|
public String downloadMap(EdgeCommonVO edgeCommonVO, String mapName) {
|
||||||
AgvCommand.FreeGoPoint freeGoPoint,
|
|
||||||
String taskId) {
|
|
||||||
if (freeGoPoint == null) {
|
|
||||||
throw new GlobalException("自由导航目标点不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
|
|
||||||
// 构建请求数据,使用freego参数
|
|
||||||
AgvCommand.RobotGoTargetReqData.Builder dataBuilder = AgvCommand.RobotGoTargetReqData.newBuilder()
|
|
||||||
.setSourceId("SELF_POSITION") // 从当前位置开始
|
|
||||||
.setId("SELF_POSITION") // 不使用站点ID
|
|
||||||
.setFreego(freeGoPoint); // 设置自由导航点
|
|
||||||
|
|
||||||
// 设置可选参数
|
|
||||||
if (StrUtil.isNotBlank(taskId)) {
|
|
||||||
dataBuilder.setTaskId(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AgvCommand.RobotGoTargetCommand.Request request = AgvCommand.RobotGoTargetCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(dataBuilder.build())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
AgvCommand.RobotGoTargetResData result = executeGrpcCall(() -> stub.robotGoTarget(request)).getData();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("自由导航任务下发失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotTaskPauseCommand.Feedback.Result robotTaskPause(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotTaskPauseCommand.Request request = AgvCommand.RobotTaskPauseCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotTaskPauseCommand.Feedback.Result result = executeGrpcCall(() -> stub.robotTaskPause(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("暂停导航任务失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotTaskResumeCommand.Feedback.Result robotTaskResume(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotTaskResumeCommand.Request request = AgvCommand.RobotTaskResumeCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotTaskResumeCommand.Feedback.Result result = executeGrpcCall(() -> stub.robotTaskResume(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("继续导航任务失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotTaskCancelCommand.Feedback.Result robotTaskCancel(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotTaskCancelCommand.Request request = AgvCommand.RobotTaskCancelCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotTaskCancelCommand.Feedback.Result result = executeGrpcCall(() -> stub.robotTaskCancel(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("取消导航任务失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotStatusTaskResData getRobotStatusTaskCurrent(EdgeCommonVO edgeCommonVO, boolean simple) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.RobotStatusTaskReqData requestData = AgvCommand.RobotStatusTaskReqData.newBuilder()
|
|
||||||
.setSimple(simple)
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotStatusTaskCurrentCommand.Request request = AgvCommand.RobotStatusTaskCurrentCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(requestData)
|
|
||||||
.build();
|
|
||||||
return executeGrpcCall(() -> stub.robotStatusTaskCurrent(request)).getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.QueryStationListResult queryStationList(EdgeCommonVO edgeCommonVO) {
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
|
||||||
AgvCommand.QueryStationListCommand.Request request = AgvCommand.QueryStationListCommand.Request.newBuilder()
|
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.build();
|
|
||||||
AgvCommand.QueryStationListResult result = executeGrpcCall(() -> stub.queryStationList(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("查询站点列表失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AgvCommand.RobotLoadMapResult robotLoadMap(EdgeCommonVO edgeCommonVO, String mapName) {
|
|
||||||
if (StrUtil.isBlank(mapName)) {
|
if (StrUtil.isBlank(mapName)) {
|
||||||
throw new GlobalException("地图名称不能为空");
|
throw new GlobalException("地图名称不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
AgvCommand.RobotLoadMapRequestData requestData = AgvCommand.RobotLoadMapRequestData.newBuilder()
|
AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
|
||||||
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.setMapName(mapName)
|
.setMapName(mapName)
|
||||||
.build();
|
.build();
|
||||||
AgvCommand.RobotLoadMapCommand.Request request = AgvCommand.RobotLoadMapCommand.Request.newBuilder()
|
return executeGrpcCall(() -> stub.downloadMap(request)).getContent();
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
|
||||||
.setData(requestData)
|
|
||||||
.build();
|
|
||||||
AgvCommand.RobotLoadMapResult result = executeGrpcCall(() -> stub.robotLoadMap(request)).getStatus();
|
|
||||||
|
|
||||||
if (result.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("切换地图失败: " + result.getErrMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.RobotQueryLoadMapStatusResult queryLoadMapStatus(EdgeCommonVO edgeCommonVO) {
|
public String startMapping(EdgeCommonVO edgeCommonVO, Agv.AgvMapDimension dimension, String mapName, boolean realTime) {
|
||||||
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
AgvCommand.RobotQueryLoadMapStatusCommand.Request request = AgvCommand.RobotQueryLoadMapStatusCommand.Request.newBuilder()
|
AgvCommand.AgvStartMappingCommand.Request.Builder requestBuilder = AgvCommand.AgvStartMappingCommand.Request.newBuilder()
|
||||||
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
.setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
|
||||||
.build();
|
.setDimension(dimension != null ? dimension : Agv.AgvMapDimension.AGV_MAP_DIMENSION_UNSPECIFIED)
|
||||||
return executeGrpcCall(() -> stub.queryLoadMapStatus(request)).getStatus();
|
.setRealTime(realTime);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(mapName)) {
|
||||||
|
requestBuilder.setMapName(mapName);
|
||||||
|
}
|
||||||
|
|
||||||
|
AgvCommand.AgvStartMappingCommand.Request request = requestBuilder.build();
|
||||||
|
return executeGrpcCall(() -> stub.startMapping(request)).getSessionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopMapping(EdgeCommonVO edgeCommonVO) {
|
||||||
|
AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
|
||||||
|
edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
|
||||||
|
Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
|
||||||
|
executeGrpcCall(() -> stub.stopMapping(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -23,70 +23,64 @@ public final class AgvServiceOuterClass {
|
|||||||
descriptor;
|
descriptor;
|
||||||
static {
|
static {
|
||||||
java.lang.String[] descriptorData = {
|
java.lang.String[] descriptorData = {
|
||||||
"\n\032cmvr/api/agv_service.proto\022\010cmvr.api\032\032" +
|
"\n\032cmvr/api/agv_service.proto\022\010cmvr.api\032\025" +
|
||||||
"cmvr/api/agv_command.proto2\244\021\n\nAgvServic" +
|
"cmvr/api/common.proto\032\032cmvr/api/agv_comm" +
|
||||||
"e\022f\n\rGetStatusInfo\022).cmvr.api.GetAgvStat" +
|
"and.proto2\320\016\n\nAgvService\022f\n\017getRuntimeSt" +
|
||||||
"usInfoCommand.Request\032*.cmvr.api.GetAgvS" +
|
"ate\022(.cmvr.api.AgvRuntimeStateCommand.Re" +
|
||||||
"tatusInfoCommand.Feedback\022m\n\020GetBatteryS" +
|
"quest\032).cmvr.api.AgvRuntimeStateCommand." +
|
||||||
"tatus\022+.cmvr.api.RobotStatusBatteryComma" +
|
"Feedback\022r\n\023getNavigationStatus\022,.cmvr.a" +
|
||||||
"nd.Request\032,.cmvr.api.RobotStatusBattery" +
|
"pi.AgvNavigationStatusCommand.Request\032-." +
|
||||||
"Command.Feedback\022e\n\020GetRobotLocation\022\'.c" +
|
"cmvr.api.AgvNavigationStatusCommand.Feed" +
|
||||||
"mvr.api.RobotStatusLocCommand.Request\032(." +
|
"back\022R\n\remergencyStop\022\037.cmvr.api.Command" +
|
||||||
"cmvr.api.RobotStatusLocCommand.Feedback\022" +
|
"Header.Request\032 .cmvr.api.CommandHeader." +
|
||||||
"{\n\026RobotConfigDownloadMap\022/.cmvr.api.Rob" +
|
"Feedback\022O\n\nclearFault\022\037.cmvr.api.Comman" +
|
||||||
"otConfigDownloadMapCommand.Request\0320.cmv" +
|
"dHeader.Request\032 .cmvr.api.CommandHeader" +
|
||||||
"r.api.RobotConfigDownloadMapCommand.Feed" +
|
".Feedback\022i\n\016navigateToPose\022*.cmvr.api.A" +
|
||||||
"back\022a\n\014GetMapStatus\022\'.cmvr.api.RobotSta" +
|
"gvNavigateToPoseCommand.Request\032+.cmvr.a" +
|
||||||
"tusMapCommand.Request\032(.cmvr.api.RobotSt" +
|
"pi.AgvNavigateToPoseCommand.Feedback\022r\n\021" +
|
||||||
"atusMapCommand.Feedback\022u\n\024RobotConfigUp" +
|
"navigateToStation\022-.cmvr.api.AgvNavigate" +
|
||||||
"loadMap\022-.cmvr.api.RobotConfigUploadMapC" +
|
"ToStationCommand.Request\032..cmvr.api.AgvN" +
|
||||||
"ommand.Request\032..cmvr.api.RobotConfigUpl" +
|
"avigateToStationCommand.Feedback\022]\n\nfoll" +
|
||||||
"oadMapCommand.Feedback\022f\n\017RobotConfigLoc" +
|
"owPath\022&.cmvr.api.AgvFollowPathCommand.R" +
|
||||||
"k\022(.cmvr.api.RobotConfigLockCommand.Requ" +
|
"equest\032\'.cmvr.api.AgvFollowPathCommand.F" +
|
||||||
"est\032).cmvr.api.RobotConfigLockCommand.Fe" +
|
"eedback\022T\n\017pauseNavigation\022\037.cmvr.api.Co" +
|
||||||
"edback\022y\n\024GetCurrentLockStatus\022/.cmvr.ap" +
|
"mmandHeader.Request\032 .cmvr.api.CommandHe" +
|
||||||
"i.RobotStatusCurrentLockCommand.Request\032" +
|
"ader.Feedback\022U\n\020resumeNavigation\022\037.cmvr" +
|
||||||
"0.cmvr.api.RobotStatusCurrentLockCommand" +
|
".api.CommandHeader.Request\032 .cmvr.api.Co" +
|
||||||
".Feedback\022o\n\022RobotMotionControl\022+.cmvr.a" +
|
"mmandHeader.Feedback\022U\n\020cancelNavigation" +
|
||||||
"pi.RobotMotionControlCommand.Request\032,.c" +
|
"\022\037.cmvr.api.CommandHeader.Request\032 .cmvr" +
|
||||||
"mvr.api.RobotMotionControlCommand.Feedba" +
|
".api.CommandHeader.Feedback\022`\n\013setVeloci" +
|
||||||
"ck\022]\n\014RobotLoadMap\022%.cmvr.api.RobotLoadM" +
|
"ty\022\'.cmvr.api.AgvSetVelocityCommand.Requ" +
|
||||||
"apCommand.Request\032&.cmvr.api.RobotLoadMa" +
|
"est\032(.cmvr.api.AgvSetVelocityCommand.Fee" +
|
||||||
"pCommand.Feedback\022y\n\022QueryLoadMapStatus\022" +
|
"dback\022X\n\023stopVelocityControl\022\037.cmvr.api." +
|
||||||
"0.cmvr.api.RobotQueryLoadMapStatusComman" +
|
"CommandHeader.Request\032 .cmvr.api.Command" +
|
||||||
"d.Request\0321.cmvr.api.RobotQueryLoadMapSt" +
|
"Header.Feedback\022W\n\010listMaps\022$.cmvr.api.A" +
|
||||||
"atusCommand.Feedback\022i\n\020QueryStationList" +
|
"gvListMapsCommand.Request\032%.cmvr.api.Agv" +
|
||||||
"\022).cmvr.api.QueryStationListCommand.Requ" +
|
"ListMapsCommand.Feedback\022c\n\014listStations" +
|
||||||
"est\032*.cmvr.api.QueryStationListCommand.F" +
|
"\022(.cmvr.api.AgvListStationsCommand.Reque" +
|
||||||
"eedback\022l\n\021RobotGoTargetList\022*.cmvr.api." +
|
"st\032).cmvr.api.AgvListStationsCommand.Fee" +
|
||||||
"RobotGoTargetListCommand.Request\032+.cmvr." +
|
"dback\022N\n\tswitchMap\022\037.cmvr.api.AgvMapComm" +
|
||||||
"api.RobotGoTargetListCommand.Feedback\022{\n" +
|
"and.Request\032 .cmvr.api.AgvMapCommand.Fee" +
|
||||||
"\026RobotStatusTaskCurrent\022/.cmvr.api.Robot" +
|
"dback\022N\n\tuploadMap\022\037.cmvr.api.AgvMapComm" +
|
||||||
"StatusTaskCurrentCommand.Request\0320.cmvr." +
|
"and.Request\032 .cmvr.api.AgvMapCommand.Fee" +
|
||||||
"api.RobotStatusTaskCurrentCommand.Feedba" +
|
"dback\022P\n\013downloadMap\022\037.cmvr.api.AgvMapCo" +
|
||||||
"ck\022{\n\026RobotStatusTaskPackage\022/.cmvr.api." +
|
"mmand.Request\032 .cmvr.api.AgvMapCommand.F" +
|
||||||
"RobotStatusTaskPackageCommand.Request\0320." +
|
"eedback\022c\n\014startMapping\022(.cmvr.api.AgvSt" +
|
||||||
"cmvr.api.RobotStatusTaskPackageCommand.F" +
|
"artMappingCommand.Request\032).cmvr.api.Agv" +
|
||||||
"eedback\022`\n\rRobotGoTarget\022&.cmvr.api.Robo" +
|
"StartMappingCommand.Feedback\022\\\n\tstreamMa" +
|
||||||
"tGoTargetCommand.Request\032\'.cmvr.api.Robo" +
|
"p\022%.cmvr.api.AgvMapStreamCommand.Request" +
|
||||||
"tGoTargetCommand.Feedback\022i\n\020RobotContro" +
|
"\032&.cmvr.api.AgvMapStreamCommand.Feedback" +
|
||||||
"lStop\022).cmvr.api.RobotControlStopCommand" +
|
"0\001\022P\n\013stopMapping\022\037.cmvr.api.CommandHead" +
|
||||||
".Request\032*.cmvr.api.RobotControlStopComm" +
|
"er.Request\032 .cmvr.api.CommandHeader.Feed" +
|
||||||
"and.Feedback\022c\n\016RobotTaskPause\022\'.cmvr.ap" +
|
"backb\006proto3"
|
||||||
"i.RobotTaskPauseCommand.Request\032(.cmvr.a" +
|
|
||||||
"pi.RobotTaskPauseCommand.Feedback\022f\n\017Rob" +
|
|
||||||
"otTaskResume\022(.cmvr.api.RobotTaskResumeC" +
|
|
||||||
"ommand.Request\032).cmvr.api.RobotTaskResum" +
|
|
||||||
"eCommand.Feedback\022f\n\017RobotTaskCancel\022(.c" +
|
|
||||||
"mvr.api.RobotTaskCancelCommand.Request\032)" +
|
|
||||||
".cmvr.api.RobotTaskCancelCommand.Feedbac" +
|
|
||||||
"kb\006proto3"
|
|
||||||
};
|
};
|
||||||
descriptor = com.google.protobuf.Descriptors.FileDescriptor
|
descriptor = com.google.protobuf.Descriptors.FileDescriptor
|
||||||
.internalBuildGeneratedFileFrom(descriptorData,
|
.internalBuildGeneratedFileFrom(descriptorData,
|
||||||
new com.google.protobuf.Descriptors.FileDescriptor[] {
|
new com.google.protobuf.Descriptors.FileDescriptor[] {
|
||||||
|
cmvr.api.Common.getDescriptor(),
|
||||||
cmvr.api.AgvCommand.getDescriptor(),
|
cmvr.api.AgvCommand.getDescriptor(),
|
||||||
});
|
});
|
||||||
|
cmvr.api.Common.getDescriptor();
|
||||||
cmvr.api.AgvCommand.getDescriptor();
|
cmvr.api.AgvCommand.getDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,74 +1,72 @@
|
|||||||
/**
|
|
||||||
* @file agv_service.proto
|
|
||||||
* @brief 定义AGV服务的gRPC接口,聚合所有AGV相关命令。
|
|
||||||
* 服务端实现类为 gRPCAGVServiceImpl。
|
|
||||||
*/
|
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
import "cmvr/api/agv_command.proto";
|
|
||||||
|
|
||||||
package cmvr.api;
|
package cmvr.api;
|
||||||
|
|
||||||
|
import "cmvr/api/common.proto";
|
||||||
|
import "cmvr/api/agv_command.proto";
|
||||||
|
|
||||||
|
// AGV 通用服务。该服务只暴露控制器无关的能力,
|
||||||
|
// 厂商协议、地图文件格式和控制器特有参数由具体 AGV 适配器内部处理。
|
||||||
service AgvService {
|
service AgvService {
|
||||||
// 基本控制
|
// 获取 AGV 当前运行状态快照。
|
||||||
rpc GetStatusInfo(GetAgvStatusInfoCommand.Request) returns (GetAgvStatusInfoCommand.Feedback);
|
rpc getRuntimeState(AgvRuntimeStateCommand.Request) returns (AgvRuntimeStateCommand.Feedback);
|
||||||
|
|
||||||
rpc GetBatteryStatus(RobotStatusBatteryCommand.Request) returns (RobotStatusBatteryCommand.Feedback);
|
// 获取当前导航任务状态。
|
||||||
|
rpc getNavigationStatus(AgvNavigationStatusCommand.Request) returns (AgvNavigationStatusCommand.Feedback);
|
||||||
|
|
||||||
rpc GetRobotLocation(RobotStatusLocCommand.Request) returns (RobotStatusLocCommand.Feedback);
|
// 执行急停或等效安全停止动作。
|
||||||
|
rpc emergencyStop(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
rpc RobotConfigDownloadMap(RobotConfigDownloadMapCommand.Request) returns (RobotConfigDownloadMapCommand.Feedback);
|
// 清除可恢复故障或告警。
|
||||||
|
rpc clearFault(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
|
// 导航到指定地图位姿。目标位姿 x/y 单位为米,theta 单位为弧度。
|
||||||
|
rpc navigateToPose(AgvNavigateToPoseCommand.Request) returns (AgvNavigateToPoseCommand.Feedback);
|
||||||
|
|
||||||
rpc GetMapStatus(RobotStatusMapCommand.Request) returns (RobotStatusMapCommand.Feedback);
|
// 导航到指定地图站点。
|
||||||
|
rpc navigateToStation(AgvNavigateToStationCommand.Request) returns (AgvNavigateToStationCommand.Feedback);
|
||||||
|
|
||||||
|
// 按显式站点路径执行导航。
|
||||||
|
rpc followPath(AgvFollowPathCommand.Request) returns (AgvFollowPathCommand.Feedback);
|
||||||
|
|
||||||
rpc RobotConfigUploadMap(RobotConfigUploadMapCommand.Request) returns (RobotConfigUploadMapCommand.Feedback);
|
// 暂停当前导航任务。
|
||||||
|
rpc pauseNavigation(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
// 抢占机器人控制权
|
// 恢复已暂停的导航任务。
|
||||||
rpc RobotConfigLock(RobotConfigLockCommand.Request) returns (RobotConfigLockCommand.Feedback);
|
rpc resumeNavigation(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
// 查询当前控制权所有者
|
// 取消当前导航任务。
|
||||||
rpc GetCurrentLockStatus(RobotStatusCurrentLockCommand.Request) returns (RobotStatusCurrentLockCommand.Feedback);
|
rpc cancelNavigation(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
// 开环速度运动控制
|
// 下发底盘速度控制指令。vx/vy 单位为米/秒,wz 单位为弧度/秒。
|
||||||
rpc RobotMotionControl(RobotMotionControlCommand.Request) returns (RobotMotionControlCommand.Feedback);
|
rpc setVelocity(AgvSetVelocityCommand.Request) returns (AgvSetVelocityCommand.Feedback);
|
||||||
|
|
||||||
// 切换载入地图 命令码2022
|
// 停止底盘速度控制。该接口不等价于取消导航任务。
|
||||||
rpc RobotLoadMap(RobotLoadMapCommand.Request) returns (RobotLoadMapCommand.Feedback);
|
rpc stopVelocityControl(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
|
// 查询 AGV 控制器可用地图名称列表。
|
||||||
|
rpc listMaps(AgvListMapsCommand.Request) returns (AgvListMapsCommand.Feedback);
|
||||||
|
|
||||||
// 查询地图载入状态 命令码1022
|
// 查询当前地图中的站点列表。
|
||||||
rpc QueryLoadMapStatus(RobotQueryLoadMapStatusCommand.Request) returns (RobotQueryLoadMapStatusCommand.Feedback);
|
rpc listStations(AgvListStationsCommand.Request) returns (AgvListStationsCommand.Feedback);
|
||||||
|
|
||||||
|
// 切换当前使用地图。
|
||||||
|
rpc switchMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback);
|
||||||
|
|
||||||
// 查询当前地图站点列表 命令码1301
|
// 上传地图内容到 AGV 控制器。地图内容字段由适配器解释。
|
||||||
rpc QueryStationList(QueryStationListCommand.Request) returns (QueryStationListCommand.Feedback);
|
rpc uploadMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback);
|
||||||
|
|
||||||
|
// 下载指定地图内容。
|
||||||
|
rpc downloadMap(AgvMapCommand.Request) returns (AgvMapCommand.Feedback);
|
||||||
|
|
||||||
// 指定路径导航 命令码3066
|
// 开始建图/扫图会话。请求只选择 2D、3D 或二者都要,
|
||||||
rpc RobotGoTargetList(RobotGoTargetListCommand.Request) returns (RobotGoTargetListCommand.Feedback);
|
// 控制器特有地图格式由 AGV 适配器内部转换。
|
||||||
|
rpc startMapping(AgvStartMappingCommand.Request) returns (AgvStartMappingCommand.Feedback);
|
||||||
|
|
||||||
// 查询当前导航状态 1020 robot_status_task_req
|
// 以服务端流方式发送统一地图。resume_token 为空时应先发送全量快照;
|
||||||
// 1020 查询当前实时导航 robot_status_task_req
|
// 后续是否发送增量由 AGV 适配器能力决定,并通过 update_type 标记。
|
||||||
rpc RobotStatusTaskCurrent(RobotStatusTaskCurrentCommand.Request) returns (RobotStatusTaskCurrentCommand.Feedback);
|
rpc streamMap(AgvMapStreamCommand.Request) returns (stream AgvMapStreamCommand.Feedback);
|
||||||
|
|
||||||
// 批量查询任务状态 1110 robot_status_task_status_package_req
|
// 停止当前建图/扫图会话。
|
||||||
rpc RobotStatusTaskPackage(RobotStatusTaskPackageCommand.Request) returns (RobotStatusTaskPackageCommand.Feedback);
|
rpc stopMapping(CommandHeader.Request) returns (CommandHeader.Feedback);
|
||||||
|
|
||||||
|
|
||||||
// 3051 单点站点自动规划导航 robot_task_gotarget_req 0x0BEB
|
|
||||||
rpc RobotGoTarget(RobotGoTargetCommand.Request) returns (RobotGoTargetCommand.Feedback);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 0x07D0 停止开环运动
|
|
||||||
rpc RobotControlStop(RobotControlStopCommand.Request) returns (RobotControlStopCommand.Feedback);
|
|
||||||
|
|
||||||
// 暂停当前导航任务 命令码 3001 (0x0BB9)
|
|
||||||
rpc RobotTaskPause(RobotTaskPauseCommand.Request) returns (RobotTaskPauseCommand.Feedback);
|
|
||||||
// 继续当前导航任务 命令码 3002 (0x0BBA)
|
|
||||||
rpc RobotTaskResume(RobotTaskResumeCommand.Request) returns (RobotTaskResumeCommand.Feedback);
|
|
||||||
// 取消当前导航任务 命令码 3003 (0x0BBB)
|
|
||||||
rpc RobotTaskCancel(RobotTaskCancelCommand.Request) returns (RobotTaskCancelCommand.Feedback);
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,310 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package cmvr.msgs;
|
||||||
|
|
||||||
|
// AGV 在地图平面坐标系中的二维位姿。
|
||||||
|
message AgvPose2d {
|
||||||
|
// X 坐标,单位:米。
|
||||||
|
double x = 1;
|
||||||
|
// Y 坐标,单位:米。
|
||||||
|
double y = 2;
|
||||||
|
// 航向角,单位:弧度,逆时针为正。
|
||||||
|
double theta = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AGV 车体坐标系下的平面速度。
|
||||||
|
message AgvVelocity {
|
||||||
|
// 车体 X 方向线速度,单位:米/秒。
|
||||||
|
double vx = 1;
|
||||||
|
// 车体 Y 方向线速度,单位:米/秒。
|
||||||
|
double vy = 2;
|
||||||
|
// 绕 Z 轴角速度,单位:弧度/秒。
|
||||||
|
double wz = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AGV 电池状态。
|
||||||
|
message AgvBatteryState {
|
||||||
|
// 电量比例,范围:[0, 1],例如 0.8 表示 80%。
|
||||||
|
double percentage = 1;
|
||||||
|
// 电池电压,单位:伏特。
|
||||||
|
double voltage = 2;
|
||||||
|
// 电池电流,单位:安培;正负号含义由具体 AGV 适配器保持一致。
|
||||||
|
double current = 3;
|
||||||
|
// 电池温度,单位:摄氏度。
|
||||||
|
double temperature = 4;
|
||||||
|
// 是否正在充电。
|
||||||
|
bool charging = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航任务的通用运动约束和执行选项。
|
||||||
|
message AgvMotionOptions {
|
||||||
|
// 最大线速度,单位:米/秒;0 表示使用 AGV 默认值。
|
||||||
|
double max_speed = 1;
|
||||||
|
// 最大角速度,单位:弧度/秒;0 表示使用 AGV 默认值。
|
||||||
|
double max_angular_speed = 2;
|
||||||
|
// 最大线加速度,单位:米/秒^2;0 表示使用 AGV 默认值。
|
||||||
|
double max_acceleration = 3;
|
||||||
|
// 最大角加速度,单位:弧度/秒^2;0 表示使用 AGV 默认值。
|
||||||
|
double max_angular_acceleration = 4;
|
||||||
|
// 到达目标点的距离容差,单位:米;0 表示使用 AGV 默认值。
|
||||||
|
double reach_distance = 5;
|
||||||
|
// 到达目标角度的角度容差,单位:弧度;0 表示使用 AGV 默认值。
|
||||||
|
double reach_angle = 6;
|
||||||
|
// 速度比例,范围通常为 [0, 1];1 表示不降速。
|
||||||
|
double speed_ratio = 7;
|
||||||
|
// 是否异步执行;true 表示下发任务后立即返回。
|
||||||
|
bool asynchronous = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AGV 适配器扩展参数。用于传递厂商或控制器特有的参数。
|
||||||
|
message AgvAdapterParams {
|
||||||
|
// 参数键值表。键和值都使用字符串,具体含义由 AGV 适配器解释。
|
||||||
|
map<string, string> values = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AGV 当前运行状态快照。
|
||||||
|
message AgvRuntimeState {
|
||||||
|
// 状态采样时间,Unix 时间戳,单位:秒。
|
||||||
|
double timestamp = 1;
|
||||||
|
// 运行模式,取值对应服务端内部 AgvMode 枚举的整数值。
|
||||||
|
int32 mode = 2;
|
||||||
|
// 是否已连接 AGV 控制器。
|
||||||
|
bool connected = 3;
|
||||||
|
// 是否已定位成功。
|
||||||
|
bool localized = 4;
|
||||||
|
// AGV 是否处于运动状态。
|
||||||
|
bool moving = 5;
|
||||||
|
// AGV 是否处于故障状态。
|
||||||
|
bool fault = 6;
|
||||||
|
// AGV 是否处于急停状态。
|
||||||
|
bool emergency_stopped = 7;
|
||||||
|
// 当前地图坐标系下的二维位姿。
|
||||||
|
AgvPose2d pose = 8;
|
||||||
|
// 当前车体速度。
|
||||||
|
AgvVelocity velocity = 9;
|
||||||
|
// 当前电池状态。
|
||||||
|
AgvBatteryState battery = 10;
|
||||||
|
// 当前加载地图名称;为空表示未知或控制器未返回。
|
||||||
|
string current_map = 11;
|
||||||
|
// 当前或最近站点 id;为空表示未知或当前不在站点附近。
|
||||||
|
string current_station = 12;
|
||||||
|
// 最近一次错误信息;为空表示无错误或未知。
|
||||||
|
string last_error = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地图中的站点信息。
|
||||||
|
message AgvStation {
|
||||||
|
// 站点唯一 id。
|
||||||
|
string id = 1;
|
||||||
|
// 站点类型;具体枚举由地图或控制器定义。
|
||||||
|
string type = 2;
|
||||||
|
// 站点在地图坐标系下的二维位姿。
|
||||||
|
AgvPose2d pose = 3;
|
||||||
|
// 站点描述或备注。
|
||||||
|
string description = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显式站点路径中的一段路径。
|
||||||
|
message AgvPathSegment {
|
||||||
|
// 起点站点 id。
|
||||||
|
string source_station = 1;
|
||||||
|
// 目标站点 id。
|
||||||
|
string target_station = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地图维度请求。这里只描述上位机想要 2D、3D 还是二者都要,
|
||||||
|
// 不用于指定厂商文件格式;厂商格式必须在 AGV 适配器内部转换。
|
||||||
|
enum AgvMapDimension {
|
||||||
|
// 未指定。服务端应选择最有用的默认地图,通常是当前加载地图。
|
||||||
|
AGV_MAP_DIMENSION_UNSPECIFIED = 0;
|
||||||
|
// 只请求统一 2D 地图。
|
||||||
|
AGV_MAP_2D = 1;
|
||||||
|
// 只请求统一 3D 地图。
|
||||||
|
AGV_MAP_3D = 2;
|
||||||
|
// 在同一个流中请求统一 2D 和统一 3D 地图。
|
||||||
|
AGV_MAP_2D_AND_3D = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地图流更新类型。上位机应根据该字段判断是全量、增量还是缓存重置。
|
||||||
|
enum AgvMapUpdateType {
|
||||||
|
// 未指定。
|
||||||
|
AGV_MAP_UPDATE_UNSPECIFIED = 0;
|
||||||
|
// 全量地图快照。首次请求或无法增量续传时应发送该类型。
|
||||||
|
AGV_MAP_UPDATE_SNAPSHOT = 1;
|
||||||
|
// 全量快照之后的增量更新。仅当适配器能够可靠生成差异时发送。
|
||||||
|
AGV_MAP_UPDATE_INCREMENTAL = 2;
|
||||||
|
// 上位机本地缓存已失效,应丢弃缓存并等待后续全量快照。
|
||||||
|
AGV_MAP_UPDATE_RESET = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2D/3D 地图共用的语义对象类型。
|
||||||
|
enum AgvMapObjectType {
|
||||||
|
// 未指定。
|
||||||
|
AGV_MAP_OBJECT_UNSPECIFIED = 0;
|
||||||
|
// 导航站点或路径点。
|
||||||
|
AGV_MAP_OBJECT_STATION = 1;
|
||||||
|
// 路径线、禁行线、引导线等线对象。
|
||||||
|
AGV_MAP_OBJECT_LINE = 2;
|
||||||
|
// 多边形区域,例如禁行区、限速区、作业区。
|
||||||
|
AGV_MAP_OBJECT_AREA = 3;
|
||||||
|
// 二维码、天码或其他标签地标。
|
||||||
|
AGV_MAP_OBJECT_QR_TAG = 4;
|
||||||
|
// 反光板或反光柱地标。
|
||||||
|
AGV_MAP_OBJECT_REFLECTOR = 5;
|
||||||
|
// 库位、货位或储位。
|
||||||
|
AGV_MAP_OBJECT_BIN_LOCATION = 6;
|
||||||
|
// 门、电梯、充电桩等外部设备。
|
||||||
|
AGV_MAP_OBJECT_EXTERNAL_DEVICE = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地图坐标系下的三维点。单位:米。
|
||||||
|
message AgvMapPoint3D {
|
||||||
|
// X 坐标,单位:米。
|
||||||
|
double x = 1;
|
||||||
|
// Y 坐标,单位:米。
|
||||||
|
double y = 2;
|
||||||
|
// Z 坐标,单位:米;纯 2D 几何可置为 0。
|
||||||
|
double z = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一 2D 地图。栅格数据按行优先排列:index = y * width + x。
|
||||||
|
message AgvUnifiedMap2D {
|
||||||
|
// 坐标系名称,例如 "map"。
|
||||||
|
string frame_id = 1;
|
||||||
|
// 地图采样或更新时间,Unix 时间戳,单位:秒。
|
||||||
|
double timestamp = 2;
|
||||||
|
// 栅格分辨率,单位:米/格。
|
||||||
|
double resolution = 3;
|
||||||
|
// 栅格宽度,单位:格。
|
||||||
|
uint32 width = 4;
|
||||||
|
// 栅格高度,单位:格。
|
||||||
|
uint32 height = 5;
|
||||||
|
// 栅格 (0, 0) 在世界/地图坐标系下的位姿;x/y 单位:米,theta 单位:弧度。
|
||||||
|
AgvPose2d origin = 6;
|
||||||
|
// 占据值:-1 表示未知,0 表示空闲,100 表示占据。
|
||||||
|
repeated int32 data = 7;
|
||||||
|
// 地图中的统一语义对象,例如站点、线、区域、标签、反光板等。
|
||||||
|
repeated AgvMapObject objects = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一 3D 点样本。坐标单位:米。
|
||||||
|
message AgvMapPointSample3D {
|
||||||
|
// X 坐标,单位:米。
|
||||||
|
double x = 1;
|
||||||
|
// Y 坐标,单位:米。
|
||||||
|
double y = 2;
|
||||||
|
// Z 坐标,单位:米。
|
||||||
|
double z = 3;
|
||||||
|
// 激光强度;无强度信息时置为 0。
|
||||||
|
float intensity = 4;
|
||||||
|
// 激光雷达线束/通道编号;无该信息时置为 0。
|
||||||
|
uint32 ring = 5;
|
||||||
|
// 相对地图时间戳的时间偏移,单位:秒;无该信息时置为 0。
|
||||||
|
double time_offset = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一 3D 体素。体素索引基于 AgvUnifiedMap3D.voxel_resolution。
|
||||||
|
message AgvMapVoxel3D {
|
||||||
|
// 体素 X 索引。
|
||||||
|
int32 x = 1;
|
||||||
|
// 体素 Y 索引。
|
||||||
|
int32 y = 2;
|
||||||
|
// 体素 Z 索引。
|
||||||
|
int32 z = 3;
|
||||||
|
// 占据概率,范围:[0, 1];未知时置为 -1。
|
||||||
|
float probability = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一 3D 平面特征。平面方程:
|
||||||
|
// normal.x * x + normal.y * y + normal.z * z + d = 0。
|
||||||
|
message AgvMapPlane3D {
|
||||||
|
// 平面中心点,单位:米。
|
||||||
|
AgvMapPoint3D center = 1;
|
||||||
|
// 平面单位法向量。
|
||||||
|
AgvMapPoint3D normal = 2;
|
||||||
|
// 平面方程偏移量,单位:米。
|
||||||
|
double d = 3;
|
||||||
|
// 平面特征近似半径,单位:米。
|
||||||
|
double radius = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一语义对象。几何点均使用地图坐标系,单位:米。
|
||||||
|
message AgvMapObject {
|
||||||
|
// 对象稳定 id 或名称。
|
||||||
|
string id = 1;
|
||||||
|
// 对象类型。
|
||||||
|
AgvMapObjectType type = 2;
|
||||||
|
// 对象几何点。点对象使用 1 个点,线对象使用多个点,区域对象使用多边形顶点。
|
||||||
|
repeated AgvMapPoint3D points = 3;
|
||||||
|
// 朝向角,单位:弧度;不适用时置为 0。
|
||||||
|
double heading = 4;
|
||||||
|
// 额外归一化属性。为兼容不同 AGV,属性值统一使用字符串。
|
||||||
|
map<string, string> properties = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一 3D 地图。虽然内部包含点、体素、平面和语义对象,
|
||||||
|
// 但对上位机来说它仍然是唯一的 3D 地图格式。
|
||||||
|
message AgvUnifiedMap3D {
|
||||||
|
// 坐标系名称,例如 "map"。
|
||||||
|
string frame_id = 1;
|
||||||
|
// 地图采样或更新时间,Unix 时间戳,单位:秒。
|
||||||
|
double timestamp = 2;
|
||||||
|
// 体素分辨率,单位:米/体素;没有体素数据时置为 0。
|
||||||
|
double voxel_resolution = 3;
|
||||||
|
// 统一点云点样本。
|
||||||
|
repeated AgvMapPointSample3D points = 4;
|
||||||
|
// 统一占据体素。
|
||||||
|
repeated AgvMapVoxel3D voxels = 5;
|
||||||
|
// 统一平面特征。
|
||||||
|
repeated AgvMapPlane3D planes = 6;
|
||||||
|
// 统一 3D 语义对象,例如站点、区域、标签、地标等。
|
||||||
|
repeated AgvMapObject objects = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地图流中的单条更新。AGV 适配器必须先把厂商地图转换成 map_2d 或 map_3d,
|
||||||
|
// 再通过该消息发送给上位机。
|
||||||
|
message AgvUnifiedMapUpdate {
|
||||||
|
// 实际发送的地图 id 或名称。请求 map_name 为空时,AGV 可选择当前或最近地图。
|
||||||
|
string map_id = 1;
|
||||||
|
// 建图或地图流会话 id。
|
||||||
|
string session_id = 2;
|
||||||
|
// 会话内单调递增序号,从 0 或 1 开始均可,但同一会话内必须保持递增。
|
||||||
|
uint64 sequence = 3;
|
||||||
|
// 用于断点续传或增量订阅的不透明令牌。
|
||||||
|
string resume_token = 4;
|
||||||
|
// 本条更新的数据维度。
|
||||||
|
AgvMapDimension dimension = 5;
|
||||||
|
// 本条更新是全量、增量还是缓存重置。
|
||||||
|
AgvMapUpdateType update_type = 6;
|
||||||
|
// 坐标系名称,例如 "map"。
|
||||||
|
string frame_id = 7;
|
||||||
|
// 本条更新产生时间,Unix 时间戳,单位:秒。
|
||||||
|
double timestamp = 8;
|
||||||
|
// 是否为全量快照的第一条消息。
|
||||||
|
bool snapshot_begin = 9;
|
||||||
|
// 是否为全量快照的最后一条消息。
|
||||||
|
bool snapshot_end = 10;
|
||||||
|
// 大地图分片发送时的分片序号,从 0 开始。
|
||||||
|
uint32 chunk_index = 11;
|
||||||
|
// 大地图分片总数;0 表示未知或连续流。
|
||||||
|
uint32 chunk_count = 12;
|
||||||
|
|
||||||
|
oneof payload {
|
||||||
|
// 统一 2D 地图或 2D 地图增量。
|
||||||
|
AgvUnifiedMap2D map_2d = 20;
|
||||||
|
// 统一 3D 地图或 3D 地图增量。
|
||||||
|
AgvUnifiedMap3D map_3d = 21;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前导航任务状态。
|
||||||
|
message AgvNavigationStatus {
|
||||||
|
// 导航状态,取值对应服务端内部 AgvTaskState 枚举的整数值。
|
||||||
|
int32 state = 1;
|
||||||
|
// 导航任务类型,取值对应服务端内部 AgvTaskType 枚举的整数值。
|
||||||
|
int32 type = 2;
|
||||||
|
// 当前任务进度,范围:[0, 1];未知时置为 0。
|
||||||
|
double progress = 3;
|
||||||
|
// 状态描述或错误信息。
|
||||||
|
string message = 4;
|
||||||
|
}
|
||||||
@ -22,6 +22,8 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ -197,7 +199,7 @@ public class MinioService {
|
|||||||
* @param bucketName bucket名称
|
* @param bucketName bucket名称
|
||||||
* @param path 路径
|
* @param path 路径
|
||||||
* @param fileName 文件名
|
* @param fileName 文件名
|
||||||
* @return
|
* @return true/false
|
||||||
*/
|
*/
|
||||||
public Boolean isExist(String bucketName, String path, String fileName) {
|
public Boolean isExist(String bucketName, String path, String fileName) {
|
||||||
try {
|
try {
|
||||||
@ -236,5 +238,68 @@ public class MinioService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件流
|
||||||
|
*
|
||||||
|
* @param bucketName bucket名称
|
||||||
|
* @param objectName 对象名称(完整路径)
|
||||||
|
* @param inputStream 输入流
|
||||||
|
* @param size 文件大小
|
||||||
|
* @param contentType 内容类型
|
||||||
|
*/
|
||||||
|
public void uploadStream(String bucketName, String objectName, InputStream inputStream, long size, String contentType) {
|
||||||
|
try {
|
||||||
|
Map<String, String> extraHeaders = new HashMap<>();
|
||||||
|
extraHeaders.put("x-amz-acl", "public-read");
|
||||||
|
PutObjectArgs objectArgs = PutObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.stream(inputStream, size, -1)
|
||||||
|
.extraHeaders(extraHeaders)
|
||||||
|
.contentType(contentType)
|
||||||
|
.build();
|
||||||
|
minioClient.putObject(objectArgs);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("上传文件流失败, objectName: {}", objectName, e);
|
||||||
|
throw new RuntimeException("上传文件流失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
*
|
||||||
|
* @param bucketName bucket名称
|
||||||
|
* @param objectName 对象名称
|
||||||
|
*/
|
||||||
|
public void deleteFile(String bucketName, String objectName) {
|
||||||
|
try {
|
||||||
|
minioClient.removeObject(RemoveObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除文件失败, objectName: {}", objectName, e);
|
||||||
|
throw new RuntimeException("删除文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件输入流
|
||||||
|
*
|
||||||
|
* @param bucketName bucket名称
|
||||||
|
* @param objectName 对象名称
|
||||||
|
* @return 输入流
|
||||||
|
*/
|
||||||
|
public InputStream getObject(String bucketName, String objectName) {
|
||||||
|
try {
|
||||||
|
return minioClient.getObject(GetObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取文件失败, objectName: {}", objectName, e);
|
||||||
|
throw new RuntimeException("获取文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,21 @@
|
|||||||
package com.cmvr.common.utils.http;
|
package com.cmvr.common.utils.http;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Map;
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
@ -271,4 +276,90 @@ public class HttpUtils
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定 URL 发送POST方法的请求,返回字节数组(用于接收文件流)
|
||||||
|
*
|
||||||
|
* @param url 发送请求的 URL
|
||||||
|
* @param params 请求参数
|
||||||
|
* @return 所代表远程资源的响应结果(字节数组)
|
||||||
|
*/
|
||||||
|
public static byte[] sendPostReturnBytes(String url, Map<String, Object> params)
|
||||||
|
{
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log.info("sendPostReturnBytes - {}", url);
|
||||||
|
URL realUrl = new URL(url);
|
||||||
|
conn = (HttpURLConnection) realUrl.openConnection();
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("accept", "*/*");
|
||||||
|
conn.setRequestProperty("connection", "Keep-Alive");
|
||||||
|
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
|
||||||
|
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
conn.setDoInput(true);
|
||||||
|
conn.setConnectTimeout(30000);
|
||||||
|
conn.setReadTimeout(60000);
|
||||||
|
|
||||||
|
// 发送请求参数
|
||||||
|
String jsonParams = JSONUtil.toJsonStr(params);
|
||||||
|
try (OutputStream os = conn.getOutputStream())
|
||||||
|
{
|
||||||
|
os.write(jsonParams.getBytes(StandardCharsets.UTF_8));
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
int responseCode = conn.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK)
|
||||||
|
{
|
||||||
|
try (InputStream is = conn.getInputStream();
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream())
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buffer)) != -1)
|
||||||
|
{
|
||||||
|
baos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
byte[] result = baos.toByteArray();
|
||||||
|
log.info("recv bytes length: {}", result.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("HTTP error code: {}", responseCode);
|
||||||
|
throw new RuntimeException("HTTP error code: " + responseCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ConnectException e)
|
||||||
|
{
|
||||||
|
log.error("调用HttpUtils.sendPostReturnBytes ConnectException, url=" + url, e);
|
||||||
|
throw new RuntimeException("连接外部TTS服务失败", e);
|
||||||
|
}
|
||||||
|
catch (SocketTimeoutException e)
|
||||||
|
{
|
||||||
|
log.error("调用HttpUtils.sendPostReturnBytes SocketTimeoutException, url=" + url, e);
|
||||||
|
throw new RuntimeException("外部TTS服务超时", e);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
log.error("调用HttpUtils.sendPostReturnBytes IOException, url=" + url, e);
|
||||||
|
throw new RuntimeException("IO异常", e);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
log.error("调用HttpUtils.sendPostReturnBytes Exception, url=" + url, e);
|
||||||
|
throw new RuntimeException("调用外部TTS服务异常", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (conn != null)
|
||||||
|
{
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,10 @@ package com.cmvr.inspection.service;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import cmvr.msgs.Agv;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.cmvr.inspection.domain.InspectionRobot;
|
import com.cmvr.inspection.domain.InspectionRobot;
|
||||||
import com.cmvr.inspection.domain.vo.InspectionRobotVo;
|
import com.cmvr.inspection.domain.vo.InspectionRobotVo;
|
||||||
import cmvr.api.AgvCommand;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 巡检机器人Service接口
|
* 巡检机器人Service接口
|
||||||
@ -60,9 +60,9 @@ public interface IInspectionRobotService extends IService<InspectionRobot>
|
|||||||
* 获取机器人地图列表(从AGV获取)
|
* 获取机器人地图列表(从AGV获取)
|
||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @return 地图状态信息
|
* @return 地图列表
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvMapStatus getRobotMapList(String robotId);
|
List<String> getRobotMapList(String robotId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定机器人地图
|
* 绑定机器人地图
|
||||||
@ -78,7 +78,7 @@ public interface IInspectionRobotService extends IService<InspectionRobot>
|
|||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @param mapName 地图名称
|
* @param mapName 地图名称
|
||||||
* @return 地图ID
|
* @return 地图内容
|
||||||
*/
|
*/
|
||||||
String downloadMapFromRobot(String robotId, String mapName);
|
String downloadMapFromRobot(String robotId, String mapName);
|
||||||
|
|
||||||
@ -102,9 +102,9 @@ public interface IInspectionRobotService extends IService<InspectionRobot>
|
|||||||
* 获取机器人实时位置
|
* 获取机器人实时位置
|
||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @return 机器人位置信息(包含X、Y坐标、角度、当前站点等)
|
* @return 机器人位置信息
|
||||||
*/
|
*/
|
||||||
AgvCommand.AgvRobotLocation getRobotRealtimeLocation(String robotId);
|
Agv.AgvPose2d getRobotRealtimeLocation(String robotId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导航到指定位置(坐标)
|
* 导航到指定位置(坐标)
|
||||||
@ -113,10 +113,25 @@ public interface IInspectionRobotService extends IService<InspectionRobot>
|
|||||||
* @param x X坐标(米)
|
* @param x X坐标(米)
|
||||||
* @param y Y坐标(米)
|
* @param y Y坐标(米)
|
||||||
* @param theta 朝向角(弧度)
|
* @param theta 朝向角(弧度)
|
||||||
* @param taskId 任务ID(可选)
|
|
||||||
* @return 导航任务下发结果
|
|
||||||
*/
|
*/
|
||||||
AgvCommand.RobotGoTargetResData navigateToPosition(String robotId, Double x, Double y,
|
void navigateToPosition(String robotId, Double x, Double y, Double theta);
|
||||||
Double theta, String taskId);
|
|
||||||
|
/**
|
||||||
|
* 开始建图
|
||||||
|
*
|
||||||
|
* @param robotId 机器人ID
|
||||||
|
* @param dimension 建图维度(0:未指定 1:2D 2:3D 3:2D+3D)
|
||||||
|
* @param mapName 地图名称(可选)
|
||||||
|
* @param realTime 是否实时建图
|
||||||
|
* @return 会话ID
|
||||||
|
*/
|
||||||
|
String startMapping(String robotId, int dimension, String mapName, boolean realTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止建图
|
||||||
|
*
|
||||||
|
* @param robotId 机器人ID
|
||||||
|
*/
|
||||||
|
void stopMapping(String robotId);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,12 +1,11 @@
|
|||||||
|
|
||||||
package com.cmvr.inspection.service.impl;
|
package com.cmvr.inspection.service.impl;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.msgs.Agv;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.cmvr.common.utils.SecurityUtils;
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
import com.cmvr.device.domain.DeDeviceTerminalConfig;
|
import com.cmvr.device.domain.DeDeviceTerminalConfig;
|
||||||
@ -134,10 +133,10 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
* 获取机器人地图列表(从AGV获取)
|
* 获取机器人地图列表(从AGV获取)
|
||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @return 地图状态信息
|
* @return 地图列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvMapStatus getRobotMapList(String robotId)
|
public List<String> getRobotMapList(String robotId)
|
||||||
{
|
{
|
||||||
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
||||||
if (robot == null) {
|
if (robot == null) {
|
||||||
@ -151,7 +150,7 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
return edgeAgvService.getMapStatus(edgeCommonVO);
|
return edgeAgvService.listMaps(edgeCommonVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +185,7 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @param mapName 地图名称
|
* @param mapName 地图名称
|
||||||
* @return 地图ID
|
* @return 地图内容
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String downloadMapFromRobot(String robotId, String mapName)
|
public String downloadMapFromRobot(String robotId, String mapName)
|
||||||
@ -200,26 +199,7 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
AgvCommand.AgvDownloadMapResult result = edgeAgvService.robotConfigDownloadMap(edgeCommonVO, mapName);
|
return edgeAgvService.downloadMap(edgeCommonVO, mapName);
|
||||||
|
|
||||||
// 保存地图到数据库
|
|
||||||
// InspectionMap inspectionMap = new InspectionMap();
|
|
||||||
// inspectionMap.setId(UUID.randomUUID().toString().replace("-", ""));
|
|
||||||
// inspectionMap.setMapName(mapName);
|
|
||||||
// inspectionMap.setMapSourceRobotId(robotId);
|
|
||||||
// inspectionMap.setMapSourceName(mapName);
|
|
||||||
|
|
||||||
// TODO: 将地图内容保存到文件系统,并返回文件路径
|
|
||||||
// String filePath = saveMapToFile(result.getMapContent(), mapName);
|
|
||||||
// inspectionMap.setMapFilePath(filePath);
|
|
||||||
|
|
||||||
// inspectionMap.setStatus("0");
|
|
||||||
// inspectionMap.setCreateTime(DateUtils.getNowDate());
|
|
||||||
// inspectionMap.setCreateBy(SecurityUtils.getUsername());
|
|
||||||
//
|
|
||||||
// inspectionMapMapper.insertInspectionMap(inspectionMap);
|
|
||||||
|
|
||||||
return result.getMapContent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,15 +242,8 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
sourceEdgeVO.setTerminalId(sourceRobot.getTerminalId());
|
sourceEdgeVO.setTerminalId(sourceRobot.getTerminalId());
|
||||||
sourceEdgeVO.setDeviceId(sourceRobot.getRobotCode());
|
sourceEdgeVO.setDeviceId(sourceRobot.getRobotCode());
|
||||||
|
|
||||||
AgvCommand.AgvDownloadMapResult downloadResult = edgeAgvService.robotConfigDownloadMap(
|
String mapContent = edgeAgvService.downloadMap(sourceEdgeVO, map.getMapSourceName());
|
||||||
sourceEdgeVO, map.getMapSourceName()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (downloadResult.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("从来源机器人下载地图失败: " + downloadResult.getErrMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
String mapContent = downloadResult.getMapContent();
|
|
||||||
if (StrUtil.isBlank(mapContent)) {
|
if (StrUtil.isBlank(mapContent)) {
|
||||||
throw new GlobalException("下载的地图内容为空");
|
throw new GlobalException("下载的地图内容为空");
|
||||||
}
|
}
|
||||||
@ -280,13 +253,7 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
targetEdgeVO.setTerminalId(targetRobot.getTerminalId());
|
targetEdgeVO.setTerminalId(targetRobot.getTerminalId());
|
||||||
targetEdgeVO.setDeviceId(targetRobot.getRobotCode());
|
targetEdgeVO.setDeviceId(targetRobot.getRobotCode());
|
||||||
|
|
||||||
AgvCommand.AgvUploadMapResult uploadResult = edgeAgvService.robotConfigUploadMap(
|
edgeAgvService.uploadMap(targetEdgeVO, map.getMapSourceName(), mapContent);
|
||||||
targetEdgeVO, mapContent
|
|
||||||
);
|
|
||||||
|
|
||||||
if (uploadResult.getRetCode() != 0) {
|
|
||||||
throw new GlobalException("上传地图到目标机器人失败: " + uploadResult.getErrMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
return "上传成功";
|
return "上传成功";
|
||||||
}
|
}
|
||||||
@ -310,16 +277,19 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取电池状态
|
// 获取运行时状态(包含电池、位置等信息)
|
||||||
cmvr.api.AgvCommand.AgvBatteryStatus batteryStatus = edgeAgvService.getBatteryStatus(edgeCommonVO);
|
Agv.AgvRuntimeState runtimeState = edgeAgvService.getRuntimeState(edgeCommonVO);
|
||||||
robot.setBatteryLevel((int)(batteryStatus.getBatteryLevel() * 100));
|
|
||||||
|
|
||||||
// 获取位置信息
|
// 设置电池电量
|
||||||
cmvr.api.AgvCommand.AgvRobotLocation location = edgeAgvService.getRobotLocation(edgeCommonVO);
|
if (runtimeState.hasBattery()) {
|
||||||
robot.setCurrentPosition(location.getX() + "," + location.getY() + "," + location.getAngle());
|
robot.setBatteryLevel((int)(runtimeState.getBattery().getPercentage() * 100));
|
||||||
|
}
|
||||||
|
|
||||||
// 获取状态信息
|
// 设置位置信息
|
||||||
cmvr.api.AgvCommand.AgvStatusInfo statusInfo = edgeAgvService.getStatusInfo(edgeCommonVO);
|
if (runtimeState.hasPose()) {
|
||||||
|
Agv.AgvPose2d pose = runtimeState.getPose();
|
||||||
|
robot.setCurrentPosition(pose.getX() + "," + pose.getY() + "," + pose.getTheta());
|
||||||
|
}
|
||||||
|
|
||||||
robot.setUpdateTime(DateUtils.getNowDate());
|
robot.setUpdateTime(DateUtils.getNowDate());
|
||||||
inspectionRobotMapper.updateInspectionRobot(robot);
|
inspectionRobotMapper.updateInspectionRobot(robot);
|
||||||
@ -336,10 +306,10 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
* 获取机器人实时位置
|
* 获取机器人实时位置
|
||||||
*
|
*
|
||||||
* @param robotId 机器人ID
|
* @param robotId 机器人ID
|
||||||
* @return 机器人位置信息(包含X、Y坐标、角度、当前站点等)
|
* @return 机器人位置信息
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.AgvRobotLocation getRobotRealtimeLocation(String robotId)
|
public Agv.AgvPose2d getRobotRealtimeLocation(String robotId)
|
||||||
{
|
{
|
||||||
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
||||||
if (robot == null) {
|
if (robot == null) {
|
||||||
@ -350,7 +320,8 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
return edgeAgvService.getRobotLocation(edgeCommonVO);
|
Agv.AgvRuntimeState runtimeState = edgeAgvService.getRuntimeState(edgeCommonVO);
|
||||||
|
return runtimeState.hasPose() ? runtimeState.getPose() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,12 +331,9 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
* @param x X坐标(米)
|
* @param x X坐标(米)
|
||||||
* @param y Y坐标(米)
|
* @param y Y坐标(米)
|
||||||
* @param theta 朝向角(弧度)
|
* @param theta 朝向角(弧度)
|
||||||
* @param taskId 任务ID(可选)
|
|
||||||
* @return 导航任务下发结果
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AgvCommand.RobotGoTargetResData navigateToPosition(String robotId, Double x, Double y,
|
public void navigateToPosition(String robotId, Double x, Double y, Double theta)
|
||||||
Double theta, String taskId)
|
|
||||||
{
|
{
|
||||||
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
||||||
if (robot == null) {
|
if (robot == null) {
|
||||||
@ -376,8 +344,8 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
throw new GlobalException("X和Y坐标不能为空");
|
throw new GlobalException("X和Y坐标不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建自由导航点
|
// 构建目标位姿
|
||||||
AgvCommand.FreeGoPoint freeGoPoint = AgvCommand.FreeGoPoint.newBuilder()
|
Agv.AgvPose2d pose = Agv.AgvPose2d.newBuilder()
|
||||||
.setX(x)
|
.setX(x)
|
||||||
.setY(y)
|
.setY(y)
|
||||||
.setTheta(theta != null ? theta : 0.0)
|
.setTheta(theta != null ? theta : 0.0)
|
||||||
@ -387,8 +355,53 @@ public class InspectionRobotServiceImpl extends ServiceImpl<InspectionRobotMappe
|
|||||||
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
// 调用边缘端接口,使用freego参数进行自由导航
|
// 调用边缘端接口进行导航
|
||||||
return edgeAgvService.robotGoTargetWithFreeGo(edgeCommonVO, freeGoPoint, taskId);
|
edgeAgvService.navigateToPose(edgeCommonVO, pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始建图
|
||||||
|
*
|
||||||
|
* @param robotId 机器人ID
|
||||||
|
* @param dimension 建图维度(0:未指定 1:2D 2:3D 3:2D+3D)
|
||||||
|
* @param mapName 地图名称(可选)
|
||||||
|
* @param realTime 是否实时建图
|
||||||
|
* @return 会话ID
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String startMapping(String robotId, int dimension, String mapName, boolean realTime)
|
||||||
|
{
|
||||||
|
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
||||||
|
if (robot == null) {
|
||||||
|
throw new GlobalException("机器人不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||||
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
|
Agv.AgvMapDimension mapDimension = Agv.AgvMapDimension.forNumber(dimension);
|
||||||
|
return edgeAgvService.startMapping(edgeCommonVO, mapDimension, mapName, realTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止建图
|
||||||
|
*
|
||||||
|
* @param robotId 机器人ID
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void stopMapping(String robotId)
|
||||||
|
{
|
||||||
|
InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId);
|
||||||
|
if (robot == null) {
|
||||||
|
throw new GlobalException("机器人不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||||
|
edgeCommonVO.setTerminalId(robot.getTerminalId());
|
||||||
|
edgeCommonVO.setDeviceId(robot.getRobotCode());
|
||||||
|
|
||||||
|
edgeAgvService.stopMapping(edgeCommonVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.cmvr.test.flow.runtime.operator.edge;
|
package com.cmvr.test.flow.runtime.operator.edge;
|
||||||
|
|
||||||
import cmvr.api.AgvCommand;
|
import cmvr.msgs.Agv;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.cmvr.common.exception.GlobalException;
|
import com.cmvr.common.exception.GlobalException;
|
||||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||||
@ -17,7 +17,7 @@ import org.springframework.stereotype.Service;
|
|||||||
* 处理AGV相关的设备行为,如移动到指定位置
|
* 处理AGV相关的设备行为,如移动到指定位置
|
||||||
*
|
*
|
||||||
* @author cmvr-iot
|
* @author cmvr-iot
|
||||||
* @since 2026-06-29
|
* @since 2026-07-02
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -52,15 +52,14 @@ public class EdgeAgvOperateService implements EdgeOperateService {
|
|||||||
Double x = inputParams.getDouble("x");
|
Double x = inputParams.getDouble("x");
|
||||||
Double y = inputParams.getDouble("y");
|
Double y = inputParams.getDouble("y");
|
||||||
Double theta = inputParams.getDouble("theta");
|
Double theta = inputParams.getDouble("theta");
|
||||||
String taskId = inputParams.getString("taskId");
|
|
||||||
|
|
||||||
// 参数验证
|
// 参数验证
|
||||||
if (x == null || y == null) {
|
if (x == null || y == null) {
|
||||||
throw new GlobalException("X和Y坐标不能为空");
|
throw new GlobalException("X和Y坐标不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建自由导航点
|
// 构建目标位姿
|
||||||
AgvCommand.FreeGoPoint freeGoPoint = AgvCommand.FreeGoPoint.newBuilder()
|
Agv.AgvPose2d pose = Agv.AgvPose2d.newBuilder()
|
||||||
.setX(x)
|
.setX(x)
|
||||||
.setY(y)
|
.setY(y)
|
||||||
.setTheta(theta != null ? theta : 0.0)
|
.setTheta(theta != null ? theta : 0.0)
|
||||||
@ -72,10 +71,9 @@ public class EdgeAgvOperateService implements EdgeOperateService {
|
|||||||
edgeCommonVO.setDeviceId(deviceId);
|
edgeCommonVO.setDeviceId(deviceId);
|
||||||
|
|
||||||
// 直接调用边缘端AGV服务执行导航
|
// 直接调用边缘端AGV服务执行导航
|
||||||
AgvCommand.RobotGoTargetResData result =
|
edgeAgvService.navigateToPose(edgeCommonVO, pose);
|
||||||
edgeAgvService.robotGoTargetWithFreeGo(edgeCommonVO, freeGoPoint, taskId);
|
|
||||||
|
|
||||||
log.info("AGV移动任务下发成功,返回码: {}", result.getRetCode());
|
log.info("AGV移动任务下发成功");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.cmvr.test.service;
|
package com.cmvr.test.service;
|
||||||
|
|
||||||
|
import cmvr.msgs.Agv;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
@ -14,7 +15,6 @@ import com.cmvr.edge.client.service.EdgeMicrophoneService;
|
|||||||
import com.cmvr.edge.client.service.EdgeSpeakerService;
|
import com.cmvr.edge.client.service.EdgeSpeakerService;
|
||||||
import com.cmvr.edge.client.service.EdgeAgvService;
|
import com.cmvr.edge.client.service.EdgeAgvService;
|
||||||
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
import com.cmvr.llm.service.LLMAiAgentPlatformService;
|
||||||
import com.cmvr.llm.service.LLMAiTtsService;
|
|
||||||
import com.cmvr.test.enums.ActionEnum;
|
import com.cmvr.test.enums.ActionEnum;
|
||||||
import com.cmvr.test.model.vo.FlowActionRequestVO;
|
import com.cmvr.test.model.vo.FlowActionRequestVO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -118,29 +118,26 @@ public class FlowActionExecutorService {
|
|||||||
Double x = payload.getDouble("x");
|
Double x = payload.getDouble("x");
|
||||||
Double y = payload.getDouble("y");
|
Double y = payload.getDouble("y");
|
||||||
Double theta = payload.getDouble("theta");
|
Double theta = payload.getDouble("theta");
|
||||||
String taskId = payload.getString("taskId");
|
|
||||||
|
|
||||||
// 参数验证
|
// 参数验证
|
||||||
if (x == null || y == null) {
|
if (x == null || y == null) {
|
||||||
throw new GlobalException("X和Y坐标不能为空");
|
throw new GlobalException("X和Y坐标不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建自由导航点
|
// 构建目标位姿
|
||||||
cmvr.api.AgvCommand.FreeGoPoint freeGoPoint = cmvr.api.AgvCommand.FreeGoPoint.newBuilder()
|
Agv.AgvPose2d pose = Agv.AgvPose2d.newBuilder()
|
||||||
.setX(x)
|
.setX(x)
|
||||||
.setY(y)
|
.setY(y)
|
||||||
.setTheta(theta != null ? theta : 0.0)
|
.setTheta(theta != null ? theta : 0.0)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 直接调用边缘端AGV服务
|
// 直接调用边缘端AGV服务
|
||||||
cmvr.api.AgvCommand.RobotGoTargetResData result =
|
edgeAgvService.navigateToPose(edgeCommonVO, pose);
|
||||||
edgeAgvService.robotGoTargetWithFreeGo(edgeCommonVO, freeGoPoint, taskId);
|
|
||||||
|
|
||||||
log.info("AGV移动任务下发成功,返回码: {}", result.getRetCode());
|
log.info("AGV移动任务下发成功");
|
||||||
|
|
||||||
// 返回结果字符串
|
// 返回结果字符串
|
||||||
return String.format("AGV移动任务下发成功, retCode=%d, errMsg=%s",
|
return "AGV移动任务下发成功";
|
||||||
result.getRetCode(), result.getErrMsg());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
33
cmvr-iot-tts/pom.xml
Normal file
33
cmvr-iot-tts/pom.xml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot</artifactId>
|
||||||
|
<version>3.8.9</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>cmvr-iot-tts</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
智能座舱语音语料采集模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- 通用工具-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 系统模块-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-system</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.cmvr.tts.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语料分类对象 tts_corpus_category
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("tts_corpus_category")
|
||||||
|
@ApiModel("语料分类请求对象")
|
||||||
|
public class CorpusCategory extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父分类ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("父分类ID")
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("分类名称")
|
||||||
|
private String categoryName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("排序")
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
109
cmvr-iot-tts/src/main/java/com/cmvr/tts/domain/CorpusInfo.java
Normal file
109
cmvr-iot-tts/src/main/java/com/cmvr/tts/domain/CorpusInfo.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package com.cmvr.tts.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据对象 tts_corpus_info
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("tts_corpus_info")
|
||||||
|
@ApiModel("车载语料数据请求对象")
|
||||||
|
public class CorpusInfo extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本内容
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("文本内容")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼音
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("拼音")
|
||||||
|
private String pinyin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属分类ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("所属分类ID")
|
||||||
|
private String categoryId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语种")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方言
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("情绪")
|
||||||
|
private String emotion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说话人
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("说话人")
|
||||||
|
private String speaker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 适用场景
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("适用场景")
|
||||||
|
private String scene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频文件路径
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频文件路径")
|
||||||
|
private String audioFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频时长(秒)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频时长(秒)")
|
||||||
|
private BigDecimal audioDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小(字节)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("文件大小(字节)")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID列表(用于批量查询)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("ID列表")
|
||||||
|
private String[] ids;
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
package com.cmvr.tts.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.cmvr.common.core.domain.BaseEntity;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务对象 tts_synthesize_task
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("tts_synthesize_task")
|
||||||
|
@ApiModel("TTS合成任务请求对象")
|
||||||
|
public class TtsSynthesizeTask extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
@TableId(value = "id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务编码
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合成文本
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("合成文本")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语种")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方言
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("情绪")
|
||||||
|
private String emotion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语速
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语速")
|
||||||
|
private BigDecimal speed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音量
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音量")
|
||||||
|
private BigDecimal volume;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音高
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音高")
|
||||||
|
private BigDecimal pitch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采样率
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("采样率")
|
||||||
|
private String sampleRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出格式
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("输出格式")
|
||||||
|
private String outputFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说话风格模板名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("说话风格模板名称")
|
||||||
|
private String styleTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态(0待处理 1合成中 2成功已完成 3失败)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("任务状态(0待处理 1合成中 2成功已完成 3失败)")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频文件存储路径
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频文件存储路径")
|
||||||
|
private String audioFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频时长(秒)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频时长(秒)")
|
||||||
|
private BigDecimal audioDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小(字节)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("文件大小(字节)")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败原因
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("失败原因")
|
||||||
|
private String errorMsg;
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.cmvr.tts.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语料分类树形VO对象
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("语料分类树形视图对象")
|
||||||
|
public class CorpusCategoryTreeVo {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父分类ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("父分类ID")
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("分类名称")
|
||||||
|
private String categoryName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("排序")
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子分类列表
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("子分类列表")
|
||||||
|
private List<CorpusCategoryTreeVo> children;
|
||||||
|
}
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
package com.cmvr.tts.domain.vo;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据VO对象(包含关联信息)
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("车载语料数据视图对象")
|
||||||
|
public class CorpusInfoVo {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本内容
|
||||||
|
*/
|
||||||
|
@Excel(name = "文本内容")
|
||||||
|
@ApiModelProperty("文本内容")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼音
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("拼音")
|
||||||
|
private String pinyin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属分类ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("所属分类ID")
|
||||||
|
private String categoryId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "分类名称")
|
||||||
|
@ApiModelProperty("分类名称")
|
||||||
|
private String categoryName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语种")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "语种")
|
||||||
|
@ApiModelProperty("语种名称")
|
||||||
|
private String languageName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方言
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("情绪")
|
||||||
|
private String emotion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "情绪")
|
||||||
|
@ApiModelProperty("情绪名称")
|
||||||
|
private String emotionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "音色")
|
||||||
|
@ApiModelProperty("音色名称")
|
||||||
|
private String voiceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说话人
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("说话人")
|
||||||
|
private String speaker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 适用场景
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("适用场景")
|
||||||
|
private String scene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频文件路径
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频文件路径")
|
||||||
|
private String audioFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频时长(秒)
|
||||||
|
*/
|
||||||
|
@Excel(name = "音频时长")
|
||||||
|
@ApiModelProperty("音频时长(秒)")
|
||||||
|
private BigDecimal audioDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小(字节)
|
||||||
|
*/
|
||||||
|
@Excel(name = "文件大小")
|
||||||
|
@ApiModelProperty("文件大小(字节)")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("创建者")
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("更新者")
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("更新时间")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.cmvr.tts.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLM查询请求对象
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("LLM查询请求对象")
|
||||||
|
public class LlmQueryVo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询文本
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("查询文本")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语种")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数量
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("数量")
|
||||||
|
private Integer count;
|
||||||
|
}
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
package com.cmvr.tts.domain.vo;
|
||||||
|
|
||||||
|
import com.cmvr.common.annotation.Excel;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务VO对象(包含关联信息)
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel("TTS合成任务视图对象")
|
||||||
|
public class TtsSynthesizeTaskVo {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("主键ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务编码
|
||||||
|
*/
|
||||||
|
@Excel(name = "任务编码")
|
||||||
|
@ApiModelProperty("任务编码")
|
||||||
|
private String taskCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合成文本
|
||||||
|
*/
|
||||||
|
@Excel(name = "合成文本")
|
||||||
|
@ApiModelProperty("合成文本")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语种")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语种名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "语种")
|
||||||
|
@ApiModelProperty("语种名称")
|
||||||
|
private String languageName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方言
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("方言")
|
||||||
|
private String dialect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音色")
|
||||||
|
private String voice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音色名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "音色")
|
||||||
|
@ApiModelProperty("音色名称")
|
||||||
|
private String voiceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("情绪")
|
||||||
|
private String emotion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 情绪名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "情绪")
|
||||||
|
@ApiModelProperty("情绪名称")
|
||||||
|
private String emotionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语速
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("语速")
|
||||||
|
private BigDecimal speed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音量
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音量")
|
||||||
|
private BigDecimal volume;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音高
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音高")
|
||||||
|
private BigDecimal pitch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采样率
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("采样率")
|
||||||
|
private String sampleRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出格式
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("输出格式")
|
||||||
|
private String outputFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说话风格模板名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("说话风格模板名称")
|
||||||
|
private String styleTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态(0待处理 1合成中 2成功已完成 3失败)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("任务状态(0待处理 1合成中 2成功已完成 3失败)")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "任务状态")
|
||||||
|
@ApiModelProperty("任务状态名称")
|
||||||
|
private String statusName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频文件存储路径
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("音频文件存储路径")
|
||||||
|
private String audioFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音频时长(秒)
|
||||||
|
*/
|
||||||
|
@Excel(name = "音频时长")
|
||||||
|
@ApiModelProperty("音频时长(秒)")
|
||||||
|
private BigDecimal audioDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小(字节)
|
||||||
|
*/
|
||||||
|
@Excel(name = "文件大小")
|
||||||
|
@ApiModelProperty("文件大小(字节)")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败原因
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("失败原因")
|
||||||
|
private String errorMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("创建者")
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("更新者")
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty("更新时间")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.cmvr.tts.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.tts.domain.CorpusCategory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语料分类Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
public interface CorpusCategoryMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料分类列表
|
||||||
|
*
|
||||||
|
* @param category 语料分类
|
||||||
|
* @return 语料分类集合
|
||||||
|
*/
|
||||||
|
List<CorpusCategory> selectList(CorpusCategory category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语料分类
|
||||||
|
*
|
||||||
|
* @param category 语料分类
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insert(CorpusCategory category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语料分类
|
||||||
|
*
|
||||||
|
* @param category 语料分类
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateById(CorpusCategory category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语料分类
|
||||||
|
*
|
||||||
|
* @param id 语料分类主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.cmvr.tts.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.domain.vo.CorpusInfoVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
public interface CorpusInfoMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询车载语料数据
|
||||||
|
*
|
||||||
|
* @param id 车载语料数据主键
|
||||||
|
* @return 车载语料数据
|
||||||
|
*/
|
||||||
|
CorpusInfo selectCorpusById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询车载语料数据列表
|
||||||
|
*
|
||||||
|
* @param corpus 车载语料数据
|
||||||
|
* @return 车载语料数据集合
|
||||||
|
*/
|
||||||
|
List<CorpusInfo> selectCorpusList(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询车载语料数据视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param corpus 车载语料数据
|
||||||
|
* @return 车载语料数据视图集合
|
||||||
|
*/
|
||||||
|
List<CorpusInfoVo> selectCorpusVoList(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增车载语料数据
|
||||||
|
*
|
||||||
|
* @param corpus 车载语料数据
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertCorpus(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改车载语料数据
|
||||||
|
*
|
||||||
|
* @param corpus 车载语料数据
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateCorpus(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除车载语料数据
|
||||||
|
*
|
||||||
|
* @param id 车载语料数据主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteCorpusById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除车载语料数据
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteCorpusByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计看板指标数据
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> selectDashboardStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计昨日数据用于环比计算
|
||||||
|
*
|
||||||
|
* @return 昨日统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> selectYesterdayStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种分组统计语料数量
|
||||||
|
*
|
||||||
|
* @return 语种统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByLanguage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按方言分组统计语料数量
|
||||||
|
*
|
||||||
|
* @return 方言统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByDialect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪分组统计语料数量
|
||||||
|
*
|
||||||
|
* @return 情绪统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByEmotion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按功能分类统计语料数量
|
||||||
|
*
|
||||||
|
* @return 分类统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByCategory();
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package com.cmvr.tts.mapper;
|
||||||
|
|
||||||
|
import com.cmvr.tts.domain.TtsSynthesizeTask;
|
||||||
|
import com.cmvr.tts.domain.vo.TtsSynthesizeTaskVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务Mapper接口
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
public interface TtsSynthesizeTaskMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务
|
||||||
|
*
|
||||||
|
* @param id TTS合成任务主键
|
||||||
|
* @return TTS合成任务
|
||||||
|
*/
|
||||||
|
TtsSynthesizeTask selectTtsTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务列表
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return TTS合成任务集合
|
||||||
|
*/
|
||||||
|
List<TtsSynthesizeTask> selectTtsTaskList(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务视图列表(包含关联信息)
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return TTS合成任务视图集合
|
||||||
|
*/
|
||||||
|
List<TtsSynthesizeTaskVo> selectTtsTaskVoList(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增TTS合成任务
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertTtsTask(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改TTS合成任务
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateTtsTask(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS合成任务
|
||||||
|
*
|
||||||
|
* @param id TTS合成任务主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteTtsTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除TTS合成任务
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的数据主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteTtsTaskByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计看板指标数据
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> selectDashboardStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计昨日数据用于环比计算
|
||||||
|
*
|
||||||
|
* @return 昨日统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> selectYesterdayStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种分组统计任务总量
|
||||||
|
*
|
||||||
|
* @return 语种统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByLanguage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按音色分组统计任务总量
|
||||||
|
*
|
||||||
|
* @return 音色统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByVoice();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪分组统计任务总量
|
||||||
|
*
|
||||||
|
* @return 情绪统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectStatsByEmotion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近7日每日合成任务数量趋势
|
||||||
|
*
|
||||||
|
* @return 每日任务数量
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectLast7DaysTrend();
|
||||||
|
}
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
package com.cmvr.tts.service;
|
||||||
|
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.domain.vo.CorpusCategoryTreeVo;
|
||||||
|
import com.cmvr.tts.domain.vo.CorpusInfoVo;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
public interface ICorpusInfoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料列表
|
||||||
|
*/
|
||||||
|
TableDataInfo selectCorpusList(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语料
|
||||||
|
*/
|
||||||
|
int insertCorpus(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语料
|
||||||
|
*/
|
||||||
|
int updateCorpus(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语料
|
||||||
|
*/
|
||||||
|
int deleteCorpusByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料详情
|
||||||
|
*/
|
||||||
|
CorpusInfoVo selectCorpusById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频流
|
||||||
|
*/
|
||||||
|
void getAudioStream(String corpusId, HttpServletResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传语料音频
|
||||||
|
*/
|
||||||
|
String uploadCorpusAudio(String corpusId, MultipartFile file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入语料
|
||||||
|
*/
|
||||||
|
Map<String, Object> importCorpus(MultipartFile file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出语料
|
||||||
|
*/
|
||||||
|
byte[] exportCorpusList(CorpusInfo corpus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDashboardStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByLanguage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按方言统计
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByDialect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByEmotion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按分类统计
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByCategory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分类树
|
||||||
|
*/
|
||||||
|
List<CorpusCategoryTreeVo> getCategoryTree();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增分类
|
||||||
|
*/
|
||||||
|
int insertCategory(com.cmvr.tts.domain.CorpusCategory category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改分类
|
||||||
|
*/
|
||||||
|
int updateCategory(com.cmvr.tts.domain.CorpusCategory category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除分类
|
||||||
|
*/
|
||||||
|
int deleteCategoryById(String id);
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
package com.cmvr.tts.service;
|
||||||
|
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.tts.domain.TtsSynthesizeTask;
|
||||||
|
import com.cmvr.tts.domain.vo.TtsSynthesizeTaskVo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务Service接口
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
public interface ITtsSynthesizeTaskService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务列表
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return TTS合成任务集合
|
||||||
|
*/
|
||||||
|
TableDataInfo selectTtsTaskList(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务
|
||||||
|
*
|
||||||
|
* @param id TTS合成任务主键
|
||||||
|
* @return TTS合成任务
|
||||||
|
*/
|
||||||
|
TtsSynthesizeTaskVo selectTtsTaskById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增TTS合成任务
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
TtsSynthesizeTask insertTtsTask(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增TTS合成任务
|
||||||
|
*
|
||||||
|
* @param tasks TTS合成任务列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int batchInsertTtsTask(List<TtsSynthesizeTask> tasks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改TTS合成任务
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateTtsTask(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS合成任务
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的TTS合成任务主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteTtsTaskByIds(String[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重生成TTS任务
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int regenerateTask(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频文件流
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @param response 响应
|
||||||
|
*/
|
||||||
|
void getAudioStream(String taskId, HttpServletResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出TTS合成任务列表
|
||||||
|
*
|
||||||
|
* @param task TTS合成任务
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
byte[] exportTtsTaskList(TtsSynthesizeTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDashboardStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByLanguage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按音色统计
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByVoice();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getStatsByEmotion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近7日趋势
|
||||||
|
*
|
||||||
|
* @return 趋势数据
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getLast7DaysTrend();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务到语料库
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @param categoryId 分类ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int saveToCorpus(String taskId, String categoryId);
|
||||||
|
}
|
||||||
@ -0,0 +1,335 @@
|
|||||||
|
package com.cmvr.tts.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.cmvr.common.core.minio.MinioService;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.common.utils.StringUtils;
|
||||||
|
import com.cmvr.tts.domain.CorpusCategory;
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.domain.vo.CorpusCategoryTreeVo;
|
||||||
|
import com.cmvr.tts.domain.vo.CorpusInfoVo;
|
||||||
|
import com.cmvr.tts.mapper.CorpusCategoryMapper;
|
||||||
|
import com.cmvr.tts.mapper.CorpusInfoMapper;
|
||||||
|
import com.cmvr.tts.service.ICorpusInfoService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车载语料数据Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class CorpusInfoServiceImpl implements ICorpusInfoService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CorpusInfoMapper corpusInfoMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CorpusCategoryMapper corpusCategoryMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MinioService minioService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TableDataInfo selectCorpusList(CorpusInfo corpus) {
|
||||||
|
List<CorpusInfoVo> list = corpusInfoMapper.selectCorpusVoList(corpus);
|
||||||
|
return new TableDataInfo(list, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增语料
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertCorpus(CorpusInfo corpus) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (corpus.getId() == null || corpus.getId().isEmpty()) {
|
||||||
|
corpus.setId(IdUtil.fastSimpleUUID());
|
||||||
|
}
|
||||||
|
corpus.setCreateTime(DateUtils.getNowDate());
|
||||||
|
corpus.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
return corpusInfoMapper.insertCorpus(corpus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改语料
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateCorpus(CorpusInfo corpus) {
|
||||||
|
corpus.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
corpus.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
return corpusInfoMapper.updateCorpus(corpus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语料
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int deleteCorpusByIds(String[] ids) {
|
||||||
|
for (String id : ids) {
|
||||||
|
CorpusInfo corpus = corpusInfoMapper.selectCorpusById(id);
|
||||||
|
if (corpus != null && StringUtils.isNotEmpty(corpus.getAudioFilePath())) {
|
||||||
|
try {
|
||||||
|
minioService.deleteFile("cmvr-iot", corpus.getAudioFilePath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除音频文件失败: {}", corpus.getAudioFilePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
corpusInfoMapper.deleteCorpusById(id);
|
||||||
|
}
|
||||||
|
return ids.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语料详情
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CorpusInfoVo selectCorpusById(String id) {
|
||||||
|
CorpusInfo corpus = corpusInfoMapper.selectCorpusById(id);
|
||||||
|
if (corpus == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CorpusInfoVo vo = new CorpusInfoVo();
|
||||||
|
BeanUtils.copyProperties(corpus, vo);
|
||||||
|
// TODO: 补充关联查询
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频流
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void getAudioStream(String corpusId, HttpServletResponse response) {
|
||||||
|
CorpusInfo corpus = corpusInfoMapper.selectCorpusById(corpusId);
|
||||||
|
if (corpus == null || StringUtils.isEmpty(corpus.getAudioFilePath())) {
|
||||||
|
throw new RuntimeException("音频文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream inputStream = minioService.getObject("cmvr-iot", corpus.getAudioFilePath());
|
||||||
|
response.setContentType("audio/wav");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("corpus_" + corpusId + ".wav", "UTF-8"));
|
||||||
|
|
||||||
|
OutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取音频流失败", e);
|
||||||
|
throw new RuntimeException("获取音频流失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传语料音频
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String uploadCorpusAudio(String corpusId, MultipartFile file) {
|
||||||
|
CorpusInfo corpus = corpusInfoMapper.selectCorpusById(corpusId);
|
||||||
|
if (corpus == null) {
|
||||||
|
throw new RuntimeException("语料不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String objectName = "corpus/" + DateUtils.datePath() + "/" + corpusId + "_" + System.currentTimeMillis() + ".wav";
|
||||||
|
minioService.upload("cmvr-iot", "corpus/" + DateUtils.datePath(), file);
|
||||||
|
|
||||||
|
corpus.setAudioFilePath(objectName);
|
||||||
|
corpus.setFileSize(file.getSize());
|
||||||
|
corpusInfoMapper.updateCorpus(corpus);
|
||||||
|
|
||||||
|
return objectName;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("上传音频失败", e);
|
||||||
|
throw new RuntimeException("上传音频失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入语料
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> importCorpus(MultipartFile file) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("successCount", 0);
|
||||||
|
result.put("failCount", 0);
|
||||||
|
result.put("failDetails", new ArrayList<>());
|
||||||
|
|
||||||
|
// TODO: 实现Excel解析和批量导入逻辑
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出语料
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] exportCorpusList(CorpusInfo corpus) {
|
||||||
|
List<CorpusInfoVo> list = corpusInfoMapper.selectCorpusVoList(corpus);
|
||||||
|
// TODO: 使用Excel工具类导出
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getDashboardStats() {
|
||||||
|
Map<String, Object> todayStats = corpusInfoMapper.selectDashboardStats();
|
||||||
|
Map<String, Object> yesterdayStats = corpusInfoMapper.selectYesterdayStats();
|
||||||
|
|
||||||
|
// 计算环比
|
||||||
|
if (yesterdayStats != null && !yesterdayStats.isEmpty()) {
|
||||||
|
Long todayTotal = ((Number) todayStats.get("totalCorpus")).longValue();
|
||||||
|
Long yesterdayTotal = ((Number) yesterdayStats.get("totalCorpus")).longValue();
|
||||||
|
todayStats.put("totalCorpusGrowth", calculatePercent(todayTotal, yesterdayTotal));
|
||||||
|
} else {
|
||||||
|
todayStats.put("totalCorpusGrowth", "0%");
|
||||||
|
}
|
||||||
|
|
||||||
|
return todayStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByLanguage() {
|
||||||
|
return corpusInfoMapper.selectStatsByLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按方言统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByDialect() {
|
||||||
|
return corpusInfoMapper.selectStatsByDialect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByEmotion() {
|
||||||
|
return corpusInfoMapper.selectStatsByEmotion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按分类统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByCategory() {
|
||||||
|
return corpusInfoMapper.selectStatsByCategory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分类树
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<CorpusCategoryTreeVo> getCategoryTree() {
|
||||||
|
CorpusCategory queryParam = new CorpusCategory();
|
||||||
|
List<CorpusCategory> allCategories = corpusCategoryMapper.selectList(queryParam);
|
||||||
|
return buildCategoryTree(allCategories, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增分类
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertCategory(CorpusCategory category) {
|
||||||
|
category.setId(IdUtil.fastSimpleUUID());
|
||||||
|
category.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return corpusCategoryMapper.insert(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改分类
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateCategory(CorpusCategory category) {
|
||||||
|
category.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return corpusCategoryMapper.updateById(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除分类
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int deleteCategoryById(String id) {
|
||||||
|
// 检查是否有子分类
|
||||||
|
CorpusCategory queryParam = new CorpusCategory();
|
||||||
|
queryParam.setParentId(id);
|
||||||
|
List<CorpusCategory> children = corpusCategoryMapper.selectList(queryParam);
|
||||||
|
if (children != null && !children.isEmpty()) {
|
||||||
|
throw new RuntimeException("存在子分类,无法删除");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有关联语料
|
||||||
|
CorpusInfo corpusParam = new CorpusInfo();
|
||||||
|
corpusParam.setCategoryId(id);
|
||||||
|
List<CorpusInfo> corpusList = corpusInfoMapper.selectCorpusList(corpusParam);
|
||||||
|
if (corpusList != null && !corpusList.isEmpty()) {
|
||||||
|
throw new RuntimeException("分类下存在语料,无法删除");
|
||||||
|
}
|
||||||
|
|
||||||
|
return corpusCategoryMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分类树
|
||||||
|
*/
|
||||||
|
private List<CorpusCategoryTreeVo> buildCategoryTree(List<CorpusCategory> allCategories, String parentId) {
|
||||||
|
return allCategories.stream()
|
||||||
|
.filter(category -> parentId.equals(category.getParentId()))
|
||||||
|
.map(category -> {
|
||||||
|
CorpusCategoryTreeVo treeVo = new CorpusCategoryTreeVo();
|
||||||
|
treeVo.setId(category.getId());
|
||||||
|
treeVo.setParentId(category.getParentId());
|
||||||
|
treeVo.setCategoryName(category.getCategoryName());
|
||||||
|
treeVo.setSortOrder(category.getSortOrder());
|
||||||
|
|
||||||
|
List<CorpusCategoryTreeVo> children = buildCategoryTree(allCategories, category.getId());
|
||||||
|
if (!children.isEmpty()) {
|
||||||
|
treeVo.setChildren(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return treeVo;
|
||||||
|
})
|
||||||
|
.sorted(Comparator.comparingInt(CorpusCategoryTreeVo::getSortOrder))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算环比增长率
|
||||||
|
*/
|
||||||
|
private String calculatePercent(Long current, Long previous) {
|
||||||
|
if (previous == 0) {
|
||||||
|
return current > 0 ? "+100%" : "0%";
|
||||||
|
}
|
||||||
|
double growth = (current - previous) * 100.0 / previous;
|
||||||
|
return String.format("%+.2f%%", growth);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,392 @@
|
|||||||
|
package com.cmvr.tts.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.cmvr.common.core.minio.MinioService;
|
||||||
|
import com.cmvr.common.core.page.TableDataInfo;
|
||||||
|
import com.cmvr.common.utils.DateUtils;
|
||||||
|
import com.cmvr.common.utils.SecurityUtils;
|
||||||
|
import com.cmvr.common.utils.StringUtils;
|
||||||
|
import com.cmvr.common.utils.http.HttpUtils;
|
||||||
|
import com.cmvr.tts.domain.CorpusInfo;
|
||||||
|
import com.cmvr.tts.domain.TtsSynthesizeTask;
|
||||||
|
import com.cmvr.tts.domain.vo.TtsSynthesizeTaskVo;
|
||||||
|
import com.cmvr.tts.mapper.CorpusInfoMapper;
|
||||||
|
import com.cmvr.tts.mapper.TtsSynthesizeTaskMapper;
|
||||||
|
import com.cmvr.tts.service.ITtsSynthesizeTaskService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTS合成任务Service业务层处理
|
||||||
|
*
|
||||||
|
* @author cmvr
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class TtsSynthesizeTaskServiceImpl implements ITtsSynthesizeTaskService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TtsSynthesizeTaskMapper ttsTaskMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CorpusInfoMapper corpusInfoMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MinioService minioService;
|
||||||
|
|
||||||
|
@org.springframework.beans.factory.annotation.Value("${tts.external-api.url:http://192.168.1.101:8080/tts/synthesize}")
|
||||||
|
private String externalTtsUrl;
|
||||||
|
|
||||||
|
@org.springframework.beans.factory.annotation.Value("${minio.bucketName:cmvr-iot}")
|
||||||
|
private String bucketName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TableDataInfo selectTtsTaskList(TtsSynthesizeTask task) {
|
||||||
|
List<TtsSynthesizeTaskVo> list = ttsTaskMapper.selectTtsTaskVoList(task);
|
||||||
|
return new TableDataInfo(list, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询TTS合成任务详情
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TtsSynthesizeTaskVo selectTtsTaskById(String id) {
|
||||||
|
TtsSynthesizeTask task = ttsTaskMapper.selectTtsTaskById(id);
|
||||||
|
if (task == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 转换为VO,包含关联信息
|
||||||
|
List<TtsSynthesizeTaskVo> voList = ttsTaskMapper.selectTtsTaskVoList(task);
|
||||||
|
return voList != null && !voList.isEmpty() ? voList.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public TtsSynthesizeTask insertTtsTask(TtsSynthesizeTask task) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (task.getId() == null || task.getId().isEmpty()) {
|
||||||
|
task.setId(IdUtil.fastSimpleUUID());
|
||||||
|
}
|
||||||
|
task.setTaskCode(IdUtil.fastSimpleUUID());
|
||||||
|
task.setStatus("0");
|
||||||
|
task.setCreateTime(DateUtils.getNowDate());
|
||||||
|
task.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
|
||||||
|
int rows = ttsTaskMapper.insertTtsTask(task);
|
||||||
|
|
||||||
|
// 异步调用外部TTS接口
|
||||||
|
if (rows > 0) {
|
||||||
|
callExternalTtsApi(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增TTS合成任务
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int batchInsertTtsTask(List<TtsSynthesizeTask> tasks) {
|
||||||
|
int count = 0;
|
||||||
|
for (TtsSynthesizeTask task : tasks) {
|
||||||
|
// 生成UUID作为主键
|
||||||
|
if (task.getId() == null || task.getId().isEmpty()) {
|
||||||
|
task.setId(IdUtil.fastSimpleUUID());
|
||||||
|
}
|
||||||
|
task.setTaskCode(IdUtil.fastSimpleUUID());
|
||||||
|
task.setStatus("0");
|
||||||
|
task.setCreateTime(DateUtils.getNowDate());
|
||||||
|
task.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
ttsTaskMapper.insertTtsTask(task);
|
||||||
|
|
||||||
|
// 异步调用外部TTS接口
|
||||||
|
callExternalTtsApi(task);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改TTS合成任务
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateTtsTask(TtsSynthesizeTask task) {
|
||||||
|
task.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
task.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
return ttsTaskMapper.updateTtsTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除TTS合成任务
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int deleteTtsTaskByIds(String[] ids) {
|
||||||
|
for (String id : ids) {
|
||||||
|
TtsSynthesizeTask task = ttsTaskMapper.selectTtsTaskById(id);
|
||||||
|
if (task != null && StringUtils.isNotEmpty(task.getAudioFilePath())) {
|
||||||
|
// 删除音频文件
|
||||||
|
try {
|
||||||
|
minioService.deleteFile(bucketName, task.getAudioFilePath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除音频文件失败: {}", task.getAudioFilePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ttsTaskMapper.deleteTtsTaskById(id);
|
||||||
|
}
|
||||||
|
return ids.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重生成TTS任务
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int regenerateTask(String taskId) {
|
||||||
|
TtsSynthesizeTask task = ttsTaskMapper.selectTtsTaskById(taskId);
|
||||||
|
if (task == null) {
|
||||||
|
throw new RuntimeException("任务不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态为待处理
|
||||||
|
task.setStatus("0");
|
||||||
|
task.setErrorMsg(null);
|
||||||
|
task.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
task.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
ttsTaskMapper.updateTtsTask(task);
|
||||||
|
|
||||||
|
// 重新调用外部TTS接口
|
||||||
|
callExternalTtsApi(task);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频文件流
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void getAudioStream(String taskId, HttpServletResponse response) {
|
||||||
|
TtsSynthesizeTask task = ttsTaskMapper.selectTtsTaskById(taskId);
|
||||||
|
if (task == null || StringUtils.isEmpty(task.getAudioFilePath())) {
|
||||||
|
throw new RuntimeException("音频文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream inputStream = minioService.getObject(bucketName, task.getAudioFilePath());
|
||||||
|
response.setContentType("audio/wav");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("audio_" + taskId + ".wav", "UTF-8"));
|
||||||
|
|
||||||
|
OutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取音频流失败", e);
|
||||||
|
throw new RuntimeException("获取音频流失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出TTS合成任务列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] exportTtsTaskList(TtsSynthesizeTask task) {
|
||||||
|
List<TtsSynthesizeTaskVo> list = ttsTaskMapper.selectTtsTaskVoList(task);
|
||||||
|
// TODO: 使用Excel工具类导出
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询看板统计数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getDashboardStats() {
|
||||||
|
Map<String, Object> todayStats = ttsTaskMapper.selectDashboardStats();
|
||||||
|
Map<String, Object> yesterdayStats = ttsTaskMapper.selectYesterdayStats();
|
||||||
|
|
||||||
|
// 计算环比
|
||||||
|
calculateGrowthRate(todayStats, yesterdayStats);
|
||||||
|
|
||||||
|
return todayStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按语种统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByLanguage() {
|
||||||
|
return ttsTaskMapper.selectStatsByLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按音色统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByVoice() {
|
||||||
|
return ttsTaskMapper.selectStatsByVoice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按情绪统计
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getStatsByEmotion() {
|
||||||
|
return ttsTaskMapper.selectStatsByEmotion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 近7日趋势
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getLast7DaysTrend() {
|
||||||
|
return ttsTaskMapper.selectLast7DaysTrend();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用外部TTS接口
|
||||||
|
*/
|
||||||
|
private void callExternalTtsApi(TtsSynthesizeTask task) {
|
||||||
|
try {
|
||||||
|
// 更新状态为合成中
|
||||||
|
task.setStatus("1");
|
||||||
|
ttsTaskMapper.updateTtsTask(task);
|
||||||
|
|
||||||
|
// 构建请求参数 - 只支持text, voice, speed, volume, pitch, sampleRate, format
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("text", task.getText());
|
||||||
|
params.put("voice", task.getVoice());
|
||||||
|
params.put("speed", task.getSpeed());
|
||||||
|
params.put("volume", task.getVolume());
|
||||||
|
params.put("pitch", task.getPitch());
|
||||||
|
params.put("sampleRate", task.getSampleRate());
|
||||||
|
params.put("format", task.getOutputFormat());
|
||||||
|
|
||||||
|
// 调用外部TTS接口,返回音频文件(字节数组)
|
||||||
|
byte[] audioBytes = HttpUtils.sendPostReturnBytes(externalTtsUrl, params);
|
||||||
|
|
||||||
|
if (audioBytes != null && audioBytes.length > 0) {
|
||||||
|
// 上传音频到Minio
|
||||||
|
String objectName = "tts/" + DateUtils.datePath() + "/" + task.getTaskCode() + ".wav";
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(audioBytes);
|
||||||
|
|
||||||
|
// 使用MinioService上传
|
||||||
|
minioService.uploadStream(bucketName, objectName, inputStream, audioBytes.length, "audio/wav");
|
||||||
|
|
||||||
|
// 更新任务状态
|
||||||
|
task.setStatus("2");
|
||||||
|
task.setAudioFilePath(objectName);
|
||||||
|
task.setFileSize((long) audioBytes.length);
|
||||||
|
|
||||||
|
// 估算音频时长(假设WAV格式,16bit采样)
|
||||||
|
Integer sampleRateInt = Integer.parseInt(task.getSampleRate());
|
||||||
|
double duration = audioBytes.length / (sampleRateInt * 2.0);
|
||||||
|
task.setAudioDuration(BigDecimal.valueOf(duration).setScale(2, BigDecimal.ROUND_HALF_UP));
|
||||||
|
ttsTaskMapper.updateTtsTask(task);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("外部TTS接口返回空数据");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调用外部TTS接口失败", e);
|
||||||
|
task.setStatus("3");
|
||||||
|
task.setErrorMsg(e.getMessage());
|
||||||
|
ttsTaskMapper.updateTtsTask(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存任务到语料库
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int saveToCorpus(String taskId, String categoryId) {
|
||||||
|
// 查询任务
|
||||||
|
TtsSynthesizeTask task = ttsTaskMapper.selectTtsTaskById(taskId);
|
||||||
|
if (task == null) {
|
||||||
|
throw new RuntimeException("任务不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有音频文件
|
||||||
|
if (StringUtils.isEmpty(task.getAudioFilePath())) {
|
||||||
|
throw new RuntimeException("任务尚未合成音频,无法保存到语料库");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建语料记录
|
||||||
|
CorpusInfo corpus = new CorpusInfo();
|
||||||
|
corpus.setId(IdUtil.fastSimpleUUID());
|
||||||
|
corpus.setCategoryId(categoryId);
|
||||||
|
corpus.setText(task.getText());
|
||||||
|
corpus.setLanguage(task.getLanguage());
|
||||||
|
corpus.setDialect(task.getDialect());
|
||||||
|
corpus.setEmotion(task.getEmotion());
|
||||||
|
corpus.setVoice(task.getVoice());
|
||||||
|
corpus.setAudioFilePath(task.getAudioFilePath());
|
||||||
|
corpus.setAudioDuration(task.getAudioDuration());
|
||||||
|
corpus.setFileSize(task.getFileSize());
|
||||||
|
corpus.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
corpus.setCreateTime(DateUtils.getNowDate());
|
||||||
|
|
||||||
|
return corpusInfoMapper.insertCorpus(corpus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算环比增长率
|
||||||
|
*/
|
||||||
|
private void calculateGrowthRate(Map<String, Object> today, Map<String, Object> yesterday) {
|
||||||
|
if (yesterday == null || yesterday.isEmpty()) {
|
||||||
|
today.put("totalTasksGrowth", "0%");
|
||||||
|
today.put("todayTasksGrowth", "0%");
|
||||||
|
today.put("avgDurationGrowth", "0%");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总任务数环比
|
||||||
|
Long todayTotal = ((Number) today.get("totalTasks")).longValue();
|
||||||
|
Long yesterdayTotal = ((Number) yesterday.get("totalTasks")).longValue();
|
||||||
|
today.put("totalTasksGrowth", calculatePercent(todayTotal, yesterdayTotal));
|
||||||
|
|
||||||
|
// 今日任务数环比
|
||||||
|
Long todayNew = ((Number) today.get("todayTasks")).longValue();
|
||||||
|
Long yesterdayNew = ((Number) yesterday.get("todayTasks")).longValue();
|
||||||
|
today.put("todayTasksGrowth", calculatePercent(todayNew, yesterdayNew));
|
||||||
|
|
||||||
|
// 平均时长环比
|
||||||
|
Double todayAvg = ((Number) today.get("avgDuration")).doubleValue();
|
||||||
|
Double yesterdayAvg = ((Number) yesterday.get("avgDuration")).doubleValue();
|
||||||
|
today.put("avgDurationGrowth", calculatePercentDouble(todayAvg, yesterdayAvg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String calculatePercent(Long current, Long previous) {
|
||||||
|
if (previous == 0) {
|
||||||
|
return current > 0 ? "+100%" : "0%";
|
||||||
|
}
|
||||||
|
double growth = (current - previous) * 100.0 / previous;
|
||||||
|
return String.format("%+.2f%%", growth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String calculatePercentDouble(Double current, Double previous) {
|
||||||
|
if (previous == 0 || previous.isNaN()) {
|
||||||
|
return "0%";
|
||||||
|
}
|
||||||
|
double growth = (current - previous) * 100.0 / previous;
|
||||||
|
return String.format("%+.2f%%", growth);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.cmvr.tts.mapper.CorpusCategoryMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.tts.domain.CorpusCategory" id="CorpusCategoryResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="parentId" column="parent_id"/>
|
||||||
|
<result property="categoryName" column="category_name"/>
|
||||||
|
<result property="sortOrder" column="sort_order"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="selectList" parameterType="com.cmvr.tts.domain.CorpusCategory" resultMap="CorpusCategoryResult">
|
||||||
|
select id, parent_id, category_name, sort_order, create_by, create_time, update_by, update_time, remark
|
||||||
|
from tts_corpus_category
|
||||||
|
<where>
|
||||||
|
<if test="parentId != null and parentId != ''"> and parent_id = #{parentId}</if>
|
||||||
|
<if test="categoryName != null and categoryName != ''"> and category_name like concat('%', #{categoryName}, '%')</if>
|
||||||
|
</where>
|
||||||
|
order by sort_order asc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insert" parameterType="com.cmvr.tts.domain.CorpusCategory">
|
||||||
|
insert into tts_corpus_category
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="parentId != null">parent_id,</if>
|
||||||
|
<if test="categoryName != null">category_name,</if>
|
||||||
|
<if test="sortOrder != null">sort_order,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="parentId != null">#{parentId},</if>
|
||||||
|
<if test="categoryName != null">#{categoryName},</if>
|
||||||
|
<if test="sortOrder != null">#{sortOrder},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateById" parameterType="com.cmvr.tts.domain.CorpusCategory">
|
||||||
|
update tts_corpus_category
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="parentId != null">parent_id = #{parentId},</if>
|
||||||
|
<if test="categoryName != null">category_name = #{categoryName},</if>
|
||||||
|
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteById" parameterType="String">
|
||||||
|
delete from tts_corpus_category where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
248
cmvr-iot-tts/src/main/resources/mapper/tts/CorpusInfoMapper.xml
Normal file
248
cmvr-iot-tts/src/main/resources/mapper/tts/CorpusInfoMapper.xml
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.cmvr.tts.mapper.CorpusInfoMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.tts.domain.CorpusInfo" id="CorpusResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="text" column="text"/>
|
||||||
|
<result property="pinyin" column="pinyin"/>
|
||||||
|
<result property="categoryId" column="category_id"/>
|
||||||
|
<result property="language" column="language"/>
|
||||||
|
<result property="dialect" column="dialect"/>
|
||||||
|
<result property="emotion" column="emotion"/>
|
||||||
|
<result property="voice" column="voice"/>
|
||||||
|
<result property="speaker" column="speaker"/>
|
||||||
|
<result property="scene" column="scene"/>
|
||||||
|
<result property="audioFilePath" column="audio_file_path"/>
|
||||||
|
<result property="audioDuration" column="audio_duration"/>
|
||||||
|
<result property="fileSize" column="file_size"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.tts.domain.vo.CorpusInfoVo" id="CorpusVoResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="text" column="text"/>
|
||||||
|
<result property="pinyin" column="pinyin"/>
|
||||||
|
<result property="categoryId" column="category_id"/>
|
||||||
|
<result property="categoryName" column="category_name"/>
|
||||||
|
<result property="language" column="language"/>
|
||||||
|
<result property="languageName" column="language_name"/>
|
||||||
|
<result property="dialect" column="dialect"/>
|
||||||
|
<result property="emotion" column="emotion"/>
|
||||||
|
<result property="emotionName" column="emotion_name"/>
|
||||||
|
<result property="voice" column="voice"/>
|
||||||
|
<result property="voiceName" column="voice_name"/>
|
||||||
|
<result property="speaker" column="speaker"/>
|
||||||
|
<result property="scene" column="scene"/>
|
||||||
|
<result property="audioFilePath" column="audio_file_path"/>
|
||||||
|
<result property="audioDuration" column="audio_duration"/>
|
||||||
|
<result property="fileSize" column="file_size"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectCorpusVo">
|
||||||
|
select c.id, c.text, c.pinyin, c.category_id, c.language, c.dialect, c.emotion,
|
||||||
|
c.voice, c.speaker, c.scene, c.audio_file_path, c.audio_duration, c.file_size,
|
||||||
|
c.create_by, c.create_time, c.update_by, c.update_time, c.remark,
|
||||||
|
cc.category_name as category_name,
|
||||||
|
dict_lang.dict_label as language_name,
|
||||||
|
dict_emotion.dict_label as emotion_name,
|
||||||
|
dict_voice.dict_label as voice_name
|
||||||
|
from tts_corpus_info c
|
||||||
|
left join tts_corpus_category cc on c.category_id = cc.id
|
||||||
|
left join sys_dict_data dict_lang on c.language = dict_lang.dict_value and dict_lang.dict_type = 'tts_language'
|
||||||
|
left join sys_dict_data dict_emotion on c.emotion = dict_emotion.dict_value and dict_emotion.dict_type = 'tts_emotion'
|
||||||
|
left join sys_dict_data dict_voice on c.voice = dict_voice.dict_value and dict_voice.dict_type = 'tts_voice'
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectCorpusList" parameterType="com.cmvr.tts.domain.CorpusInfo" resultMap="CorpusResult">
|
||||||
|
select id, text, pinyin, category_id, language, dialect, emotion, voice, speaker, scene,
|
||||||
|
audio_file_path, audio_duration, file_size,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
from tts_corpus_info
|
||||||
|
<where>
|
||||||
|
<if test="ids != null and ids.length > 0">
|
||||||
|
and id in
|
||||||
|
<foreach item="id" collection="ids" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="text != null and text != ''"> and text like concat('%', #{text}, '%')</if>
|
||||||
|
<if test="categoryId != null and categoryId != ''"> and category_id = #{categoryId}</if>
|
||||||
|
<if test="language != null and language != ''"> and language = #{language}</if>
|
||||||
|
<if test="dialect != null and dialect != ''"> and dialect = #{dialect}</if>
|
||||||
|
<if test="emotion != null and emotion != ''"> and emotion = #{emotion}</if>
|
||||||
|
<if test="voice != null and voice != ''"> and voice = #{voice}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCorpusById" parameterType="String" resultMap="CorpusResult">
|
||||||
|
select id, text, pinyin, category_id, language, dialect, emotion, voice, speaker, scene,
|
||||||
|
audio_file_path, audio_duration, file_size,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
from tts_corpus_info
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCorpusVoList" parameterType="com.cmvr.tts.domain.CorpusInfo" resultMap="CorpusVoResult">
|
||||||
|
<include refid="selectCorpusVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="ids != null and ids.length > 0">
|
||||||
|
and c.id in
|
||||||
|
<foreach item="id" collection="ids" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="text != null and text != ''"> and c.text like concat('%', #{text}, '%')</if>
|
||||||
|
<if test="categoryId != null and categoryId != ''"> and c.category_id = #{categoryId}</if>
|
||||||
|
<if test="language != null and language != ''"> and c.language = #{language}</if>
|
||||||
|
<if test="dialect != null and dialect != ''"> and c.dialect = #{dialect}</if>
|
||||||
|
<if test="emotion != null and emotion != ''"> and c.emotion = #{emotion}</if>
|
||||||
|
<if test="voice != null and voice != ''"> and c.voice = #{voice}</if>
|
||||||
|
</where>
|
||||||
|
order by c.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertCorpus" parameterType="com.cmvr.tts.domain.CorpusInfo">
|
||||||
|
insert into tts_corpus_info
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="text != null">text,</if>
|
||||||
|
<if test="pinyin != null">pinyin,</if>
|
||||||
|
<if test="categoryId != null">category_id,</if>
|
||||||
|
<if test="language != null">language,</if>
|
||||||
|
<if test="dialect != null">dialect,</if>
|
||||||
|
<if test="emotion != null">emotion,</if>
|
||||||
|
<if test="voice != null">voice,</if>
|
||||||
|
<if test="speaker != null">speaker,</if>
|
||||||
|
<if test="scene != null">scene,</if>
|
||||||
|
<if test="audioFilePath != null">audio_file_path,</if>
|
||||||
|
<if test="audioDuration != null">audio_duration,</if>
|
||||||
|
<if test="fileSize != null">file_size,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="text != null">#{text},</if>
|
||||||
|
<if test="pinyin != null">#{pinyin},</if>
|
||||||
|
<if test="categoryId != null">#{categoryId},</if>
|
||||||
|
<if test="language != null">#{language},</if>
|
||||||
|
<if test="dialect != null">#{dialect},</if>
|
||||||
|
<if test="emotion != null">#{emotion},</if>
|
||||||
|
<if test="voice != null">#{voice},</if>
|
||||||
|
<if test="speaker != null">#{speaker},</if>
|
||||||
|
<if test="scene != null">#{scene},</if>
|
||||||
|
<if test="audioFilePath != null">#{audioFilePath},</if>
|
||||||
|
<if test="audioDuration != null">#{audioDuration},</if>
|
||||||
|
<if test="fileSize != null">#{fileSize},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateCorpus" parameterType="com.cmvr.tts.domain.CorpusInfo">
|
||||||
|
update tts_corpus_info
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="text != null">text = #{text},</if>
|
||||||
|
<if test="pinyin != null">pinyin = #{pinyin},</if>
|
||||||
|
<if test="categoryId != null">category_id = #{categoryId},</if>
|
||||||
|
<if test="language != null">language = #{language},</if>
|
||||||
|
<if test="dialect != null">dialect = #{dialect},</if>
|
||||||
|
<if test="emotion != null">emotion = #{emotion},</if>
|
||||||
|
<if test="voice != null">voice = #{voice},</if>
|
||||||
|
<if test="speaker != null">speaker = #{speaker},</if>
|
||||||
|
<if test="scene != null">scene = #{scene},</if>
|
||||||
|
<if test="audioFilePath != null">audio_file_path = #{audioFilePath},</if>
|
||||||
|
<if test="audioDuration != null">audio_duration = #{audioDuration},</if>
|
||||||
|
<if test="fileSize != null">file_size = #{fileSize},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteCorpusById" parameterType="String">
|
||||||
|
delete from tts_corpus_info where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteCorpusByIds" parameterType="String">
|
||||||
|
delete from tts_corpus_info where id in
|
||||||
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectDashboardStats" resultType="java.util.Map">
|
||||||
|
select
|
||||||
|
count(*) as totalCorpus,
|
||||||
|
sum(case when date_format(create_time,'%Y-%m-%d') = curdate() then 1 else 0 end) as todayCorpus,
|
||||||
|
count(distinct language) as totalLanguages,
|
||||||
|
count(distinct voice) as totalVoices,
|
||||||
|
avg(audio_duration) as avgDuration
|
||||||
|
from tts_corpus_info
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectYesterdayStats" resultType="java.util.Map">
|
||||||
|
select
|
||||||
|
count(*) as totalCorpus,
|
||||||
|
sum(case when date_format(create_time,'%Y-%m-%d') = date_sub(curdate(), interval 1 day) then 1 else 0 end) as todayCorpus,
|
||||||
|
count(distinct language) as totalLanguages,
|
||||||
|
count(distinct voice) as totalVoices,
|
||||||
|
avg(audio_duration) as avgDuration
|
||||||
|
from tts_corpus_info
|
||||||
|
where date_format(create_time,'%Y-%m-%d') <= date_sub(curdate(), interval 1 day)
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByLanguage" resultType="java.util.Map">
|
||||||
|
select language as name, count(*) as value
|
||||||
|
from tts_corpus_info
|
||||||
|
group by language
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByDialect" resultType="java.util.Map">
|
||||||
|
select dialect as name, count(*) as value
|
||||||
|
from tts_corpus_info
|
||||||
|
where dialect is not null
|
||||||
|
group by dialect
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByEmotion" resultType="java.util.Map">
|
||||||
|
select emotion as name, count(*) as value
|
||||||
|
from tts_corpus_info
|
||||||
|
where emotion is not null
|
||||||
|
group by emotion
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByCategory" resultType="java.util.Map">
|
||||||
|
select cc.category_name as name, count(c.id) as value
|
||||||
|
from tts_corpus_category cc
|
||||||
|
left join tts_corpus_info c on cc.id = c.category_id
|
||||||
|
group by cc.id, cc.category_name
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,260 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.cmvr.tts.mapper.TtsSynthesizeTaskMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.tts.domain.TtsSynthesizeTask" id="TtsTaskResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
<result property="taskCode" column="task_code"/>
|
||||||
|
<result property="text" column="text"/>
|
||||||
|
<result property="language" column="language"/>
|
||||||
|
<result property="dialect" column="dialect"/>
|
||||||
|
<result property="voice" column="voice"/>
|
||||||
|
<result property="emotion" column="emotion"/>
|
||||||
|
<result property="speed" column="speed"/>
|
||||||
|
<result property="volume" column="volume"/>
|
||||||
|
<result property="pitch" column="pitch"/>
|
||||||
|
<result property="sampleRate" column="sample_rate"/>
|
||||||
|
<result property="outputFormat" column="output_format"/>
|
||||||
|
<result property="styleTemplate" column="style_template"/>
|
||||||
|
<result property="status" column="status"/>
|
||||||
|
<result property="audioFilePath" column="audio_file_path"/>
|
||||||
|
<result property="audioDuration" column="audio_duration"/>
|
||||||
|
<result property="fileSize" column="file_size"/>
|
||||||
|
<result property="errorMsg" column="error_msg"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="com.cmvr.tts.domain.vo.TtsSynthesizeTaskVo" id="TtsTaskVoResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="taskCode" column="task_code"/>
|
||||||
|
<result property="text" column="text"/>
|
||||||
|
<result property="language" column="language"/>
|
||||||
|
<result property="languageName" column="language_name"/>
|
||||||
|
<result property="dialect" column="dialect"/>
|
||||||
|
<result property="voice" column="voice"/>
|
||||||
|
<result property="voiceName" column="voice_name"/>
|
||||||
|
<result property="emotion" column="emotion"/>
|
||||||
|
<result property="emotionName" column="emotion_name"/>
|
||||||
|
<result property="speed" column="speed"/>
|
||||||
|
<result property="volume" column="volume"/>
|
||||||
|
<result property="pitch" column="pitch"/>
|
||||||
|
<result property="sampleRate" column="sample_rate"/>
|
||||||
|
<result property="outputFormat" column="output_format"/>
|
||||||
|
<result property="styleTemplate" column="style_template"/>
|
||||||
|
<result property="status" column="status"/>
|
||||||
|
<result property="statusName" column="status_name"/>
|
||||||
|
<result property="audioFilePath" column="audio_file_path"/>
|
||||||
|
<result property="audioDuration" column="audio_duration"/>
|
||||||
|
<result property="fileSize" column="file_size"/>
|
||||||
|
<result property="errorMsg" column="error_msg"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectTtsTaskVo">
|
||||||
|
select t.id, t.task_code, t.text, t.language, t.dialect, t.voice, t.emotion,
|
||||||
|
t.speed, t.volume, t.pitch, t.sample_rate, t.output_format, t.style_template,
|
||||||
|
t.status, t.audio_file_path, t.audio_duration, t.file_size, t.error_msg,
|
||||||
|
t.create_by, t.create_time, t.update_by, t.update_time, t.remark,
|
||||||
|
dict_lang.dict_label as language_name,
|
||||||
|
dict_voice.dict_label as voice_name,
|
||||||
|
dict_emotion.dict_label as emotion_name,
|
||||||
|
case t.status
|
||||||
|
when '0' then '待处理'
|
||||||
|
when '1' then '合成中'
|
||||||
|
when '2' then '成功已完成'
|
||||||
|
when '3' then '失败'
|
||||||
|
else '未知'
|
||||||
|
end as status_name
|
||||||
|
from tts_synthesize_task t
|
||||||
|
left join sys_dict_data dict_lang on t.language = dict_lang.dict_value and dict_lang.dict_type = 'tts_language'
|
||||||
|
left join sys_dict_data dict_voice on t.voice = dict_voice.dict_value and dict_voice.dict_type = 'tts_voice'
|
||||||
|
left join sys_dict_data dict_emotion on t.emotion = dict_emotion.dict_value and dict_emotion.dict_type = 'tts_emotion'
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectTtsTaskList" parameterType="com.cmvr.tts.domain.TtsSynthesizeTask" resultMap="TtsTaskResult">
|
||||||
|
select id, task_code, text, language, dialect, voice, emotion, speed, volume, pitch,
|
||||||
|
sample_rate, output_format, style_template, status, audio_file_path, audio_duration,
|
||||||
|
file_size, error_msg, create_by, create_time, update_by, update_time, remark
|
||||||
|
from tts_synthesize_task
|
||||||
|
<where>
|
||||||
|
<if test="taskCode != null and taskCode != ''"> and task_code = #{taskCode}</if>
|
||||||
|
<if test="text != null and text != ''"> and text like concat('%', #{text}, '%')</if>
|
||||||
|
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||||
|
<if test="language != null and language != ''"> and language = #{language}</if>
|
||||||
|
<if test="voice != null and voice != ''"> and voice = #{voice}</if>
|
||||||
|
</where>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectTtsTaskById" parameterType="String" resultMap="TtsTaskResult">
|
||||||
|
select id, task_code, text, language, dialect, voice, emotion, speed, volume, pitch,
|
||||||
|
sample_rate, output_format, style_template, status, audio_file_path, audio_duration,
|
||||||
|
file_size, error_msg, create_by, create_time, update_by, update_time, remark
|
||||||
|
from tts_synthesize_task
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectTtsTaskVoList" parameterType="com.cmvr.tts.domain.TtsSynthesizeTask" resultMap="TtsTaskVoResult">
|
||||||
|
<include refid="selectTtsTaskVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="taskCode != null and taskCode != ''"> and t.task_code = #{taskCode}</if>
|
||||||
|
<if test="text != null and text != ''"> and t.text like concat('%', #{text}, '%')</if>
|
||||||
|
<if test="status != null and status != ''"> and t.status = #{status}</if>
|
||||||
|
<if test="params.beginTime != null and params.beginTime != ''">
|
||||||
|
and date_format(t.create_time,'%Y%m%d') >= date_format(#{params.beginTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
<if test="params.endTime != null and params.endTime != ''">
|
||||||
|
and date_format(t.create_time,'%Y%m%d') <= date_format(#{params.endTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by t.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertTtsTask" parameterType="com.cmvr.tts.domain.TtsSynthesizeTask">
|
||||||
|
insert into tts_synthesize_task
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
<if test="taskCode != null">task_code,</if>
|
||||||
|
<if test="text != null">text,</if>
|
||||||
|
<if test="language != null">language,</if>
|
||||||
|
<if test="dialect != null">dialect,</if>
|
||||||
|
<if test="voice != null">voice,</if>
|
||||||
|
<if test="emotion != null">emotion,</if>
|
||||||
|
<if test="speed != null">speed,</if>
|
||||||
|
<if test="volume != null">volume,</if>
|
||||||
|
<if test="pitch != null">pitch,</if>
|
||||||
|
<if test="sampleRate != null">sample_rate,</if>
|
||||||
|
<if test="outputFormat != null">output_format,</if>
|
||||||
|
<if test="styleTemplate != null">style_template,</if>
|
||||||
|
<if test="status != null">status,</if>
|
||||||
|
<if test="audioFilePath != null">audio_file_path,</if>
|
||||||
|
<if test="audioDuration != null">audio_duration,</if>
|
||||||
|
<if test="fileSize != null">file_size,</if>
|
||||||
|
<if test="errorMsg != null">error_msg,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
<if test="taskCode != null">#{taskCode},</if>
|
||||||
|
<if test="text != null">#{text},</if>
|
||||||
|
<if test="language != null">#{language},</if>
|
||||||
|
<if test="dialect != null">#{dialect},</if>
|
||||||
|
<if test="voice != null">#{voice},</if>
|
||||||
|
<if test="emotion != null">#{emotion},</if>
|
||||||
|
<if test="speed != null">#{speed},</if>
|
||||||
|
<if test="volume != null">#{volume},</if>
|
||||||
|
<if test="pitch != null">#{pitch},</if>
|
||||||
|
<if test="sampleRate != null">#{sampleRate},</if>
|
||||||
|
<if test="outputFormat != null">#{outputFormat},</if>
|
||||||
|
<if test="styleTemplate != null">#{styleTemplate},</if>
|
||||||
|
<if test="status != null">#{status},</if>
|
||||||
|
<if test="audioFilePath != null">#{audioFilePath},</if>
|
||||||
|
<if test="audioDuration != null">#{audioDuration},</if>
|
||||||
|
<if test="fileSize != null">#{fileSize},</if>
|
||||||
|
<if test="errorMsg != null">#{errorMsg},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateTtsTask" parameterType="com.cmvr.tts.domain.TtsSynthesizeTask">
|
||||||
|
update tts_synthesize_task
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="taskCode != null">task_code = #{taskCode},</if>
|
||||||
|
<if test="text != null">text = #{text},</if>
|
||||||
|
<if test="language != null">language = #{language},</if>
|
||||||
|
<if test="dialect != null">dialect = #{dialect},</if>
|
||||||
|
<if test="voice != null">voice = #{voice},</if>
|
||||||
|
<if test="emotion != null">emotion = #{emotion},</if>
|
||||||
|
<if test="speed != null">speed = #{speed},</if>
|
||||||
|
<if test="volume != null">volume = #{volume},</if>
|
||||||
|
<if test="pitch != null">pitch = #{pitch},</if>
|
||||||
|
<if test="sampleRate != null">sample_rate = #{sampleRate},</if>
|
||||||
|
<if test="outputFormat != null">output_format = #{outputFormat},</if>
|
||||||
|
<if test="styleTemplate != null">style_template = #{styleTemplate},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
<if test="audioFilePath != null">audio_file_path = #{audioFilePath},</if>
|
||||||
|
<if test="audioDuration != null">audio_duration = #{audioDuration},</if>
|
||||||
|
<if test="fileSize != null">file_size = #{fileSize},</if>
|
||||||
|
<if test="errorMsg != null">error_msg = #{errorMsg},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteTtsTaskById" parameterType="String">
|
||||||
|
delete from tts_synthesize_task where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectDashboardStats" resultType="java.util.Map">
|
||||||
|
select
|
||||||
|
count(*) as totalTasks,
|
||||||
|
sum(case when date_format(create_time,'%Y-%m-%d') = curdate() then 1 else 0 end) as todayTasks,
|
||||||
|
count(distinct language) as totalLanguages,
|
||||||
|
count(distinct voice) as totalVoices,
|
||||||
|
avg(audio_duration) as avgDuration
|
||||||
|
from tts_synthesize_task
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectYesterdayStats" resultType="java.util.Map">
|
||||||
|
select
|
||||||
|
count(*) as totalTasks,
|
||||||
|
sum(case when date_format(create_time,'%Y-%m-%d') = date_sub(curdate(), interval 1 day) then 1 else 0 end) as todayTasks,
|
||||||
|
count(distinct language) as totalLanguages,
|
||||||
|
count(distinct voice) as totalVoices,
|
||||||
|
avg(audio_duration) as avgDuration
|
||||||
|
from tts_synthesize_task
|
||||||
|
where date_format(create_time,'%Y-%m-%d') <= date_sub(curdate(), interval 1 day)
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByLanguage" resultType="java.util.Map">
|
||||||
|
select language as name, count(*) as value
|
||||||
|
from tts_synthesize_task
|
||||||
|
group by language
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByVoice" resultType="java.util.Map">
|
||||||
|
select voice as name, count(*) as value
|
||||||
|
from tts_synthesize_task
|
||||||
|
group by voice
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectStatsByEmotion" resultType="java.util.Map">
|
||||||
|
select emotion as name, count(*) as value
|
||||||
|
from tts_synthesize_task
|
||||||
|
group by emotion
|
||||||
|
order by value desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectLast7DaysTrend" resultType="java.util.Map">
|
||||||
|
select date_format(create_time,'%Y-%m-%d') as date, count(*) as value
|
||||||
|
from tts_synthesize_task
|
||||||
|
where create_time >= date_sub(curdate(), interval 6 day)
|
||||||
|
group by date_format(create_time,'%Y-%m-%d')
|
||||||
|
order by date
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
8
pom.xml
8
pom.xml
@ -316,6 +316,13 @@
|
|||||||
<version>${cmvr-iot.version}</version>
|
<version>${cmvr-iot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 智能座舱语音语料采集-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cmvr</groupId>
|
||||||
|
<artifactId>cmvr-iot-tts</artifactId>
|
||||||
|
<version>${cmvr-iot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- huTool-->
|
<!-- huTool-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
@ -354,6 +361,7 @@
|
|||||||
<module>cmvr-iot-evaluation</module>
|
<module>cmvr-iot-evaluation</module>
|
||||||
<module>cmvr-iot-inspection</module>
|
<module>cmvr-iot-inspection</module>
|
||||||
<module>cmvr-iot-aima</module>
|
<module>cmvr-iot-aima</module>
|
||||||
|
<module>cmvr-iot-tts</module>
|
||||||
</modules>
|
</modules>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
|||||||
77
sql/tts_corpus_module.sql
Normal file
77
sql/tts_corpus_module.sql
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- 智能座舱语音语料采集模块数据库表结构
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- 1. TTS合成任务表
|
||||||
|
DROP TABLE IF EXISTS `tts_synthesize_task`;
|
||||||
|
CREATE TABLE `tts_synthesize_task` (
|
||||||
|
`id` varchar(64) NOT NULL COMMENT '主键ID',
|
||||||
|
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`task_code` varchar(64) DEFAULT NULL COMMENT '任务编码',
|
||||||
|
`text` text NOT NULL COMMENT '合成文本',
|
||||||
|
`language` varchar(20) DEFAULT 'zh-CN' COMMENT '语种',
|
||||||
|
`dialect` varchar(20) DEFAULT NULL COMMENT '方言',
|
||||||
|
`voice` varchar(50) DEFAULT NULL COMMENT '音色',
|
||||||
|
`emotion` varchar(20) DEFAULT NULL COMMENT '情绪',
|
||||||
|
`speed` decimal(5,2) DEFAULT '1.00' COMMENT '语速',
|
||||||
|
`volume` decimal(5,2) DEFAULT '1.00' COMMENT '音量',
|
||||||
|
`pitch` decimal(5,2) DEFAULT '1.00' COMMENT '音高',
|
||||||
|
`sample_rate` int(11) DEFAULT null COMMENT '采样率',
|
||||||
|
`output_format` varchar(20) DEFAULT 'wav' COMMENT '输出格式',
|
||||||
|
`style_template` varchar(50) DEFAULT NULL COMMENT '说话风格模板名称',
|
||||||
|
`status` char(1) DEFAULT '0' COMMENT '任务状态(0待处理 1合成中 2成功已完成 3失败)',
|
||||||
|
`audio_file_path` varchar(500) DEFAULT NULL COMMENT '音频文件存储路径',
|
||||||
|
`audio_duration` decimal(10,2) DEFAULT NULL COMMENT '音频时长(秒)',
|
||||||
|
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||||
|
`error_msg` text COMMENT '失败原因',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_task_code` (`task_code`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='TTS合成任务表';
|
||||||
|
|
||||||
|
-- 2. 语料分类树形表
|
||||||
|
DROP TABLE IF EXISTS `tts_corpus_category`;
|
||||||
|
CREATE TABLE `tts_corpus_category` (
|
||||||
|
`id` varchar(64) NOT NULL COMMENT '主键ID',
|
||||||
|
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`parent_id` varchar(64) DEFAULT '0' COMMENT '父分类ID',
|
||||||
|
`category_name` varchar(100) NOT NULL COMMENT '分类名称',
|
||||||
|
`sort_order` int(11) DEFAULT '0' COMMENT '排序',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_parent_id` (`parent_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='语料分类树形表';
|
||||||
|
|
||||||
|
-- 3. 车载语料数据表
|
||||||
|
DROP TABLE IF EXISTS `tts_corpus_info`;
|
||||||
|
CREATE TABLE `tts_corpus_info` (
|
||||||
|
`id` varchar(64) NOT NULL COMMENT '主键ID',
|
||||||
|
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`text` text NOT NULL COMMENT '文本内容',
|
||||||
|
`pinyin` varchar(500) DEFAULT NULL COMMENT '拼音',
|
||||||
|
`category_id` varchar(64) DEFAULT NULL COMMENT '所属分类ID',
|
||||||
|
`language` varchar(20) DEFAULT 'zh-CN' COMMENT '语种',
|
||||||
|
`dialect` varchar(20) DEFAULT NULL COMMENT '方言',
|
||||||
|
`emotion` varchar(20) DEFAULT NULL COMMENT '情绪',
|
||||||
|
`voice` varchar(50) DEFAULT NULL COMMENT '音色',
|
||||||
|
`speaker` varchar(50) DEFAULT NULL COMMENT '说话人',
|
||||||
|
`scene` varchar(100) DEFAULT NULL COMMENT '适用场景',
|
||||||
|
`audio_file_path` varchar(500) DEFAULT NULL COMMENT '音频文件路径',
|
||||||
|
`audio_duration` decimal(10,2) DEFAULT NULL COMMENT '音频时长(秒)',
|
||||||
|
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_category_id` (`category_id`),
|
||||||
|
KEY `idx_language` (`language`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='车载语料数据表';
|
||||||
Loading…
Reference in New Issue
Block a user