Topik ini menjelaskan cara mengakses layanan sintesis suara CosyVoice menggunakan koneksi WebSocket.
SDK DashScope hanya mendukung Java dan Python. Untuk membangun aplikasi sintesis suara CosyVoice dalam bahasa pemrograman lain, gunakan koneksi WebSocket untuk berkomunikasi dengan layanan tersebut.
Panduan pengguna: Untuk ikhtisar model dan saran pemilihan, lihat Sintesis suara real-time — CosyVoice.
WebSocket adalah protokol jaringan yang mendukung komunikasi full-duplex. Klien dan server membentuk koneksi persisten melalui satu proses jabat tangan, memungkinkan kedua pihak saling mendorong data secara aktif. Hal ini memberikan keunggulan signifikan dalam hal kinerja dan efisiensi real-time.
Untuk bahasa pemrograman umum, tersedia banyak pustaka dan contoh WebSocket siap pakai, seperti:
-
Go:
gorilla/websocket -
PHP:
Ratchet -
Node.js:
ws
Pahami prinsip dasar dan detail teknis WebSocket sebelum memulai pengembangan.
Model CosyVoice hanya mendukung koneksi WebSocket—bukan API REST HTTP. Jika Anda memanggil layanan menggunakan permintaan HTTP (misalnya POST), layanan akan mengembalikan kesalahan InvalidParameter atau URL.
Persyaratan Awal
Anda telah memperoleh Kunci API.
Model dan harga
Batasan panjang teks dan aturan format sintesis suara
Batasan panjang teks
Setiap instruksi continue-task harus berisi tidak lebih dari 20.000 karakter. Secara keseluruhan, jumlah total karakter yang dikirimkan melalui semua panggilan ke instruksi continue-task tidak boleh melebihi 200.000 karakter.
Aturan penghitungan karakter
Karakter Tionghoa (termasuk Tionghoa sederhana dan tradisional, Kanji Jepang, serta Hanja Korea) dihitung sebagai dua karakter. Semua karakter lainnya, seperti tanda baca, huruf, angka, serta Kana Jepang/Hangul Korea, dihitung sebagai satu karakter.
Tag SSML tidak dimasukkan dalam perhitungan panjang teks.
Contoh:
"你好"→ 2 (karakter Tionghoa) + 2 (karakter Tionghoa) = 4 karakter"中A文123"→ 2 (karakter Tionghoa) + 1 (A) + 2 (karakter Tionghoa) + 1 (1) + 1 (2) + 1 (3) = 8 karakter"中文。"→ 2 (karakter Tionghoa) + 2 (karakter Tionghoa) + 1 (.) = 5 karakter"中 文。"→ 2 (karakter Tionghoa) + 1 (spasi) + 2 (karakter Tionghoa) + 1 (.) = 6 karakter"<speak>你好</speak>"→ 2 (karakter Tionghoa) + 2 (karakter Tionghoa) = 4 karakter
Format pengkodean
Gunakan pengkodean UTF-8.
Dukungan ekspresi matematika
Penguraian ekspresi matematika hanya tersedia untuk cosyvoice-v3.5-flash, cosyvoice-v3.5-plus, cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2. Fitur ini mendukung ekspresi matematika umum tingkat sekolah dasar dan menengah, termasuk operasi dasar, aljabar, dan geometri.
Fitur ini hanya mendukung bahasa Tionghoa.
Lihat Konversi rumus LaTeX menjadi ucapan (hanya bahasa Tionghoa).
Dukungan bahasa markup SSML
Untuk menggunakan SSML, penuhi semua kondisi berikut:
Dukungan model: Hanya cosyvoice-v3.5-flash, cosyvoice-v3.5-plus, cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung SSML.
Dukungan suara: Anda harus menggunakan suara yang mendukung SSML. Suara-suara yang didukung meliputi berikut ini:
Semua suara hasil kloning (suara kustom yang dibuat melalui API kloning suara).
Suara sistem yang ditandai sebagai mendukung SSML dalam daftar suara.
CatatanJika Anda menggunakan suara sistem yang tidak mendukung SSML (misalnya beberapa suara dasar), mengaktifkan parameter
enable_ssmlakan mengembalikan kesalahan “SSML text is not supported at the moment!”.Pengaturan parameter: Dalam instruksi run-task, atur parameter
enable_ssmlketrue.
Setelah memenuhi semua kondisi, kirimkan teks berformat SSML menggunakan instruksi continue-task. Untuk contoh lengkap, lihat Panduan Cepat Mulai.
Alur interaksi
Pesan yang dikirimkan klien ke server disebut instruksi. Server mengembalikan dua jenis pesan ke klien: event berformat JSON dan aliran audio biner.
Secara kronologis, alur interaksi antara klien dan server adalah sebagai berikut:
Membentuk koneksi: Klien membentuk koneksi WebSocket dengan server.
Memulai tugas: Klien mengirimkan instruksi run-task untuk memulai tugas.
Menunggu konfirmasi: Klien menerima event task-started dari server, yang mengonfirmasi bahwa tugas berhasil dimulai. Klien kemudian dapat melanjutkan ke langkah-langkah berikutnya.
Mengirimkan teks untuk disintesis:
Klien mengirimkan satu atau lebih instruksi continue-task yang berisi teks untuk disintesis, secara berurutan. Setelah menerima kalimat lengkap, server mengembalikan event result-generated dan aliran audio. (Batasan panjang teks berlaku. Lihat deskripsi bidang
textdalam instruksi continue-task.)CatatanAnda dapat mengirimkan beberapa instruksi continue-task, mengirimkan fragmen teks secara berurutan. Server secara otomatis membaginya menjadi kalimat:
Server menyintesis kalimat lengkap secara langsung, sehingga klien menerima audio segera.
Server menyimpan sementara kalimat yang belum lengkap dan baru menyintesisnya setelah menjadi lengkap. Tidak ada audio yang dikembalikan untuk kalimat yang belum lengkap.
Ketika Anda mengirimkan instruksi finish-task, server memaksa penyintesisan seluruh konten yang tersimpan sementara.
Menerima audio: Terima aliran audio melalui saluran
binary.Menginformasikan server untuk mengakhiri tugas:
Setelah mengirimkan seluruh teks, klien mengirimkan instruksi finish-task untuk menginformasikan server agar mengakhiri tugas. Lanjutkan menerima audio dari server. Jangan lewati langkah ini. Jika tidak, Anda mungkin kehilangan audio atau akhir dari aliran audio.
Tugas berakhir:
Klien menerima event task-finished dari server, yang menandai akhir tugas.
Menutup koneksi: Klien menutup koneksi WebSocket.
Untuk meningkatkan penggunaan sumber daya, gunakan kembali satu koneksi WebSocket untuk beberapa tugas, bukan membuka koneksi baru untuk setiap tugas. Untuk informasi selengkapnya, lihat Overhead koneksi dan penggunaan kembali.
task_id harus tetap konsisten sepanjang proses: Untuk satu tugas sintesis, instruksi run-task, semua instruksi continue-task, dan finish-task harus menggunakan task_id yang sama.
Akibat kesalahan: Menggunakan task_id yang berbeda menyebabkan:
Server tidak dapat mengaitkan permintaan, sehingga pengiriman aliran audio menjadi tidak teratur.
Konten teks dialokasikan ke tugas yang salah, mengakibatkan ketidaksesuaian ucapan.
Status tugas menjadi abnormal, kemungkinan kehilangan event task-finished.
Penagihan gagal, dan statistik penggunaan menjadi tidak akurat.
Pendekatan yang benar:
Buat task_id unik (misalnya menggunakan UUID) saat mengirimkan run-task.
Simpan task_id tersebut dalam sebuah variabel.
Gunakan task_id yang sama untuk semua instruksi continue-task dan finish-task berikutnya.
Setelah tugas berakhir (setelah menerima task-finished), buat task_id baru untuk tugas baru apa pun.
Catatan implementasi klien
Saat mengimplementasikan klien WebSocket—terutama pada platform Flutter, web, atau seluler—tentukan tanggung jawab antara server dan klien secara jelas untuk memastikan tugas sintesis suara yang lengkap dan stabil.
Tanggung jawab server dan klien
Tanggung jawab server
Server menjamin pengembalian aliran audio lengkap secara berurutan. Anda tidak perlu khawatir tentang urutan atau kelengkapan data audio—server menghasilkan dan mendorong semua potongan audio sesuai urutan teks.
Tanggung jawab klien
Klien harus menangani tugas-tugas kritis berikut:
Baca dan gabungkan semua potongan audio
Server mengirimkan audio sebagai beberapa frame biner. Klien harus menerima semua potongan dan menggabungkannya untuk membentuk file audio akhir. Contoh kode:
# Contoh Python: Gabungkan potongan audio with open("output.mp3", "ab") as f: # Mode tambah f.write(audio_chunk) # audio_chunk adalah setiap potongan audio biner yang diterima// Contoh JavaScript: Gabungkan potongan audio const audioChunks = []; ws.onmessage = (event) => { if (event.data instanceof Blob) { audioChunks.push(event.data); // Kumpulkan semua potongan audio } }; // Gabungkan audio setelah tugas selesai const audioBlob = new Blob(audioChunks, { type: 'audio/mp3' });Pertahankan siklus hidup WebSocket secara penuh
Selama seluruh tugas sintesis suara—mulai dari mengirimkan instruksi run-task hingga menerima event task-finished—jangan putuskan koneksi WebSocket terlalu dini. Kesalahan umum meliputi berikut ini:
Menutup koneksi sebelum semua potongan audio tiba, mengakibatkan audio tidak lengkap.
Lupa mengirimkan instruksi finish-task, sehingga teks yang tersimpan sementara tidak diproses.
Gagal menangani keepalive WebSocket secara tepat saat halaman beralih atau aplikasi berpindah ke latar belakang.
PentingAplikasi seluler (Flutter, iOS, Android) harus mengelola koneksi jaringan secara cermat saat masuk ke latar belakang. Pertahankan WebSocket dalam tugas latar belakang atau layanan latar depan, atau periksa status tugas dan hubungkan kembali saat kembali ke latar depan.
Integritas teks dalam alur kerja ASR→LLM→TTS
Dalam alur kerja ASR→LLM→TTS, pastikan teks yang diteruskan ke TTS lengkap—tidak terpotong di tengah aliran. Misalnya:
Tunggu LLM menghasilkan kalimat atau paragraf lengkap sebelum mengirimkan instruksi continue-task, bukan mengalirkannya karakter per karakter.
Jika sintesis aliran diperlukan (menghasilkan sambil memutar), kirimkan teks dalam potongan kalimat alami—misalnya setelah titik atau tanda tanya.
Setelah output LLM selesai, selalu kirimkan instruksi finish-task untuk menghindari kehilangan konten akhir.
Tips khusus platform
Flutter: Saat menggunakan paket
web_socket_channel, tutup koneksi secara benar dalam metodedisposeuntuk mencegah kebocoran memori. Selain itu, tangani peristiwa siklus hidup aplikasi (sepertiAppLifecycleState.paused) untuk transisi ke latar belakang.Web (browser): Beberapa browser membatasi koneksi WebSocket. Gunakan kembali satu koneksi untuk beberapa tugas. Gunakan peristiwa
beforeunloaduntuk menutup koneksi sebelum halaman keluar, menghindari koneksi yang usang.Seluler (iOS/Android native): Sistem operasi dapat menjeda atau menghentikan koneksi jaringan saat aplikasi berpindah ke latar belakang. Gunakan tugas latar belakang atau layanan latar depan untuk mempertahankan WebSocket aktif, atau inisialisasi ulang tugas saat kembali ke latar depan.
URL
URL WebSocket bersifat tetap sebagai berikut:
Internasional
Dalam mode penyebaran internasional, titik akses dan penyimpanan data keduanya berlokasi di wilayah Singapura. Sumber daya komputasi inferensi model dijadwalkan secara dinamis secara global, kecuali untuk Tiongkok daratan.
URL WebSocket: wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference
Tiongkok daratan
Dalam mode penyebaran Tiongkok daratan, titik akses dan penyimpanan data keduanya berlokasi di wilayah Beijing. Sumber daya komputasi inferensi model dibatasi hanya untuk Tiongkok daratan.
URL WebSocket: wss://dashscope.aliyuncs.com/api-ws/v1/inference
Kesalahan umum dalam konfigurasi URL:
Kesalahan: Menggunakan URL yang dimulai dengan http:// atau https:// → Benar: Anda harus menggunakan protokol wss://.
Kesalahan: Menempatkan parameter Authorization dalam string kueri URL (misalnya
?Authorization=bearer <your_api_key>) → Benar: Atur parameter Authorization dalam header jabat tangan HTTP. Untuk informasi selengkapnya, lihat Header.Kesalahan: Menambahkan nama model atau parameter jalur lain ke akhir URL → Benar: URL bersifat tetap. Anda dapat menentukan model menggunakan parameter
payload.modeldalam instruksi run-task.
Header
Tambahkan header berikut ke permintaan Anda:
Parameter | Jenis | Wajib | Deskripsi |
Authorization | string | Ya | Token otentikasi dalam format |
user-agent | string | Tidak | Identifikasi klien untuk membantu server melacak sumber. |
X-DashScope-WorkSpace | string | Tidak | ID ruang kerja Alibaba Cloud Model Studio Anda. |
X-DashScope-DataInspection | string | Tidak | Apakah akan mengaktifkan pemeriksaan kepatuhan data. Nilai bawaan adalah tidak diatur atau |
Waktu otentikasi dan kesalahan umum
Validasi otentikasi terjadi selama jabat tangan WebSocket, bukan saat Anda mengirimkan instruksi run-task. Jika header Authorization tidak ada atau Kunci API tidak valid, server menolak jabat tangan dan mengembalikan kesalahan HTTP 401 atau 403. Pustaka klien biasanya melaporkan ini sebagai pengecualian WebSocketBadStatus.
Menangani kegagalan otentikasi
Jika koneksi WebSocket gagal, Anda dapat mengikuti langkah-langkah berikut:
Periksa format Kunci API: Pastikan header Authorization menggunakan format
bearer <your_api_key>, dengan spasi antara `bearer` dan Kunci API.Verifikasi kevalidan Kunci API: Di konsol Model Studio, pastikan Kunci API belum dihapus atau dinonaktifkan dan memiliki izin untuk memanggil model CosyVoice.
Periksa pengaturan header: Pastikan header Authorization diatur dengan benar selama jabat tangan WebSocket. Metode pengaturan header bervariasi tergantung bahasa pemrograman:
Python (pustaka websockets):
extra_headers={"Authorization": f"bearer {api_key}"}JavaScript: API WebSocket bawaan browser tidak mendukung header kustom. Anda dapat menggunakan proksi sisi server atau pustaka lain, seperti ws.
Go (gorilla/websocket):
header.Add("Authorization", fmt.Sprintf("bearer %s", apiKey))
Uji konektivitas jaringan: Anda dapat menggunakan curl atau Postman untuk menguji apakah Kunci API berfungsi dengan API DashScope lain yang didukung HTTP.
Menggunakan WebSocket di lingkungan browser
Di lingkungan browser, seperti Vue3 atau React, API WebSocket bawaan browser memiliki pembatasan keamanan yang mencegah penggunaan header kustom. API bawaan new WebSocket(url) tidak mengizinkan header permintaan kustom (seperti Authorization) selama jabat tangan. Ini merupakan pembatasan keamanan browser. Akibatnya, Anda tidak dapat melakukan otentikasi langsung dengan Kunci API dalam kode frontend Anda.
Solusi: Gunakan proksi sisi server
Bentuk koneksi WebSocket dari layanan backend Anda (seperti Node.js, Java, atau Python) ke layanan CosyVoice. Layanan backend Anda dapat mengatur header Authorization dengan benar.
Hubungkan frontend Anda ke layanan backend Anda menggunakan WebSocket. Layanan backend kemudian bertindak sebagai proksi untuk meneruskan pesan ke CosyVoice.
Manfaat: Pendekatan ini menjaga keamanan Kunci API di sisi backend. Anda juga dapat menambahkan logika bisnis, seperti otentikasi, pencatatan, dan pembatasan laju, di sisi backend.
Jangan menyematkan Kunci API Anda secara langsung dalam kode frontend atau mengirimkannya langsung dari browser. Paparan Kunci API dapat menyebabkan pelanggaran akun, tagihan tinggi, atau pelanggaran data.
Contoh kode:
Untuk bahasa pemrograman lain, Anda dapat menyesuaikan logika dalam contoh ini atau menggunakan alat AI untuk mengonversinya.
Frontend (web asli) + Backend (Node.js Express): cosyvoiceNodeJs_en.zip
Frontend (web asli) + Backend (Python Flask): cosyvoiceFlask_en.zip
Instruksi (klien → server)
Instruksi adalah pesan berformat JSON yang dikirimkan klien ke server. Instruksi menggunakan format Frame Teks untuk mengontrol awal, akhir, dan batas tugas.
Kirimkan instruksi secara ketat berurutan. Jika tidak, tugas dapat gagal:
Kirimkan instruksi run-task
Memulai tugas sintesis suara.
task_idyang dikembalikan harus digunakan secara konsisten dalam instruksi continue-task dan instruksi finish-task berikutnya.
Kirimkan instruksi continue-task
Mengirimkan teks untuk disintesis.
Kirimkan hanya setelah menerima event task-started dari server.
Kirimkan instruksi finish-task
Mengakhiri tugas sintesis suara.
Kirimkan setelah semua instruksi continue-task dikirimkan.
1. instruksi run-task: Memulai tugas
Instruksi ini memulai tugas sintesis suara. Anda dapat mengonfigurasi suara, laju sampel, dan parameter permintaan lainnya di sini.
Kapan mengirimkan: Setelah koneksi WebSocket terbentuk.
Jangan mengirimkan teks untuk disintesis: Mengirimkan teks dalam instruksi run-task mempersulit pemecahan masalah. Hindari hal ini. Sebagai gantinya, kirimkan teks menggunakan instruksi continue-task.
Bidang input harus ada: Payload harus mencakup bidang input (sebagai
{}). Menghilangkannya akan mengembalikan pesan kesalahan 'task can not be null'.
Contoh:
{
"header": {
"action": "run-task",
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // UUID acak
"streaming": "duplex"
},
"payload": {
"task_group": "audio",
"task": "tts",
"function": "SpeechSynthesizer",
"model": "cosyvoice-v3-flash",
"parameters": {
"text_type": "PlainText",
"voice": "longanyang", // Suara
"format": "mp3", // Format audio
"sample_rate": 22050, // Laju sampel
"volume": 50, // Volume
"rate": 1, // Laju ucapan
"pitch": 1 // Nada
},
"input": {// input harus ada, atau akan mengembalikan kesalahan
}
}
}header Referensi parameter:
Parameter | Type | Required | Description |
header.action | string | Yes | Jenis instruksi. Untuk instruksi ini, nilainya selalu "run-task". |
header.task_id | string | Yes | ID task untuk permintaan ini. Sebuah pengidentifikasi unik universal (UUID) sepanjang 32 karakter, terdiri dari 32 huruf dan angka yang dihasilkan secara acak. UUID tersebut dapat menyertakan tanda hubung (misalnya, Untuk instruksi continue-task dan finish-task berikutnya, gunakan task_id yang sama seperti pada instruksi run-task. |
header.streaming | string | Yes | String tetap: "duplex" |
muatan referensi parameter:
Parameter | Type | Required | Description |
payload.task_group | string | Yes | String tetap: "audio". |
payload.task | string | Yes | String tetap: "tts". |
payload.function | string | Yes | String tetap: "SpeechSynthesizer". |
payload.model | string | Yes | model sintesis suara. Versi model yang berbeda memerlukan versi voice yang sesuai:
|
payload.input | object | Yes | Dalam instruksi run-task, bidang input harus ada (tidak boleh dihilangkan), tetapi jangan mengirimkan teks untuk disintesis di sini (gunakan objek kosong Format Penting Kesalahan umum: Menghilangkan bidang input atau menambahkan bidang yang tidak diharapkan (seperti mode atau content) menyebabkan server menolak permintaan dengan pesan “InvalidParameter: task can not be null” atau menutup koneksi (kode WebSocket 1007). |
payload.parameters | |||
text_type | string | Yes | String tetap: "PlainText". |
voice | string | Yes | Voice yang digunakan untuk sintesis suara. Voice sistem dan voice hasil kloning didukung:
|
format | string | No | Format pengkodean audio. Mendukung pcm, wav, mp3 (default), dan opus. Saat format adalah opus, sesuaikan bitrate menggunakan parameter |
sample_rate | integer | No | Laju sampel audio (dalam Hz). Default: 22050. Nilai yang valid: 8000, 16000, 22050, 24000, 44100, 48000. Catatan Laju sampel default merepresentasikan laju optimal untuk voice yang dipilih. Output menggunakan laju ini secara default, tetapi downsampling dan upsampling didukung. |
volume | integer | No | Volume. Nilai default: 50. Nilai yang valid: [0, 100]. Nilai 50 merepresentasikan volume default. Volume berskala secara linear terhadap nilai ini. Nilai 0 berarti senyap, dan 100 adalah volume maksimum. |
rate | float | No | Laju bicara. Nilai default: 1.0. Nilai yang valid: [0.5, 2.0]. Nilai 1.0 adalah laju bicara standar. Nilai kurang dari 1.0 memperlambat bicara, dan nilai lebih dari 1.0 mempercepatnya. |
pitch | float | No | Pitch. Nilai ini berfungsi sebagai pengali untuk penyesuaian pitch, tetapi hubungannya dengan perubahan pitch yang dirasakan tidak sepenuhnya linear atau logaritmik. Kami menyarankan melakukan pengujian untuk menemukan nilai yang sesuai. Nilai default: 1.0. Nilai yang valid: [0.5, 2.0]. Nilai 1.0 adalah pitch alami dari voice. Nilai lebih dari 1.0 meningkatkan pitch, dan nilai kurang dari 1.0 menurunkannya. |
enable_ssml | boolean | No | Aktifkan SSML. Jika diatur ke |
bit_rate | int | No | Bitrate audio dalam kbps. Jika format audio adalah Opus, sesuaikan bitrate menggunakan parameter Nilai default: 32. Nilai yang valid: [6, 510]. |
word_timestamp_enabled | boolean | No | Menentukan apakah akan mengaktifkan timestamp tingkat kata. Nilai default: false.
Fitur ini hanya tersedia untuk voice hasil kloning dari model cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2, serta voice sistem yang ditandai sebagai didukung dalam voice list. Saat word_timestamp_enabled diaktifkan, informasi timestamp muncul dalam event result-generated. Contoh: |
seed | int | No | Seed acak yang digunakan selama proses generasi. Seed yang berbeda menghasilkan output sintesis yang berbeda. Jika model, teks, voice, dan parameter lainnya identik, penggunaan seed yang sama akan mereproduksi output yang sama. Nilai default: 0. Nilai yang valid: [0, 65535]. |
language_hints | array[string] | No | Menentukan target language untuk sintesis suara guna meningkatkan kualitas sintesis. Gunakan parameter ini ketika pelafalan angka, singkatan, atau simbol, atau kualitas sintesis untuk bahasa yang kurang umum tidak sesuai harapan. Contohnya:
Nilai yang valid:
Catatan: Parameter ini berupa array, tetapi versi saat ini hanya memproses elemen pertama. Oleh karena itu, kami menyarankan hanya mengirimkan satu nilai. Penting Parameter ini menentukan target language untuk sintesis suara. Pengaturan ini independen dari bahasa audio sampel yang digunakan untuk voice cloning. Untuk mengatur source language pada tugas cloning, lihat CosyVoice Voice Cloning/Design API. |
instruction | string | No | Mengatur instruksi untuk mengontrol efek sintesis seperti dialek, emosi, atau gaya bicara. Fitur ini hanya tersedia untuk voice hasil kloning dari model cosyvoice-v3.5-flash, cosyvoice-v3.5-plus, dan cosyvoice-v3-flash, serta voice sistem yang ditandai mendukung Instruct dalam voice list. Batas panjang: 100 karakter. Satu karakter Cina (termasuk Cina sederhana dan tradisional, Kanji Jepang, dan Hanja Korea) dihitung sebagai dua karakter. Semua karakter lain, seperti tanda baca, huruf, angka, dan Kana/Hangul Jepang/Korea, dihitung sebagai satu karakter. Persyaratan penggunaan (berbeda-beda tergantung model):
|
enable_aigc_tag | boolean | No | Menentukan apakah akan menambahkan identifier AIGC tak terlihat ke audio yang dihasilkan. Jika diatur ke true, identifier tak terlihat akan disisipkan ke dalam audio dalam format yang didukung (WAV, MP3, dan Opus). Nilai default: false. Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini. |
aigc_propagator | string | No | Mengatur bidang Nilai default: Alibaba Cloud UID. Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini. |
aigc_propagate_id | string | No | 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. |
hot_fix | object | No | Konfigurasi untuk hotpatching teks. Memungkinkan Anda menyesuaikan pelafalan kata tertentu atau mengganti teks sebelum sintesis. Fitur ini hanya tersedia untuk voice hasil kloning dari cosyvoice-v3-flash. Parameter:
Contoh: |
enable_markdown_filter | boolean | No | Menentukan apakah akan mengaktifkan penyaringan Markdown. Jika diaktifkan, sistem secara otomatis menghapus simbol Markdown dari teks input sebelum mensintesis suara, sehingga simbol tersebut tidak terbaca. Fitur ini hanya tersedia untuk voice hasil kloning dari cosyvoice-v3-flash. Nilai default: false. Nilai yang valid:
|
2. Instruksi Melanjutkan Tugas
Instruksi ini mengirimkan teks untuk disintesis.
Anda dapat mengirimkan seluruh teks dalam satu instruksi continue-task, atau membaginya ke dalam beberapa instruksi continue-task, secara berurutan.
Kapan mengirimkan: Setelah menerima event task-started.
Jangan menunggu lebih dari 23 detik antara pengiriman fragmen teks, jika tidak, akan muncul kesalahan 'request timeout after 23 seconds'.
Jika tidak ada teks lagi yang tersisa, kirimkan instruksi finish-task untuk mengakhiri tugas.
Server memberlakukan batas waktu 23 detik. Klien tidak dapat mengubah batas waktu ini.
Contoh:
{
"header": {
"aksi": "continue-task",
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // UUID acak
"streaming": "duplex"
},
"muatan": {
"input": {
"teks": "Di depan tempat tidurku, cahaya bulan bersinar terang; kusangka itu embun beku di atas tanah."
}
}
}Header referensi parameter:
Parameter | Type | Required | Description |
header.action | string | Yes | Jenis instruksi. Untuk instruksi ini, nilainya selalu "continue-task". |
header.task_id | string | Yes | ID task untuk permintaan ini. Harus sesuai dengan task_id yang digunakan dalam instruksi run-task. |
header.streaming | string | Yes | String tetap: "duplex" |
muatan referensi parameter:
Parameter | Type | Required | Description |
input.text | string | Yes | Teks yang akan disintesis. |
3. instruksi penyelesaian tugas: Mengakhiri tugas
Instruksi ini mengakhiri task sintesis suara.
Selalu kirim instruksi ini. Jika tidak, Anda mungkin mengalami:
Audio tidak lengkap: Server tidak akan memaksa mensintesis kalimat yang tersimpan di cache secara tidak lengkap, sehingga bagian akhir audio akan hilang.
Timeout koneksi: Jika Anda menunggu lebih dari 23 detik setelah instruksi continue-task terakhir sebelum mengirim finish-task, koneksi akan timeout dan ditutup.
Masalah penagihan: Task yang tidak diakhiri secara normal dapat mengembalikan informasi penggunaan yang tidak akurat.
Kapan harus dikirim: Kirim segera setelah semua instruksi continue-task telah dikirim. Jangan menunggu hingga audio selesai atau menunda pengiriman—hal ini dapat memicu timeout.
Contoh:
{
"header": {
"action": "finish-task",
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
"streaming": "duplex"
},
"payload": {
"input": {}//input harus ada, atau akan mengembalikan error
}
}header referensi parameter:
Parameter | Tipe | Wajib | Deskripsi |
header.action | string | Ya | Jenis instruksi. Untuk instruksi ini, nilainya selalu "finish-task". |
header.task_id | string | Ya | ID task untuk permintaan ini. Harus sesuai dengan task_id yang digunakan dalam instruksi run-task. |
header.streaming | string | Ya | String tetap: "duplex" |
payload referensi parameter:
Parameter | Tipe | Wajib | Deskripsi |
payload.input | object | Ya | Format tetap: {}. |
Events (server → client)
Events adalah pesan berformat JSON yang dikirim oleh server ke client. Setiap event merepresentasikan tahap pemrosesan.
Server mengirim audio data biner secara terpisah—tidak termasuk dalam event apa pun.
1. task-started event: Tugas dimulai
Saat Anda menerima event task-started, tugas telah berhasil dimulai. Anda hanya boleh mengirim instruksi continue-task atau finish-task setelah menerima event ini. Jika tidak, tugas akan gagal.
Event task-started tidak memiliki konten dalam payload-nya.
Contoh:
{
"header": {
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
"event": "task-started",
"attributes": {}
},
"payload": {}
}header referensi parameter:
Parameter | Tipe | Deskripsi |
header.event | string | Jenis event. Untuk event ini, nilainya selalu "task-started". |
header.task_id | string | ID task yang dihasilkan oleh client. |
2. result-generated event
Selama Anda mengirim instruksi continue-task dan finish-task, server terus-menerus mengembalikan event result-generated.
Untuk menghubungkan audio data dengan teks yang sesuai, server menyertakan metadata kalimat dalam event result-generated bersamaan dengan audio. Server secara otomatis membagi teks input menjadi kalimat-kalimat. Sintesis setiap kalimat terdiri dari tiga sub-event:
sentence-begin: Menandai awal kalimat dan mengembalikan teks yang akan disintesis.sentence-synthesis: Menandai chunk audio data. Setiap event segera diikuti oleh frame audio data melalui saluran biner WebSocket.Satu kalimat menghasilkan beberapa event
sentence-synthesis—satu untuk setiap chunk audio.Client harus menerima chunk audio ini secara berurutan dan menambahkannya ke file yang sama.
Setiap event
sentence-synthesismemiliki korespondensi satu-ke-satu dengan frame audio berikutnya—tidak terjadi ketidaksesuaian.
sentence-end: Menandai akhir kalimat dan mengembalikan teks kalimat serta jumlah karakter yang ditagih secara kumulatif.
Gunakan bidang payload.output.type untuk membedakan jenis sub-event.
Contoh:
sentence-begin
{
"header": {
"task_id": "3f2d5c86-0550-45c0-801f-xxxxxxxxxx",
"event": "result-generated",
"attributes": {}
},
"payload": {
"output": {
"sentence": {
"index": 0,
"words": []
},
"type": "sentence-begin",
"original_text": "Before my bed, moonlight shines bright,"
}
}
}sentence-synthesis
{
"header": {
"task_id": "3f2d5c86-0550-45c0-801f-xxxxxxxxxx",
"event": "result-generated",
"attributes": {}
},
"payload": {
"output": {
"sentence": {
"index": 0,
"words": []
},
"type": "sentence-synthesis"
}
}
}sentence-end
{
"header": {
"task_id": "3f2d5c86-0550-45c0-801f-xxxxxxxxxx",
"event": "result-generated",
"attributes": {}
},
"payload": {
"output": {
"sentence": {
"index": 0,
"words": []
},
"type": "sentence-end",
"original_text": "Before my bed, moonlight shines bright,"
},
"usage": {
"characters": 11
}
}
}header referensi parameter:
Parameter | Tipe | Deskripsi |
header.event | string | Jenis event. Untuk event ini, nilainya selalu "result-generated". |
header.task_id | string | ID task yang dihasilkan oleh client. |
header.attributes | object | Atribut tambahan—biasanya berupa objek kosong. |
payload referensi parameter:
Parameter | Tipe | Deskripsi |
payload.output.type | string | Jenis sub-event. Nilai:
Alur event lengkap Untuk setiap kalimat yang akan disintesis, server mengembalikan event dalam urutan berikut:
|
payload.output.sentence.index | integer | Nomor kalimat, dimulai dari 0. |
payload.output.sentence.words | array | Array informasi karakter. |
payload.output.sentence.words.text | string | Teks kata. |
payload.output.sentence.words.begin_index | integer | Indeks posisi awal kata dalam kalimat, dihitung dari 0. |
payload.output.sentence.words.end_index | integer | Indeks posisi akhir kata dalam kalimat, dihitung dari 1. |
payload.output.sentence.words.begin_time | integer | Timestamp awal audio kata, dalam milidetik. |
payload.output.sentence.words.end_time | integer | Timestamp akhir audio kata, dalam milidetik. |
payload.output.original_text | string | Konten kalimat setelah teks input pengguna dibagi. Kalimat terakhir mungkin tidak menyertakan bidang ini. |
payload.usage.characters | integer | Total karakter yang ditagih dalam permintaan ini hingga saat ini.
Dalam satu task, bidang |
3. task-finished event: Tugas selesai
Saat Anda menerima event task-finished, tugas telah berakhir.
Setelah tugas berakhir, Anda dapat menutup koneksi WebSocket dan keluar, atau menggunakan kembali koneksi tersebut untuk mengirim instruksi run-task baru (lihat Connection overhead and reuse).
Contoh:
{
"header": {
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
"event": "task-finished",
"attributes": {
"request_uuid": "0a9dba9e-d3a6-45a4-be6d-xxxxxxxxxxxx"
}
},
"payload": {
"output": {
"sentence": {
"words": []
}
},
"usage": {
"characters": 13
}
}
}header referensi parameter:
Parameter | Tipe | Deskripsi |
header.event | string | Jenis event. Untuk event ini, nilainya selalu "task-finished". |
header.task_id | string | ID task yang dihasilkan oleh client. |
header.attributes.request_uuid | string | ID permintaan. Berikan ini kepada pengembang CosyVoice untuk diagnosis masalah. |
payload referensi parameter:
Parameter | Tipe | Deskripsi |
payload.usage.characters | integer | Total karakter yang ditagih dalam permintaan ini hingga saat ini.
Dalam satu task, bidang |
4. task-failed event: Tugas gagal
Jika Anda menerima event task-failed, tugas telah gagal. Tutup koneksi WebSocket dan tangani error tersebut. Analisis pesan error—jika kegagalan disebabkan oleh masalah kode, perbaiki kode tersebut.
Contoh:
{
"header": {
"task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
"event": "task-failed",
"error_code": "InvalidParameter",
"error_message": "[tts:]Engine return error code: 418",
"attributes": {}
},
"payload": {}
}header referensi parameter:
Parameter | Tipe | Deskripsi |
header.event | string | Jenis event. Untuk event ini, statusnya selalu task-failed. |
header.task_id | string | ID task yang dihasilkan oleh client. |
header.error_code | string | Deskripsi jenis error. |
header.error_message | string | Alasan error secara detail. |
Metode penginterupsi Tugas
Selama sintesis streaming, Anda dapat menginterupsi tugas saat ini lebih awal—misalnya, jika pengguna membatalkan pemutaran atau menginterupsi percakapan langsung—dengan menggunakan salah satu metode berikut:
Interrupt Mode | Server behavior | Use case |
Directly close the connection |
| Immediate interruption: Pengguna membatalkan pemutaran, mengganti konten, atau keluar dari aplikasi. |
Send a finish-task command |
| Elegant end: Anda berhenti mengirim teks baru tetapi tetap menerima audio untuk konten yang telah di-cache. |
Overhead koneksi dan penggunaan ulang
Layanan WebSocket mendukung penggunaan ulang koneksi untuk meningkatkan efisiensi resource dan menghindari overhead saat menyiapkan koneksi.
Setelah server menerima run-task instruction dari client, server memulai task baru. Setelah client mengirim finish-task instruction, server mengembalikan task-finished event ketika task selesai. Setelah task berakhir, koneksi WebSocket dapat digunakan ulang dengan mengirim run-task instruction lain untuk memulai task berikutnya.
Anda hanya dapat mengirim run-task instruction baru setelah server mengembalikan task-finished event.
Task yang berbeda pada koneksi yang digunakan ulang harus menggunakan task_id yang berbeda.
Jika sebuah task gagal selama eksekusi, server mengembalikan task-failed event dan menutup koneksi. Koneksi ini tidak dapat digunakan ulang.
Jika tidak ada task baru yang dimulai dalam waktu 60 detik setelah task berakhir, koneksi akan timeout dan ditutup secara otomatis.
Metrik kinerja dan batas konkurensi
Batas konkurensi
Untuk informasi lebih lanjut, lihat Rate limiting.
Untuk menambah kuota konkurensi Anda, misalnya guna mendukung lebih banyak koneksi bersamaan, Anda dapat menghubungi layanan pelanggan. Penyesuaian kuota memerlukan tinjauan dan biasanya selesai dalam 1 hingga 3 hari kerja.
Praktik terbaik: Untuk meningkatkan penggunaan resource, Anda dapat menggunakan kembali satu koneksi WebSocket untuk multiple task alih-alih membuka koneksi baru untuk setiap task. Untuk informasi lebih lanjut, lihat Connection overhead and reuse.
Kinerja koneksi dan latensi
Waktu koneksi tipikal:
Klien di Tiongkok daratan: Pembentukan koneksi WebSocket (dari newWebSocket hingga onOpen) biasanya memakan waktu 200 hingga 1.000 ms.
Koneksi lintas batas (seperti Hong Kong atau wilayah internasional): Latensi koneksi dapat mencapai 1 hingga 3 detik. Dalam kasus jarang terjadi, latensi tersebut dapat mencapai 10 hingga 30 detik.
Pemecahan masalah waktu koneksi yang lama:
Jika pembentukan koneksi WebSocket memerlukan waktu lebih dari 30 detik, penyebabnya mungkin salah satu dari isu berikut:
Isu jaringan: Latensi jaringan tinggi antara client dan server, seperti latensi akibat koneksi lintas batas atau kualitas ISP yang buruk.
Resolusi DNS lambat: Waktu resolusi DNS yang lama untuk dashscope.aliyuncs.com. Anda dapat mencoba menggunakan DNS publik, seperti 8.8.8.8, atau mengonfigurasi file hosts lokal Anda.
Proses jabat tangan TLS lambat: Versi TLS yang usang pada client atau validasi sertifikat yang lambat. Kami menyarankan Anda menggunakan TLS 1.2 atau versi yang lebih baru.
Proxy atau firewall: Jaringan perusahaan mungkin memblokir koneksi WebSocket atau mengharuskan penggunaan proxy.
Alat pemecahan masalah:
Anda dapat menggunakan Wireshark atau tcpdump untuk menganalisis waktu fase jabat tangan TCP, jabat tangan TLS, dan Upgrade WebSocket.
Anda dapat menguji latensi koneksi HTTP dengan curl:
curl -w "@curl-format.txt" -o /dev/null -s https://dashscope.aliyuncs.com
API WebSocket CosyVoice dideploy di wilayah Beijing, Tiongkok daratan. Jika client Anda berada di wilayah lain, seperti Hong Kong atau wilayah luar negeri, Anda dapat menggunakan server relay terdekat atau CDN untuk mempercepat koneksi.
Kinerja generasi audio
Kecepatan sintesis:
Faktor Real-time (RTF): Model CosyVoice biasanya mensintesis audio dengan kecepatan 0,1 hingga 0,5 kali kecepatan Real-time. Artinya, menghasilkan audio selama 1 detik memerlukan waktu 0,1 hingga 0,5 detik. Kecepatan aktual bergantung pada versi model, panjang teks, dan beban server.
Latensi paket pertama: Latensi dari pengiriman instruksi continue-task hingga penerimaan chunk audio pertama biasanya 200 hingga 800 ms.
Kode contoh
Kode contoh ini hanya menunjukkan konektivitas layanan dasar. Anda harus mengimplementasikan logika siap produksi untuk kasus penggunaan spesifik Anda.
Saat menulis kode klien WebSocket, gunakan pemrograman asinkron untuk mengirim dan menerima pesan secara bersamaan. Ikuti langkah-langkah berikut:
Kode kesalahan
Jika terjadi kesalahan, lihat Pesan kesalahan untuk pemecahan masalah.
FAQ
Fitur, penagihan, dan pembatasan laju
T: Apa yang bisa saya lakukan jika pengucapan tidak akurat?
Gunakan SSML untuk menyesuaikan efek sintesis suara.
T: Mengapa menggunakan WebSocket alih-alih HTTP/HTTPS? Mengapa tidak menyediakan API RESTful?
Layanan Ucapan menggunakan WebSocket alih-alih HTTP/HTTPS atau API RESTful karena memerlukan komunikasi full-duplex. WebSocket memungkinkan server dan klien mendorong data secara proaktif, seperti pembaruan progres real-time untuk sintesis atau pengenalan. API RESTful melalui HTTP hanya mendukung siklus permintaan-respons yang diprakarsai klien dan tidak dapat memenuhi persyaratan interaksi real-time.
T: Sintesis suara ditagih per karakter. Bagaimana cara memeriksa atau mengambil jumlah karakter untuk setiap sintesis?
Anda dapat memperoleh jumlah karakter dari parameter payload.usage.characters dalam event result-generated server. Gunakan nilai dari event result-generated terakhir yang diterima.
Pemecahan masalah
Jika kode Anda melemparkan kesalahan, periksa apakah instruksi yang dikirimkan ke server benar. Cetak instruksi tersebut dan verifikasi format serta bidang yang diperlukan. Jika instruksi benar, lihat kode kesalahan untuk diagnosis lebih lanjut.
T: Bagaimana cara mendapatkan Request ID?
Anda dapat memperolehnya dengan dua cara:
Anda dapat mengurai informasi yang dikembalikan oleh sisi server dalam event result-generated.
Uraikan informasi yang dikembalikan server dalam event task-finished.
T: Mengapa SSML gagal?
Pecahkan masalah ini langkah demi langkah:
Pastikan Anda mengikuti dengan benar batasan dan kendala.
Pastikan Anda memanggil SSML dengan benar. Untuk informasi selengkapnya, lihat Dukungan bahasa markup SSML.
Pastikan teks Anda adalah teks biasa dan memenuhi persyaratan format. Untuk informasi selengkapnya, lihat Ikhtisar bahasa markup SSML.
T: Mengapa audio tidak dapat diputar?
Periksa skenario berikut satu per satu:
Audio disimpan sebagai file lengkap (seperti xx.mp3).
Konsistensi format audio: Pastikan format audio yang diatur dalam parameter permintaan sesuai dengan ekstensi file. Misalnya, mengatur format WAV tetapi menyimpan dengan ekstensi .mp3 menyebabkan pemutaran gagal.
Kompatibilitas pemutar: Verifikasi bahwa pemutar Anda mendukung format dan laju sampel file audio. Beberapa pemutar mungkin tidak mendukung laju sampel tinggi atau pengkodean audio tertentu.
Audio diputar dalam aliran.
Simpan aliran audio sebagai file lengkap dan coba putar dengan pemutar. Jika file tidak dapat diputar, lihat metode pemecahan masalah untuk skenario 1.
Jika file diputar secara normal, masalahnya mungkin pada implementasi pemutaran aliran Anda. Verifikasi bahwa pemutar Anda mendukung pemutaran aliran.
Alat dan pustaka umum yang mendukung pemutaran aliran meliputi FFmpeg, PyAudio (Python), AudioFormat (Java), dan MediaSource (JavaScript).
T: Mengapa pemutaran audio tersendat?
Periksa skenario berikut satu per satu:
Periksa kecepatan pengiriman teks: Pastikan interval antara segmen teks masuk akal. Hindari situasi di mana segmen berikutnya tidak dikirim tepat waktu setelah segmen audio sebelumnya selesai diputar.
Periksa kinerja fungsi callback:
Periksa apakah ada terlalu banyak logika bisnis dalam fungsi callback, yang dapat menyebabkan pemblokiran.
Fungsi callback berjalan di thread WebSocket. Jika diblokir, WebSocket mungkin gagal menerima paket jaringan tepat waktu, menyebabkan pemutaran audio tersendat.
Kami merekomendasikan menulis data audio ke buffer terpisah dan memprosesnya di thread lain untuk menghindari pemblokiran thread WebSocket.
Periksa stabilitas jaringan: Pastikan koneksi jaringan Anda stabil untuk menghindari gangguan atau penundaan transmisi audio akibat fluktuasi jaringan.
T: Mengapa sintesis suara memakan waktu lama?
Ikuti langkah-langkah berikut untuk memecahkan masalah:
Periksa interval input
Periksa interval input. Jika Anda menggunakan sintesis ucapan aliran, verifikasi apakah interval antara pengiriman segmen teks terlalu lama (misalnya, penundaan beberapa detik). Interval yang lama meningkatkan total waktu sintesis.
Analisis metrik kinerja.
Latensi paket pertama: Biasanya sekitar 500 ms.
RTF (RTF = Total waktu sintesis / Durasi audio): Biasanya kurang dari 1,0.
T: Bagaimana cara menangani pengucapan yang salah dalam ucapan hasil sintesis?
Gunakan tag <phoneme> SSML untuk menentukan pengucapan yang benar.
T: Mengapa tidak ada audio yang dikembalikan? Mengapa bagian akhir teks hilang dari audio? (Audio hilang)
Konfirmasi bahwa Anda tidak lupa mengirimkan instruksi finish-task. Selama sintesis, server menunggu hingga menyimpan cukup teks sebelum memulai. Jika Anda lupa mengirimkan finish-task, teks akhir dalam cache mungkin tidak pernah dikonversi menjadi audio.
T: Mengapa urutan aliran audio acak, menyebabkan pemutaran kacau?
Pecahkan masalah ini di dua area:
Pastikan instruksi run-task, instruksi continue-task, dan instruksi finish-task untuk satu tugas sintesis semuanya menggunakan
task_idyang sama.Periksa apakah operasi asinkron menyebabkan file audio ditulis dalam urutan yang berbeda dari penerimaan data biner.
T: Bagaimana cara menangani kesalahan koneksi WebSocket?
Bagaimana cara menangani penutupan koneksi WebSocket (kode 1007)?
Koneksi WebSocket ditutup segera setelah mengirimkan instruksi run-task, dengan kode penutupan 1007.
Akar penyebab: Server mendeteksi kesalahan protokol atau format data dan memutus koneksi. Alasan umum meliputi berikut ini:
Bidang tidak valid dalam payload run-task, seperti menambahkan bidang selain
"input": {}.Kesalahan format JSON, seperti koma yang hilang atau tanda kurung yang tidak cocok.
Bidang wajib hilang, seperti task_id atau action.
Solusi:
Validasi format JSON: Periksa sintaks badan permintaan.
Verifikasi bidang wajib: Konfirmasi bahwa header.action, header.task_id, header.streaming, payload.task_group, payload.task, payload.function, payload.model, dan payload.input semuanya diatur.
Hapus bidang tidak valid: Dalam payload.input run-task, izinkan hanya objek kosong
{}atau bidang teks. Jangan tambahkan bidang lain.
Bagaimana cara menangani WebSocketBadStatus, 401 Unauthorized, atau 403 Forbidden?
Koneksi WebSocket gagal dengan WebSocketBadStatus, 401 Unauthorized, atau 403 Forbidden.
Akar penyebab: Kegagalan otentikasi. Server memvalidasi header Authorization selama jabat tangan WebSocket. Kunci API yang tidak valid atau hilang memicu penolakan.
Solusi: Untuk informasi selengkapnya, lihat Pemecahan masalah kegagalan otentikasi.
Izin dan otentikasi
T: Bagaimana cara membatasi Kunci API saya hanya untuk layanan sintesis suara CosyVoice saja (isolasi izin)?
Buat ruang kerja dan berikan otorisasi hanya ke model tertentu untuk membatasi cakupan Kunci API. Untuk informasi selengkapnya, lihat Kelola ruang kerja.
Pertanyaan lainnya
Lihat QA di GitHub.