feat: 语音交互调整

This commit is contained in:
stream 2025-09-30 15:35:52 +08:00
parent ac37baf54b
commit b900d854a8
3 changed files with 120 additions and 33 deletions

View File

@ -92,22 +92,20 @@ public class FlowNodeParamPreparer {
Object loopNumVal = input.get("loopNum"); Object loopNumVal = input.get("loopNum");
int loopCount = 0; int loopCount = 0;
if (loopNumVal instanceof Number) { // 根据迭代路径找到当前层的集合对象
loopCount = ((Number) loopNumVal).intValue(); Object target = resolveLoopTarget(loopNumVal, rootMessage.getIterations(), 0);
} else if (loopNumVal instanceof JSONArray) {
// 支持 JSON 数组 if (target instanceof JSONArray) {
loopCount = ((JSONArray) loopNumVal).size(); loopCount = ((JSONArray) target).size();
} } else if (target instanceof Collection) {
else if (loopNumVal instanceof Collection) { loopCount = ((Collection<?>) target).size();
// 支持所有 Java Collection } else if (target != null && target.getClass().isArray()) {
loopCount = ((Collection<?>) loopNumVal).size(); loopCount = Array.getLength(target);
} } else if (target instanceof Number) {
else if (loopNumVal != null && loopNumVal.getClass().isArray()) { loopCount = ((Number) target).intValue();
// 支持 Java 数组 } else if (target != null) {
loopCount = Array.getLength(loopNumVal);
} else if (loopNumVal != null) {
try { try {
loopCount = Integer.parseInt(loopNumVal.toString()); loopCount = Integer.parseInt(target.toString());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new GlobalException("loopNum 参数格式错误: " + loopNumVal); throw new GlobalException("loopNum 参数格式错误: " + loopNumVal);
} }
@ -165,4 +163,42 @@ public class FlowNodeParamPreparer {
} }
return curr; return curr;
} }
/**
* 根据迭代路径iterations逐层解析嵌套集合
* 例子
* - iterations = [] 返回最外层对象
* - iterations = [2] 返回 list[1]
* - iterations = [2,3] 返回 list[1][2]
*/
private Object resolveLoopTarget(Object obj, List<Integer> iterations, int depth) {
if (obj == null) return null;
// 已经走到当前循环层返回目标
if (depth >= iterations.size()) {
return obj;
}
int idx = iterations.get(depth) - 1;
if (obj instanceof List) {
List<?> list = (List<?>) obj;
if (idx >= 0 && idx < list.size()) {
return resolveLoopTarget(list.get(idx), iterations, depth + 1);
}
} else if (obj instanceof JSONArray) {
JSONArray arr = (JSONArray) obj;
if (idx >= 0 && idx < arr.size()) {
return resolveLoopTarget(arr.get(idx), iterations, depth + 1);
}
} else if (obj != null && obj.getClass().isArray()) {
int length = Array.getLength(obj);
if (idx >= 0 && idx < length) {
return resolveLoopTarget(Array.get(obj, idx), iterations, depth + 1);
}
}
// 如果不是集合类型直接返回
return obj;
}
} }

View File

@ -131,7 +131,7 @@ public class LLMTTSOperateService implements LLMOperateService {
Map<String, Object> body = new HashMap<>(); Map<String, Object> body = new HashMap<>();
body.put("text", text); body.put("text", text);
body.put("dialect", "普通话"); body.put("dialect", "普通话");
body.put("timbre", "标准男"); body.put("timbre", "员工女");
body.put("language", "中文"); body.put("language", "中文");
body.put("tone", "中性"); body.put("tone", "中性");
@ -219,5 +219,4 @@ public class LLMTTSOperateService implements LLMOperateService {
private final long generateMs; private final long generateMs;
private final CountDownLatch latch; // 仅最后一段有 private final CountDownLatch latch; // 仅最后一段有
} }
} }

View File

@ -7,11 +7,17 @@ import com.cmvr.edge.client.service.EdgeSpeakerService;
import com.cmvr.test.enums.ActionEnum; import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult; import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
import com.cmvr.test.flow.runtime.operator.edge.EdgeOperateService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import java.io.File;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -34,21 +40,67 @@ public class ViPlayOperateService implements VIOperateService {
String deviceId = inputParams.getString("deviceId"); String deviceId = inputParams.getString("deviceId");
String audioPath = inputParams.getString("audioPath"); String audioPath = inputParams.getString("audioPath");
String terminalId = message.getTerminalId(); String terminalId = message.getTerminalId();
log.info("播放语料成功,deviceId={},audioPath={},terminalId={}", deviceId, audioPath, terminalId); // log.info("播放语料成功,deviceId={},audioPath={},terminalId={}", deviceId, audioPath, terminalId);
// edgeSpeakerService.playAudio(terminalId, deviceId, audioPath); edgeSpeakerService.playAudio(terminalId, deviceId, audioPath);
// // 等待播放完成 // 等待播放完成
// while (true) { while (true) {
// try { try {
// Thread.sleep(1000); Thread.sleep(1000);
// } catch (InterruptedException e) { } catch (InterruptedException e) {
// throw new RuntimeException(e); throw new RuntimeException(e);
// } }
// SpeakerCommand.GetSpeakerStateCommand.Feedback status = edgeSpeakerService.getStatus(terminalId, deviceId); SpeakerCommand.GetSpeakerStateCommand.Feedback status = edgeSpeakerService.getStatus(terminalId, deviceId);
// boolean isRunning = status.getState().getIsRunning(); boolean isRunning = status.getState().getIsRunning();
// if (!isRunning) { if (!isRunning) {
// break; break;
// } }
// } }
// todo 本机测试播放
// playAudio(audioPath);
return TaskNodeExecuteResult.success(); return TaskNodeExecuteResult.success();
} }
/**
* 播放一个音频文件阻塞直到播完
*/
private void playAudio(String filePath) {
try (AudioInputStream sourceStream = AudioSystem.getAudioInputStream(new File(filePath))) {
AudioFormat baseFormat = sourceStream.getFormat();
AudioFormat targetFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false
);
try (AudioInputStream pcmStream = AudioSystem.getAudioInputStream(targetFormat, sourceStream)) {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, targetFormat);
try (SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
line.open(targetFormat);
line.start();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = pcmStream.read(buffer, 0, buffer.length)) != -1) {
line.write(buffer, 0, bytesRead);
}
// 确保缓冲区播完
line.drain();
line.stop();
}
}
log.info("播放完成: {}", filePath);
} catch (Exception e) {
throw new GlobalException("播放失败: ", e);
}
}
} }