DashScope Java SDK を使用して、CosyVoice で音声合成を行います。
ユーザーガイド: モデルの紹介および選択に関する推奨事項については、「音声合成」をご参照ください。
サービスエンドポイント
デフォルトでは、SDK は 中国 (北京) リージョンのエンドポイントに接続します。他のリージョンを使用するには、SDK の初期化前に Constants.baseWebsocketApiUrl を設定してください。
シンガポール
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference
{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。
中国 (北京)
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。
シンガポールリージョンへの切り替え:
import com.alibaba.dashscope.utils.Constants;
// SDK 初期化前にこの設定を行ってください
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
Alibaba Cloud Model Studio は、中国 (北京) およびシンガポールリージョン向けにワークスペース専用ドメインをリリースしました。新しい専用ドメインは、推論リクエストに対して優れたパフォーマンスと高い安定性を提供します。以下の新しいドメインへの移行を推奨します。
中国 (北京):
dashscope.aliyuncs.comから{WorkspaceId}.cn-beijing.maas.aliyuncs.comへシンガポール:
dashscope-intl.aliyuncs.comから{WorkspaceId}.ap-southeast-1.maas.aliyuncs.comへ
{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。既存のドメインは引き続き完全に機能します。
SpeechSynthesizer
パッケージ: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer
コンストラクター
public SpeechSynthesizer(SpeechSynthesisParam param, ResultCallback<SpeechSynthesisResult> callback)
パラメーター:
-
param: 音声合成パラメーター。SpeechSynthesisParam.builder() で構築します。 -
callback: ストリーミング呼び出し用のコールバック関数です。非ストリーミング呼び出しの場合は null を渡します。
call() - 非ストリーミング / 単方向ストリーミング合成
メソッドシグネチャー:
public ByteBuffer call(String text)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
text |
String |
はい |
合成するテキスト。最大長: 20,000 文字。 |
戻り値: ByteBuffer または null。非ストリーミング呼び出しの場合、完全なオーディオデータを返します。単方向ストリーミング呼び出しの場合、このメソッドは null を返し、オーディオはコールバックを通じて配信されます。
streamingCall() - 双方向ストリーミング合成
メソッドシグネチャー:
public void streamingCall(String text)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
text |
String |
はい |
合成するテキスト。最大長: 20,000 文字。複数回呼び出してテキストを追加できます。 |
streamingComplete() - 双方向ストリーミングの終了
メソッドシグネチャー:
public void streamingComplete()
双方向ストリーミング呼び出しを終了し、サーバーにすべてのテキストが送信されたことを通知します。
callAsFlowable() - 単方向ストリーミング合成 (リアクティブ)
メソッドシグネチャー:
public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
text |
String |
はい |
合成するテキスト。 |
戻り値: Flowable<SpeechSynthesisResult> リアクティブストリーム。
streamingCallAsFlowable() - 双方向ストリーミング合成 (リアクティブ)
メソッドシグネチャー:
public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
textStream |
Flowable<String> |
はい |
テキストのリアクティブストリーム。 |
戻り値: Flowable<SpeechSynthesisResult> リアクティブストリーム。
getDuplexApi().close() - WebSocket 接続のクローズ
メソッドシグネチャー:
public boolean getDuplexApi().close(int code, String reason)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
code |
int |
はい |
コードを閉じる。 |
|
reason |
String |
はい |
クローズ理由。 |
戻り値: boolean。接続が正常にクローズされた場合は true、それ以外の場合は false を返します。
getLastRequestId() - リクエスト ID の取得
メソッドシグネチャー:
public String getLastRequestId()
戻り値: String。リクエスト ID です。
getFirstPackageDelay() - 初期パケット遅延の取得
メソッドシグネチャー:
public long getFirstPackageDelay()
戻り値: long。最初のテキストセグメントを送信してから最初のオーディオパケットを受信するまでの初期パケット遅延(ミリ秒単位)です。
SpeechSynthesisParam
パッケージ: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam
例:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // モデル
.voice("longanyang") // 音声
.format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // オーディオエンコード形式およびサンプルレート
.volume(50) // ボリューム。値の範囲: [0, 100]
.speechRate(1.0f) // 音声速度。値の範囲: [0.5, 2]
.pitchRate(1.0f) // ピッチ。値の範囲: [0.5, 2]
.build();
ビルダーメソッド
|
メソッド |
パラメーター型 |
必須 |
説明 |
|
|
String |
はい |
モデル名。 |
|
|
String |
はい |
voice 音声合成に使用する音声。
|
|
|
enum |
いいえ |
オーディオエンコード形式およびサンプルレート。 デフォルト: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS。 SpeechSynthesisAudioFormat パッケージ: |
|
|
int |
いいえ |
ボリュームレベル。 デフォルト値: 50。 有効値: [0, 100]。 |
|
|
float |
いいえ |
音声速度。 デフォルト値: 1.0。 有効値: [0.5, 2.0]。 |
|
|
float |
いいえ |
ピッチ。 デフォルト値: 1.0。 有効値: [0.5, 2.0]。 |
|
|
boolean |
いいえ |
単語レベルのタイムスタンプを有効にするかどうかを指定します。 デフォルト値: false。 ストリーミング出力モードでのみ利用可能です。サポート対象の音声: cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のクローン音声、および「CosyVoice 音声リスト」でサポート済みとしてマークされたシステム音声。その他のモデルのクローン音声はこの機能をサポートしていません。 |
|
|
int |
いいえ |
合成出力のバリエーションを制御するためのランダムシード。モデルバージョン、テキスト、音声、およびその他のパラメーターが変更されない場合、同じシードを使用すると同一の結果が得られます。 デフォルト値: 0。 有効値: [0, 65535]。 2.21.7 より前の SDK バージョンでは、追加パラメーターを通じて |
|
|
List<String> |
いいえ |
重要
音声合成のターゲット言語を指定して、出力品質を向上させます。 数字の発音、略語の展開、記号の読み上げ、または少数言語の合成が期待どおりでない場合に、このパラメーターを使用します。例:
有効値:
|
|
|
String |
いいえ |
方言、感情、話し方などの合成特性を制御します。 使用方法の詳細については、「命令による制御」をご参照ください。 |
|
|
ParamHotFix |
いいえ |
合成前に適用される発音修正およびテキスト置換を構成します。 この機能は cosyvoice-v2 ではサポートされていません。 パラメーター:
例:
|
|
|
String, Object |
いいえ |
追加パラメーターを設定します。 |
|
|
Map |
いいえ |
追加パラメーターを設定します。 |
追加パラメーター
parameter() または parameters() を通じて設定します。
例:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash")
.voice("longanyang")
.parameter("enable_markdown_filter", true)
.build();
|
パラメーター |
型 |
必須 |
説明 |
|
|
integer |
いいえ |
オーディオビットレート(kbps 単位)。オーディオ形式が opus の場合、 デフォルト値: 32。 有効値: [6, 510]。 |
|
|
boolean |
いいえ |
生成されたオーディオに AIGC ウォーターマークを埋め込むかどうかを指定します。true に設定すると、サポートされている形式(wav/mp3/opus)のオーディオファイルにウォーターマークが埋め込まれます。 デフォルト値: false。 cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。 |
|
|
String |
いいえ |
AIGC ウォーターマーク内の デフォルト値: Alibaba Cloud UID。 cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。 |
|
|
String |
いいえ |
AIGC ウォーターマーク内の デフォルト値: 現在の音声合成リクエストのリクエスト ID。 cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。 |
|
|
boolean |
いいえ |
重要
cosyvoice-v3-flash のクローン音声のみがこの機能をサポートしています。 Markdown フィルタリングを有効にするかどうかを指定します。有効にすると、合成前に入力テキストから Markdown マークアップ記号が自動的に削除され、読み上げられることを防ぎます。 デフォルト値: false。 有効値:
|
ResultCallback
パッケージ: com.alibaba.dashscope.common.ResultCallback
onEvent() - オーディオデータの受信
メソッドシグネチャー:
public void onEvent(SpeechSynthesisResult result)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
result |
はい |
合成イベントを受信したときにトリガーされます。オーディオフレーム、タイムスタンプ情報、出力情報(イベントタイプ、元のテキストなど)を含みます。 |
onComplete() - 合成完了
メソッドシグネチャー:
public void onComplete()
音声合成が完了したときにトリガーされます。
onError() - エラー処理
メソッドシグネチャー:
public void onError(Exception e)
パラメーター:
|
パラメーター |
型 |
必須 |
説明 |
|
e |
Exception |
はい |
エラーが発生したときにトリガーされます。例外情報を含みます。 |
SpeechSynthesisResult
パッケージ: com.alibaba.dashscope.audio.tts.SpeechSynthesisResult
getAudioFrame() - オーディオデータフレームの取得
メソッドシグネチャー:
public ByteBuffer getAudioFrame()
戻り値: ByteBuffer。オーディオデータフレームです。
getTimestamp() - タイムスタンプ情報の取得
メソッドシグネチャー:
public Sentence getTimestamp()
戻り値: Sentence。タイムスタンプ情報です。
getOutput() - 出力情報の取得
メソッドシグネチャー:
public JsonObject getOutput()
戻り値: com.google.gson.JsonObject。合成イベントの 出力情報 で、イベントタイプおよびテキスト内容を含みます。SDK バージョン >= 2.22.0 が必要です。
文レベルのタイムスタンプ情報 (Sentence)
Sentence は、文レベルのタイムスタンプ情報をカプセル化します。
getBeginTime() - 文の開始時刻の取得
メソッドシグネチャー:
public int getBeginTime()
戻り値: 文の開始時刻(ミリ秒単位)。
getEndTime() - 文の終了時刻の取得
メソッドシグネチャー:
public int getEndTime()
戻り値: 文の終了時刻(ミリ秒単位)。
getWords() - 単語レベルのタイムスタンプの取得
メソッドシグネチャー:
public List<Word> getWords()
戻り値: 単語レベルのタイムスタンプ情報を含む Word オブジェクトの List。空の場合があります。
単語レベルのタイムスタンプ情報 (Word)
Word は、単語レベルのタイムスタンプ情報をカプセル化します。
getBeginTime() - 単語の開始時刻の取得
メソッドシグネチャー:
public int getBeginTime()
戻り値: 単語の開始時刻(ミリ秒単位)。
getEndTime() - 単語の終了時刻の取得
メソッドシグネチャー:
public int getEndTime()
戻り値: 単語の終了時刻(ミリ秒単位)。
getText() - テキストの取得
メソッドシグネチャー:
public String getText()
戻り値: String。テキスト内容です。
getPhonemes() - 音素レベルのタイムスタンプの取得
メソッドシグネチャー:
public List<Phoneme> getPhonemes()
戻り値: 音素レベルのタイムスタンプ情報を含む Phoneme オブジェクトの List。空の場合があります。
音素レベルのタイムスタンプ情報 (Phoneme)
Phoneme は、音素レベルのタイムスタンプ情報をカプセル化します。
getBeginTime() - 音素の開始時刻の取得
メソッドシグネチャー:
public int getBeginTime()
戻り値: 音素の開始時刻(ミリ秒単位)。
getEndTime() - 音素の終了時刻の取得
メソッドシグネチャー:
public int getEndTime()
戻り値: 音素の終了時刻(ミリ秒単位)。
getText() - テキストの取得
メソッドシグネチャー:
public String getText()
戻り値: String。テキスト内容です。
getTone() - トーンの取得
メソッドシグネチャー:
public int getTone()
戻り値: トーン値。
-
英語では、0、1、2 はそれぞれ非強勢、主強勢、副強勢を表します。
-
中国語ピンインでは、1、2、3、4、5 はそれぞれ第1声、第2声、第3声、第4声、軽声を表します。
出力情報 (output)
getOutput() は、合成イベントの出力情報をカプセル化する JsonObject を返します。onEvent コールバックまたは Flowable ストリーム内で取得します。次のフィールドを含みます。
|
フィールド |
型 |
説明 |
|
type |
String |
イベントタイプ。可能な値: |
|
original_text |
String |
現在の文の元のテキスト。 |
|
sentence |
JsonObject |
文情報。文のインデックス( |
サンプルコード
SDK は次の合成モードをサポートしています。
-
非ストリーミング: 完全なテキストを一度に送信し、完全なオーディオを直接返すブロッキング呼び出し。短いテキストの音声合成に最適です。
-
単方向ストリーミング: 完全なテキストを一度に送信し、コールバック関数を通じてオーディオデータ(チャンクの可能性あり)を配信するノンブロッキング呼び出し。低遅延が求められる短いテキストのシナリオに最適です。
-
双方向ストリーミング: 複数のセグメントに分けてテキストを送信し、コールバック関数を通じてリアルタイムで増分的に合成されたオーディオを配信するノンブロッキング呼び出し。低遅延が求められる長いテキストのシナリオに最適です。
非ストリーミング呼び出し
1 回のリクエストあたりのテキスト長は 20,000 文字を超えてはなりません。
call メソッドを呼び出す前に、SpeechSynthesizer インスタンスを再初期化してください。
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.utils.Constants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class Main {
// モデル
private static String model = "cosyvoice-v3-flash";
// 音声
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
// リクエストパラメーター
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // モデル
.voice(voice) // 音声
.build();
// 同期モード: コールバックを無効化(第 2 パラメーターは null)
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
ByteBuffer audio = null;
try {
// オーディオが返されるまでブロック
audio = synthesizer.call("What's the weather like today?");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// タスク完了後に WebSocket 接続をクローズ
synthesizer.getDuplexApi().close(1000, "bye");
}
if (audio != null) {
// オーディオデータをローカルファイル "output.mp3" に保存
File file = new File("output.mp3");
// 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", 初期パケット遅延 (ms): "
+ synthesizer.getFirstPackageDelay());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(audio.array());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
// 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}単方向ストリーミング呼び出し
1 回のリクエストあたりのテキスト長は 20,000 文字を超えてはなりません。
call メソッドを呼び出す前に、SpeechSynthesizer インスタンスを再初期化してください。
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CountDownLatch;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
// モデル
private static String model = "cosyvoice-v3-flash";
// 音声
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
CountDownLatch latch = new CountDownLatch(1);
// ResultCallback インターフェイスを実装
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
if (result.getAudioFrame() != null) {
// オーディオデータをローカルに保存するロジックをここに実装
System.out.println(TimeUtils.getTimestamp() + " オーディオを受信");
}
// イベントタイプおよび元のテキストを含む出力情報を取得
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
+ ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " 完了を受信、音声合成が終了しました");
latch.countDown();
}
@Override
public void onError(Exception e) {
System.out.println("例外が発生しました: " + e.toString());
latch.countDown();
}
};
// リクエストパラメーター
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // モデル
.voice(voice) // 音声
.build();
// 第 2 パラメーターとして "callback" を渡すことで非同期モードを有効化
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// ノンブロッキング呼び出しで即座に null を返します(実際の結果はコールバックインターフェイスを介して非同期で配信されます)。バイナリオーディオはコールバックインターフェイスの onEvent メソッドを通じてリアルタイムで受信
try {
synthesizer.call("What's the weather like today?");
// 合成が完了するまで待機
latch.await();
// 再生スレッドが再生を終了するのを待機
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// タスク完了後に WebSocket 接続をクローズ
synthesizer.getDuplexApi().close(1000, "bye");
}
// 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", 初期パケット遅延 (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}双方向ストリーミング呼び出し
個別の呼び出しあたりのテキスト長は 20,000 文字を超えてはならず、すべての呼び出しにわたる累積テキスト長は 200,000 文字を超えてはなりません。
-
ストリーミング入力中は、
streamingCallを複数回呼び出して、順番にテキストセグメントを送信します。サーバーは受信したテキストを自動的に文に分割します。-
完全な文はすぐに合成されます。
-
不完全な文は、完全な文になるまでバッファリングされます。
streamingCompleteが呼び出されると、サーバーは未処理のすべての受信テキストセグメント(不完全な文を含む)を強制的に合成します。 -
-
連続するテキストセグメント間の間隔は 23 秒を超えてはなりません。この制限を超えると、「23 秒後にリクエストがタイムアウトしました」という例外が発生します。
保留中のテキストがない場合は、
streamingCompleteを速やかに呼び出してタスクを終了させてください。重要常に
streamingCompleteメソッドを呼び出してください。そうしないと、末尾のテキストセグメントが音声に変換されない可能性があります。サーバーはクライアント側で変更できない 23 秒のタイムアウトを適用します。
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String[] textArray = {"Streaming text-to-speech SDK, ",
"can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
"streaming synthesis offers better real-time performance. ", "While users input text, ",
"they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
"and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
"perform speech synthesis ", "with streaming text input."};
private static String model = "cosyvoice-v3-flash"; // モデル
private static String voice = "longanyang"; // 音声
public static void streamAudioDataToSpeaker() {
// コールバック関数を構成
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
// System.out.println("メッセージを受信: " + result);
if (result.getAudioFrame() != null) {
// オーディオデータを処理するロジックをここに実装
System.out.println(TimeUtils.getTimestamp() + " オーディオを受信");
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " 完了を受信、音声合成が終了しました");
}
@Override
public void onError(Exception e) {
System.out.println("例外が発生しました: " + e.toString());
}
};
// リクエストパラメーター
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model)
.voice(voice)
.format(SpeechSynthesisAudioFormat
.PCM_22050HZ_MONO_16BIT) // ストリーミング合成には PCM または MP3 を使用
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// コールバック付きの呼び出しメソッドは現在のスレッドをブロックしません
try {
for (String text : textArray) {
// テキストフラグメントを送信し、コールバックインターフェイスの onEvent メソッドを通じてバイナリオーディオをリアルタイムで受信
synthesizer.streamingCall(text);
}
// ストリーミング音声合成が終了するのを待機
synthesizer.streamingComplete();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// タスク完了後に WebSocket 接続をクローズ
synthesizer.getDuplexApi().close(1000, "bye");
}
// 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", 初期パケット遅延 (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Flowable ベースの呼び出し
Flowable はバックプレッシャーをサポートするリアクティブストリームを表す RxJava 型です。詳細については、「RxJava Flowable ドキュメント」をご参照ください。
Flowable を使用する前に、RxJava ライブラリが統合されており、リアクティブプログラミングの基本を理解していることを確認してください。
個別の呼び出しあたりのテキスト長は 20,000 文字を超えてはならず、すべての呼び出しにわたる累積テキスト長は 200,000 文字を超えてはなりません。
単方向ストリーミング呼び出し
次の例は、Flowable オブジェクトの blockingForEach インターフェイスを使用して、ストリーミングされた各 SpeechSynthesisResult オブジェクトをブロッキング方式で取得する方法を示しています。
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String model = "cosyvoice-v3-flash"; // モデル
private static String voice = "longanyang"; // 音声
public static void streamAudioDataToSpeaker() throws NoApiKeyException {
// リクエストパラメーター
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // モデル
.voice(voice) // 音声
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// オーディオデータを処理するロジックをここに実装
System.out.println(TimeUtils.getTimestamp() + " オーディオを受信");
}
// イベントタイプおよび元のテキストを含む出力情報を取得
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
+ ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
// タスク完了後に WebSocket 接続をクローズ
synthesizer.getDuplexApi().close(1000, "bye");
// 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", 初期パケット遅延 (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
双方向ストリーミング呼び出し
次の例は、テキストストリーミングの入力パラメーターとして Flowable オブジェクトを使用し、返された Flowable オブジェクトの blockingForEach インターフェイスを使用して、ストリーミングされた各 SpeechSynthesisResult オブジェクトをブロッキング方式で取得する方法を示しています。
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String[] textArray = {"Streaming text-to-speech SDK, ",
"can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
"streaming synthesis offers better real-time performance. ", "While users input text, ",
"they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
"and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
"perform speech synthesis ", "with streaming text input."};
private static String model = "cosyvoice-v3-flash";
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() throws NoApiKeyException {
// ストリーミング入力をシミュレート
Flowable<String> textSource = Flowable.create(emitter -> {
new Thread(() -> {
for (int i = 0; i < textArray.length; i++) {
emitter.onNext(textArray[i]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
emitter.onComplete();
}).start();
}, BackpressureStrategy.BUFFER);
// リクエストパラメーター
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // モデル
.voice(voice) // 音声
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// オーディオを再生するロジックをここに実装
System.out.println(
TimeUtils.getTimestamp() +
" バイナリオーディオサイズ: " + result.getAudioFrame().capacity());
}
// イベントタイプおよび元のテキストを含む出力情報を取得
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
+ ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
synthesizer.getDuplexApi().close(1000, "bye");
// 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", 初期パケット遅延 (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
高同時実行呼び出し
DashScope Java SDK は、繰り返し接続を確立するオーバーヘッドを削減するために OkHttp3 コネクションプーリングを使用します。詳細については、「高同時実行のベストプラクティス」をご参照ください。