利用TTS,讓你的AI Agent發聲!
1 語音邏輯設計
一個AI Agent應用的語音邏輯設計流程圖。
1.1 基本流程
- 用戶 -> Agent -> 文本回答
最基礎的交互模式。用戶輸入被傳遞給Agent,Agent生成文本回答。
1.2 添加語音功能
- 用戶 -> Agent -> 文本回答
|
v
TTS服務 -> MSTTS -> 語音回答
基本流程基礎上,增加文本轉語音(TTS)服務。Agent生成的文本回答被發送到TTS服務,然后通過MSTTS(Microsoft Text-to-Speech)轉換為語音回答。
1.3 完整流程
- 用戶 -> Agent -> 文本回答
|
v (異步)
TTS服務 -> MSTTS -> 語音回答
文本回答和語音回答是并行處理的。Agent生成文本回答后,同時開始TTS轉換過程,這個過程被標記為"異步"。
1.4 設計思路
- 模塊化:將文本處理和語音轉換分離,便于獨立開發和維護。
- 異步處理:文本回答可以立即呈現,而語音轉換在后臺進行,提高響應速度。
- 靈活性:可以根據需求選擇只使用文本回答或同時使用語音回答。
- 技術整合:利用MSTTS等成熟技術,提高語音質量。
這種設計允許AI Agent應用在保持高效文本交互的同時,提供更豐富的語音交互體驗。
2 TTS能力介紹
以 Google Cloud Text-To-Speech 服務為例說明。
開發人員可用 Text-to-Speech 創建可播放音頻格式的自然發音的合成人類語音。可用由 Text-to-Speech 創建的音頻數據文件來豐富應用功能或者擴大視頻或錄音等媒體。
Text-to-Speech 會將文本或語音合成標記語言 (SSML) 輸入轉換為音頻數據,例如 MP3 或 LINEAR16(WAV 文件中使用的編碼)。
2.1 基本示例
Text-to-Speech 適用于向用戶播放人類語音音頻的任何應用。您可以使用它將任意字符串、字詞和句子轉換為表述相同內容的人的語音。
設想您有一個語音輔助應用,可以通過可播放音頻文件,向您的用戶提供自然語言反饋。您的應用可能會執行某個操作,然后向用戶提供人類語音作為反饋。
例如,您的應用可能想要報告它已成功將某項活動添加到用戶的日歷中。您的應用會構建一個響應字符串向用戶報告操作已成功,例如“我已將活動添加到您的日歷中”。
使用 Text-to-Speech,您可以將該響應字符串轉換為實際的人類語音以播放給用戶,類似于下面提供的示例。
示例 1:Text-to-Speech 生成的音頻文件
要創建音頻文件,請向 Text-to-Speech 發送請求,如:
curl -H "Authorization: Bearer "$(gcloud auth print-access-token) -H "x-goog-user-project: <var>PROJECT_ID</var>" -H "Content-Type: application/json; charset=utf-8" --data "{
'input':{
'text':'I\'ve 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 語音合成
將文本輸入轉換為音頻數據的過程稱為合成,而輸出合成則稱為合成語音。Text-to-Speech 采用兩種類型的輸入:原始文本或 SSML 格式的數據(下文詳解)。要創建新的音頻文件,可調用 API 的 synthesize
端點。
語音合成過程會生成原始音頻數據,格式為 base64 編碼字符串。您必須先將 base64 編碼字符串解碼為音頻文件,應用才可以播放相應文件。大多數平臺和操作系統都具備將 base64 文本解碼為可播放媒體文件的工具。
2.3 語音
Text-to-Speech 生成自然人類語音的原始音頻數據。也就是說,它生成的音頻聽上去像人在說話。當您向 Text-to-Speech 發送合成請求時,您必須指定“說出”字詞的語音。
Text-to-Speech 有多種自定義語音供您選擇。語音因語言、性別和口音(適用于某些語言)而異。例如,你可以創建模仿帶有英國口音的女性說英語的聲音音頻,如以上示例 1您也可以將同一文本轉換為不同的語音,比方說有澳大利亞口音的男性說英語的聲音。
2.4 WaveNet 語音
Text-to-Speech 還同其他傳統合成語音一起,提供優質的 WaveNet 生成語音。用戶發現 Wavenet 生成語音比其他合成語音更溫暖,更像人聲。
WaveNet 語音的主要不同之處在于生成語音所用的 WaveNet 模型。WaveNet 模型一直在使用真人發聲的原始音頻樣本進行訓練。因此,這些模型生成的合成語音,其音節、音位和字詞的重音與音調更像人類。
2.5 其他音頻輸出設置
除了語音之外,您還可以配置語音合成創建的音頻數據輸出的其他方面。Text-to-Speech 支持您配置語速、音高、音量和采樣率(單位為赫茲)。
2.6 語音合成標記語言 (SSML) 支持
可通過語音合成標記語言 (SSML) 對文本進行標記來增強 Text-to-Speech 生成的合成語音。SSML 可讓您在 Text-to-Speech 生成的音頻數據中插入暫停、首字母縮寫詞發音或其他細節。
注意:Text-to-Speech 不支持特定可用語言的部分 SSML 元素。
例如,您可以通過提供具有標記序數詞的 SSML 輸入的 Text-to-Speech 來確保合成語音正確地讀出序數詞。
創建服務賬號:
圖片
為其創建密鑰:
圖片
添加密鑰:
圖片
新建 json 類型密鑰:
圖片
下載該 json 密鑰存儲到項目路徑下:
圖片
項目配置該密鑰:
圖片
為項目啟用 API 服務:
圖片
3 Voice函數的實現
@app.post("/chat")
def chat(query: str, background_tasks: BackgroundTasks):
master = Master()
msg = master.run(query)
unique_id = str(uuid.uuid4())
background_tasks.add_task(master.background_voice_synthesis, msg, unique_id)
return {"msg": msg, "id": unique_id}
def background_voice_synthesis(self, text: str, uid: str):
# 無返回值,只是觸發語音合成
asyncio.run(self.get_voice(text, uid))
# text 要轉換為語音的文本
async def get_voice(self, text: str, uid: str):
print("text2speech", text)
print("uid", uid)
print("當前Edge大師應該的語氣是:", self.emotion)
# 默認 grpc 會報 503 錯誤,必須 rest 請求
client = texttospeech.TextToSpeechClient(transport="rest")
input_text = texttospeech.SynthesisInput(text="fsfsdfsd")
print("input_text=", input_text)
# Note: the voice can also be specified by name.
# Names of voices can be retrieved with client.list_voices().
voice = texttospeech.VoiceSelectionParams(
language_code="en-US",
name="en-US-Studio-O",
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.LINEAR16,
speaking_rate=1
)
response = client.synthesize_speech(
request={"input": input_text, "voice": voice, "audio_config": audio_config}
)
print("respnotallow=", response)
# The response's audio_content is binary.
with open("output.mp3", "wb") as out:
out.write(response.audio_content)
print('Audio content written to file "output.mp3"')
終端輸出:
圖片
生成文件:
圖片
4 語音克隆+TTS增強
4.1 Bark
直達官網,第二代Bark聲音克隆 ?? & 全新中文聲音克隆:
圖片
4.2 阿里Sambert語音合成
提供SAMBERT+NSFGAN深度神經網絡算法與傳統領域知識深度結合的文字轉語音服務,兼具讀音準確,韻律自然,聲音還原度高,表現力強的特點。
語音合成API基于達摩院改良的自回歸韻律模型,具有推理速度快,合成效果佳的特點。開發者可以通過以下鏈接,了解如何通過大模型服務平臺調用Sambert語音合成API:
Sambert語音合成API基于達摩院改良的自回歸韻律模型,支持文本至語音的實時流式合成。可被應用于:
- 智能設備/機器人播報的語音內容,如智能客服機器人、智能音箱、數字人等。
- 音視頻創作中需要將文字轉為語音播報的場景,如小說閱讀、新聞播報、影視解說、配音等。
① 將合成音頻保存為文件
以下代碼展示了將流式返回的二進制音頻,保存為本地文件。
import os
from dotenv import load_dotenv
load_dotenv("qwen.env")
import sys
from dashscope.audio.tts import SpeechSynthesizer
result = SpeechSynthesizer.call(model='sambert-zhichu-v1',
text='今天天氣怎么樣',
sample_rate=48000)
if result.get_audio_data() is not None:
with open('output.wav', 'wb') as f:
f.write(result.get_audio_data())
print('SUCCESS: get audio data: %dbytes in output.wav' %
(sys.getsizeof(result.get_audio_data())))
else:
print('ERROR: response is %s' % (result.get_response()))
圖片
② 將合成音頻通過設備播放
調用成功后,通過本地設備播放實時返回的音頻內容。
運行示例前,需要通過pip安裝第三方音頻播放套件。
# Installation instructions for pyaudio:
# APPLE Mac OS X
# brew install portaudio
# pip install pyaudio
# Debian/Ubuntu
# sudo apt-get install python-pyaudio python3-pyaudio
# or
# pip install pyaudio
# CentOS
# sudo yum install -y portaudio portaudio-devel && pip install pyaudio
# Microsoft Windows
# python -m pip install pyaudio
import dashscope
import sys
import pyaudio
from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse
from dashscope.audio.tts import ResultCallback, SpeechSynthesizer, SpeechSynthesisResult
dashscope.api_key='sk-xxx'
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
print('Speech synthesizer is opened.')
self._player = pyaudio.PyAudio()
self._stream = self._player.open(
format=pyaudio.paInt16,
channels=1,
rate=48000,
output=True)
def on_complete(self):
print('Speech synthesizer is completed.')
def on_error(self, response: SpeechSynthesisResponse):
print('Speech synthesizer failed, response is %s' % (str(response)))
def on_close(self):
print('Speech synthesizer is closed.')
self._stream.stop_stream()
self._stream.close()
self._player.terminate()
def on_event(self, result: SpeechSynthesisResult):
if result.get_audio_frame() is not None:
print('audio result length:', sys.getsizeof(result.get_audio_frame()))
self._stream.write(result.get_audio_frame())
if result.get_timestamp() is not None:
print('timestamp result:', str(result.get_timestamp()))
callback = Callback()
SpeechSynthesizer.call(model='sambert-zhichu-v1',
text='你是睿智的JavaEdge',
sample_rate=48000,
format='pcm',
callback=callback)
執行完后,你就能聽到系統語音播放內容了!