即時語音合成(Qwen-Audio-TTS/CosyVoice)
即時語音合成Qwen-Audio-TTS/CosyVoice Python SDK
本文介紹通過DashScope Python SDK進行Qwen-Audio-TTS/CosyVoice即時語音合成的類定義、請求參數和範例程式碼。
使用者指南:關於模型介紹和選型建議請參見語音合成。
介面地址
SDK的介面地址需在初始化前設定為下方地址(包含WorkspaceId)。如需切換到其他地區,請修改 dashscope.base_websocket_api_url為對應地區的URL。
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference調用時請將{WorkspaceId}替換為真實的Workspace ID。wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference調用時請將{WorkspaceId}替換為真實的Workspace ID。
切換到新加坡地區:
import dashscope
# 調用時請將"{WorkspaceId}"替換為真實的業務空間ID
dashscope.base_websocket_api_url = 'wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
阿里雲百鍊為華北2(北京)、新加坡地區推出了業務空間專屬網域名稱,能夠為推理請求提供卓越的效能和更高的穩定性,建議遷移至新網域名稱:
- 華北2(北京)地區:從
dashscope.aliyuncs.com 遷移至 {WorkspaceId}.cn-beijing.maas.aliyuncs.com
- 新加坡地區:從
dashscope-intl.aliyuncs.com 遷移至 {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
{WorkspaceId}需要替換為真實的Workspace ID。現有網域名稱仍可正常使用。
SpeechSynthesizer
包路徑:dashscope.audio.tts_v2.SpeechSynthesizer
構造方法
SpeechSynthesizer(
model: str,
voice: str,
format: AudioFormat = AudioFormat.MP3_22050HZ_MONO_256KBPS,
volume: int = 50,
speech_rate: float = 1.0,
pitch_rate: float = 1.0,
callback: ResultCallback = None)
call() - 非流式調用
方法簽名:
def call(self, text: str) -> bytes
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
text | str | 是 | 待合成的完整文本,長度不得超過20000字元。 |
傳回值:bytes,完整音頻資料。
說明:非流式調用,阻塞等待並一次性返回完整音頻資料。適用於短文本、對即時性無嚴格要求的情境。每次調用前需重新初始化SpeechSynthesizer執行個體。
streaming_call() - 流式調用
方法簽名:
def streaming_call(self, text: str) -> None
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
text | str | 是 | 當前待合成的文本片段。可多次調用以追加文本,單次不超過20000字元,累計不超過20萬字元。 |
說明:雙向流式調用,支援分區提交文本並通過回調即時擷取合成音頻。適用於與大語言模型對接、邊產生文本邊合成語音的情境。發送完畢後需調用streaming_complete()結束合成。
streaming_complete() - 結束流式合成
方法簽名:
def streaming_complete(self) -> None
說明:通知服務端所有文本已發送完畢,阻塞當前線程直到剩餘文本合成完成並返回所有音頻資料。未調用此方法可能導致尾部文本無法轉換為語音。
streaming_cancel() - 取消流式合成
方法簽名:
def streaming_cancel(self, complete_timeout_millis: int = 10000) -> None
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
complete_timeout_millis | int | 否 | 等待服務端返回 task-finished 事件的逾時時間,單位毫秒。預設值:10000。 |
說明:取消當前輪次的流式語音合成任務。調用後,SDK 會立即結束當前任務。取消後可在當前串連上繼續發起新的合成任務,無需重新初始化 SpeechSynthesizer 執行個體。
版本要求:使用該功能需要 Python SDK 版本不低於 1.26.4。
模型限制:
- 華北2(北京)地區:Qwen-Audio-TTS 系列模型的所有模型都支援該功能;CosyVoice 系列模型僅 v2 及以上版本支援該功能。
- 新加坡地區:Qwen-Audio-TTS 系列模型的所有模型都支援該功能;CosyVoice 系列模型不支援該功能。
get_last_request_id() - 擷取請求ID
方法簽名:
def get_last_request_id(self) -> str
傳回值:str,最近一次請求的request_id,可用於問題排查和日誌關聯。
get_first_package_delay() - 擷取首包延遲
方法簽名:
def get_first_package_delay(self) -> float
傳回值:float,從發送文本到收到第一塊音頻資料的延遲時間(毫秒)。需在合成完成後調用。
get_response() - 擷取響應訊息
方法簽名:
def get_response(self) -> dict
傳回值:dict,最近一次合成任務的響應訊息(含 header/payload 鍵)。
構造參數
以下參數通過SpeechSynthesizer構造方法設定,用於控制合成音訊模型、音色、格式和音頻特徵。
| 參數 | 類型 | 是否必須 | 說明 |
|---|
| model | str | 是 | 模型名稱。 |
| voice | str | 是 | voicestring(必選)語音合成所使用的音色。 |
| format | enum | 否 | 音頻編碼格式及採樣率。預設值:AudioFormat.MP3_22050HZ_MONO_256KBPS。AudioFormat枚舉類的包路徑:dashscope.audio.tts_v2,支援MP3、WAV、PCM等格式。 |
| volume | int | 否 | 音量。預設值:50。取值範圍:[0, 100]。 |
| speech_rate | float | 否 | 語速。預設值:1.0。取值範圍:[0.5, 2.0]。 |
| pitch_rate | float | 否 | 音調。預設值:1.0。取值範圍:[0.5, 2.0]。 |
| bit_rate | int | 否 | 音頻碼率(kbps)。音頻格式為mp3或opus時,支援通過bit_rate參數調整碼率。預設值:32。取值範圍:[6, 510]。bit_rate需要通過additional_params參數進行設定:synthesizer = SpeechSynthesizer(
model="qwen-audio-3.0-tts-flash",
voice="longanhuan_v3.6",
additional_params={"bit_rate": 128}
)
|
| word_timestamp_enabled | bool | 否 | 是否開啟字層級時間戳記。預設值:false。僅在流式輸出模式下可用。支援的音色範圍:cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色,以及Qwen-Audio-TTS音色列表、CosyVoice音色列表中標記為支援的系統音色。其他模型的複刻音色不支援此功能。word_timestamp_enabled需要通過additional_params參數進行設定:synthesizer = SpeechSynthesizer(
model="cosyvoice-v3-flash",
voice="your_voice", # 支援字層級時間戳記的系統音色或複刻音色
additional_params={"word_timestamp_enabled": True}
)
|
| seed | int | 否 | 產生時使用的隨機數種子,使合成的效果產生變化。在模型版本、文本、音色及其他參數均相同的前提下,使用相同的seed可複現相同的合成結果。預設值0。取值範圍:[0, 65535]。 |
| language_hints | list[str] | 否 |
- 此參數為數組,但目前的版本僅處理第一個元素,因此建議只傳入一個值。
- 此參數用於指定語音合成的目標語言,該設定與聲音複刻時的樣本音訊語種無關。如需設定複刻任務的源語言,請參見聲音複刻API參考。
指定語音合成的目標語言,提升合成效果。當數字、縮寫、符號等朗讀方式或者小語種合成效果不符合預期時使用,例如:
- 數字朗讀方式不符合預期,“hello, this is 110”讀成“hello, this is one one zero”而非“hello, this is 么么零”
- 符號朗讀不準確,“@”讀成“艾特”而非“at”
- 小語種合成效果差,合成不自然
取值範圍:
- zh:中文
- en:英語
- fr:法語
- de:德語
- ja:日語
- ko:韓語
- ru:俄語
- pt:葡萄牙語
- th:泰語
- id:印尼語
- vi:越南語
- es:西班牙語
- it:意大利語
- ms:馬來西亞語
- fil:菲律賓語
- ar:阿拉伯語
|
| instruction | str | 否 | 設定指令,用於控制方言、情感或角色等合成效果。使用說明請參見指令控制。 |
| enable_aigc_tag | bool | 否 | 是否在產生的音頻中添加AIGC隱性標識。設定為true時,會將隱性標識嵌入到支援格式(wav/mp3/opus)的音頻中。預設值:false。僅qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支援該功能。enable_aigc_tag、aigc_propagator和aigc_propagate_id需要通過additional_params參數進行設定:synthesizer = SpeechSynthesizer(
model="qwen-audio-3.0-tts-flash",
voice="longanhuan_v3.6",
additional_params={
"enable_aigc_tag": True,
"aigc_propagator": "your_propagator",
"aigc_propagate_id": "your_propagate_id"
}
)
|
| aigc_propagator | str | 否 | 設定AIGC隱性標識中的 ContentPropagator 欄位,用於標識內容的傳播者。僅在 enable_aigc_tag 為 true 時生效。預設值:阿里雲UID。僅qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支援該功能。需要通過additional_params參數進行設定,參見enable_aigc_tag的樣本。 |
| aigc_propagate_id | str | 否 | 設定AIGC隱性標識中的 PropagateID 欄位,用於唯一標識一次具體的傳播行為。僅在 enable_aigc_tag 為 true 時生效。預設值:本次語音合成請求Request ID。僅qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支援該功能。需要通過additional_params參數進行設定,參見enable_aigc_tag的樣本。 |
| hot_fix | dict | 否 | 文本熱修複配置,用於自訂指定詞語的發音或對待合成文本進行替換。qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash、cosyvoice-v2不支援該功能。參數介紹:
- pronunciation:自訂發音。指定詞語的拼音標註,用於糾正預設發音不準確的情況。
- replace:文本替換。在語音合成前將指定詞語替換為目標文本,替換後的文本將作為實際合成內容。
樣本:synthesizer = SpeechSynthesizer(
model="cosyvoice-v3.5-plus",
voice="cosyvoice-v3.5-plus-vd-announcer-xxxxxx", # 音色
hot_fix={
"pronunciation": [{"天氣": "tian1 qi4"}],
"replace": [{"今天": "金天"}]
}
)
|
| enable_markdown_filter | bool | 否 | 僅cosyvoice-v3-flash複刻音色支援該功能。 是否啟用 Markdown 過濾。啟用該功能後,系統在合成語音前自動過濾輸入文本中的 Markdown 標記符號,避免將其朗讀為文字內容。預設值:false。取值範圍:
- true:啟用Markdown過濾
- false:禁用Markdown過濾
enable_markdown_filter需要通過additional_params參數進行設定:synthesizer = SpeechSynthesizer(
model="cosyvoice-v3-flash",
voice="your_voice", # cosyvoice-v3-flash複刻音色
additional_params={"enable_markdown_filter": True}
)
|
| callback | ResultCallback | 否 | 回呼函數執行個體,用於非同步接收合成音頻和事件通知。設定此參數時,call()方法以流式模式運行,音頻資料通過on_data回調返回;不設定時,call()以非流式模式運行,直接返回完整音訊bytes資料。 |
ResultCallback
包路徑:dashscope.audio.tts_v2.ResultCallback
on_open() - 串連建立
方法簽名:
def on_open(self) -> None
觸發時機:WebSocket串連成功建立時觸發。可在此回調中初始化音訊輸出流或開啟檔案等資源。
on_event() - 接收服務端回複
方法簽名:
def on_event(self, message: str) -> None
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
message | str | 是 | 服務端響應事件(JSON格式),包含header(請求資訊)和payload(輸出資訊)。其中payload.output包含事件類型、原始文本等資訊,詳見on_event訊息中的output欄位。 |
觸發時機:接收到服務端回複時觸發。訊息為JSON字串,包含合成事件的輸出資訊(事件類型、原始文本、句子資訊等)。可通過json.loads(message)解析後訪問payload.output擷取詳細資料。
on_complete() - 合成完成
方法簽名:
def on_complete(self) -> None
觸發時機:所有文本合成完成且音頻資料已全部通過on_data返回後觸發。可在此回調中調用get_first_package_delay()擷取效能指標。
on_data() - 接收音頻資料
方法簽名:
def on_data(self, data: bytes) -> None
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
data | bytes | 是 | 當前批次的音頻位元據片段,格式由構造參數format指定。 |
觸發時機:每接收到一塊音頻資料時觸發,合成過程中會被多次調用。可在此回調中將資料寫入檔案或送入播放裝置。
on_error() - 發生錯誤
方法簽名:
def on_error(self, message: str) -> None
參數說明:
參數 | 類型 | 必填 | 說明 |
|---|
message | str | 是 | 錯誤描述資訊,包含錯誤碼和詳細原因。 |
觸發時機:合成過程中發生錯誤時觸發。觸發後串連將自動關閉,建議在此回調中記錄錯誤記錄檔以便排查問題。
on_close() - 串連關閉
方法簽名:
def on_close(self) -> None
觸發時機:WebSocket串連關閉時觸發(無論正常結束還是異常斷開)。可在此回調中釋放音頻播放裝置等資源。
on_event訊息中的output欄位
on_event回調接收的JSON訊息中,payload.output包含合成事件的輸出資訊,可用於跟蹤合成進度和擷取逐句資訊。以下為output欄位的結構說明:
欄位 | 類型 | 說明 |
|---|
type | str | 事件類型。取值為sentence-begin(句子合成開始)、sentence-synthesis(句子合成中)或sentence-end(句子合成結束)。 |
original_text | str | 當前句子的原始文本。在sentence-begin和sentence-end事件中返回。 |
sentence | dict | 句子資訊。包含index(句子序號)和words(詞列表,開啟word_timestamp_enabled時返回時間戳記資訊)。 |
訊息樣本:
{
"header": {
"task_id": "xxx",
"event": "result-generated",
"attributes": {}
},
"payload": {
"output": {
"type": "sentence-begin",
"original_text": "今天天氣怎麼樣?",
"sentence": {
"index": 0,
"words": []
}
}
}
}
解析樣本:
import json
def on_event(self, message):
data = json.loads(message)
output = data.get('payload', {}).get('output', {})
event_type = output.get('type', '')
original_text = output.get('original_text', '')
if event_type:
print(f'事件類型: {event_type}, 原始文本: {original_text}')
範例程式碼
SDK提供了語音合成的關鍵介面,支援以下幾種調用方式:
- 非流式調用:阻塞式,一次性發送完整文本,直接返回完整音頻。適合短文本語音合成情境。
- 單向流式調用:非阻塞式,一次性發送完整文本,通過回呼函數接收音頻資料(可能分區)。適用於對即時性要求高的短文本語音合成情境。
- 雙向流式調用:非阻塞式,可分多次發送文本片段,通過回呼函數即時接收增量合成的音頻流。適合即時性要求高的長文本語音合成情境。
非流式調用
單次調用發送的文本長度不得超過20000字元,超出限制將返回錯誤。
每次調用call方法前,需要重新初始化SpeechSynthesizer執行個體。
# coding=utf-8
import dashscope
from dashscope.audio.tts_v2 import *
import os
# 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區的配置,調用時請將"{WorkspaceId}"替換為真實的業務空間ID,各地區的配置不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# 模型
model = "qwen-audio-3.0-tts-flash"
# 音色
voice = "longanhuan_v3.6"
# 執行個體化SpeechSynthesizer,並在構造方法中傳入模型(model)、音色(voice)等請求參數
synthesizer = SpeechSynthesizer(model=model, voice=voice)
# 發送待合成文本,擷取二進位音頻
audio = synthesizer.call("今天天氣怎麼樣?")
# 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
print('[Metric] requestId為:{},首包延遲為:{}毫秒'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
# 將音頻儲存至本地
with open('output.mp3', 'wb') as f:
f.write(audio)
單向流式調用
單次調用發送的文本長度不得超過20000字元,超出限制將返回錯誤。
每次調用call方法前,需要重新初始化SpeechSynthesizer執行個體。
# coding=utf-8
import os
import json
import dashscope
from dashscope.audio.tts_v2 import *
from datetime import datetime
def get_timestamp():
now = datetime.now()
formatted_timestamp = now.strftime("[%Y-%m-%d %H:%M:%S.%f]")
return formatted_timestamp
# 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區的配置,調用時請將"{WorkspaceId}"替換為真實的業務空間ID,各地區的配置不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# 模型
model = "qwen-audio-3.0-tts-flash"
# 音色
voice = "longanhuan_v3.6"
# 定義回調介面
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
self.file = open("output.mp3", "wb")
print("串連建立:" + get_timestamp())
def on_complete(self):
print("語音合成完成,所有合成結果已被接收:" + get_timestamp())
# 當任務完成(on_complete 回調觸發)後,才可調用 get_first_package_delay 擷取延遲
# 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
print('[Metric] requestId為:{},首包延遲為:{}毫秒'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
def on_error(self, message: str):
print(f"語音合成出現異常:{message}")
def on_close(self):
print("串連關閉:" + get_timestamp())
self.file.close()
def on_event(self, message):
# 解析服務端事件,擷取輸出資訊
data = json.loads(message)
output = data.get('payload', {}).get('output', {})
event_type = output.get('type', '')
original_text = output.get('original_text', '')
if event_type:
print(f"事件類型: {event_type}, 原始文本: {original_text}")
def on_data(self, data: bytes) -> None:
print(get_timestamp() + " 二進位音頻長度為:" + str(len(data)))
self.file.write(data)
callback = Callback()
# 執行個體化SpeechSynthesizer,並在構造方法中傳入模型(model)、音色(voice)等請求參數
synthesizer = SpeechSynthesizer(
model=model,
voice=voice,
callback=callback,
)
# 發送待合成文本,在回調介面的on_data方法中即時擷取二進位音頻
synthesizer.call("今天天氣怎麼樣?")
雙向流式調用
單次發送文本長度不得超過 20000 字元,且累計發送文本總長度不得超過 20 萬字元。
-
流式輸入時可多次調用
streaming_call按順序提交文本片段。服務端接收文本片段後自動進行分句:
調用 streaming_complete 時,服務端會強制合成所有已接收但未處理的文本片段(包括未完成的句子)。
-
發送文本片段的間隔不得超過23秒,否則觸發“request timeout after 23 seconds”異常。
若無待發送文本,需及時調用
streaming_complete結束任務。
請務必確保調用streaming_complete方法,否則可能會導致結尾部分的文本無法成功轉換為語音。
服務端強制設定23秒逾時機制,用戶端無法修改該配置。
# coding=utf-8
#
# pyaudio安裝說明:
# 如果是macOS作業系統,執行如下命令:
# brew install portaudio
# pip install pyaudio
# 如果是Debian/Ubuntu作業系統,執行如下命令:
# sudo apt-get install python-pyaudio python3-pyaudio
# 或者
# pip install pyaudio
# 如果是CentOS作業系統,執行如下命令:
# sudo yum install -y portaudio portaudio-devel && pip install pyaudio
# 如果是Microsoft Windows,執行如下命令:
# python -m pip install pyaudio
import os
import time
import pyaudio
import json
import dashscope
from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse
from dashscope.audio.tts_v2 import *
from datetime import datetime
def get_timestamp():
now = datetime.now()
formatted_timestamp = now.strftime("[%Y-%m-%d %H:%M:%S.%f]")
return formatted_timestamp
# 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區的配置,調用時請將"{WorkspaceId}"替換為真實的業務空間ID,各地區的配置不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# 模型
model = "qwen-audio-3.0-tts-flash"
# 音色
voice = "longanhuan_v3.6"
# 定義回調介面
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
print("串連建立:" + get_timestamp())
self._player = pyaudio.PyAudio()
self._stream = self._player.open(
format=pyaudio.paInt16, channels=1, rate=22050, output=True
)
def on_complete(self):
print("語音合成完成,所有合成結果已被接收:" + get_timestamp())
def on_error(self, message: str):
print(f"語音合成出現異常:{message}")
def on_close(self):
print("串連關閉:" + get_timestamp())
# 停止播放器
self._stream.stop_stream()
self._stream.close()
self._player.terminate()
def on_event(self, message):
# 解析服務端事件,擷取輸出資訊
data = json.loads(message)
output = data.get('payload', {}).get('output', {})
event_type = output.get('type', '')
original_text = output.get('original_text', '')
if event_type:
print(f"事件類型: {event_type}, 原始文本: {original_text}")
def on_data(self, data: bytes) -> None:
print(get_timestamp() + " 二進位音頻長度為:" + str(len(data)))
self._stream.write(data)
callback = Callback()
test_text = [
"流式文本語音合成SDK,",
"可以將輸入的文本",
"合成為語音位元據,",
"相比於非流式語音合成,",
"流式合成的優勢在於即時性",
"更強。使用者在輸入文本的同時",
"可以聽到接近同步的語音輸出,",
"極大地提升了互動體驗,",
"減少了使用者等待時間。",
"適用於調用大規模",
"語言模型(LLM),以",
"流式輸入文本的方式",
"進行語音合成的情境。",
]
# 執行個體化SpeechSynthesizer,並在構造方法中傳入模型(model)、音色(voice)等請求參數
synthesizer = SpeechSynthesizer(
model=model,
voice=voice,
format=AudioFormat.PCM_22050HZ_MONO_16BIT,
callback=callback,
)
# 流式發送待合成文本。在回調介面的on_data方法中即時擷取二進位音頻
for text in test_text:
synthesizer.streaming_call(text)
time.sleep(0.1)
# 結束流式語音合成
synthesizer.streaming_complete()
# 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
print('[Metric] requestId為:{},首包延遲為:{}毫秒'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))