diff --git a/main/manager-api/src/main/resources/db/changelog/202508081701.sql b/main/manager-api/src/main/resources/db/changelog/202508081701.sql new file mode 100644 index 00000000..4f427514 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202508081701.sql @@ -0,0 +1,32 @@ +-- 添加Index-TTS-vLLM流式TTS供应器 +delete from `ai_model_provider` where id = 'SYSTEM_TTS_IndexStreamTTS'; +INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +('SYSTEM_TTS_IndexStreamTTS', 'TTS', 'index_stream', 'Index-TTS-vLLM流式语音合成', '[{"key":"api_url","label":"API服务地址","type":"string"},{"key":"voice","label":"默认音色","type":"string"},{"key":"audio_format","label":"音频格式","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 16, 1, NOW(), 1, NOW()); + +-- 添加Index-TTS-vLLM流式TTS模型配置 +delete from `ai_model_config` where id = 'TTS_IndexStreamTTS'; +INSERT INTO `ai_model_config` VALUES ('TTS_IndexStreamTTS', 'TTS', 'IndexStreamTTS', 'Index-TTS-vLLM流式语音合成', 0, 1, '{\"type\": \"index_stream\", \"api_url\": \"http://127.0.0.1:11996/tts\", \"voice\": \"jay_klee\", \"audio_format\": \"pcm\", \"output_dir\": \"tmp/\"}', NULL, NULL, 19, NULL, NULL, NULL, NULL); + +-- 更新Index-TTS-vLLM流式TTS配置说明 +UPDATE `ai_model_config` SET +`doc_link` = 'https://github.com/Ksuriuri/index-tts-vllm', +`remark` = 'Index-TTS-vLLM流式TTS配置说明: +1. Index-TTS-vLLM是基于Index-TTS项目的vLLM推理服务,提供流式语音合成功能 +2. 支持多种音色,音质自然,适合各种语音交互场景 +3. 需要先部署Index-TTS-vLLM服务,然后配置API地址 +4. 支持实时流式合成,具有较低的延迟 +5. 支持自定义音色,可在项目assets文件夹下注册新音色 +部署步骤: +1. 克隆项目:git clone https://github.com/Ksuriuri/index-tts-vllm.git +2. 安装依赖:pip install -r requirements.txt +3. 启动服务:python app.py +4. 服务默认运行在 http://127.0.0.1:11996 +5. 如需其他音色,可到项目assets文件夹下注册 +6. 支持多种音频格式:pcm、wav、mp3等 +如需了解更多配置,请参考:https://github.com/Ksuriuri/index-tts-vllm/blob/master/README.md +' WHERE `id` = 'TTS_IndexStreamTTS'; + +-- 添加Index-TTS-vLLM流式TTS音色 +delete from `ai_tts_voice` where tts_model_id = 'TTS_IndexStreamTTS'; +-- 默认音色 +INSERT INTO `ai_tts_voice` VALUES ('TTS_IndexStreamTTS_0001', 'TTS_IndexStreamTTS', 'Jay Klee', 'jay_klee', '中文及中英文混合', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL); diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 72000ee3..c36272eb 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -282,3 +282,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202507081646.sql + - changeSet: + id: 202508081701 + author: hrz + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202508081701.sql diff --git a/main/xiaozhi-server/config.yaml b/main/xiaozhi-server/config.yaml index a725c5e4..8e9e77cd 100644 --- a/main/xiaozhi-server/config.yaml +++ b/main/xiaozhi-server/config.yaml @@ -902,7 +902,7 @@ TTS: IndexStreamTTS: # 基于Index-TTS-vLLM项目的TTS接口服务 # 参照教程:https://github.com/Ksuriuri/index-tts-vllm/blob/master/README.md - type: IndexStream + type: index_stream api_url: http://127.0.0.1:11996/tts audio_format: "pcm" # 默认音色,如需其他音色可到项目assets文件夹下注册 diff --git a/main/xiaozhi-server/core/providers/tts/IndexStream.py b/main/xiaozhi-server/core/providers/tts/index_stream.py similarity index 94% rename from main/xiaozhi-server/core/providers/tts/IndexStream.py rename to main/xiaozhi-server/core/providers/tts/index_stream.py index b027af06..5ea9eb36 100644 --- a/main/xiaozhi-server/core/providers/tts/IndexStream.py +++ b/main/xiaozhi-server/core/providers/tts/index_stream.py @@ -19,7 +19,11 @@ class TTSProvider(TTSProviderBase): def __init__(self, config, delete_audio_file): super().__init__(config, delete_audio_file) self.interface_type = InterfaceType.SINGLE_STREAM - self.voice = config.get("voice", "xiao_he") # 默认音色 + self.voice = config.get("voice", "xiao_he") + if config.get("private_voice"): + self.voice = config.get("private_voice") + else: + self.voice = config.get("voice", "xiao_he") self.api_url = config.get("api_url", "http://8.138.114.124:11996/tts") self.audio_format = "pcm" self.before_stop_play_files = [] @@ -80,7 +84,7 @@ class TTSProvider(TTSProviderBase): bool: 是否成功处理了文本 """ full_text = "".join(self.tts_text_buff) - remaining_text = full_text[self.processed_chars:] + remaining_text = full_text[self.processed_chars :] if remaining_text: segment_text = textUtils.get_string_no_punctuation_or_emoji(remaining_text) if segment_text: @@ -118,10 +122,7 @@ class TTSProvider(TTSProviderBase): async def text_to_speak(self, text, is_last): """流式处理TTS音频,每句只推送一次音频列表""" - payload = { - "text": text, - "character": self.voice - } + payload = {"text": text, "character": self.voice} frame_bytes = int( self.opus_encoder.sample_rate @@ -132,9 +133,7 @@ class TTSProvider(TTSProviderBase): ) # 16-bit = 2 bytes try: async with aiohttp.ClientSession() as session: - async with session.post( - self.api_url, json=payload, timeout=10 - ) as resp: + async with session.post(self.api_url, json=payload, timeout=10) as resp: if resp.status != 200: logger.bind(tag=TAG).error( @@ -220,15 +219,10 @@ class TTSProvider(TTSProviderBase): start_time = time.time() text = MarkdownCleaner.clean_markdown(text) - payload = { - "text": text, - "character": self.character - } + payload = {"text": text, "character": self.character} try: - with requests.post( - self.api_url, json=payload, timeout=5 - ) as response: + with requests.post(self.api_url, json=payload, timeout=5) as response: if response.status_code != 200: logger.bind(tag=TAG).error( f"TTS请求失败: {response.status_code}, {response.text}" @@ -252,7 +246,7 @@ class TTSProvider(TTSProviderBase): # 分帧处理PCM数据 for i in range(0, len(pcm_data), frame_bytes): - frame = pcm_data[i: i + frame_bytes] + frame = pcm_data[i : i + frame_bytes] if len(frame) < frame_bytes: # 最后一帧可能不足,用0填充 frame = frame + b"\x00" * (frame_bytes - len(frame))