diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java index ebb29fbd..d15a1df7 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java @@ -41,6 +41,9 @@ public class AgentUpdateDTO implements Serializable { @Schema(description = "音色标识", example = "voice_02", nullable = true) private String ttsVoiceId; + @Schema(description = "音色语言", example = "普通话", nullable = true) + private String ttsLanguage; + @Schema(description = "记忆模型标识", example = "mem_model_02", nullable = true) private String memModelId; diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java index d92d49b8..7f63b688 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java @@ -45,6 +45,9 @@ public class AgentEntity { @Schema(description = "音色标识") private String ttsVoiceId; + @Schema(description = "音色语言") + private String ttsLanguage; + @Schema(description = "记忆模型标识") private String memModelId; diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java index a7704e5b..ae9c3c40 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java @@ -64,6 +64,11 @@ public class AgentTemplateEntity implements Serializable { */ private String ttsVoiceId; + /** + * 音色语言 + */ + private String ttsLanguage; + /** * 记忆模型标识 */ diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java index 5485e425..95a55434 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java @@ -282,6 +282,9 @@ public class AgentServiceImpl extends BaseServiceImpl imp if (dto.getTtsVoiceId() != null) { existingEntity.setTtsVoiceId(dto.getTtsVoiceId()); } + if (dto.getTtsLanguage() != null) { + existingEntity.setTtsLanguage(dto.getTtsLanguage()); + } if (dto.getMemModelId() != null) { existingEntity.setMemModelId(dto.getMemModelId()); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index 49885614..9cc3bbfb 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -87,6 +87,7 @@ public class ConfigServiceImpl implements ConfigService { null, null, null, + null, agent.getVadModelId(), agent.getAsrModelId(), null, @@ -135,15 +136,24 @@ public class ConfigServiceImpl implements ConfigService { String voice = null; String referenceAudio = null; String referenceText = null; + String language = null; TimbreDetailsVO timbre = timbreService.get(agent.getTtsVoiceId()); if (timbre != null) { voice = timbre.getTtsVoice(); referenceAudio = timbre.getReferenceAudio(); referenceText = timbre.getReferenceText(); + // 优先使用用户选择的语言,如果没有则使用音色支持的第一个语言 + if (StringUtils.isNotBlank(agent.getTtsLanguage())) { + language = agent.getTtsLanguage(); + } else if (StringUtils.isNotBlank(timbre.getLanguages())) { + language = timbre.getLanguages().split("、")[0].trim(); + } } else { VoiceCloneEntity voice_print = cloneVoiceService.selectById(agent.getTtsVoiceId()); if (voice_print != null) { voice = voice_print.getVoiceId(); + // 优先使用用户选择的语言,如果没有则使用默认值 + language = StringUtils.isNotBlank(agent.getTtsLanguage()) ? agent.getTtsLanguage() : "普通话"; } } // 构建返回数据 @@ -208,6 +218,7 @@ public class ConfigServiceImpl implements ConfigService { voice, referenceAudio, referenceText, + language, agent.getVadModelId(), agent.getAsrModelId(), agent.getLlmModelId(), @@ -385,6 +396,7 @@ public class ConfigServiceImpl implements ConfigService { String voice, String referenceAudio, String referenceText, + String language, String vadModelId, String asrModelId, String llmModelId, @@ -423,6 +435,8 @@ public class ConfigServiceImpl implements ConfigService { ((Map) model.getConfigJson()).put("ref_audio", referenceAudio); if (referenceText != null) ((Map) model.getConfigJson()).put("ref_text", referenceText); + if (language != null) + ((Map) model.getConfigJson()).put("language", language); // 火山引擎声音克隆需要替换resource_id Map map = (Map) model.getConfigJson(); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java index e69608a9..9bc4fa8f 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java @@ -23,6 +23,9 @@ public class VoiceDTO implements Serializable { @Schema(description = "音频播放地址") private String voiceDemo; + @Schema(description = "语言类型") + private String languages; + @Schema(description = "是否为克隆音色") private Boolean isClone; @@ -31,6 +34,7 @@ public class VoiceDTO implements Serializable { this.id = id; this.name = name; this.voiceDemo = null; + this.languages = null; this.isClone = false; // 默认不是克隆音色 } @@ -39,6 +43,7 @@ public class VoiceDTO implements Serializable { this.id = id; this.name = name; this.voiceDemo = voiceDemo; + this.languages = null; this.isClone = false; } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java index a1f018a8..165824f6 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java @@ -129,6 +129,7 @@ public class TimbreServiceImpl extends BaseServiceImpl .map(entity -> { VoiceDTO dto = new VoiceDTO(entity.getId(), entity.getName()); dto.setVoiceDemo(entity.getVoiceDemo()); + dto.setLanguages(entity.getLanguages()); // 设置语言类型 dto.setIsClone(false); // 设置为普通音色 return dto; }) @@ -146,6 +147,7 @@ public class TimbreServiceImpl extends BaseServiceImpl voiceDTO.setName(MessageUtils.getMessage(ErrorCode.VOICE_CLONE_PREFIX) + entity.getName()); // 保留从数据库查询到的voiceDemo字段 voiceDTO.setVoiceDemo(entity.getVoiceDemo()); + voiceDTO.setLanguages(entity.getLanguages()); voiceDTO.setIsClone(true); // 设置为克隆音色 redisUtils.set(RedisKeys.getTimbreNameById(voiceDTO.getId()), voiceDTO.getName(), RedisUtils.NOT_EXPIRE); diff --git a/main/manager-api/src/main/resources/db/changelog/202602061650.sql b/main/manager-api/src/main/resources/db/changelog/202602061650.sql index 72a3d23b..4341cf59 100644 --- a/main/manager-api/src/main/resources/db/changelog/202602061650.sql +++ b/main/manager-api/src/main/resources/db/changelog/202602061650.sql @@ -11,4 +11,10 @@ SET languages = CASE WHEN languages = '中文(粤语)及中英文混合' THEN '粤语、英语' WHEN languages = '粤语及粤英混合' THEN '粤语、英语' ELSE languages -END; \ No newline at end of file +END; + +-- 添加音色语言字段到 ai_agent 表 +ALTER TABLE `ai_agent` ADD COLUMN `tts_language` VARCHAR(50) NULL COMMENT '音色语言' AFTER `tts_voice_id`; + +-- 添加音色语言字段到 ai_agent_template 表 +ALTER TABLE `ai_agent_template` ADD COLUMN `tts_language` VARCHAR(50) NULL COMMENT '音色语言' AFTER `tts_voice_id`; diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml index 439be096..95ca0246 100644 --- a/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml +++ b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml @@ -16,6 +16,7 @@ + @@ -45,6 +46,7 @@ a.vllm_model_id AS vllmModelId, a.tts_model_id AS ttsModelId, a.tts_voice_id AS ttsVoiceId, + a.tts_language AS ttsLanguage, a.mem_model_id AS memModelId, a.intent_model_id AS intentModelId, COALESCE( diff --git a/main/manager-web/src/components/HeaderBar.vue b/main/manager-web/src/components/HeaderBar.vue index dc9c6fb5..ecdf7d89 100644 --- a/main/manager-web/src/components/HeaderBar.vue +++ b/main/manager-web/src/components/HeaderBar.vue @@ -871,8 +871,8 @@ export default { } .equipment-management { - width: 79px; - font-size: 9px; + min-width: 80px; + font-size: 10px; } } diff --git a/main/manager-web/src/i18n/de.js b/main/manager-web/src/i18n/de.js index 77f75f4d..bd511ccf 100644 --- a/main/manager-web/src/i18n/de.js +++ b/main/manager-web/src/i18n/de.js @@ -762,6 +762,7 @@ export default { 'roleConfig.memoryHis': 'Speicher', 'roleConfig.memory': 'Speicher', 'roleConfig.intent': 'Intent', + 'roleConfig.language': 'Sprache auswählen', 'roleConfig.voiceType': 'Stimmtyp', 'roleConfig.pleaseEnterContent': 'Bitte Inhalt eingeben', 'roleConfig.pleaseEnterLangCode': 'Bitte Sprachcode eingeben, z.B.: en_US', diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 2ecabb97..5e184cd9 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -762,6 +762,7 @@ export default { 'roleConfig.memoryHis': 'Memory', 'roleConfig.memory': 'Memory Model', 'roleConfig.intent': 'Intent Recognition', + 'roleConfig.language': 'Select Language', 'roleConfig.voiceType': 'Voice Type', 'roleConfig.pleaseEnterContent': 'Please enter content', 'roleConfig.pleaseEnterLangCode': 'Please enter language code, e.g.: en_US', diff --git a/main/manager-web/src/i18n/vi.js b/main/manager-web/src/i18n/vi.js index 5fc17c24..8a124b35 100644 --- a/main/manager-web/src/i18n/vi.js +++ b/main/manager-web/src/i18n/vi.js @@ -762,6 +762,7 @@ export default { 'roleConfig.memoryHis': 'Bộ nhớ', 'roleConfig.memory': 'Mô hình bộ nhớ', 'roleConfig.intent': 'Nhận dạng ý định', + 'roleConfig.language': 'Chọn ngôn ngữ', 'roleConfig.voiceType': 'Loại giọng nói', 'roleConfig.pleaseEnterContent': 'Vui lòng nhập nội dung', 'roleConfig.pleaseEnterLangCode': 'Vui lòng nhập mã ngôn ngữ, ví dụ: en_US', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index ef1c8511..2edf4f04 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -762,6 +762,7 @@ export default { 'roleConfig.memoryHis': '记忆', 'roleConfig.memory': '记忆模式', 'roleConfig.tts': '语音合成(TTS)', + 'roleConfig.language': '选择语言', 'roleConfig.voiceType': '声音音色(Voice)', 'roleConfig.pleaseEnterContent': '请输入内容', 'roleConfig.pleaseEnterLangCode': '请输入语言编码,如:zh_CN', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index 6744f094..7af2fdba 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -762,6 +762,7 @@ export default { 'roleConfig.memoryHis': '記憶', 'roleConfig.memory': '記憶模式', 'roleConfig.intent': '意圖識別(Intent)', + 'roleConfig.language': '選擇語言', 'roleConfig.voiceType': '聲音音色(Voice)', 'roleConfig.pleaseEnterContent': '請輸入內容', 'roleConfig.pleaseEnterLangCode': '請輸入語言編碼,如:zh_TW', diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index 580b6989..4f4a0f8e 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -232,47 +232,71 @@ - - - -
+ + +
+ - {{ item.label }} - -
- - -
+ > + {{ item.label }} + +
+
+
+ +
+ @@ -357,6 +381,9 @@ export default { isPaused: false, currentAudio: null, currentPlayingVoiceId: null, + // 语言筛选相关状态 + languageOptions: [], // 语言选项列表 + selectedLanguage: '', // 当前选中的语言 // 功能状态 featureStatus: { vad: false, // 语言检测活动功能状态 @@ -378,6 +405,7 @@ export default { vllmModelId: this.form.model.vllmModelId, ttsModelId: this.form.model.ttsModelId, ttsVoiceId: this.form.ttsVoiceId, + ttsLanguage: this.selectedLanguage, chatHistoryConf: this.form.chatHistoryConf, memModelId: this.form.model.memModelId, intentModelId: this.form.model.intentModelId, @@ -592,32 +620,84 @@ export default { if (!modelId) { this.voiceOptions = []; this.voiceDetails = {}; + this.languageOptions = []; + this.selectedLanguage = ''; return; } Api.model.getModelVoices(modelId, "", ({ data }) => { if (data.code === 0 && data.data) { - this.voiceOptions = data.data.map((voice) => ({ - value: voice.id, - label: voice.name, - // 只保留后端实际返回的音频相关字段 - voiceDemo: voice.voiceDemo, - voice_demo: voice.voice_demo, - // 使用后端实际返回的 isClone 字段 - isClone: Boolean(voice.isClone), - // 保存训练状态字段 - train_status: voice.trainStatus, - })); - // 保存完整的音色信息,添加调试信息 + // 保存完整的音色信息 this.voiceDetails = data.data.reduce((acc, voice) => { acc[voice.id] = voice; return acc; }, {}); + + // 提取所有语言选项并去重 + const allLanguages = new Set(); + data.data.forEach(voice => { + if (voice.languages) { + const languagesArray = voice.languages.split('、').map(lang => lang.trim()).filter(lang => lang); + languagesArray.forEach(lang => allLanguages.add(lang)); + } + }); + + this.languageOptions = Array.from(allLanguages).map(lang => ({ + value: lang, + label: lang + })); + + // 使用后端返回的用户选择的语言,如果没有则使用第一个语言选项 + if (this.form.ttsLanguage && this.languageOptions.some(option => option.value === this.form.ttsLanguage)) { + this.selectedLanguage = this.form.ttsLanguage; + } else if (this.languageOptions.length > 0) { + this.selectedLanguage = this.languageOptions[0].value; + } + + // 根据选中的语言筛选音色 + this.filterVoicesByLanguage(); } else { this.voiceOptions = []; this.voiceDetails = {}; + this.languageOptions = []; + this.selectedLanguage = ''; } }); }, + + // 根据语言筛选音色 + filterVoicesByLanguage() { + if (!this.voiceDetails || Object.keys(this.voiceDetails).length === 0) { + this.voiceOptions = []; + return; + } + + const allVoices = Object.values(this.voiceDetails); + + // 根据选中的语言筛选音色 + const filteredVoices = allVoices.filter(voice => { + if (!voice.languages) return false; + const languagesArray = voice.languages.split('、').map(lang => lang.trim()).filter(lang => lang); + return languagesArray.includes(this.selectedLanguage); + }); + + this.voiceOptions = filteredVoices.map((voice) => ({ + value: voice.id, + label: voice.name, + voiceDemo: voice.voiceDemo, + voice_demo: voice.voice_demo, + isClone: Boolean(voice.isClone), + train_status: voice.trainStatus, + })); + + // 检查当前选中的音色是否支持当前语言,如果不支持则选择第一个 + const currentVoiceSupportsLanguage = this.form.ttsVoiceId && + filteredVoices.some(voice => voice.id === this.form.ttsVoiceId); + + if (!currentVoiceSupportsLanguage) { + this.form.ttsVoiceId = filteredVoices.length > 0 ? filteredVoices[0].id : ''; + } + }, + getFunctionDisplayChar(name) { if (!name || name.length === 0) return ""; diff --git a/main/xiaozhi-server/agent-base-prompt.txt b/main/xiaozhi-server/agent-base-prompt.txt index 7fd90d21..3aeb1f0d 100644 --- a/main/xiaozhi-server/agent-base-prompt.txt +++ b/main/xiaozhi-server/agent-base-prompt.txt @@ -2,6 +2,10 @@ {{base_prompt}} + +【语言规范】你必须使用{{language}}进行回复和交流。无论用户使用何种语言提问,你都应该用{{language}}来回答。 + + 【核心目标】你不是冰冷的机器!请敏锐感知用户情绪,作为懂人心的伙伴,用有温度的回应照亮对话。 - **情感融入:** diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index 51701d15..81c5c0b1 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -733,6 +733,7 @@ TTS: type: edge voice: zh-CN-XiaoxiaoNeural output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 DoubaoTTS: # 定义TTS API类型 type: doubao @@ -751,6 +752,7 @@ TTS: speed_ratio: 1.0 volume_ratio: 1.0 pitch_ratio: 1.0 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 #火山tts,支持双向流式tts HuoshanDoubleStreamTTS: type: huoshan_double_stream @@ -791,6 +793,7 @@ TTS: # mix_factor: 0.3 # - source_speaker: zh_male_ahu_conversation_wvae_bigtts # mix_factor: 0.4 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 CosyVoiceSiliconflow: type: siliconflow # 硅基流动TTS @@ -800,6 +803,7 @@ TTS: output_dir: tmp/ access_token: 你的硅基流动API密钥 response_format: wav + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 CozeCnTTS: type: cozecn # COZECN TTS @@ -808,6 +812,7 @@ TTS: output_dir: tmp/ access_token: 你的coze web key response_format: wav + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 VolcesAiGatewayTTS: type: openai # 火山引擎 - 边缘大模型网关 @@ -822,6 +827,7 @@ TTS: voice: zh_male_shaonianzixin_moon_bigtts speed: 1 output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 FishSpeech: # 参照教程:https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/fish-speech-integration.md type: fishspeech @@ -843,6 +849,7 @@ TTS: rate: 44100 api_key: "你的api_key" api_url: "http://127.0.0.1:8080/v1/tts" + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 GPT_SOVITS_V2: # 定义TTS API类型 #启动tts方法: @@ -868,6 +875,7 @@ TTS: parallel_infer: true repetition_penalty: 1.35 aux_ref_audio_paths: [] + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 GPT_SOVITS_V3: # 定义TTS API类型 GPT-SoVITS-v3lora-20250228 #启动tts方法: @@ -887,6 +895,7 @@ TTS: inp_refs: [] sample_steps: 32 if_sr: false + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 MinimaxTTSHTTPStream: # Minimax流式语音合成服务 type: minimax_httpstream @@ -918,6 +927,7 @@ TTS: # voice_id: female-shaonv # weight: 1 # language_boost: auto + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 AliyunTTS: # 阿里云智能语音交互服务,需要先在阿里云平台开通服务,然后获取验证信息 # 平台地址:https://nls-portal.console.aliyun.com/ @@ -937,6 +947,7 @@ TTS: # volume: 50 # speech_rate: 0 # pitch_rate: 0 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 AliyunStreamTTS: # 阿里云CosyVoice大模型流式文本语音合成 # 采用FlowingSpeechSynthesizer接口,支持更低延迟和更自然的语音质量 @@ -950,7 +961,7 @@ TTS: output_dir: tmp/ appkey: 你的阿里云智能语音交互服务项目Appkey token: 你的阿里云智能语音交互服务AccessToken,临时的24小时,要长期用下方的access_key_id,access_key_secret - voice: longxiaochun + voice: longxiaochun access_key_id: 你的阿里云账号access_key_id access_key_secret: 你的阿里云账号access_key_secret # 截至2025年7月21日大模型音色只有北京节点采用,其他节点暂不支持 @@ -960,6 +971,7 @@ TTS: # volume: 50 # 音量:0-100 # speech_rate: 0 # 语速:-500到500 # pitch_rate: 0 # 语调:-500到500 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 TencentTTS: # 腾讯云智能语音交互服务,需要先在腾讯云平台开通服务 # appid、secret_id、secret_key申请地址:https://console.cloud.tencent.com/cam/capi @@ -971,6 +983,7 @@ TTS: secret_key: 你的腾讯云SecretKey region: ap-guangzhou voice: 101001 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 TTS302AI: # 302AI语音合成服务,需要先在302平台创建账户充值,并获取密钥信息 @@ -985,6 +998,7 @@ TTS: voice: "zh_female_wanwanxiaohe_moon_bigtts" output_dir: tmp/ access_token: "你的302API密钥" + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 GizwitsTTS: type: doubao # 火山引擎作为基座,可以完全使用企业级火山引擎语音合成服务 @@ -996,6 +1010,7 @@ TTS: voice: "zh_female_wanwanxiaohe_moon_bigtts" output_dir: tmp/ access_token: "你的机智云API key" + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 ACGNTTS: #在线网址:https://acgn.ttson.cn/ #token购买:www.ttson.cn @@ -1013,6 +1028,7 @@ TTS: format: mp3 output_dir: tmp/ emotion: 1 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 OpenAITTS: # openai官方文本转语音服务,可支持全球大多数语种 type: openai @@ -1028,6 +1044,7 @@ TTS: # 语速范围0.25-4.0 speed: 1 output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 CustomTTS: # 自定义的TTS接口服务,请求参数可自定义,可接入众多TTS服务 # 以本地部署的KokoroTTS为例 @@ -1050,6 +1067,7 @@ TTS: # Authorization: Bearer xxxx format: mp3 # 接口返回的音频格式 output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 LinkeraiTTS: type: linkerai api_url: https://tts.linkerai.cn/tts @@ -1061,6 +1079,7 @@ TTS: access_token: "U4YdYXVfpwWnk2t5Gp822zWPCuORyeJL" voice: "OUeAo1mhq6IBExi" output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 PaddleSpeechTTS: #百度飞浆 PaddleSpeech 支持本地离线部署 支持模型训练 #框架地址 https://www.paddlepaddle.org.cn/ @@ -1074,6 +1093,7 @@ TTS: speed: 1.0 # 语速,1.0 表示正常语速,>1 表示加快,<1 表示减慢 volume: 1.0 # 音量,1.0 表示正常音量,>1 表示增大,<1 表示减小 save_path: # 保存路径 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 IndexStreamTTS: # 基于Index-TTS-vLLM项目的TTS接口服务 # 参照教程:https://github.com/Ksuriuri/index-tts-vllm/blob/master/README.md @@ -1083,6 +1103,7 @@ TTS: # 默认音色,如需其他音色可到项目assets文件夹下注册 voice: "jay_klee" output_dir: tmp/ + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 AliBLTTS: # 阿里百炼CosyVoice大模型流式文本语音合成 # 可在这里找到你的 api_key https://bailian.console.aliyun.com/?apiKey=1#/api-key @@ -1097,6 +1118,7 @@ TTS: # volume: 50 # 音量:0-100 # rate: 1 # 语速:0.5~2 # pitch: 1 # 语调:0.5~2 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 XunFeiTTS: # 讯飞TTS服务 官方网站:https://www.xfyun.cn/ # 登录讯飞语音技术平台 https://console.xfyun.cn/app/myapp 创建相关应用 @@ -1118,3 +1140,4 @@ TTS: # volume: 50 # 音量:0-100 # speed: 50 # 语速:0-100 # pitch: 50 # 语调:0-100 + # language: "中文" # 指定输出语种,如:中文、英语、日语、韩语等,请根据所选音色支持的语言进行设置,不填则默认为中文 diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 6e8f5a8b..3f917963 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -134,7 +134,6 @@ class ConnectionHandler: self.asr_audio = [] self.asr_audio_queue = queue.Queue() self.current_speaker = None # 存储当前说话人 - self.current_language_tag = None # 存储当前ASR识别的语言标签 # llm相关变量 self.dialogue = Dialogue() diff --git a/main/xiaozhi-server/core/handle/receiveAudioHandle.py b/main/xiaozhi-server/core/handle/receiveAudioHandle.py index df466df5..4f69aa99 100644 --- a/main/xiaozhi-server/core/handle/receiveAudioHandle.py +++ b/main/xiaozhi-server/core/handle/receiveAudioHandle.py @@ -67,11 +67,6 @@ async def startToChat(conn: "ConnectionHandler", text): conn.current_speaker = speaker_name else: conn.current_speaker = None - # 保存语种信息到连接对象 - if language_tag: - conn.current_language_tag = language_tag - else: - conn.current_language_tag = "zh" if conn.need_bind: await check_bind_device(conn) diff --git a/main/xiaozhi-server/core/utils/prompt_manager.py b/main/xiaozhi-server/core/utils/prompt_manager.py index f7171603..fbd3fda0 100644 --- a/main/xiaozhi-server/core/utils/prompt_manager.py +++ b/main/xiaozhi-server/core/utils/prompt_manager.py @@ -251,6 +251,15 @@ class PromptManager: or "" ) + # 获取TTS选择的语言,默认值为中文 + language = ( + self.config.get("TTS", {}) + .get(self.config.get("selected_module", {}).get("TTS", ""), {}) + .get("language") + or "中文" + ) + self.logger.bind(tag=TAG).debug(f"获取到选择的语言: {language}") + # 替换模板变量 template = Template(self.base_prompt_template) enhanced_prompt = template.render( @@ -265,6 +274,7 @@ class PromptManager: device_id=device_id, client_ip=client_ip, dynamic_context=self.context_data, + language=language, *args, **kwargs, )