|
@@ -13,7 +13,7 @@ import cn.iocoder.byzs.module.ai.dal.mysql.tts.AiTtsMapper;
|
|
|
import cn.iocoder.byzs.module.ai.enums.ErrorCodeConstants;
|
|
import cn.iocoder.byzs.module.ai.enums.ErrorCodeConstants;
|
|
|
import cn.iocoder.byzs.module.ai.service.chat.AiChatConversationService;
|
|
import cn.iocoder.byzs.module.ai.service.chat.AiChatConversationService;
|
|
|
import cn.iocoder.byzs.module.ai.service.model.AiChatRoleService;
|
|
import cn.iocoder.byzs.module.ai.service.model.AiChatRoleService;
|
|
|
-import cn.iocoder.byzs.module.ai.util.tts.StreamTtsService;
|
|
|
|
|
|
|
+import cn.iocoder.byzs.module.ai.util.tts.StreamingAliyunTtsService;
|
|
|
import cn.iocoder.byzs.module.ai.util.tts.WavHeader;
|
|
import cn.iocoder.byzs.module.ai.util.tts.WavHeader;
|
|
|
import com.alibaba.nls.client.protocol.SampleRateEnum;
|
|
import com.alibaba.nls.client.protocol.SampleRateEnum;
|
|
|
import jakarta.annotation.Resource;
|
|
import jakarta.annotation.Resource;
|
|
@@ -60,7 +60,7 @@ public class WebAiServiceImpl {
|
|
|
private AiTtsMapper ttsMapper;
|
|
private AiTtsMapper ttsMapper;
|
|
|
|
|
|
|
|
@Resource
|
|
@Resource
|
|
|
- private ObjectProvider<StreamTtsService> streamTtsServiceProvider;
|
|
|
|
|
|
|
+ private ObjectProvider<StreamingAliyunTtsService> streamTtsServiceProvider;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 发送指定回答的SSE流式响应
|
|
* 发送指定回答的SSE流式响应
|
|
@@ -82,16 +82,16 @@ public class WebAiServiceImpl {
|
|
|
log.info("开始处理文本内容: {}", contentAnswer);
|
|
log.info("开始处理文本内容: {}", contentAnswer);
|
|
|
|
|
|
|
|
// 4. 创建TTS服务实例
|
|
// 4. 创建TTS服务实例
|
|
|
- StreamTtsService streamTtsService = streamTtsServiceProvider.getObject();
|
|
|
|
|
|
|
+ StreamingAliyunTtsService streamingAliyunTtsService = streamTtsServiceProvider.getObject();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
// 5. 初始化TTS服务
|
|
// 5. 初始化TTS服务
|
|
|
- streamTtsService.startTts(aiTtsDO);
|
|
|
|
|
- return createSseFlux(sendReqVO, userId, conversation, contentAnswer, streamTtsService);
|
|
|
|
|
|
|
+ streamingAliyunTtsService.startTts(aiTtsDO);
|
|
|
|
|
+ return createSseFlux(sendReqVO, userId, conversation, contentAnswer, streamingAliyunTtsService);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("发送指定回答失败", e);
|
|
log.error("发送指定回答失败", e);
|
|
|
AtomicBoolean tempTtsStopped = new AtomicBoolean(false);
|
|
AtomicBoolean tempTtsStopped = new AtomicBoolean(false);
|
|
|
- cleanupTtsResources(streamTtsService, tempTtsStopped);
|
|
|
|
|
|
|
+ cleanupTtsResources(streamingAliyunTtsService, tempTtsStopped);
|
|
|
// 即使发生异常,也要返回文本数据,确保前端至少能收到文本
|
|
// 即使发生异常,也要返回文本数据,确保前端至少能收到文本
|
|
|
return Flux.just(createFallbackTextResponse(sendReqVO, userId, conversation, contentAnswer));
|
|
return Flux.just(createFallbackTextResponse(sendReqVO, userId, conversation, contentAnswer));
|
|
|
}
|
|
}
|
|
@@ -117,7 +117,7 @@ public class WebAiServiceImpl {
|
|
|
*/
|
|
*/
|
|
|
private Flux<CommonResult<AiChatMessageSendRespVO>> createSseFlux(
|
|
private Flux<CommonResult<AiChatMessageSendRespVO>> createSseFlux(
|
|
|
AiChatMessageSendReqVO sendReqVO, Long userId, AiChatConversationDO conversation,
|
|
AiChatMessageSendReqVO sendReqVO, Long userId, AiChatConversationDO conversation,
|
|
|
- String contentAnswer, StreamTtsService streamTtsService) {
|
|
|
|
|
|
|
+ String contentAnswer, StreamingAliyunTtsService streamingAliyunTtsService) {
|
|
|
return Flux.<CommonResult<AiChatMessageSendRespVO>>create(sink -> {
|
|
return Flux.<CommonResult<AiChatMessageSendRespVO>>create(sink -> {
|
|
|
// 初始化句子处理相关组件
|
|
// 初始化句子处理相关组件
|
|
|
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
|
|
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
|
|
@@ -135,18 +135,18 @@ public class WebAiServiceImpl {
|
|
|
sendTextData(sink, sendReqVO, userId, conversation, contentAnswer);
|
|
sendTextData(sink, sendReqVO, userId, conversation, contentAnswer);
|
|
|
|
|
|
|
|
// 创建音频流并订阅
|
|
// 创建音频流并订阅
|
|
|
- createAndSubscribeToAudioStream(sink, streamTtsService, scheduler, ttsTask, ttsStopped);
|
|
|
|
|
|
|
+ createAndSubscribeToAudioStream(sink, streamingAliyunTtsService, scheduler, ttsTask, ttsStopped);
|
|
|
|
|
|
|
|
// 开始处理文本分段并发送到TTS
|
|
// 开始处理文本分段并发送到TTS
|
|
|
Pattern sentencePattern = Pattern.compile("[。!?;\n\r]");
|
|
Pattern sentencePattern = Pattern.compile("[。!?;\n\r]");
|
|
|
- processTextSegments(streamTtsService, contentTTSBuffer, sentencePattern,
|
|
|
|
|
|
|
+ processTextSegments(streamingAliyunTtsService, contentTTSBuffer, sentencePattern,
|
|
|
scheduler, ttsTask, ttsStopped, allTextProcessed, sink);
|
|
scheduler, ttsTask, ttsStopped, allTextProcessed, sink);
|
|
|
|
|
|
|
|
// 添加超时检测(60秒)
|
|
// 添加超时检测(60秒)
|
|
|
ScheduledFuture<?> timeoutTask = scheduler.schedule(() -> {
|
|
ScheduledFuture<?> timeoutTask = scheduler.schedule(() -> {
|
|
|
if (!ttsStopped.get()) {
|
|
if (!ttsStopped.get()) {
|
|
|
log.warn("TTS处理超时,强制终止SSE流");
|
|
log.warn("TTS处理超时,强制终止SSE流");
|
|
|
- cleanupResources(streamTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
|
|
|
|
+ cleanupResources(streamingAliyunTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
}
|
|
}
|
|
|
}, 60, TimeUnit.SECONDS);
|
|
}, 60, TimeUnit.SECONDS);
|
|
|
|
|
|
|
@@ -156,12 +156,12 @@ public class WebAiServiceImpl {
|
|
|
if (timeoutTask != null) {
|
|
if (timeoutTask != null) {
|
|
|
timeoutTask.cancel(false);
|
|
timeoutTask.cancel(false);
|
|
|
}
|
|
}
|
|
|
- cleanupResources(streamTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
|
|
|
|
+ cleanupResources(streamingAliyunTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("创建SSE流异常", e);
|
|
log.error("创建SSE流异常", e);
|
|
|
- cleanupResources(streamTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
|
|
|
|
+ cleanupResources(streamingAliyunTtsService, scheduler, ttsTask, ttsStopped, sink);
|
|
|
sink.error(e);
|
|
sink.error(e);
|
|
|
}
|
|
}
|
|
|
}).subscribeOn(Schedulers.boundedElastic())
|
|
}).subscribeOn(Schedulers.boundedElastic())
|
|
@@ -201,7 +201,7 @@ public class WebAiServiceImpl {
|
|
|
* 创建并订阅音频流
|
|
* 创建并订阅音频流
|
|
|
*/
|
|
*/
|
|
|
private void createAndSubscribeToAudioStream(FluxSink<CommonResult<AiChatMessageSendRespVO>> mainSink,
|
|
private void createAndSubscribeToAudioStream(FluxSink<CommonResult<AiChatMessageSendRespVO>> mainSink,
|
|
|
- StreamTtsService streamTtsService,
|
|
|
|
|
|
|
+ StreamingAliyunTtsService streamingAliyunTtsService,
|
|
|
ScheduledExecutorService scheduler,
|
|
ScheduledExecutorService scheduler,
|
|
|
AtomicReference<ScheduledFuture<?>> ttsTask,
|
|
AtomicReference<ScheduledFuture<?>> ttsTask,
|
|
|
AtomicBoolean ttsStopped) {
|
|
AtomicBoolean ttsStopped) {
|
|
@@ -209,7 +209,7 @@ public class WebAiServiceImpl {
|
|
|
AtomicBoolean isFirstChunk = new AtomicBoolean(true); // 首包标志位
|
|
AtomicBoolean isFirstChunk = new AtomicBoolean(true); // 首包标志位
|
|
|
|
|
|
|
|
// 设置音频数据回调
|
|
// 设置音频数据回调
|
|
|
- streamTtsService.setAudioDataCallback(audioBytes -> {
|
|
|
|
|
|
|
+ streamingAliyunTtsService.setAudioDataCallback(audioBytes -> {
|
|
|
try {
|
|
try {
|
|
|
byte[] processedAudio = processAudioData(audioBytes, isFirstChunk);
|
|
byte[] processedAudio = processAudioData(audioBytes, isFirstChunk);
|
|
|
String base64Audio = java.util.Base64.getEncoder().encodeToString(processedAudio);
|
|
String base64Audio = java.util.Base64.getEncoder().encodeToString(processedAudio);
|
|
@@ -225,14 +225,14 @@ public class WebAiServiceImpl {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// 设置完成回调
|
|
// 设置完成回调
|
|
|
- streamTtsService.setOnCompleteCallback(() -> {
|
|
|
|
|
|
|
+ streamingAliyunTtsService.setOnCompleteCallback(() -> {
|
|
|
log.info("TTS转换完成,准备终止SSE流");
|
|
log.info("TTS转换完成,准备终止SSE流");
|
|
|
|
|
|
|
|
// 确保只停止一次TTS服务
|
|
// 确保只停止一次TTS服务
|
|
|
if (ttsStopped.compareAndSet(false, true)) {
|
|
if (ttsStopped.compareAndSet(false, true)) {
|
|
|
try {
|
|
try {
|
|
|
log.info("TTS完成回调中调用stopTts()");
|
|
log.info("TTS完成回调中调用stopTts()");
|
|
|
- streamTtsService.stopTts();
|
|
|
|
|
|
|
+ streamingAliyunTtsService.stopTts();
|
|
|
log.info("TTS完成回调中stopTts()调用完成");
|
|
log.info("TTS完成回调中stopTts()调用完成");
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("停止TTS服务异常", e);
|
|
log.error("停止TTS服务异常", e);
|
|
@@ -280,7 +280,7 @@ public class WebAiServiceImpl {
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("主SSE流设置错误异常", e);
|
|
log.error("主SSE流设置错误异常", e);
|
|
|
}
|
|
}
|
|
|
- cleanupResources(streamTtsService, scheduler, ttsTask, ttsStopped, mainSink);
|
|
|
|
|
|
|
+ cleanupResources(streamingAliyunTtsService, scheduler, ttsTask, ttsStopped, mainSink);
|
|
|
},
|
|
},
|
|
|
() -> {
|
|
() -> {
|
|
|
log.info("音频流处理完成,准备终止主SSE流");
|
|
log.info("音频流处理完成,准备终止主SSE流");
|
|
@@ -316,41 +316,41 @@ public class WebAiServiceImpl {
|
|
|
/**
|
|
/**
|
|
|
* 处理文本分段
|
|
* 处理文本分段
|
|
|
*/
|
|
*/
|
|
|
- private void processTextSegments(StreamTtsService streamTtsService, StringBuilder buffer,
|
|
|
|
|
|
|
+ private void processTextSegments(StreamingAliyunTtsService streamingAliyunTtsService, StringBuilder buffer,
|
|
|
Pattern sentencePattern, ScheduledExecutorService scheduler,
|
|
Pattern sentencePattern, ScheduledExecutorService scheduler,
|
|
|
AtomicReference<ScheduledFuture<?>> ttsTask, AtomicBoolean ttsStopped,
|
|
AtomicReference<ScheduledFuture<?>> ttsTask, AtomicBoolean ttsStopped,
|
|
|
AtomicBoolean allTextProcessed, FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
AtomicBoolean allTextProcessed, FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
|
if (buffer.isEmpty()) {
|
|
if (buffer.isEmpty()) {
|
|
|
log.info("文本为空,无需处理");
|
|
log.info("文本为空,无需处理");
|
|
|
- handleTextComplete(streamTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
|
|
|
|
+ handleTextComplete(streamingAliyunTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 立即处理文本
|
|
// 立即处理文本
|
|
|
Matcher matcher = sentencePattern.matcher(buffer);
|
|
Matcher matcher = sentencePattern.matcher(buffer);
|
|
|
if (matcher.find()) {
|
|
if (matcher.find()) {
|
|
|
- processCompleteSentence(streamTtsService, buffer, matcher);
|
|
|
|
|
|
|
+ processCompleteSentence(streamingAliyunTtsService, buffer, matcher);
|
|
|
// 继续调度处理剩余文本
|
|
// 继续调度处理剩余文本
|
|
|
- scheduleNextProcessing(streamTtsService, buffer, sentencePattern, scheduler,
|
|
|
|
|
|
|
+ scheduleNextProcessing(streamingAliyunTtsService, buffer, sentencePattern, scheduler,
|
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
|
} else if (buffer.length() > 50) { // 最长50字未结束也处理
|
|
} else if (buffer.length() > 50) { // 最长50字未结束也处理
|
|
|
- processCompleteSentence(streamTtsService, buffer, buffer.length());
|
|
|
|
|
|
|
+ processCompleteSentence(streamingAliyunTtsService, buffer, buffer.length());
|
|
|
// 继续调度处理剩余文本
|
|
// 继续调度处理剩余文本
|
|
|
- scheduleNextProcessing(streamTtsService, buffer, sentencePattern, scheduler,
|
|
|
|
|
|
|
+ scheduleNextProcessing(streamingAliyunTtsService, buffer, sentencePattern, scheduler,
|
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
|
} else {
|
|
} else {
|
|
|
// 文本较短且未结束,直接处理全部
|
|
// 文本较短且未结束,直接处理全部
|
|
|
log.info("TTS合成短文本: {}", buffer.toString());
|
|
log.info("TTS合成短文本: {}", buffer.toString());
|
|
|
- streamTtsService.sendText(buffer.toString());
|
|
|
|
|
|
|
+ streamingAliyunTtsService.sendText(buffer.toString());
|
|
|
buffer.setLength(0);
|
|
buffer.setLength(0);
|
|
|
- handleTextComplete(streamTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
|
|
|
|
+ handleTextComplete(streamingAliyunTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 调度下一次文本处理
|
|
* 调度下一次文本处理
|
|
|
*/
|
|
*/
|
|
|
- private void scheduleNextProcessing(StreamTtsService streamTtsService, StringBuilder buffer,
|
|
|
|
|
|
|
+ private void scheduleNextProcessing(StreamingAliyunTtsService streamingAliyunTtsService, StringBuilder buffer,
|
|
|
Pattern sentencePattern, ScheduledExecutorService scheduler,
|
|
Pattern sentencePattern, ScheduledExecutorService scheduler,
|
|
|
AtomicReference<ScheduledFuture<?>> ttsTask, AtomicBoolean ttsStopped,
|
|
AtomicReference<ScheduledFuture<?>> ttsTask, AtomicBoolean ttsStopped,
|
|
|
AtomicBoolean allTextProcessed, FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
AtomicBoolean allTextProcessed, FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
@@ -360,19 +360,19 @@ public class WebAiServiceImpl {
|
|
|
ttsTask.get().cancel(false); // 取消之前的延迟任务
|
|
ttsTask.get().cancel(false); // 取消之前的延迟任务
|
|
|
}
|
|
}
|
|
|
ttsTask.set(scheduler.schedule(() -> {
|
|
ttsTask.set(scheduler.schedule(() -> {
|
|
|
- processTextSegments(streamTtsService, buffer, sentencePattern, scheduler,
|
|
|
|
|
|
|
+ processTextSegments(streamingAliyunTtsService, buffer, sentencePattern, scheduler,
|
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
ttsTask, ttsStopped, allTextProcessed, sink);
|
|
|
}, 200, TimeUnit.MILLISECONDS));
|
|
}, 200, TimeUnit.MILLISECONDS));
|
|
|
} else {
|
|
} else {
|
|
|
// 所有文本处理完毕
|
|
// 所有文本处理完毕
|
|
|
- handleTextComplete(streamTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
|
|
|
|
+ handleTextComplete(streamingAliyunTtsService, scheduler, ttsStopped, allTextProcessed, sink);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 处理文本完成后的逻辑
|
|
* 处理文本完成后的逻辑
|
|
|
*/
|
|
*/
|
|
|
- private void handleTextComplete(StreamTtsService streamTtsService, ScheduledExecutorService scheduler,
|
|
|
|
|
|
|
+ private void handleTextComplete(StreamingAliyunTtsService streamingAliyunTtsService, ScheduledExecutorService scheduler,
|
|
|
AtomicBoolean ttsStopped, AtomicBoolean allTextProcessed,
|
|
AtomicBoolean ttsStopped, AtomicBoolean allTextProcessed,
|
|
|
FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
FluxSink<CommonResult<AiChatMessageSendRespVO>> sink) {
|
|
|
allTextProcessed.set(true);
|
|
allTextProcessed.set(true);
|
|
@@ -383,7 +383,7 @@ public class WebAiServiceImpl {
|
|
|
// 设置标志位
|
|
// 设置标志位
|
|
|
ttsStopped.set(true);
|
|
ttsStopped.set(true);
|
|
|
// 调用stopTts()明确通知TTS服务文本已全部发送
|
|
// 调用stopTts()明确通知TTS服务文本已全部发送
|
|
|
- streamTtsService.stopTts();
|
|
|
|
|
|
|
+ streamingAliyunTtsService.stopTts();
|
|
|
log.info("已通知TTS服务文本发送完毕,等待TTS合成完成回调");
|
|
log.info("已通知TTS服务文本发送完毕,等待TTS合成完成回调");
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("通知TTS服务文本发送完毕异常: {}", e.getMessage());
|
|
log.error("通知TTS服务文本发送完毕异常: {}", e.getMessage());
|
|
@@ -398,7 +398,7 @@ public class WebAiServiceImpl {
|
|
|
ttsStopped.set(true);
|
|
ttsStopped.set(true);
|
|
|
// 尝试停止TTS服务
|
|
// 尝试停止TTS服务
|
|
|
try {
|
|
try {
|
|
|
- streamTtsService.stopTts();
|
|
|
|
|
|
|
+ streamingAliyunTtsService.stopTts();
|
|
|
log.info("超时后主动停止TTS服务完成");
|
|
log.info("超时后主动停止TTS服务完成");
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("停止TTS服务异常: {}", e.getMessage());
|
|
log.error("停止TTS服务异常: {}", e.getMessage());
|
|
@@ -421,9 +421,9 @@ public class WebAiServiceImpl {
|
|
|
/**
|
|
/**
|
|
|
* 处理完整句子
|
|
* 处理完整句子
|
|
|
*/
|
|
*/
|
|
|
- private void processCompleteSentence(StreamTtsService streamTtsService, StringBuilder buffer, Matcher matcher) {
|
|
|
|
|
|
|
+ private void processCompleteSentence(StreamingAliyunTtsService streamingAliyunTtsService, StringBuilder buffer, Matcher matcher) {
|
|
|
String sentence = buffer.substring(0, matcher.end());
|
|
String sentence = buffer.substring(0, matcher.end());
|
|
|
- streamTtsService.sendText(sentence);
|
|
|
|
|
|
|
+ streamingAliyunTtsService.sendText(sentence);
|
|
|
buffer.delete(0, matcher.end());
|
|
buffer.delete(0, matcher.end());
|
|
|
log.info("TTS合成完整句: {}", sentence);
|
|
log.info("TTS合成完整句: {}", sentence);
|
|
|
}
|
|
}
|
|
@@ -431,9 +431,9 @@ public class WebAiServiceImpl {
|
|
|
/**
|
|
/**
|
|
|
* 处理指定长度文本
|
|
* 处理指定长度文本
|
|
|
*/
|
|
*/
|
|
|
- private void processCompleteSentence(StreamTtsService streamTtsService, StringBuilder buffer, int length) {
|
|
|
|
|
|
|
+ private void processCompleteSentence(StreamingAliyunTtsService streamingAliyunTtsService, StringBuilder buffer, int length) {
|
|
|
String sentence = buffer.substring(0, length);
|
|
String sentence = buffer.substring(0, length);
|
|
|
- streamTtsService.sendText(sentence);
|
|
|
|
|
|
|
+ streamingAliyunTtsService.sendText(sentence);
|
|
|
buffer.delete(0, length);
|
|
buffer.delete(0, length);
|
|
|
log.info("TTS合成长文本: {}", sentence);
|
|
log.info("TTS合成长文本: {}", sentence);
|
|
|
}
|
|
}
|
|
@@ -441,7 +441,7 @@ public class WebAiServiceImpl {
|
|
|
/**
|
|
/**
|
|
|
* 清理所有资源
|
|
* 清理所有资源
|
|
|
*/
|
|
*/
|
|
|
- private void cleanupResources(StreamTtsService streamTtsService,
|
|
|
|
|
|
|
+ private void cleanupResources(StreamingAliyunTtsService streamingAliyunTtsService,
|
|
|
ScheduledExecutorService scheduler,
|
|
ScheduledExecutorService scheduler,
|
|
|
AtomicReference<ScheduledFuture<?>> ttsTask,
|
|
AtomicReference<ScheduledFuture<?>> ttsTask,
|
|
|
AtomicBoolean ttsStopped,
|
|
AtomicBoolean ttsStopped,
|
|
@@ -452,7 +452,7 @@ public class WebAiServiceImpl {
|
|
|
if (scheduler != null && !scheduler.isShutdown()) {
|
|
if (scheduler != null && !scheduler.isShutdown()) {
|
|
|
scheduler.shutdownNow();
|
|
scheduler.shutdownNow();
|
|
|
}
|
|
}
|
|
|
- cleanupTtsResources(streamTtsService, ttsStopped);
|
|
|
|
|
|
|
+ cleanupTtsResources(streamingAliyunTtsService, ttsStopped);
|
|
|
ttsStopped.set(true);
|
|
ttsStopped.set(true);
|
|
|
|
|
|
|
|
// 确保SSE流终止
|
|
// 确保SSE流终止
|
|
@@ -470,16 +470,16 @@ public class WebAiServiceImpl {
|
|
|
/**
|
|
/**
|
|
|
* 清理TTS服务资源
|
|
* 清理TTS服务资源
|
|
|
*/
|
|
*/
|
|
|
- private void cleanupTtsResources(StreamTtsService streamTtsService, AtomicBoolean ttsStopped) {
|
|
|
|
|
|
|
+ private void cleanupTtsResources(StreamingAliyunTtsService streamingAliyunTtsService, AtomicBoolean ttsStopped) {
|
|
|
try {
|
|
try {
|
|
|
- if (streamTtsService != null) {
|
|
|
|
|
|
|
+ if (streamingAliyunTtsService != null) {
|
|
|
log.info("开始清理TTS服务资源");
|
|
log.info("开始清理TTS服务资源");
|
|
|
|
|
|
|
|
// 检查ttsStopped标志位,避免重复停止TTS服务
|
|
// 检查ttsStopped标志位,避免重复停止TTS服务
|
|
|
if (!ttsStopped.get()) {
|
|
if (!ttsStopped.get()) {
|
|
|
try {
|
|
try {
|
|
|
log.info("调用streamTtsService.stopTts()");
|
|
log.info("调用streamTtsService.stopTts()");
|
|
|
- streamTtsService.stopTts();
|
|
|
|
|
|
|
+ streamingAliyunTtsService.stopTts();
|
|
|
log.info("streamTtsService.stopTts()调用完成");
|
|
log.info("streamTtsService.stopTts()调用完成");
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("停止TTS服务异常", e);
|
|
log.error("停止TTS服务异常", e);
|