在AI Agent中集成语音合成:从文本到自然语音的实践
1 语音交互架构设计
一个具备语音能力的AI Agent,其交互流程通常包含以下层次:
1.1 基础交互模式
用户 → 智能体 → 文本响应
这是最简化的流程:用户输入触发智能体,智能体返回纯文本。
1.2 引入语音输出
用户 → 智能体 → 文本响应
↓
TTS引擎 → 语音输出
在基础流程上增加文本转语音(TTS)模块。智能体生成的文本被送入TTS服务,最终转换为语音。
1.3 异步并行处理
用户 → 智能体 → 文本响应
↓(异步)
TTS引擎 → 语音输出
文本响应立即返回,语音合成在后台异步执行,提升用户体验。
1.4 设计要点
- 模块解耦:文本处理与语音合成分离,便于独立升级和维护。
- 异步非阻塞:语音合成不阻塞主流程,响应速度更快。
- 灵活切换:可根据场景仅返回文本或同时提供语音。
- 接入成熟方案:如Google Cloud TTS、Azure TTS等,确保合成质量。
2 TTS技术选型与核心概念
以Google Cloud Text-to-Speech为例,其API能将文本或SSML(语音合成标记语言)转换为MP3、LINEAR16等格式的音频数据。
2.1 基本请求示例
通过curl调用合成接口:
curl -H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "x-goog-user-project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json; charset=utf-8" \
--data '{
"input": { "text": "I have added the event to your calendar." },
"voice": {
"languageCode": "en-GB",
"name": "en-GB-Standard-A",
"ssmlGender": "FEMALE"
},
"audioConfig": { "audioEncoding": "MP3" }
}' "https://texttospeech.googleapis.com/v1/text:synthesize"
2.2 合成过程
将文本输入转换为音频数据的过程称为"合成"。API返回base64编码的音频数据,需解码后保存为文件或直接播放。
2.3 语音选择
不同的语音参数(语言、性别、口音)可模拟不同说话者。例如使用英式口音女性,或澳式口音男性。
2.4 WaveNet模型
Google WaveNet是一种深度神经网络,基于真人语音样本训练,生成的语音更自然、温暖。相比传统拼接合成,音质明显提升。
2.5 可调参数
除语音外,还可调节语速、音高、音量、采样率(Hz)等。
2.6 SSML支持
通过SSML可在文本中嵌入停顿、强调、数字发音规则等细节,提升合成表现力。
3 后端语音功能实现
以下使用FastAPI框架实现一个带异步语音合成的端点。
3.1 聊天接口
@app.post("/chat")
async def chat(query: str, background_tasks: BackgroundTasks):
agent = Master()
reply = agent.run(query)
task_id = str(uuid.uuid4())
background_tasks.add_task(agent.voice_synthesis_background, reply, task_id)
return {"reply": reply, "task_id": task_id}
后台任务触发语音合成,不阻塞接口响应。
3.2 后台合成任务
def voice_synthesis_background(self, text: str, uid: str):
asyncio.run(self._synthesize_text(text, uid))
3.3 核心合成方法
async def _synthesize_text(self, text: str, uid: str):
print("TTS input:", text)
print("UID:", uid)
print("Current emotion:", self.emotion)
# 使用REST传输避免gRPC的503错误
client = texttospeech.TextToSpeechClient(transport="rest")
input_text = texttospeech.SynthesisInput(text="Hello world") # 示例文本
voice = texttospeech.VoiceSelectionParams(
language_code="en-US",
name="en-US-Studio-O",
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.LINEAR16,
speaking_rate=1.0
)
response = client.synthesize_speech(
request={"input": input_text, "voice": voice, "audio_config": audio_config}
)
# 保存音频文件
with open(f"output_{uid}.mp3", "wb") as f:
f.write(response.audio_content)
print("Audio saved to output.mp3")
4 语音克隆与增强替代方案
4.1 Bark (语音克隆)
Bark是第二代声音克隆模型,支持中文及英文等多种语言,可生成高度拟人化的语音,甚至模拟笑声、叹息等非语言声音。
4.2 阿里云Sambert语音合成
基于达摩院自研的SAMBERT+NSFGAN模型,结合深度神经网络与领域知识,具有高准确度、自然韵律和强表现力。支持实时流式合成。
4.2.1 保存音频到文件
from dashscope.audio.tts import SpeechSynthesizer
result = SpeechSynthesizer.call(
model='sambert-zhichu-v1',
text='今天天气怎么样',
sample_rate=48000
)
if result.get_audio_data():
with open('output.wav', 'wb') as f:
f.write(result.get_audio_data())
print('音频保存成功,大小:', len(result.get_audio_data()), 'bytes')
else:
print('请求失败:', result.get_response())
4.2.2 实时播放音频
import pyaudio
from dashscope.audio.tts import ResultCallback, SpeechSynthesizer, SpeechSynthesisResult
class AudioCallback(ResultCallback):
def __init__(self):
self.player = None
self.stream = None
def on_open(self):
self.player = pyaudio.PyAudio()
self.stream = self.player.open(
format=pyaudio.paInt16,
channels=1,
rate=48000,
output=True
)
def on_event(self, result: SpeechSynthesisResult):
if result.get_audio_frame():
self.stream.write(result.get_audio_frame())
if result.get_timestamp():
print('时间戳:', result.get_timestamp())
def on_close(self):
self.stream.stop_stream()
self.stream.close()
self.player.terminate()
callback = AudioCallback()
SpeechSynthesizer.call(
model='sambert-zhichu-v1',
text='你是睿智的JavaEdge',
sample_rate=48000,
format='pcm',
callback=callback
)
运行后即可通过扬声器听到合成语音。