Sintesis suara dengan CosyVoice menggunakan DashScope Java SDK.
Panduan pengguna: Untuk pengenalan model dan rekomendasi pemilihan, lihat Speech synthesis.
Titik akhir layanan
Secara default, SDK terhubung ke titik akhir Wilayah Beijing. Untuk menggunakan wilayah lain, atur Constants.baseWebsocketApiUrl sebelum menginisialisasi SDK.
Singapore
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference
Ganti {WorkspaceId} dengan workspace ID Anda yang sebenarnya.
China (Beijing)
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
Ganti {WorkspaceId} dengan workspace ID Anda yang sebenarnya.
Beralih ke wilayah Singapura:
import com.alibaba.dashscope.utils.Constants;
// Atur ini sebelum inisialisasi SDK apa pun
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
Alibaba Cloud Model Studio telah merilis domain khusus ruang kerja untuk wilayah China (Beijing) dan Singapura. Domain khusus baru ini memberikan performa lebih unggul dan stabilitas lebih tinggi untuk permintaan inferensi. Kami merekomendasikan migrasi ke domain baru berikut:
China (Beijing): dari
dashscope.aliyuncs.comke{WorkspaceId}.cn-beijing.maas.aliyuncs.comSingapura: dari
dashscope-intl.aliyuncs.comke{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
Ganti {WorkspaceId} dengan Workspace ID Anda yang sebenarnya. Domain lama tetap berfungsi penuh.
SpeechSynthesizer
Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer
Konstruktor
public SpeechSynthesizer(SpeechSynthesisParam param, ResultCallback<SpeechSynthesisResult> callback)
Parameter:
-
param: Parameter sintesis suara, dibuat dengan SpeechSynthesisParam.builder() -
callback: Callback untuk panggilan streaming. Berikan null untuk panggilan non-streaming.
call() - Sintesis non-streaming/unidirectional streaming
Tanda tangan metode:
public ByteBuffer call(String text)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
text |
String |
Ya |
Teks yang akan disintesis. Panjang maksimum: 20.000 karakter. |
Nilai kembalian: ByteBuffer atau null. Untuk panggilan non-streaming, mengembalikan seluruh data audio. Untuk panggilan unidirectional streaming, metode ini mengembalikan null; audio dikirimkan melalui callback.
streamingCall() - Sintesis bidirectional streaming
Tanda tangan metode:
public void streamingCall(String text)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
text |
String |
Ya |
Teks yang akan disintesis. Panjang maksimum: 20.000 karakter. Anda dapat memanggil metode ini beberapa kali untuk menambahkan teks. |
streamingComplete() - Mengakhiri bidirectional streaming
Tanda tangan metode:
public void streamingComplete()
Mengakhiri panggilan bidirectional streaming dan memberi tahu server bahwa seluruh teks telah dikirim.
callAsFlowable() - Sintesis unidirectional streaming (reaktif)
Tanda tangan metode:
public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
text |
String |
Ya |
Teks yang akan disintesis. |
Nilai kembalian: Flowable<SpeechSynthesisResult> aliran reaktif.
streamingCallAsFlowable() - Sintesis bidirectional streaming (reaktif)
Tanda tangan metode:
public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
textStream |
Flowable<String> |
Ya |
Aliran reaktif teks. |
Nilai kembalian: Flowable<SpeechSynthesisResult> aliran reaktif.
getDuplexApi().close() - Menutup koneksi WebSocket
Tanda tangan metode:
public boolean getDuplexApi().close(int code, String reason)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
code |
int |
Ya |
Kode penutupan. |
|
reason |
String |
Ya |
Alasan penutupan. |
Nilai kembalian: boolean. Mengembalikan true jika koneksi berhasil ditutup, false jika tidak.
getLastRequestId() - Mendapatkan ID permintaan
Tanda tangan metode:
public String getLastRequestId()
Nilai kembalian: String, ID permintaan.
getFirstPackageDelay() - Mendapatkan latensi paket pertama
Tanda tangan metode:
public long getFirstPackageDelay()
Nilai kembalian: long. Latensi paket pertama dalam milidetik, diukur dari pengiriman segmen teks pertama hingga menerima paket audio pertama.
SpeechSynthesisParam
Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam
Contoh:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // Model
.voice("longanyang") // Voice
.format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // Audio encoding format and sample rate
.volume(50) // Volume. Value range: [0, 100]
.speechRate(1.0f) // Speech rate. Value range: [0.5, 2]
.pitchRate(1.0f) // Pitch. Value range: [0.5, 2]
.build();
Metode builder
|
Metode |
Tipe parameter |
Wajib |
Deskripsi |
|
|
String |
Ya |
Nama model. |
|
|
String |
Ya |
voice Voice yang digunakan untuk sintesis suara.
|
|
|
enum |
Tidak |
Audio encoding format dan sample rate. Default: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS. Package SpeechSynthesisAudioFormat: |
|
|
int |
Tidak |
Tingkat volume. Nilai default: 50. Nilai valid: [0, 100]. |
|
|
float |
Tidak |
Kecepatan bicara. Nilai default: 1.0. Nilai valid: [0.5, 2.0]. |
|
|
float |
Tidak |
Lapangan. Nilai default: 1.0. Nilai valid: [0.5, 2.0]. |
|
|
boolean |
Tidak |
Menentukan apakah akan mengaktifkan timestamp tingkat kata. Nilai default: false. Hanya tersedia dalam mode keluaran streaming. Voice yang didukung: cloned voices dari cosyvoice-v3.5-plus, cosyvoice-v3.5-flash, cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2, serta system voices yang ditandai sebagai didukung dalam CosyVoice Voice list. Cloned voices dari model lain tidak mendukung fitur ini. |
|
|
int |
Tidak |
Seed acak untuk mengontrol variasi dalam output sintesis. Ketika versi model, teks, voice, dan parameter lainnya tidak berubah, menggunakan seed yang sama menghasilkan hasil identik. Nilai default: 0. Nilai valid: [0, 65535]. Untuk versi SDK sebelum 2.21.7, atur |
|
|
List<String> |
Tidak |
Penting
Menentukan bahasa target untuk sintesis suara guna meningkatkan kualitas output. Ketika pelafalan angka, ekspansi singkatan, pembacaan simbol, atau sintesis bahasa minoritas tidak sesuai ekspektasi, gunakan parameter ini. Contohnya:
Nilai valid:
|
|
|
String |
Tidak |
Mengontrol karakteristik sintesis seperti dialek, emosi, atau gaya berbicara. Untuk detail penggunaan, lihat Instruction-based control. |
|
|
ParamHotFix |
Tidak |
Mengonfigurasi koreksi pelafalan dan penggantian teks yang diterapkan sebelum sintesis. Fitur ini tidak didukung oleh cosyvoice-v2. Parameter:
Contoh:
|
|
|
String, Object |
Tidak |
Mengatur Parameter tambahan. |
|
|
Map |
Tidak |
Mengatur Parameter tambahan. |
Parameter tambahan
Diatur melalui parameter() atau parameters().
Contoh:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash")
.voice("longanyang")
.parameter("enable_markdown_filter", true)
.build();
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
|
integer |
Tidak |
Laju bit audio dalam kbps. Ketika format audio adalah opus, gunakan Nilai default: 32. Nilai valid: [6, 510]. |
|
|
boolean |
Tidak |
Menentukan apakah akan menyematkan watermark AIGC dalam audio yang dihasilkan. Ketika diatur ke true, watermark disematkan dalam file audio dengan format yang didukung (wav/mp3/opus). Nilai default: false. Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini. |
|
|
String |
Tidak |
Mengatur bidang Nilai default: UID Alibaba Cloud. Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini. |
|
|
String |
Tidak |
Mengatur bidang Nilai default: ID permintaan dari permintaan sintesis suara saat ini. Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini. |
|
|
boolean |
Tidak |
Penting
Hanya cloned voices dari cosyvoice-v3-flash yang mendukung fitur ini. Menentukan apakah akan mengaktifkan penyaringan Markdown. Ketika diaktifkan, sistem secara otomatis menghapus simbol markup Markdown dari teks input sebelum sintesis, sehingga simbol tersebut tidak terbaca. Nilai default: false. Nilai valid:
|
ResultCallback
Package: com.alibaba.dashscope.common.ResultCallback
onEvent() - Menerima audio data
Tanda tangan metode:
public void onEvent(SpeechSynthesisResult result)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
result |
Ya |
Dipicu ketika event sintesis diterima. Berisi frame audio, informasi timestamp, dan informasi output (tipe event, teks asli, dll.). |
onComplete() - Sintesis selesai
Tanda tangan metode:
public void onComplete()
Dipicu ketika sintesis suara selesai.
onError() - Penanganan error
Tanda tangan metode:
public void onError(Exception e)
Parameter:
|
Parameter |
Tipe |
Wajib |
Deskripsi |
|
e |
Exception |
Ya |
Dipicu ketika terjadi error. Berisi informasi exception. |
SpeechSynthesisResult
Package: com.alibaba.dashscope.audio.tts.SpeechSynthesisResult
getAudioFrame() - Mendapatkan frame data audio
Tanda tangan metode:
public ByteBuffer getAudioFrame()
Nilai kembalian: ByteBuffer, frame data audio.
getTimestamp() - Mendapatkan informasi timestamp
Tanda tangan metode:
public Sentence getTimestamp()
Nilai kembalian: Sentence, informasi timestamp.
getOutput() - Mendapatkan informasi output
Tanda tangan metode:
public JsonObject getOutput()
Nilai kembalian: com.google.gson.JsonObject, informasi output dari event sintesis, berisi tipe event dan konten teks. Memerlukan versi SDK >= 2.22.0.
Informasi timestamp tingkat kalimat (Sentence)
Sentence mengenkapsulasi informasi timestamp tingkat kalimat.
getBeginTime() - Mendapatkan waktu mulai kalimat
Tanda tangan metode:
public int getBeginTime()
Nilai kembalian: Waktu mulai kalimat dalam milidetik.
getEndTime() - Mendapatkan waktu akhir kalimat
Tanda tangan metode:
public int getEndTime()
Nilai kembalian: Waktu akhir kalimat dalam milidetik.
getWords() - Mendapatkan timestamp tingkat kata
Tanda tangan metode:
public List<Word> getWords()
Nilai kembalian: List objek Word yang berisi informasi timestamp tingkat kata. Bisa jadi kosong.
Informasi timestamp tingkat kata (Word)
Word mengenkapsulasi informasi timestamp tingkat kata.
getBeginTime() - Mendapatkan waktu mulai kata
Tanda tangan metode:
public int getBeginTime()
Nilai kembalian: Waktu mulai kata dalam milidetik.
getEndTime() - Mendapatkan waktu akhir kata
Tanda tangan metode:
public int getEndTime()
Nilai kembalian: Waktu akhir kata dalam milidetik.
getText() - Mendapatkan teks
Tanda tangan metode:
public String getText()
Nilai kembalian: String, konten teks.
getPhonemes() - Mendapatkan timestamp tingkat fonem
Tanda tangan metode:
public List<Phoneme> getPhonemes()
Nilai kembalian: List objek Phoneme yang berisi informasi timestamp tingkat fonem. Bisa jadi kosong.
Informasi timestamp tingkat fonem (Phoneme)
Phoneme mengenkapsulasi informasi timestamp tingkat fonem.
getBeginTime() - Mendapatkan waktu mulai fonem
Tanda tangan metode:
public int getBeginTime()
Nilai kembalian: Waktu mulai fonem dalam milidetik.
getEndTime() - Mendapatkan waktu akhir fonem
Tanda tangan metode:
public int getEndTime()
Nilai kembalian: Waktu akhir fonem dalam milidetik.
getText() - Mendapatkan teks
Tanda tangan metode:
public String getText()
Nilai kembalian: String, konten teks.
getTone() - Mendapatkan nada
Tanda tangan metode:
public int getTone()
Nilai kembalian: Nilai nada.
-
Dalam bahasa Inggris, 0, 1, dan 2 masing-masing merepresentasikan unstressed, primary stress, dan secondary stress.
-
Dalam pinyin Mandarin, 1, 2, 3, 4, dan 5 masing-masing merepresentasikan nada pertama, kedua, ketiga, keempat, dan netral.
Informasi output (output)
getOutput() mengembalikan JsonObject yang mengenkapsulasi informasi output event sintesis. Ambil informasi ini dalam callback onEvent atau aliran Flowable. Informasi ini berisi bidang-bidang berikut:
|
Bidang |
Tipe |
Deskripsi |
|
type |
String |
Tipe event. Nilai yang mungkin: |
|
original_text |
String |
Teks asli dari kalimat saat ini. Dikembalikan dalam event |
|
sentence |
JsonObject |
Informasi kalimat, berisi indeks kalimat ( |
Kode contoh
SDK mendukung mode sintesis berikut:
-
Non-streaming: Panggilan blocking yang mengirimkan seluruh teks sekaligus dan langsung mengembalikan audio lengkap. Paling cocok untuk sintesis suara teks pendek.
-
Unidirectional streaming: Panggilan non-blocking yang mengirimkan seluruh teks sekaligus dan mengirimkan data audio (mungkin dalam potongan) melalui fungsi callback. Paling cocok untuk skenario teks pendek yang memerlukan latensi rendah.
-
Bidirectional streaming: Panggilan non-blocking yang mengirimkan teks dalam beberapa segmen dan mengirimkan audio yang disintesis secara inkremental melalui fungsi callback secara real time. Paling cocok untuk skenario teks panjang yang memerlukan latensi rendah.
Panggilan non-streaming
Panjang teks per permintaan tidak boleh melebihi 20.000 karakter.
Inisialisasi ulang instans SpeechSynthesizer sebelum setiap pemanggilan metode call.
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 {
// Model
private static String model = "cosyvoice-v3-flash";
// Voice
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
// Synchronous mode: disable callback (second parameter is null)
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
ByteBuffer audio = null;
try {
// Block until audio is returned
audio = synthesizer.call("What's the weather like today?");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
if (audio != null) {
// Save the audio data to a local file "output.mp3"
File file = new File("output.mp3");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (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) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Panggilan unidirectional streaming
Panjang teks per permintaan tidak boleh melebihi 20.000 karakter.
Inisialisasi ulang instans SpeechSynthesizer sebelum setiap pemanggilan metode call.
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 {
// Model
private static String model = "cosyvoice-v3-flash";
// Voice
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
CountDownLatch latch = new CountDownLatch(1);
// Implement the ResultCallback interface
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
if (result.getAudioFrame() != null) {
// Implement the logic to save audio data locally here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
latch.countDown();
}
@Override
public void onError(Exception e) {
System.out.println("Exception occurred: " + e.toString());
latch.countDown();
}
};
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
// Passing "callback" as the second parameter enables asynchronous mode
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// Non-blocking call that returns null immediately (actual results are delivered asynchronously via the callback interface). Binary audio is received in real time through the onEvent method of the callback interface
try {
synthesizer.call("What's the weather like today?");
// Wait for synthesis to complete
latch.await();
// Wait for playback thread to finish playing
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Panggilan bidirectional streaming
Panjang teks per panggilan individu tidak boleh melebihi 20.000 karakter, dan panjang teks kumulatif dari semua panggilan tidak boleh melebihi 200.000 karakter.
-
Saat input streaming, panggil
streamingCallbeberapa kali untuk mengirimkan segmen teks secara berurutan. Server secara otomatis membagi teks yang diterima menjadi kalimat:-
Kalimat lengkap langsung disintesis.
-
Kalimat tidak lengkap disimpan dalam buffer hingga membentuk kalimat lengkap.
Ketika
streamingCompletedipanggil, server memaksa mensintesis semua segmen teks yang diterima namun belum diproses, termasuk kalimat yang tidak lengkap. -
-
Interval antara segmen teks berturut-turut tidak boleh melebihi 23 detik; melebihi batas ini akan memicu exception "request timeout after 23 seconds".
Jika tidak ada teks yang tertunda, segera panggil
streamingCompleteuntuk mengakhiri tugas.PentingSelalu panggil metode
streamingComplete. Jika tidak, segmen teks akhir mungkin tidak dikonversi menjadi suara.Server menerapkan timeout 23 detik yang tidak dapat diubah di sisi klien.
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"; // Model
private static String voice = "longanyang"; // Voice
public static void streamAudioDataToSpeaker() {
// Configure the callback function
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
// System.out.println("Message received: " + result);
if (result.getAudioFrame() != null) {
// Implement the logic to process audio data here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
}
@Override
public void onError(Exception e) {
System.out.println("Exception occurred: " + e.toString());
}
};
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model)
.voice(voice)
.format(SpeechSynthesisAudioFormat
.PCM_22050HZ_MONO_16BIT) // Use PCM or MP3 for streaming synthesis
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// The call method with Callback will not block the current thread
try {
for (String text : textArray) {
// Send text fragments and receive binary audio in real time through the onEvent method of the callback interface
synthesizer.streamingCall(text);
}
// Wait for streaming speech synthesis to finish
synthesizer.streamingComplete();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Panggilan berbasis Flowable
Flowable adalah tipe RxJava yang merepresentasikan aliran reaktif yang mendukung backpressure. Untuk informasi lebih lanjut, lihat dokumentasi RxJava Flowable.
Sebelum menggunakan Flowable, pastikan library RxJava telah diintegrasikan dan Anda memahami dasar-dasar pemrograman reaktif.
Panjang teks per panggilan individu tidak boleh melebihi 20.000 karakter, dan panjang teks kumulatif dari semua panggilan tidak boleh melebihi 200.000 karakter.
Panggilan unidirectional streaming
Contoh berikut menunjukkan cara menggunakan antarmuka blockingForEach dari objek Flowable untuk mengambil setiap objek SpeechSynthesisResult yang distream secara blocking.
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"; // Model
private static String voice = "longanyang"; // Voice
public static void streamAudioDataToSpeaker() throws NoApiKeyException {
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// Implement the logic to process audio data here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
Panggilan bidirectional streaming
Contoh berikut menunjukkan cara menggunakan objek Flowable sebagai parameter input untuk streaming teks, dan menggunakan antarmuka blockingForEach dari objek Flowable yang dikembalikan untuk mengambil setiap objek SpeechSynthesisResult yang distream secara blocking.
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 {
// Simulate streaming input
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);
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// Implement the logic to play audio here
System.out.println(
TimeUtils.getTimestamp() +
" Binary audio size: " + result.getAudioFrame().capacity());
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
synthesizer.getDuplexApi().close(1000, "bye");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
Panggilan konkurensi tinggi
DashScope Java SDK menggunakan pooling koneksi OkHttp3 untuk mengurangi overhead pembentukan koneksi berulang. Untuk informasi lebih lanjut, lihat Praktik terbaik konkurensi tinggi.