优化录音片段
This commit is contained in:
@@ -129,3 +129,6 @@ hikari:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.rj.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rj.common.AudioManagementConstants;
|
||||
@@ -337,7 +338,7 @@ public class AudioFileController {
|
||||
// 关联上传的文件到audio_management表
|
||||
associateAudioManagement(requestBody);
|
||||
|
||||
// 处理Audio数据 验证文件、保存文件到本地、保存信息到数据库
|
||||
// 处理Audio数据 验证文件、保存文件到本地、保存信息到数据库, 计算录音 总时长 ,标记为 服务结束
|
||||
Map<String, Object> processResult = handleAudioDataType(requestBody, audioFile);
|
||||
|
||||
log.info("检测到数据类型Audio-----------处理结束-------------------");
|
||||
@@ -1180,25 +1181,28 @@ public class AudioFileController {
|
||||
|
||||
// 8. 检查数据库中是否已存在相同的分段记录
|
||||
if (isSegmentExists(segment)) {
|
||||
log.info("音频分段记录已存在,跳过保存。父录音ID: {}, chunkIndex: {}, deviceNo: {}, startTime: {}",
|
||||
segment.getParentId(), segment.getChunkIndex(), segment.getDeviceNo(), segment.getStartTime());
|
||||
log.info("音频分段记录已存在,跳过保存。父录音ID: {}, chunkIndex: {}, deviceNo: {}, filename: {}",
|
||||
segment.getParentId(), segment.getChunkIndex(), segment.getDeviceNo(), segment.getAudioFileOriginalName());
|
||||
// 标记为已保存,避免后续重复检查
|
||||
requestBody.put(segmentSavedKey, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 9. 从AudioManagement中获取录音名称(如果存在父录音)
|
||||
// 9. 在保存之前就设置标记,防止并发保存
|
||||
requestBody.put(segmentSavedKey, true);
|
||||
|
||||
// 10. 从AudioManagement中获取录音名称(如果存在父录音)
|
||||
if (segment.getParentId() != null) {
|
||||
populateSegmentFromAudioManagement(segment, segment.getParentId());
|
||||
// populateSegmentFromAudioManagement(segment, segment.getParentId());
|
||||
}
|
||||
|
||||
// 10. 设置通用字段
|
||||
// 11. 设置通用字段
|
||||
LocalDateTime now = TimeZoneUtils.now();
|
||||
segment.setCreateTime(now);
|
||||
segment.setUploadTime(now);
|
||||
segment.setRecordingTime(now);
|
||||
|
||||
// 11. 设置默认状态
|
||||
// 12. 设置默认状态
|
||||
if (segment.getUploadStatus() == null) {
|
||||
segment.setUploadStatus("已上传");
|
||||
}
|
||||
@@ -1209,29 +1213,68 @@ public class AudioFileController {
|
||||
segment.setIsMerged(false);
|
||||
}
|
||||
|
||||
// 12. 保存到数据库
|
||||
// 13. 保存到数据库
|
||||
audioManagementSegmentsService.save(segment);
|
||||
log.info("音频分段记录保存成功,ID: {}, 父录音ID: {}, 设备号: {}, 文件名: {}",
|
||||
segment.getId(), segment.getParentId(), segment.getDeviceNo(), segment.getAudioFileOriginalName());
|
||||
// 如果文件名包含结束标志,修改主记录为结束状态
|
||||
if(segment.getAudioFileOriginalName().contains("-Z")){
|
||||
|
||||
LambdaQueryWrapper<AudioManagementSegments> audioQuery = new LambdaQueryWrapper<>();
|
||||
audioQuery.eq(AudioManagementSegments::getParentId, deviceManagement.getId()) ; // 按创建时间倒序
|
||||
List<AudioManagementSegments> segmentsList = audioManagementSegmentsService.list(audioQuery);
|
||||
BigDecimal total = new BigDecimal(0);
|
||||
segmentsList.forEach(segment2 ->{
|
||||
total.add(segment2.getDuration());//分钟
|
||||
});
|
||||
|
||||
AudioManagement audioManagement = new AudioManagement();
|
||||
audioManagement.setDuration(total);
|
||||
audioManagement.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_IN_SERVICE);
|
||||
audioManagement.setUpdateTime(LocalDateTime.now());
|
||||
serviceManager.getAudioManagementService().save(audioManagement);
|
||||
|
||||
// 14. 更新AudioManagement记录(需要设置租户上下文)
|
||||
if (segment.getParentId() != null) {
|
||||
// 保存原来的租户ID,用于后续恢复
|
||||
String originalTenantId = TenantContextHolder.getTenantId();
|
||||
String tenantId = segment.getTenantId();
|
||||
|
||||
// 如果segment中没有tenantId,尝试从DeviceManagement中获取
|
||||
if (tenantId == null || tenantId.trim().isEmpty()) {
|
||||
// deviceManagement 已在方法前面定义(第1163行)
|
||||
if (deviceManagement != null && deviceManagement.getTenantId() != null) {
|
||||
tenantId = deviceManagement.getTenantId();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 设置租户ID到上下文,使后续查询和更新自动使用该租户ID
|
||||
if (tenantId != null && !tenantId.trim().isEmpty()) {
|
||||
TenantContextHolder.setTenantId(tenantId);
|
||||
log.info("设置租户ID到上下文: {}", tenantId);
|
||||
}
|
||||
|
||||
AudioManagement audioManagement = new AudioManagement();
|
||||
audioManagement.setId(segment.getParentId());
|
||||
|
||||
// 如果文件名包含结束标志,修改主记录为结束状态
|
||||
if(segment.getAudioFileOriginalName().contains("-Z")){
|
||||
audioManagement.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_SERVICE_FINISH);
|
||||
}
|
||||
|
||||
AudioManagement byId = serviceManager.getAudioManagementService().getById(segment.getParentId());
|
||||
if (byId != null) {
|
||||
// 累加时长
|
||||
BigDecimal currentDuration = byId.getDuration();
|
||||
if (currentDuration == null) {
|
||||
currentDuration = BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal segmentDuration = segment.getDuration();
|
||||
if (segmentDuration == null) {
|
||||
segmentDuration = BigDecimal.ZERO;
|
||||
}
|
||||
audioManagement.setDuration(currentDuration.add(segmentDuration));
|
||||
audioManagement.setUpdateTime(LocalDateTime.now());
|
||||
serviceManager.getAudioManagementService().updateById(audioManagement);
|
||||
log.info("成功更新AudioManagement记录,ID: {}, 累计时长: {}", segment.getParentId(), audioManagement.getDuration());
|
||||
} else {
|
||||
log.warn("未找到AudioManagement记录,ID: {}", segment.getParentId());
|
||||
}
|
||||
} finally {
|
||||
// 恢复原来的租户ID
|
||||
if (originalTenantId != null) {
|
||||
TenantContextHolder.setTenantId(originalTenantId);
|
||||
} else {
|
||||
TenantContextHolder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 13. 标记为已保存,避免重复保存
|
||||
requestBody.put(segmentSavedKey, true);
|
||||
// 标记已在保存前设置(第1190行),这里不需要再次设置
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("保存音频分段记录到audio_management_segments表失败", e);
|
||||
@@ -1241,19 +1284,41 @@ public class AudioFileController {
|
||||
|
||||
/**
|
||||
* 检查音频分段记录是否已存在
|
||||
* 判断标准:parent_id + chunk_index + deviceNo + start_time(如果都存在)
|
||||
* 判断标准:优先使用 audio_file_original_name,备用:parent_id + chunk_index + deviceNo + start_time(如果都存在)
|
||||
*
|
||||
* @param segment 音频分段对象
|
||||
* @return true表示已存在,false表示不存在
|
||||
*/
|
||||
private boolean isSegmentExists(AudioManagementSegments segment) {
|
||||
// 保存原来的租户ID,用于后续恢复
|
||||
String originalTenantId = TenantContextHolder.getTenantId();
|
||||
String tenantId = segment.getTenantId();
|
||||
|
||||
try {
|
||||
// 设置租户ID到上下文,使后续查询自动使用该租户ID
|
||||
if (tenantId != null && !tenantId.trim().isEmpty()) {
|
||||
TenantContextHolder.setTenantId(tenantId);
|
||||
log.debug("设置租户ID到上下文用于检查重复记录: {}", tenantId);
|
||||
}
|
||||
|
||||
// 优先使用 audio_file_original_name 作为主要检查条件(最可靠)
|
||||
if (segment.getAudioFileOriginalName() != null && !segment.getAudioFileOriginalName().isEmpty()) {
|
||||
LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(AudioManagementSegments::getAudioFileOriginalName, segment.getAudioFileOriginalName());
|
||||
|
||||
|
||||
long count = audioManagementSegmentsService.count(queryWrapper);
|
||||
if (count > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果缺少关键字段,无法判断,返回false(允许保存)
|
||||
if (segment.getParentId() == null || segment.getParentId().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
// 构建查询条件(备用检查:使用其他字段组合)
|
||||
LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(AudioManagementSegments::getParentId, segment.getParentId());
|
||||
|
||||
@@ -1288,6 +1353,13 @@ public class AudioFileController {
|
||||
log.warn("检查音频分段记录是否存在时发生异常,将允许保存: {}", e.getMessage());
|
||||
// 如果检查失败,允许保存(避免因为检查逻辑问题导致数据丢失)
|
||||
return false;
|
||||
} finally {
|
||||
// 恢复原来的租户ID
|
||||
if (originalTenantId != null) {
|
||||
TenantContextHolder.setTenantId(originalTenantId);
|
||||
} else {
|
||||
TenantContextHolder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1487,47 +1559,6 @@ public class AudioFileController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从AudioManagement中获取录音名称等信息
|
||||
*
|
||||
* @param segment 音频分段对象
|
||||
* @param parentId 父录音ID
|
||||
*/
|
||||
private void populateSegmentFromAudioManagement(AudioManagementSegments segment, String parentId) {
|
||||
try {
|
||||
AudioManagement audioManagement = serviceManager.getAudioManagementService().getById(parentId);
|
||||
if (audioManagement != null) {
|
||||
// 如果录音名称为空,使用父录音的名称
|
||||
if (segment.getRecordingName() == null || segment.getRecordingName().isEmpty()) {
|
||||
segment.setRecordingName(audioManagement.getRecordingName());
|
||||
}
|
||||
|
||||
// 如果销售信息为空,使用父录音的销售信息
|
||||
if (segment.getSalesPhone() == null || segment.getSalesPhone().isEmpty()) {
|
||||
segment.setSalesPhone(audioManagement.getSalesPhone());
|
||||
}
|
||||
if (segment.getSalesName() == null || segment.getSalesName().isEmpty()) {
|
||||
segment.setSalesName(audioManagement.getSalesName());
|
||||
}
|
||||
|
||||
// 如果经销商信息为空,使用父录音的经销商信息
|
||||
if (segment.getDealershipId() == null || segment.getDealershipId().isEmpty()) {
|
||||
segment.setDealershipId(audioManagement.getDealershipId());
|
||||
}
|
||||
if (segment.getDealershipName() == null || segment.getDealershipName().isEmpty()) {
|
||||
segment.setDealershipName(audioManagement.getDealershipName());
|
||||
}
|
||||
|
||||
// 如果租户ID为空,使用父录音的租户ID
|
||||
if (segment.getTenantId() == null || segment.getTenantId().isEmpty()) {
|
||||
segment.setTenantId(audioManagement.getTenantId());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("从AudioManagement获取信息失败,parentId: {}", parentId, e);
|
||||
// 不影响主流程,只记录日志
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取请求头信息
|
||||
@@ -2064,13 +2095,139 @@ public class AudioFileController {
|
||||
|
||||
/**
|
||||
* 处理AudioText数据类型(语音转写)
|
||||
* 根据deviceNo和filename查询并更新audio_management_segments表的recording_text字段
|
||||
* recording_text的值等于所有segments中text字段的累加
|
||||
*/
|
||||
private Map<String, Object> handleAudioTextDataType(Map<String, Object> requestBody) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
log.info("语音转写处理功能待实现,数据: {}", requestBody);
|
||||
result.put("success", true);
|
||||
result.put("message", "语音转写接收成功(处理功能待实现)");
|
||||
return result;
|
||||
log.info("开始处理AudioText数据类型(语音转写)");
|
||||
|
||||
try {
|
||||
// 1. 提取data字段
|
||||
Map<String, Object> dataMap = extractDataField(requestBody);
|
||||
if (dataMap == null || dataMap.isEmpty()) {
|
||||
log.warn("AudioText数据中data字段为空或不存在");
|
||||
return createErrorResult("AudioText数据中data字段为空或不存在");
|
||||
}
|
||||
|
||||
// 2. 提取deviceNo和filename
|
||||
String deviceNo = extractStringFieldWithFallback(requestBody, dataMap, "deviceNo");
|
||||
String filename = extractStringField(dataMap, "filename");
|
||||
|
||||
if (deviceNo == null || deviceNo.trim().isEmpty()) {
|
||||
log.warn("AudioText数据中deviceNo字段为空");
|
||||
return createErrorResult("AudioText数据中deviceNo字段为空");
|
||||
}
|
||||
|
||||
if (filename == null || filename.trim().isEmpty()) {
|
||||
log.warn("AudioText数据中filename字段为空");
|
||||
return createErrorResult("AudioText数据中filename字段为空");
|
||||
}
|
||||
|
||||
log.info("处理语音转写数据,deviceNo: {}, filename: {}", deviceNo, filename);
|
||||
|
||||
// 3. 提取segments数组
|
||||
Object segmentsObj = dataMap.get("segments");
|
||||
if (segmentsObj == null) {
|
||||
log.warn("AudioText数据中segments字段为空");
|
||||
return createErrorResult("AudioText数据中segments字段为空");
|
||||
}
|
||||
|
||||
// 4. 解析segments并累加text字段
|
||||
List<Map<String, Object>> segmentsList;
|
||||
try {
|
||||
segmentsList = objectMapper.convertValue(segmentsObj,
|
||||
new TypeReference<List<Map<String, Object>>>() {});
|
||||
} catch (Exception e) {
|
||||
log.error("解析segments字段失败", e);
|
||||
return createErrorResult("解析segments字段失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (segmentsList == null || segmentsList.isEmpty()) {
|
||||
log.warn("AudioText数据中segments数组为空");
|
||||
return createErrorResult("AudioText数据中segments数组为空");
|
||||
}
|
||||
|
||||
// 5. 累加所有segments中的text字段
|
||||
StringBuilder recordingTextBuilder = new StringBuilder();
|
||||
for (Map<String, Object> segment : segmentsList) {
|
||||
Object textObj = segment.get("text");
|
||||
if (textObj != null) {
|
||||
String text = textObj.toString().trim();
|
||||
if (!text.isEmpty()) {
|
||||
if (recordingTextBuilder.length() > 0) {
|
||||
recordingTextBuilder.append(" ");
|
||||
}
|
||||
recordingTextBuilder.append(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String recordingText = recordingTextBuilder.toString();
|
||||
log.info("累加的录音文本长度: {} 字符", recordingText.length());
|
||||
|
||||
// 6. 获取DeviceManagement和tenantId(参考插入时的处理逻辑)
|
||||
DeviceManagement deviceManagement = (DeviceManagement) requestBody.get(deviceKey);
|
||||
|
||||
// 如果requestBody中没有DeviceManagement,则根据deviceNo查询
|
||||
if (deviceManagement == null) {
|
||||
try {
|
||||
deviceManagement = deviceManagementMapper.selectByDeviceCodeIgnoreTenant(deviceNo);
|
||||
if (deviceManagement != null) {
|
||||
requestBody.put(deviceKey, deviceManagement);
|
||||
log.info("根据设备编号 {} 查询到DeviceManagement", deviceNo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询DeviceManagement失败,设备编号: {}", deviceNo, e);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 设置租户ID到上下文,使后续查询自动使用该租户ID(参考associateAudioManagement的处理逻辑)
|
||||
String originalTenantId = TenantContextHolder.getTenantId();
|
||||
String tenantId = null;
|
||||
|
||||
if (deviceManagement != null && deviceManagement.getTenantId() != null) {
|
||||
tenantId = deviceManagement.getTenantId();
|
||||
TenantContextHolder.setTenantId(tenantId);
|
||||
log.info("设置租户ID到上下文: {}", tenantId);
|
||||
} else {
|
||||
log.warn("deviceManagement为空或tenantId为空,无法设置租户上下文");
|
||||
}
|
||||
|
||||
try {
|
||||
// 8. 根据filename直接更新audio_management_segments表的recording_text字段
|
||||
// 注意:不手动添加tenant_id条件,让多租户拦截器自动添加
|
||||
AudioManagementSegments updateEntity = new AudioManagementSegments();
|
||||
updateEntity.setRecordingText(recordingText);
|
||||
|
||||
LambdaUpdateWrapper<AudioManagementSegments> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(AudioManagementSegments::getAudioFileOriginalName, filename);
|
||||
|
||||
boolean updateResult = audioManagementSegmentsService.update(updateEntity, updateWrapper);
|
||||
|
||||
if (updateResult) {
|
||||
log.info("成功更新录音文本,deviceNo: {}, filename: {}", deviceNo, filename);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", true);
|
||||
result.put("message", "语音转写数据更新成功");
|
||||
result.put("recordingTextLength", recordingText.length());
|
||||
return result;
|
||||
} else {
|
||||
log.warn("更新录音文本失败,deviceNo: {}, filename: {}", deviceNo, filename);
|
||||
return createErrorResult("更新录音文本失败,可能未找到匹配的记录");
|
||||
}
|
||||
} finally {
|
||||
// 恢复原来的租户ID
|
||||
if (originalTenantId != null) {
|
||||
TenantContextHolder.setTenantId(originalTenantId);
|
||||
} else {
|
||||
TenantContextHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理AudioText数据类型异常", e);
|
||||
return createErrorResult("处理AudioText数据类型异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ CREATE TABLE `yhy_datatype_log` (
|
||||
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键,UUID',
|
||||
`data_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '数据类型,固定值:HeartbeatLog',
|
||||
`device_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '设备号',
|
||||
`contents` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '内容',
|
||||
`contents` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '内容',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '系统创建时间',
|
||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '系统更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
|
||||
Reference in New Issue
Block a user