DashScope Python SDK を使用して、非ストリーミング、一方向ストリーミング、または双方向ストリーミングモードで、CosyVoice のリアルタイム音声合成をアプリケーションに統合します。
サービスエンドポイント
SDK は、デフォルトで北京リージョンのエンドポイントを使用します。別のリージョンに切り替えるには、初期化の前に dashscope.base_websocket_api_url を変更します。
Singapore
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference
{WorkspaceId} を実際のワークスペース ID に置き換えます。
China (Beijing)
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
{WorkspaceId} を実際のワークスペース ID に置き換えます。
Singapore リージョンへの切り替え:
import dashscope
# コードの先頭で設定します
dashscope.base_websocket_api_url = 'wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
重要Alibaba Cloud Model Studio は、China (Beijing) および Singapore リージョン向けに、ワークスペース専用ドメインをリリースしました。新しい専用ドメインは、推論リクエストに対して優れたパフォーマンスと高い安定性を提供します。新しいドメインへの移行を推奨します:
- China (Beijing):
dashscope.aliyuncs.comから{WorkspaceId}.cn-beijing.maas.aliyuncs.comへ - Singapore:
dashscope-intl.aliyuncs.comから{WorkspaceId}.ap-southeast-1.maas.aliyuncs.comへ
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 | はい | 合成する全文テキスト。最大長: 20,000 文字。 |
戻り値: 完全な音声データを含む bytes。
説明: このメソッドは、コンストラクターで callback パラメーターが設定されているかどうかによって、動作が異なります。
streaming_call() - ストリーミング
メソッドシグネチャ:
def streaming_call(self, text: str) -> None
パラメーター:
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
text | str | はい | 合成するテキストセグメント。このメソッドを複数回呼び出してテキストを追加します。1 回の呼び出しあたりの最大長: 20,000 文字。累計の最大長: 200,000 文字。 |
説明: この双方向ストリーミングコールは、テキストをセグメント単位で受け付け、リアルタイムでコールバックを通じて合成された音声を配信します。テキストが段階的に生成される大規模言語モデルとの統合に最適です。すべてのテキストを送信した後、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 | いいえ | サーバーがタスク終了イベントを返すのを待つタイムアウト時間 (ミリ秒)。デフォルト値: 10000。 |
説明: 現在のストリーミング音声合成のターンをキャンセルします。このメソッドを呼び出すと、SDK は現在のタスクをただちに終了します。SpeechSynthesizer インスタンスを再初期化することなく、同じ接続で新しい合成タスクを開始できます。
重要バージョン要件: この機能には Python SDK 1.26.4 以降が必要です。
重要モデルの制限:
- 中国 (北京):CosyVoice モデルは v2 以降が必要です。
- シンガポール:CosyVoice モデルはこの機能をサポートしていません。
get_last_request_id() - リクエスト ID の取得
メソッドシグネチャ:
def get_last_request_id(self) -> str
戻り値: 直近のリクエストのリクエスト ID を含む str。トラブルシューティングやトレースに使用します。
get_first_package_delay() - 初回パケットレイテンシーの取得
メソッドシグネチャ:
def get_first_package_delay(self) -> int
戻り値: テキストを送信してから最初のオーディオチャンクを受信するまでの遅延 (ミリ秒) を表す int 値。 合成完了後に呼び出します。
get_response() - レスポンスメッセージの取得
メソッドシグネチャ:
def get_response(self) -> str
戻り値: str。リクエストステータスと出力情報を含む、最新の合成タスクからの JSON 形式のレスポンスメッセージ。
コンストラクターパラメーター
以下のパラメーターは SpeechSynthesizer コンストラクターで設定し、モデル、音声、フォーマット、および音声特性を制御します。
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
model | str | はい | モデル名。 |
voice | str | はい | 音声合成に使用する音声。
|
format | enum | いいえ | 音声のエンコーディング形式とサンプリングレート。 デフォルト: AudioFormat enum は |
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]。
|
word_timestamp_enabled | bool | いいえ | 単語レベルのタイムスタンプを有効にするかどうかを指定します。 デフォルト値: false。 ストリーミング出力モードでのみ使用可能です。サポートされている音声は、cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2 のクローン音声、およびCosyVoice 音声リストでサポート対象として記載されているシステム音声です。他のモデルのクローン音声はこの機能をサポートしていません。
|
seed | int | いいえ | 合成出力のバリエーションを制御するためのランダムシード。モデルのバージョン、テキスト、音声、およびその他のパラメーターが変更されない場合、同じシードを使用すると同一の結果が生成されます。 デフォルト値: 0。 有効な値: [0, 65535]。 |
language_hints | list[str] | いいえ | 重要
出力品質を向上させるために、音声合成のターゲット言語を指定します。 数字の発音、略語の展開、記号の読み上げ、または少数言語の合成が期待どおりでない場合に、このパラメーターを使用します。例:
有効な値
|
instruction | str | いいえ | 方言、感情、話し方などの合成特性を制御します。 使用方法の詳細については、「Instruction control」をご参照ください。 |
enable_aigc_tag | bool | いいえ | 生成された音声に AIGC ウォーターマークを埋め込むかどうかを指定します。true に設定すると、サポートされている形式 (wav/mp3/opus) の音声ファイルにウォーターマークが埋め込まれます。デフォルト値: false。 注記cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2 のみがこの機能をサポートしています。
|
aigc_propagator | str | いいえ | AIGC 透かしの ContentPropagator フィールドを設定してコンテンツプロパゲーターを識別するもので、enable_aigc_tag が true の場合にのみ有効になります。デフォルト値: Alibaba Cloud UID。 注記cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2 のみがこの機能をサポートしています。
|
aigc_propagate_id | str | いいえ | AIGC ウォーターマークの PropagateID フィールドを設定して、特定の伝播アクションを一意に識別します。enable_aigc_tag が true の場合にのみ有効になります。デフォルト値: 現在の音声合成リクエストのリクエスト ID。 注記cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2 のみがこの機能をサポートしています。
|
hot_fix | dict | いいえ | 合成前に適用される発音補正とテキスト置換を設定します。 注記この機能は cosyvoice-v2 ではサポートされていません。 パラメーター:
例: |
enable_markdown_filter | bool | いいえ | 注記cosyvoice-v3-flash のクローン音声のみがこの機能をサポートしています。 Markdown フィルタリングを有効にするかどうかを指定します。有効にすると、システムは合成前に入力テキストから Markdown マークアップ記号を自動的に除去し、それらが読み上げられるのを防ぎます。 デフォルト値: false。 有効な値:
|
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 | はい | header (リクエスト情報) と payload (出力情報) を含む JSON 形式のサーバーレスポンスイベントです。payload.output フィールドには、イベントタイプ、元のテキスト、およびその他の詳細が含まれます。on_event メッセージの出力フィールドをご参照ください。 |
トリガーされるタイミング: サーバーからの応答を受信したとき。メッセージは、合成イベントの出力 (イベントタイプ、元のテキスト、文の情報) を含む 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": "How is the weather today?",
"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: {event_type}, Original text: {original_text}')
コード例
SDK は、次の合成モードをサポートしています:
- ノンストリーミング: 完全なテキストを一度に送信し、完全な音声を直接返すブロッキングコールです。短いテキストの音声合成に最適です。
- 単方向ストリーミング: 完全なテキストを一度に送信し、コールバック関数を介して音声データ (チャンク単位) を配信するノンブロッキングコールです。低レイテンシーが求められる短いテキストのシナリオに最適です。
- 双方向ストリーミング: テキストを複数のセグメントで送信し、段階的に合成された音声をリアルタイムでコールバック関数を介して配信するノンブロッキングコールです。低レイテンシーが求められる長いテキストのシナリオに最適です。
ノンストリーミング
1 回の呼び出しで送信されるテキストは 20,000 文字を超えてはなりません。この制限を超えるとエラーが発生します。
重要各 call の前に SpeechSynthesizer インスタンスを再初期化してください。
# coding=utf-8
import dashscope
from dashscope.audio.tts_v2 import *
import os
# Singapore リージョンと China (Beijing) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
# 環境変数が設定されていない場合は、次の行を実際の Model Studio API キーに置き換えてください: dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 次の設定は Singapore リージョン用です。「{WorkspaceId}」を実際のワークスペース ID に置き換えてください。設定はリージョンによって異なります。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# モデル
model = "cosyvoice-v3-plus"
# 音声
voice = "longanyang"
# SpeechSynthesizer をインスタンス化し、コンストラクターでモデルや音声などのリクエストパラメーターを渡します
synthesizer = SpeechSynthesizer(model=model, voice=voice)
# テキストを送信して合成し、バイナリオーディオを取得します
audio = synthesizer.call("How is the weather today?")
# 最初のテキスト送信では WebSocket 接続を確立する必要があるため、初回パケットレイテンシーには接続確立時間が含まれます
print('[Metric] requestId: {}, first packet latency: {} ms'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
# 音声をローカルファイルに保存します
with open('output.mp3', 'wb') as f:
f.write(audio)
単方向ストリーミング
1 回の呼び出しで送信されるテキストは 20,000 文字を超えてはなりません。この制限を超えるとエラーが発生します。
重要各 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
# Singapore リージョンと China (Beijing) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
# 環境変数が設定されていない場合は、次の行を実際の Model Studio API キーに置き換えてください: dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 次の設定は Singapore リージョン用です。「{WorkspaceId}」を実際のワークスペース ID に置き換えてください。設定はリージョンによって異なります。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# モデル
model = "cosyvoice-v3-plus"
# 音声
voice = "longanyang"
# コールバックインターフェイスを定義します
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
self.file = open("output.mp3", "wb")
print("Connection established: " + get_timestamp())
def on_complete(self):
print("Speech synthesis completed, all results received: " + get_timestamp())
# タスクが完了した後 (on_complete コールバックがトリガーされた後) に、get_first_package_delay を呼び出してレイテンシーを取得できます
# 最初のテキスト送信では WebSocket 接続を確立する必要があるため、初回パケットレイテンシーには接続確立時間が含まれます
print('[Metric] requestId: {}, first packet latency: {} ms'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
def on_error(self, message: str):
print(f"Speech synthesis error: {message}")
def on_close(self):
print("Connection closed: " + 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: {event_type}, original text: {original_text}")
def on_data(self, data: bytes) -> None:
print(get_timestamp() + " Binary audio length: " + str(len(data)))
self.file.write(data)
callback = Callback()
# SpeechSynthesizer をインスタンス化し、コンストラクターでモデルや音声などのリクエストパラメーターを渡します
synthesizer = SpeechSynthesizer(
model=model,
voice=voice,
callback=callback,
)
# テキストを送信して合成し、on_data コールバックメソッドを介してリアルタイムでバイナリオーディオを取得します
synthesizer.call("How is the weather today?")
双方向ストリーミング
1 回の呼び出しで送信されるテキストは 20,000 文字を超えてはなりません。累積テキストは 200,000 文字を超えてはなりません。
-
ストリーミング入力中、
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
# Singapore リージョンと China (Beijing) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
# 環境変数が設定されていない場合は、次の行を実際の Model Studio API キーに置き換えてください: dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 次の設定は Singapore リージョン用です。「{WorkspaceId}」を実際のワークスペース ID に置き換えてください。設定はリージョンによって異なります。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# モデル
model = "cosyvoice-v3-plus"
# 音声
voice = "longanyang"
# コールバックインターフェイスを定義します
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
print("Connection established: " + 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("Speech synthesis completed, all results received: " + get_timestamp())
def on_error(self, message: str):
print(f"Speech synthesis error: {message}")
def on_close(self):
print("Connection closed: " + 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: {event_type}, original text: {original_text}")
def on_data(self, data: bytes) -> None:
print(get_timestamp() + " Binary audio length: " + str(len(data)))
self._stream.write(data)
callback = Callback()
test_text = [
"Streaming text-to-speech SDK,",
"converts input text",
"into binary audio data.",
"Compared with non-streaming speech synthesis,",
"streaming synthesis offers better real-time performance.",
"Users hear near-synchronous audio output while typing,",
"greatly improving interaction experience",
"and reducing wait time.",
"Ideal for large language model (LLM) integration,",
"where text is streamed for speech synthesis.",
]
# SpeechSynthesizer をインスタンス化し、コンストラクターでモデルや音声などのリクエストパラメーターを渡します
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: {}, first packet latency: {} ms'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))