Skip to content

Commit 4b7c195

Browse files
committed
2 parents bf9eec8 + 8397469 commit 4b7c195

File tree

14 files changed

+552
-182
lines changed

14 files changed

+552
-182
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# 变更日志
2+
## [2.7.58] - 2025-06-09
3+
4+
### 其他变更
5+
- chore: update version to 2.7.58 [skip ci]
6+
27
## [2.7.57] - 2025-06-09
38

49

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</parent>
1010
<groupId>com.xiaozhi.server</groupId>
1111
<artifactId>xiaozhi.server</artifactId>
12-
<version>2.7.57</version>
12+
<version>2.7.58</version>
1313
<name>xiaozhi-server</name>
1414
<description></description>
1515

src/main/java/com/xiaozhi/communication/common/MessageHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public void handleUnboundDevice(String sessionId, SysDevice device) {
211211
if (device.getDeviceName() != null && device.getModelId() == null) {
212212
String message = "设备未配置对话模型,请到配置页面完成配置后开始对话";
213213

214-
String audioFilePath = ttsService.getTtsService().textToSpeech(message);
214+
String audioFilePath = ttsService.getDefaultTtsService().textToSpeech(message);
215215
audioService.sendAudioMessage(chatSession, new DialogueService.Sentence(message, audioFilePath), true,
216216
true);
217217

@@ -231,7 +231,7 @@ public void handleUnboundDevice(String sessionId, SysDevice device) {
231231
String audioFilePath;
232232
if (!StringUtils.hasText(codeResult.getAudioPath())) {
233233
String codeMessage = "请到设备管理页面添加设备,输入验证码" + codeResult.getCode();
234-
audioFilePath = ttsService.getTtsService().textToSpeech(codeMessage);
234+
audioFilePath = ttsService.getDefaultTtsService().textToSpeech(codeMessage);
235235
codeResult.setDeviceId(deviceId);
236236
codeResult.setSessionId(sessionId);
237237
codeResult.setAudioPath(audioFilePath);

src/main/java/com/xiaozhi/dialogue/tts/TtsService.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.xiaozhi.dialogue.tts;
22

3+
import java.util.UUID;
34
import java.util.function.Consumer;
45

56
/**
@@ -12,17 +13,28 @@ public interface TtsService {
1213
*/
1314
String getProviderName();
1415

16+
/**
17+
* 音频格式
18+
*/
19+
default String audioFormat() {
20+
return "wav";
21+
}
22+
1523
/**
1624
* 生成文件名称
1725
*
1826
* @return 文件名称
1927
*/
20-
String getAudioFileName();
28+
default String getAudioFileName() {
29+
return UUID.randomUUID().toString().replace("-", "") + "." + audioFormat();
30+
}
2131

2232
/**
2333
*
2434
*/
25-
boolean isSupportStreamTts();
35+
default boolean isSupportStreamTts() {
36+
return false;
37+
}
2638

2739
/**
2840
* 将文本转换为语音(带自定义语音)
@@ -39,6 +51,8 @@ public interface TtsService {
3951
* @param audioDataConsumer 音频数据消费者,接收PCM格式的音频数据块
4052
* @throws Exception 转换过程中可能发生的异常
4153
*/
42-
void streamTextToSpeech(String text, Consumer<byte[]> audioDataConsumer) throws Exception;
54+
default void streamTextToSpeech(String text, Consumer<byte[]> audioDataConsumer) throws Exception {
55+
throw new UnsupportedOperationException("Unimplemented method 'streamTextToSpeech'");
56+
}
4357

4458
}

src/main/java/com/xiaozhi/dialogue/tts/factory/TtsServiceFactory.java

Lines changed: 29 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import org.slf4j.LoggerFactory;
99
import org.springframework.stereotype.Component;
1010
import org.springframework.util.ObjectUtils;
11-
import org.springframework.util.StringUtils;
1211

12+
import java.io.File;
1313
import java.util.Map;
1414
import java.util.concurrent.ConcurrentHashMap;
1515

@@ -34,98 +34,49 @@ public class TtsServiceFactory {
3434
* 获取默认TTS服务
3535
*/
3636
public TtsService getDefaultTtsService() {
37-
// 如果缓存中没有默认服务,则创建一个
38-
return getTtsService(DEFAULT_VOICE);
37+
var config = new SysConfig().setProvider(DEFAULT_PROVIDER);
38+
return getTtsService(config, TtsServiceFactory.DEFAULT_VOICE);
3939
}
4040

41-
public TtsService getTtsService() {
42-
return getTtsService(DEFAULT_VOICE);
43-
}
44-
45-
private TtsService getTtsService(String voiceName) {
46-
TtsService ttsService = new EdgeTtsService(voiceName, OUT_PUT_PATH);
47-
return ttsService;
48-
}
49-
50-
private String createCacheKey(SysConfig config,String provider){
51-
// 对于API服务,使用"provider:configId"作为缓存键,确保每个配置使用独立的服务实例
52-
String configIdStr;
53-
if (config == null) {
54-
configIdStr = "default";
55-
}else{
56-
Integer configId = config.getConfigId();
57-
configIdStr = configId != null ? String.valueOf(configId) : "default";
58-
}
59-
String cacheKey = provider + ":" + configIdStr;
60-
return cacheKey;
41+
// 对于API服务,使用"provider:configId"作为缓存键,确保每个配置使用独立的服务实例
42+
private String createCacheKey(SysConfig config, String provider) {
43+
var configId = config.getConfigId();
44+
var configIdStr = configId != null ? String.valueOf(configId) : "default";
45+
return provider + ":" + configIdStr;
6146
}
6247

6348
/**
6449
* 根据配置获取TTS服务
6550
*/
6651
public TtsService getTtsService(SysConfig config, String voiceName) {
67-
68-
String provider;
6952
// 如果提供商为空,则使用默认提供商
70-
if (ObjectUtils.isEmpty(config)) {
71-
provider = DEFAULT_PROVIDER;
72-
} else {
73-
provider = config.getProvider();
74-
}
75-
String cacheKey = createCacheKey(config,provider);
53+
var provider = ObjectUtils.isEmpty(config) ? DEFAULT_PROVIDER : config.getProvider();
54+
var cacheKey = createCacheKey(config, provider);
55+
7656
// 检查是否已有该配置的服务实例
7757
if (serviceCache.containsKey(cacheKey)) {
7858
return serviceCache.get(cacheKey);
79-
}else{
80-
// 如果是默认提供商且尚未初始化,则初始化
81-
if (DEFAULT_PROVIDER.equals(provider)) {
82-
if(StringUtils.hasText(voiceName)){
83-
TtsService ttsService = getTtsService(voiceName);
84-
serviceCache.put(cacheKey, ttsService);
85-
return ttsService;
86-
}else{
87-
TtsService ttsService = getTtsService();
88-
serviceCache.put(cacheKey, ttsService);
89-
return ttsService;
90-
}
91-
}
92-
// 创建新的服务实例
93-
try {
94-
TtsService service;
95-
// 创建其他API服务
96-
service = createApiService(config, voiceName, OUT_PUT_PATH);
97-
serviceCache.put(cacheKey, service);
98-
return service;
99-
} catch (Exception e) {
100-
logger.error("创建{}服务失败", provider, e);
101-
return getDefaultTtsService(); // 失败时返回默认服务
102-
}
10359
}
60+
61+
var service = createApiService(config, voiceName, OUT_PUT_PATH);
62+
serviceCache.put(cacheKey, service);
63+
return service;
10464
}
10565

10666
/**
10767
* 根据配置创建API类型的TTS服务
10868
*/
10969
private TtsService createApiService(SysConfig config, String voiceName, String outputPath) {
110-
String provider = config.getProvider();
111-
112-
// 如果是Edge,直接返回Edge服务
113-
if (DEFAULT_PROVIDER.equals(provider)) {
114-
return new EdgeTtsService(voiceName, outputPath);
115-
} else if ("aliyun".equals(provider)) {
116-
return new AliyunTtsService(config, voiceName, outputPath);
117-
} else if ("volcengine".equals(provider)) {
118-
return new VolcengineTtsService(config, voiceName, outputPath);
119-
} else if ("xfyun".equals(provider)) {
120-
return new XfyunTtsService(config, voiceName, outputPath);
121-
}/*
122-
* else if ("tencent".equals(provider)) {
123-
* return new TencentTtsService(config, voiceName, outputPath);
124-
* }
125-
*/
126-
127-
logger.warn("不支持的TTS服务提供商: {}", provider);
128-
return null;
70+
// Make sure output dir exists
71+
ensureOutputPath(outputPath);
72+
73+
return switch (config.getProvider()) {
74+
case "aliyun" -> new AliyunTtsService(config, voiceName, outputPath);
75+
case "volcengine" -> new VolcengineTtsService(config, voiceName, outputPath);
76+
case "xfyun" -> new XfyunTtsService(config, voiceName, outputPath);
77+
case "minimax" -> new MiniMaxTtsService(config, voiceName, outputPath);
78+
default -> new EdgeTtsService(voiceName, outputPath);
79+
};
12980
}
13081

13182
public void removeCache(SysConfig config) {
@@ -136,4 +87,8 @@ public void removeCache(SysConfig config) {
13687
serviceCache.remove(cacheKey);
13788
}
13889

90+
private void ensureOutputPath(String outputPath) {
91+
File dir = new File(outputPath);
92+
if (!dir.exists()) dir.mkdirs();
93+
}
13994
}

src/main/java/com/xiaozhi/dialogue/tts/providers/AliyunTtsService.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,11 @@
2222
import java.io.InputStream;
2323
import java.net.URL;
2424
import java.nio.ByteBuffer;
25-
import java.util.UUID;
2625
import java.util.concurrent.ExecutorService;
2726
import java.util.concurrent.Executors;
2827
import java.util.concurrent.Future;
2928
import java.util.concurrent.TimeUnit;
3029
import java.util.concurrent.TimeoutException;
31-
import java.util.function.Consumer;
3230

3331
public class AliyunTtsService implements TtsService {
3432
private static final Logger logger = LoggerFactory.getLogger(AliyunTtsService.class);
@@ -58,24 +56,9 @@ public String getProviderName() {
5856
return PROVIDER_NAME;
5957
}
6058

61-
@Override
62-
public boolean isSupportStreamTts() {
63-
return false;
64-
}
65-
66-
@Override
67-
public String getAudioFileName() {
68-
String uuid = UUID.randomUUID().toString().replace("-", "");
69-
return uuid + ".wav";
70-
}
71-
7259
@Override
7360
public String textToSpeech(String text) throws Exception {
7461
try {
75-
File outputDir = new File(outputPath);
76-
if (!outputDir.exists()) {
77-
outputDir.mkdirs();
78-
}
7962
if (voiceName.contains("sambert")) {
8063
return ttsSambert(text);
8164
} else if (getVoiceByName(voiceName) != null) {
@@ -394,9 +377,4 @@ public String ttsSambert(String text) {
394377
return StrUtil.EMPTY;
395378
}
396379

397-
@Override
398-
public void streamTextToSpeech(String text, Consumer<byte[]> audioDataConsumer) throws Exception {
399-
// TODO Auto-generated method stub
400-
throw new UnsupportedOperationException("Unimplemented method 'streamTextToSpeech'");
401-
}
402380
}

src/main/java/com/xiaozhi/dialogue/tts/providers/EdgeTtsService.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import java.nio.file.Files;
88
import java.nio.file.Paths;
9-
import java.util.UUID;
10-
import java.util.function.Consumer;
119
import java.util.stream.Collectors;
1210

1311
import org.slf4j.Logger;
@@ -38,14 +36,8 @@ public String getProviderName() {
3836
}
3937

4038
@Override
41-
public boolean isSupportStreamTts() {
42-
return false;
43-
}
44-
45-
@Override
46-
public String getAudioFileName() {
47-
String uuid = UUID.randomUUID().toString().replace("-", "");
48-
return uuid + ".mp3";
39+
public String audioFormat() {
40+
return "mp3";
4941
}
5042

5143
@Override
@@ -80,9 +72,4 @@ public String textToSpeech(String text) throws Exception {
8072
return AudioUtils.AUDIO_PATH + resampledFileName;
8173
}
8274

83-
@Override
84-
public void streamTextToSpeech(String text, Consumer<byte[]> audioDataConsumer) throws Exception {
85-
// TODO Auto-generated method stub
86-
throw new UnsupportedOperationException("Unimplemented method 'streamTextToSpeech'");
87-
}
8875
}

0 commit comments

Comments
 (0)