实时语音合成通过 WebSocket 协议将文本实时转换为自然语音。百炼提供 CosyVoice、Qwen-TTS 和 Sambert 系列模型,支持流式输入与输出,具备声音复刻、声音设计及精细化音频控制能力,适用于语音助手、有声读物、智能客服等场景。
概述
通过 WebSocket 协议实现低延迟实时语音合成,适用于语音助手、智能客服、直播字幕等需要即时响应的场景。
支持流式输入与输出(双向 WebSocket),首包延迟低,适合语音助手、智能客服等实时对话场景
可调节语速、语调、音量与码率,实现精细的语音效果控制
兼容主流音频格式(PCM、WAV、MP3、Opus),最高支持 48kHz 采样率输出
支持指令控制,可通过自然语言指令控制语音表现力
如果您不需要实时输出,可以使用语音合成-千问(HTTP API),适合有声读物、课件配音等批量场景。如需了解各模型的选型建议,请参见语音合成。
Sambert 为早期语音合成模型,新项目建议优先使用 CosyVoice 或 Qwen-TTS,可获得更好的合成效果和更丰富的功能支持。
前提条件
已配置 API Key并将其设置到环境变量。
如果通过 DashScope SDK 调用,需要安装最新版SDK。
快速开始
以下是各模型系列的语音合成示例代码。更多语言的示例代码和详细参数说明,请参见各模型的API参考。
CosyVoice
以下示例演示如何使用系统音色(参见音色列表)进行语音合成。
Python
# coding=utf-8
import os
import dashscope
from dashscope.audio.tts_v2 import *
# 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
# 若没有配置环境变量,请用百炼API Key将下行替换为:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference
dashscope.base_websocket_api_url='wss://dashscope.aliyuncs.com/api-ws/v1/inference'
# 模型
# 不同模型版本需要使用对应版本的音色:
# cosyvoice-v3-flash/cosyvoice-v3-plus:使用longanyang等音色。
# cosyvoice-v2:使用longxiaochun_v2等音色。
# 不同语言选择对应音色
model = "cosyvoice-v3-flash"
# 音色
voice = "longanyang"
# 实例化SpeechSynthesizer,并在构造方法中传入模型(model)、音色(voice)等请求参数
synthesizer = SpeechSynthesizer(model=model, voice=voice)
# 发送待合成文本,获取二进制音频
audio = synthesizer.call("今天天气怎么样?")
# 首次发送文本时需建立 WebSocket 连接,因此首包延迟会包含连接建立的耗时
print('[Metric] requestId为:{},首包延迟为:{}毫秒'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
# 将音频保存至本地
with open('output.mp3', 'wb') as f:
f.write(audio)Java
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 {
// 模型
// 不同模型版本需要使用对应版本的音色:
// cosyvoice-v3-flash/cosyvoice-v3-plus:使用longanyang等音色。
// cosyvoice-v2:使用longxiaochun_v2等音色。
// 每个音色支持的语言不同,合成日语、韩语等非中文语言时,需选择支持对应语言的音色。详见CosyVoice音色列表。
private static String model = "cosyvoice-v3-flash";
// 音色
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
// 请求参数
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
// 若没有配置环境变量,请用百炼API Key将下行替换为:.apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // 模型
.voice(voice) // 音色
.build();
// 同步模式:禁用回调(第二个参数为null)
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
ByteBuffer audio = null;
try {
// 阻塞直至音频返回
audio = synthesizer.call("今天天气怎么样?");
} 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 连接,因此首包延迟会包含连接建立的耗时
// 注意:getFirstPackageDelay() 需要 dashscope-sdk-java 2.18.0 及以上版本
System.out.println(
"[Metric] requestId为:"
+ synthesizer.getLastRequestId()
+ "首包延迟(毫秒)为:"
+ 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) {
// 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference
Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Qwen-TTS
使用系统音色进行语音合成
以下示例演示如何使用系统音色(参见支持的音色)进行语音合成。
如需使用指令控制功能,请将 model 替换为 qwen3-tts-instruct-flash-realtime,并通过 instructions 参数设置指令。
Python
server commit模式
import os
import base64
import threading
import time
import dashscope
from dashscope.audio.qwen_tts_realtime import *
qwen_tts_realtime: QwenTtsRealtime = None
text_to_synthesize = [
'对吧~我就特别喜欢这种超市,',
'尤其是过年的时候',
'去逛超市',
'就会觉得',
'超级超级开心!',
'想买好多好多的东西呢!'
]
DO_VIDEO_TEST = False
def init_dashscope_api_key():
"""
Set your DashScope API-key. More information:
https://github.com/aliyun/alibabacloud-bailian-speech-demo/blob/master/PREREQUISITES.md
"""
# 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
if 'DASHSCOPE_API_KEY' in os.environ:
dashscope.api_key = os.environ[
'DASHSCOPE_API_KEY'] # load API-key from environment variable DASHSCOPE_API_KEY
else:
dashscope.api_key = 'your-dashscope-api-key' # set API-key manually
class MyCallback(QwenTtsRealtimeCallback):
def __init__(self):
self.complete_event = threading.Event()
self.file = open('result_24k.pcm', 'wb')
def on_open(self) -> None:
print('connection opened, init player')
def on_close(self, close_status_code, close_msg) -> None:
self.file.close()
print('connection closed with code: {}, msg: {}, destroy player'.format(close_status_code, close_msg))
def on_event(self, response: str) -> None:
try:
global qwen_tts_realtime
type = response['type']
if 'session.created' == type:
print('start session: {}'.format(response['session']['id']))
if 'response.audio.delta' == type:
recv_audio_b64 = response['delta']
self.file.write(base64.b64decode(recv_audio_b64))
if 'response.done' == type:
print(f'response {qwen_tts_realtime.get_last_response_id()} done')
if 'session.finished' == type:
print('session finished')
self.complete_event.set()
except Exception as e:
print('[Error] {}'.format(e))
return
def wait_for_finished(self):
self.complete_event.wait()
if __name__ == '__main__':
init_dashscope_api_key()
print('Initializing ...')
callback = MyCallback()
qwen_tts_realtime = QwenTtsRealtime(
# 如需使用指令控制功能,请将model替换为qwen3-tts-instruct-flash-realtime
model='qwen3-tts-flash-realtime',
callback=callback,
# 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime
url='wss://dashscope.aliyuncs.com/api-ws/v1/realtime'
)
qwen_tts_realtime.connect()
qwen_tts_realtime.update_session(
voice = 'Cherry',
response_format = AudioFormat.PCM_24000HZ_MONO_16BIT,
# 如需使用指令控制功能,请取消下方注释,并将model替换为qwen3-tts-instruct-flash-realtime
# instructions='语速较快,带有明显的上扬语调,适合介绍时尚产品。',
# optimize_instructions=True,
mode = 'server_commit'
)
for text_chunk in text_to_synthesize:
print(f'send text: {text_chunk}')
qwen_tts_realtime.append_text(text_chunk)
time.sleep(0.1)
qwen_tts_realtime.finish()
callback.wait_for_finished()
print('[Metric] session: {}, first audio delay: {}'.format(
qwen_tts_realtime.get_session_id(),
qwen_tts_realtime.get_first_audio_delay(),
))
commit模式
import base64
import os
import threading
import dashscope
from dashscope.audio.qwen_tts_realtime import *
qwen_tts_realtime: QwenTtsRealtime = None
text_to_synthesize = [
'这是第一句话。',
'这是第二句话。',
'这是第三句话。',
]
DO_VIDEO_TEST = False
def init_dashscope_api_key():
"""
Set your DashScope API-key. More information:
https://github.com/aliyun/alibabacloud-bailian-speech-demo/blob/master/PREREQUISITES.md
"""
# 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
if 'DASHSCOPE_API_KEY' in os.environ:
dashscope.api_key = os.environ[
'DASHSCOPE_API_KEY'] # load API-key from environment variable DASHSCOPE_API_KEY
else:
dashscope.api_key = 'your-dashscope-api-key' # set API-key manually
class MyCallback(QwenTtsRealtimeCallback):
def __init__(self):
super().__init__()
self.response_counter = 0
self.complete_event = threading.Event()
self.file = open(f'result_{self.response_counter}_24k.pcm', 'wb')
def reset_event(self):
self.response_counter += 1
self.file = open(f'result_{self.response_counter}_24k.pcm', 'wb')
self.complete_event = threading.Event()
def on_open(self) -> None:
print('connection opened, init player')
def on_close(self, close_status_code, close_msg) -> None:
print('connection closed with code: {}, msg: {}, destroy player'.format(close_status_code, close_msg))
def on_event(self, response: str) -> None:
try:
global qwen_tts_realtime
type = response['type']
if 'session.created' == type:
print('start session: {}'.format(response['session']['id']))
if 'response.audio.delta' == type:
recv_audio_b64 = response['delta']
self.file.write(base64.b64decode(recv_audio_b64))
if 'response.done' == type:
print(f'response {qwen_tts_realtime.get_last_response_id()} done')
self.complete_event.set()
self.file.close()
if 'session.finished' == type:
print('session finished')
self.complete_event.set()
except Exception as e:
print('[Error] {}'.format(e))
return
def wait_for_response_done(self):
self.complete_event.wait()
if __name__ == '__main__':
init_dashscope_api_key()
print('Initializing ...')
callback = MyCallback()
qwen_tts_realtime = QwenTtsRealtime(
# 如需使用指令控制功能,请将model替换为qwen3-tts-instruct-flash-realtime
model='qwen3-tts-flash-realtime',
callback=callback,
# 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime
url='wss://dashscope.aliyuncs.com/api-ws/v1/realtime'
)
qwen_tts_realtime.connect()
qwen_tts_realtime.update_session(
voice = 'Cherry',
response_format = AudioFormat.PCM_24000HZ_MONO_16BIT,
# 如需使用指令控制功能,请取消下方注释,并将model替换为qwen3-tts-instruct-flash-realtime
# instructions='语速较快,带有明显的上扬语调,适合介绍时尚产品。',
# optimize_instructions=True,
mode = 'commit'
)
print(f'send text: {text_to_synthesize[0]}')
qwen_tts_realtime.append_text(text_to_synthesize[0])
qwen_tts_realtime.commit()
callback.wait_for_response_done()
callback.reset_event()
print(f'send text: {text_to_synthesize[1]}')
qwen_tts_realtime.append_text(text_to_synthesize[1])
qwen_tts_realtime.commit()
callback.wait_for_response_done()
callback.reset_event()
print(f'send text: {text_to_synthesize[2]}')
qwen_tts_realtime.append_text(text_to_synthesize[2])
qwen_tts_realtime.commit()
callback.wait_for_response_done()
qwen_tts_realtime.finish()
print('[Metric] session: {}, first audio delay: {}'.format(
qwen_tts_realtime.get_session_id(),
qwen_tts_realtime.get_first_audio_delay(),
))Java
server commit模式
import com.alibaba.dashscope.audio.qwen_tts_realtime.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.JsonObject;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.AudioSystem;
import java.io.*;
import java.util.Base64;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
static String[] textToSynthesize = {
"对吧~我就特别喜欢这种超市",
"尤其是过年的时候",
"去逛超市",
"就会觉得",
"超级超级开心!",
"想买好多好多的东西呢!"
};
public static QwenTtsRealtimeAudioFormat ttsFormat = QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT;
// 实时PCM音频播放器类
public static class RealtimePcmPlayer {
private int sampleRate;
private SourceDataLine line;
private AudioFormat audioFormat;
private Thread decoderThread;
private Thread playerThread;
private AtomicBoolean stopped = new AtomicBoolean(false);
private Queue<String> b64AudioBuffer = new ConcurrentLinkedQueue<>();
private Queue<byte[]> RawAudioBuffer = new ConcurrentLinkedQueue<>();
private ByteArrayOutputStream totalAudioStream = new ByteArrayOutputStream();
// 构造函数初始化音频格式和音频线路
public RealtimePcmPlayer(int sampleRate) throws LineUnavailableException {
this.sampleRate = sampleRate;
this.audioFormat = new AudioFormat(this.sampleRate, 16, 1, true, false);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
decoderThread = new Thread(new Runnable() {
@Override
public void run() {
while (!stopped.get()) {
String b64Audio = b64AudioBuffer.poll();
if (b64Audio != null) {
byte[] rawAudio = Base64.getDecoder().decode(b64Audio);
RawAudioBuffer.add(rawAudio);
// 将音频数据写入 totalAudioStream
try {
totalAudioStream.write(rawAudio);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
playerThread = new Thread(new Runnable() {
@Override
public void run() {
while (!stopped.get()) {
byte[] rawAudio = RawAudioBuffer.poll();
if (rawAudio != null) {
try {
playChunk(rawAudio);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
decoderThread.start();
playerThread.start();
}
// 播放一个音频块并阻塞直到播放完成
private void playChunk(byte[] chunk) throws IOException, InterruptedException {
if (chunk == null || chunk.length == 0) return;
int bytesWritten = 0;
while (bytesWritten < chunk.length) {
bytesWritten += line.write(chunk, bytesWritten, chunk.length - bytesWritten);
}
int audioLength = chunk.length / (this.sampleRate*2/1000);
// 等待缓冲区中的音频播放完成
Thread.sleep(audioLength - 10);
}
public void write(String b64Audio) {
b64AudioBuffer.add(b64Audio);
}
public void cancel() {
b64AudioBuffer.clear();
RawAudioBuffer.clear();
}
public void waitForComplete() throws InterruptedException {
while (!b64AudioBuffer.isEmpty() || !RawAudioBuffer.isEmpty()) {
Thread.sleep(100);
}
line.drain();
}
public void shutdown() throws InterruptedException, IOException {
stopped.set(true);
decoderThread.join();
playerThread.join();
// 保存完整音频文件
File file = new File("TotalAudio_"+ttsFormat.getSampleRate()+"."+ttsFormat.getFormat());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(totalAudioStream.toByteArray());
}
if (line != null && line.isRunning()) {
line.drain();
line.close();
}
}
}
public static void main(String[] args) throws InterruptedException, LineUnavailableException, IOException {
QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
// 如需使用指令控制功能,请将model替换为qwen3-tts-instruct-flash-realtime
.model("qwen3-tts-flash-realtime")
// 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime
.url("wss://dashscope.aliyuncs.com/api-ws/v1/realtime")
// 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
.apikey(System.getenv("DASHSCOPE_API_KEY"))
.build();
AtomicReference<CountDownLatch> completeLatch = new AtomicReference<>(new CountDownLatch(1));
final AtomicReference<QwenTtsRealtime> qwenTtsRef = new AtomicReference<>(null);
// 创建实时音频播放器实例
RealtimePcmPlayer audioPlayer = new RealtimePcmPlayer(24000);
QwenTtsRealtime qwenTtsRealtime = new QwenTtsRealtime(param, new QwenTtsRealtimeCallback() {
@Override
public void onOpen() {
// 连接建立时的处理
}
@Override
public void onEvent(JsonObject message) {
String type = message.get("type").getAsString();
switch(type) {
case "session.created":
// 会话创建时的处理
if (message.has("session")) {
String eventId = message.get("event_id").getAsString();
String sessionId = message.get("session").getAsJsonObject().get("id").getAsString();
System.out.println("[onEvent] session.created, session_id: "
+ sessionId + ", event_id: " + eventId);
}
break;
case "response.audio.delta":
String recvAudioB64 = message.get("delta").getAsString();
// 实时播放音频
audioPlayer.write(recvAudioB64);
break;
case "response.done":
// 响应完成时的处理
break;
case "session.finished":
// 会话结束时的处理
completeLatch.get().countDown();
default:
break;
}
}
@Override
public void onClose(int code, String reason) {
// 连接关闭时的处理
}
});
qwenTtsRef.set(qwenTtsRealtime);
try {
qwenTtsRealtime.connect();
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
}
QwenTtsRealtimeConfig config = QwenTtsRealtimeConfig.builder()
.voice("Cherry")
.responseFormat(ttsFormat)
.mode("server_commit")
// 如需使用指令控制功能,请取消下方注释,并将model替换为qwen3-tts-instruct-flash-realtime
// .instructions("")
// .optimizeInstructions(true)
.build();
qwenTtsRealtime.updateSession(config);
for (String text:textToSynthesize) {
qwenTtsRealtime.appendText(text);
Thread.sleep(100);
}
qwenTtsRealtime.finish();
completeLatch.get().await();
qwenTtsRealtime.close();
// 等待音频播放完成并关闭播放器
audioPlayer.waitForComplete();
audioPlayer.shutdown();
System.exit(0);
}
}commit模式
import com.alibaba.dashscope.audio.qwen_tts_realtime.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.JsonObject;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.AudioSystem;
import java.io.*;
import java.util.Base64;
import java.util.Queue;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
public static QwenTtsRealtimeAudioFormat ttsFormat = QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT;
// 实时PCM音频播放器类
public static class RealtimePcmPlayer {
private int sampleRate;
private SourceDataLine line;
private AudioFormat audioFormat;
private Thread decoderThread;
private Thread playerThread;
private AtomicBoolean stopped = new AtomicBoolean(false);
private Queue<String> b64AudioBuffer = new ConcurrentLinkedQueue<>();
private Queue<byte[]> RawAudioBuffer = new ConcurrentLinkedQueue<>();
private ByteArrayOutputStream totalAudioStream = new ByteArrayOutputStream();
// 构造函数初始化音频格式和音频线路
public RealtimePcmPlayer(int sampleRate) throws LineUnavailableException {
this.sampleRate = sampleRate;
this.audioFormat = new AudioFormat(this.sampleRate, 16, 1, true, false);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
decoderThread = new Thread(new Runnable() {
@Override
public void run() {
while (!stopped.get()) {
String b64Audio = b64AudioBuffer.poll();
if (b64Audio != null) {
byte[] rawAudio = Base64.getDecoder().decode(b64Audio);
RawAudioBuffer.add(rawAudio);
// 将音频数据写入 totalAudioStream
try {
totalAudioStream.write(rawAudio);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
playerThread = new Thread(new Runnable() {
@Override
public void run() {
while (!stopped.get()) {
byte[] rawAudio = RawAudioBuffer.poll();
if (rawAudio != null) {
try {
playChunk(rawAudio);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
decoderThread.start();
playerThread.start();
}
// 播放一个音频块并阻塞直到播放完成
private void playChunk(byte[] chunk) throws IOException, InterruptedException {
if (chunk == null || chunk.length == 0) return;
int bytesWritten = 0;
while (bytesWritten < chunk.length) {
bytesWritten += line.write(chunk, bytesWritten, chunk.length - bytesWritten);
}
int audioLength = chunk.length / (this.sampleRate*2/1000);
// 等待缓冲区中的音频播放完成
Thread.sleep(audioLength - 10);
}
public void write(String b64Audio) {
b64AudioBuffer.add(b64Audio);
}
public void cancel() {
b64AudioBuffer.clear();
RawAudioBuffer.clear();
}
public void waitForComplete() throws InterruptedException {
// 等待所有缓冲区中的音频数据播放完成
while (!b64AudioBuffer.isEmpty() || !RawAudioBuffer.isEmpty()) {
Thread.sleep(100);
}
// 等待音频线路播放完成
line.drain();
}
public void shutdown() throws InterruptedException {
stopped.set(true);
decoderThread.join();
playerThread.join();
// 保存完整音频文件
File file = new File("TotalAudio_"+ttsFormat.getSampleRate()+"."+ttsFormat.getFormat());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(totalAudioStream.toByteArray());
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
if (line != null && line.isRunning()) {
line.drain();
line.close();
}
}
}
public static void main(String[] args) throws InterruptedException, LineUnavailableException, FileNotFoundException {
Scanner scanner = new Scanner(System.in);
QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
// 如需使用指令控制功能,请将model替换为qwen3-tts-instruct-flash-realtime
.model("qwen3-tts-flash-realtime")
// 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime
.url("wss://dashscope.aliyuncs.com/api-ws/v1/realtime")
// 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
.apikey(System.getenv("DASHSCOPE_API_KEY"))
.build();
AtomicReference<CountDownLatch> completeLatch = new AtomicReference<>(new CountDownLatch(1));
// 创建实时播放器实例
RealtimePcmPlayer audioPlayer = new RealtimePcmPlayer(24000);
final AtomicReference<QwenTtsRealtime> qwenTtsRef = new AtomicReference<>(null);
QwenTtsRealtime qwenTtsRealtime = new QwenTtsRealtime(param, new QwenTtsRealtimeCallback() {
// File file = new File("result_24k.pcm");
// FileOutputStream fos = new FileOutputStream(file);
@Override
public void onOpen() {
System.out.println("connection opened");
System.out.println("输入文本并按Enter发送,输入'quit'退出程序");
}
@Override
public void onEvent(JsonObject message) {
String type = message.get("type").getAsString();
switch(type) {
case "session.created":
System.out.println("start session: " + message.get("session").getAsJsonObject().get("id").getAsString());
break;
case "response.audio.delta":
String recvAudioB64 = message.get("delta").getAsString();
byte[] rawAudio = Base64.getDecoder().decode(recvAudioB64);
// fos.write(rawAudio);
// 实时播放音频
audioPlayer.write(recvAudioB64);
break;
case "response.done":
System.out.println("response done");
// 等待音频播放完成
try {
audioPlayer.waitForComplete();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 为下一次输入做准备
completeLatch.get().countDown();
break;
case "session.finished":
System.out.println("session finished");
if (qwenTtsRef.get() != null) {
System.out.println("[Metric] response: " + qwenTtsRef.get().getResponseId() +
", first audio delay: " + qwenTtsRef.get().getFirstAudioDelay() + " ms");
}
completeLatch.get().countDown();
default:
break;
}
}
@Override
public void onClose(int code, String reason) {
System.out.println("connection closed code: " + code + ", reason: " + reason);
try {
// fos.close();
// 等待播放完成并关闭播放器
audioPlayer.waitForComplete();
audioPlayer.shutdown();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
qwenTtsRef.set(qwenTtsRealtime);
try {
qwenTtsRealtime.connect();
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
}
QwenTtsRealtimeConfig config = QwenTtsRealtimeConfig.builder()
.voice("Cherry")
.responseFormat(ttsFormat)
.mode("commit")
// 如需使用指令控制功能,请取消下方注释,并将model替换为qwen3-tts-instruct-flash-realtime
// .instructions("")
// .optimizeInstructions(true)
.build();
qwenTtsRealtime.updateSession(config);
// 循环读取用户输入
while (true) {
System.out.print("请输入要合成的文本: ");
String text = scanner.nextLine();
// 如果用户输入quit,则退出程序
if ("quit".equalsIgnoreCase(text.trim())) {
System.out.println("正在关闭连接...");
qwenTtsRealtime.finish();
completeLatch.get().await();
break;
}
// 如果用户输入为空,跳过
if (text.trim().isEmpty()) {
continue;
}
// 重新初始化倒计时锁存器
completeLatch.set(new CountDownLatch(1));
// 发送文本
qwenTtsRealtime.appendText(text);
qwenTtsRealtime.commit();
// 等待本次合成完成
completeLatch.get().await();
}
// 清理资源
audioPlayer.waitForComplete();
audioPlayer.shutdown();
scanner.close();
System.exit(0);
}
}进阶功能
以下功能用于精细控制语音合成效果。
Qwen-TTS 交互模式
Qwen-TTS Realtime API 提供两种 WebSocket 交互模式,通过 session.mode 参数切换:
server_commit 模式:由服务端智能处理文本分段与合成时机,适合大段文本的连续合成场景。客户端只需持续追加文本,无需关注分段和提交。
commit 模式:由客户端主动提交文本缓冲区以触发合成,适合需要精确控制合成时机的场景(如对话式 AI 逐轮合成)。
SDK 中设置交互模式:
Python SDK:在
update_session方法中通过mode参数设置。qwen_tts_realtime.update_session( voice='Cherry', response_format=AudioFormat.PCM_24000HZ_MONO_16BIT, mode='server_commit' )Java SDK:通过
QwenTtsRealtimeConfig.builder()设置mode参数。QwenTtsRealtimeConfig config = QwenTtsRealtimeConfig.builder() .voice("Cherry") .responseFormat(ttsFormat) .mode("server_commit") .build(); qwenTtsRealtime.updateSession(config);
完整的 SDK 代码示例请参见Python SDK和Java SDK。WebSocket 事件生命周期和连接复用方式的详细说明,请参见实时语音合成-千问API参考。
指令控制
指令控制允许您通过自然语言描述精确控制语音的表达效果,无需调整复杂的音频参数。只需用简单的文字描述,即可让合成语音呈现特定的音调、语速、情感或音色特点,无需调整复杂的音频参数。
支持的模型:
CosyVoice:
cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash不同模型对指令的格式要求不同:
cosyvoice-v3.5-plus、cosyvoice-v3.5-flash:可输入任意指令控制合成效果(如情感、语速等)。cosyvoice-v3-flash的声音设计或声音复刻音色:可输入任意指令控制合成效果。cosyvoice-v3-flash的系统音色:指令必须使用固定格式和内容,详情请参见CosyVoice音色列表。
Qwen-TTS:仅支持千问3-TTS-Instruct-Flash-Realtime系列模型。
使用方式:
CosyVoice:通过
instructions参数指定指令内容,例如“语速较快,带有明显的上扬语调,适合介绍时尚产品”。Qwen-TTS:通过
instruction参数指定指令内容,例如“语速较快,带有明显的上扬语调,适合介绍时尚产品”。
指令文本支持的语言:
CosyVoice:
cosyvoice-v3.5-plus、cosyvoice-v3.5-flash:中文、英文、法语、德语、日语、韩语、俄语、葡萄牙语、泰语、印尼语、越南语。cosyvoice-v3-flash:中文、英文、法语、德语、日语、韩语、俄语。
Qwen-TTS:仅支持中文和英文。
指令文本长度限制:
CosyVoice:不超过 100 字符。汉字(包括简体/繁体汉字、日文汉字和韩文汉字)按 2 个字符计算,其他字符(如标点符号、字母、数字、日韩文假名/谚文等)按 1 个字符计算。
Qwen-TTS:不超过 1600 Token。
适用场景:
有声书和广播剧配音
广告和宣传片配音
游戏角色和动画配音
情感化的智能语音助手
纪录片和新闻播报
如何编写高质量的声音描述:
核心原则:
具体而非模糊:使用能描绘具体声音特质的词语,如“低沉”、“清脆”、“语速偏快”。避免使用“好听”、“普通”等主观且缺乏信息量的词汇。
多维而非单一:好的描述通常结合多个维度(如音调、语速、情感等)。仅描述单一维度(如“高音”)过于宽泛,难以生成特色鲜明的效果。
客观而非主观:聚焦声音本身的物理和感知特征,而非个人喜好。例如,用“音调偏高,带有活力”代替“我最喜欢的声音”。
原创而非模仿:请描述声音的特质,而非要求模仿特定人物(如名人、演员)。模仿请求涉及版权风险,且模型不支持直接模仿。
简洁而非冗余:确保每个词都有意义。避免重复同义词或堆砌无意义的强调词(如”非常非常棒的声音”)。
描述维度参考:组合多个维度可以创造更丰富的表达效果。
维度
描述示例
音调
高音、中音、低音、偏高、偏低
语速
快速、中速、缓慢、偏快、偏慢
情感
开朗、沉稳、温柔、严肃、活泼、冷静、治愈
特点
有磁性、清脆、沙哑、圆润、甜美、浑厚、有力
用途
新闻播报、广告配音、有声书、动画角色、语音助手、纪录片解说
示例:
标准播音风格:吐字清晰精准,字正腔圆
情绪递进效果:音量由正常对话迅速增强至高喊,性格直率,情绪易激动且外露
特殊情感状态:哭腔导致发音略微含糊,略显沙哑,带有明显哭腔的紧张感
广告配音风格:音调偏高,语速中等,充满活力和感染力,适合广告配音
温柔治愈风格:语速偏慢,音调温柔甜美,语气治愈温暖,像贴心朋友般关怀
WebSocket 直连示例
如果您不使用 DashScope SDK,可以通过 WebSocket 原始协议直接连接服务端进行语音合成。以下示例仅提供最基础的调通实现,实际业务代码需您自行开发。各模型的 WebSocket 协议说明(服务端点、请求头、交互流程),请参见对应的 API 参考文档。
连接复用
WebSocket 服务支持连接复用以提升资源利用效率,避免重复建立连接的开销。一个合成任务结束后,WebSocket 连接可以被复用以开启下一个任务,无需重新建立连接。
复用流程:
CosyVoice / Sambert:客户端发送
finish-task(CosyVoice)或在任务完成后,服务端返回task-finished事件以结束任务。之后客户端可重新发送run-task事件开启新任务。Qwen-TTS:客户端发送
session.finish后,服务端返回session.finished事件以结束会话。之后客户端可重新建立新会话开启下一个合成任务。
必须等服务端返回结束事件(
task-finished或session.finished)后才可发起新任务。CosyVoice 和 Sambert 在复用连接中的不同任务需要使用不同的
task_id。如果在任务执行过程中发生失败,服务端将返回错误事件并关闭连接,此时该连接无法继续复用。
如果在任务结束后 60 秒没有新的任务,连接会超时自动断开。
各模型的事件详细说明,请参见对应的CosyVoice API参考、Qwen-TTS API参考和Sambert API参考。
高并发最佳实践
在高并发场景下,为每个请求独立创建和销毁 WebSocket 连接会产生巨大的开销。DashScope SDK 内置了连接池与对象池机制,用于复用连接和对象,显著降低延迟和资源消耗。
适用范围
不同服务部署范围支持的模型不同:
中国内地
服务部署范围为中国内地时,模型推理计算资源仅限于中国内地;静态数据存储于您所选的地域。该部署范围支持的地域:华北2(北京)。
调用以下模型时,请选择北京地域的API Key:
CosyVoice:cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-plus、cosyvoice-v3-flash、cosyvoice-v2、cosyvoice-v1
Qwen-TTS:
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime(稳定版,当前等同qwen3-tts-instruct-flash-realtime-2026-01-22)、qwen3-tts-instruct-flash-realtime-2026-01-22(最新快照版)
千问3-TTS-VD-Realtime:qwen3-tts-vd-realtime-2026-01-15(最新快照版)、qwen3-tts-vd-realtime-2025-12-16(快照版)
千问3-TTS-VC-Realtime:qwen3-tts-vc-realtime-2026-01-15(最新快照版)、qwen3-tts-vc-realtime-2025-11-27(快照版)
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime(稳定版,当前等同qwen3-tts-flash-realtime-2025-11-27)、qwen3-tts-flash-realtime-2025-11-27(最新快照版)、qwen3-tts-flash-realtime-2025-09-18(快照版)
千问-TTS-Realtime:qwen-tts-realtime(稳定版,当前等同qwen-tts-realtime-2025-07-15)、qwen-tts-realtime-latest(最新版,当前等同qwen-tts-realtime-2025-07-15)、qwen-tts-realtime-2025-07-15(快照版)
Sambert:sambert-zhinan-v1、sambert-zhiqi-v1、sambert-zhichu-v1、sambert-zhide-v1、sambert-zhijia-v1、sambert-zhiru-v1、sambert-zhiqian-v1、sambert-zhixiang-v1、sambert-zhiwei-v1、sambert-zhihao-v1、sambert-zhijing-v1、sambert-zhiming-v1、sambert-zhimo-v1、sambert-zhina-v1、sambert-zhishu-v1、sambert-zhistella-v1、sambert-zhiting-v1、sambert-zhixiao-v1、sambert-zhiya-v1、sambert-zhiye-v1、sambert-zhiying-v1、sambert-zhiyuan-v1、sambert-zhiyue-v1、sambert-zhigui-v1、sambert-zhishuo-v1、sambert-zhimiao-emo-v1、sambert-zhimao-v1、sambert-zhilun-v1、sambert-zhifei-v1、sambert-zhida-v1、sambert-camila-v1、sambert-perla-v1、sambert-indah-v1、sambert-clara-v1、sambert-hanna-v1、sambert-beth-v1、sambert-betty-v1、sambert-cally-v1、sambert-cindy-v1、sambert-eva-v1、sambert-donna-v1、sambert-brian-v1、sambert-waan-v1,详情请参见Sambert模型列表
国际
服务部署范围为国际时,模型推理计算资源在全球范围内动态调度(不含中国内地);静态数据存储于您所选的地域。该部署范围支持的地域:新加坡。
调用以下模型时,请选择新加坡地域的API Key:
CosyVoice:cosyvoice-v3-plus、cosyvoice-v3-flash
Qwen-TTS:
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime(稳定版,当前等同qwen3-tts-instruct-flash-realtime-2026-01-22)、qwen3-tts-instruct-flash-realtime-2026-01-22(最新快照版)
千问3-TTS-VD-Realtime:qwen3-tts-vd-realtime-2026-01-15(最新快照版)、qwen3-tts-vd-realtime-2025-12-16(快照版)
千问3-TTS-VC-Realtime:qwen3-tts-vc-realtime-2026-01-15(最新快照版)、qwen3-tts-vc-realtime-2025-11-27(快照版)
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime(稳定版,当前等同qwen3-tts-flash-realtime-2025-11-27)、qwen3-tts-flash-realtime-2025-11-27(最新快照版)、qwen3-tts-flash-realtime-2025-09-18(快照版)
支持的音色
不同模型支持的音色有所差异。使用时,将请求参数 voice 设置为音色列表中 voice参数 列对应的值即可。
Qwen-TTS音色列表:
voice参数详情
支持语种
支持模型
Cherry音色名:芊悦
描述:阳光积极、亲切自然小姐姐(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
千问-TTS-Realtime:qwen-tts-realtime、qwen-tts-realtime-latest、qwen-tts-realtime-2025-07-15
Serena音色名:苏瑶
描述:温柔小姐姐(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
千问-TTS-Realtime:qwen-tts-realtime、qwen-tts-realtime-latest、qwen-tts-realtime-2025-07-15
Ethan音色名:晨煦
描述:标准普通话,带部分北方口音。阳光、温暖、活力、朝气(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
千问-TTS-Realtime:qwen-tts-realtime、qwen-tts-realtime-latest、qwen-tts-realtime-2025-07-15
Chelsie音色名:千雪
描述:二次元虚拟女友(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
千问-TTS-Realtime:qwen-tts-realtime、qwen-tts-realtime-latest、qwen-tts-realtime-2025-07-15
Momo音色名:茉兔
描述:撒娇搞怪,逗你开心(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Vivian音色名:十三
描述:拽拽的、可爱的小暴躁(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Moon音色名:月白
描述:率性帅气的月白(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Maia音色名:四月
描述:知性与温柔的碰撞(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Kai音色名:凯
描述:耳朵的一场SPA(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Nofish音色名:不吃鱼
描述:不会翘舌音的设计师(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Bella音色名:萌宝
描述:喝酒不打醉拳的小萝莉(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Jennifer音色名:詹妮弗
描述:品牌级、电影质感般美语女声(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Ryan音色名:甜茶
描述:节奏拉满,戏感炸裂,真实与张力共舞(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Katerina音色名:卡捷琳娜
描述:御姐音色,韵律回味十足(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Aiden音色名:艾登
描述:精通厨艺的美语大男孩(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Eldric Sage音色名:沧明子
描述:沉稳睿智的老者,沧桑如松却心明如镜(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Mia音色名:乖小妹
描述:温顺如春水,乖巧如初雪(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Mochi音色名:沙小弥
描述:聪明伶俐的小大人,童真未泯却早慧如禅(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Bellona音色名:燕铮莺
描述:声音洪亮,吐字清晰,人物鲜活,听得人热血沸腾;金戈铁马入梦来,字正腔圆间尽显千面人声的江湖(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Vincent音色名:田叔
描述:一口独特的沙哑烟嗓,一开口便道尽了千军万马与江湖豪情(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Bunny音色名:萌小姬
描述:“萌属性”爆棚的小萝莉(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Neil音色名:阿闻
描述:平直的基线语调,字正腔圆的咬字发音,这就是最专业的新闻主持人(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Elias音色名:墨讲师
描述:既保持学科严谨性,又通过叙事技巧将复杂知识转化为可消化的认知模块(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Arthur音色名:徐大爷
描述:被岁月和旱烟浸泡过的质朴嗓音,不疾不徐地摇开了满村的奇闻异事(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Nini音色名:邻家妹妹
描述:糯米糍一样又软又黏的嗓音,那一声声拉长了的“哥哥”,甜得能把人的骨头都叫酥了(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Seren音色名:小婉
描述:温和舒缓的声线,助你更快地进入睡眠,晚安,好梦(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Pip音色名:顽屁小孩
描述:调皮捣蛋却充满童真的他来了,这是你记忆中的小新吗(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Stella音色名:少女阿月
描述:平时是甜到发腻的迷糊少女音,但在喊出“代表月亮消灭你”时,瞬间充满不容置疑的爱与正义(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Instruct-Flash-Realtime:qwen3-tts-instruct-flash-realtime、qwen3-tts-instruct-flash-realtime-2026-01-22
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Bodega音色名:博德加
描述:热情的西班牙大叔(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Sonrisa音色名:索尼莎
描述:热情开朗的拉美大姐(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Alek音色名:阿列克
描述:一开口,是战斗民族的冷,也是毛呢大衣下的暖(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Dolce音色名:多尔切
描述:慵懒的意大利大叔(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Sohee音色名:素熙
描述:温柔开朗,情绪丰富的韩国欧尼(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Ono Anna音色名:小野杏
描述:鬼灵精怪的青梅竹马(女性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Lenn音色名:莱恩
描述:理性是底色,叛逆藏在细节里——穿西装也听后朋克的德国青年(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Emilien音色名:埃米尔安
描述:浪漫的法国大哥哥(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Andre音色名:安德雷
描述:声音磁性,自然舒服、沉稳男生(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Radio Gol音色名:拉迪奥·戈尔
描述:足球诗人Rádio Gol!今天我要用名字为你们解说足球(男性)
中文(普通话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27
Jada音色名:上海-阿珍
描述:风风火火的沪上阿姐(女性)
中文(上海话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Dylan音色名:北京-晓东
描述:北京胡同里长大的少年(男性)
中文(北京话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Li音色名:南京-老李
描述:耐心的瑜伽老师(男性)
中文(南京话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Marcus音色名:陕西-秦川
描述:面宽话短,心实声沉——老陕的味道(男性)
中文(陕西话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Roy音色名:闽南-阿杰
描述:诙谐直爽、市井活泼的台湾哥仔形象(男性)
中文(闽南语)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Peter音色名:天津-李彼得
描述:天津相声,专业捧哏(男性)
中文(天津话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Sunny音色名:四川-晴儿
描述:甜到你心里的川妹子(女性)
中文(四川话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Eric音色名:四川-程川
描述:一个跳脱市井的四川成都男子(男性)
中文(四川话)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Rocky音色名:粤语-阿强
描述:幽默风趣的阿强,在线陪聊(男性)
中文(粤语)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
Kiki音色名:粤语-阿清
描述:甜美的港妹闺蜜(女性)
中文(粤语)、英语、法语、德语、俄语、意大利语、西班牙语、葡萄牙语、日语、韩语
千问3-TTS-Flash-Realtime:qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27、qwen3-tts-flash-realtime-2025-09-18
API参考
常见问题
Q:语音合成发音错误怎么办?多音字如何控制发音?
将多音字替换为同音的其他汉字,快速解决发音问题。
使用 SSML 标记语言控制发音:Sambert 和 CosyVoice 均支持 SSML。
Q:使用复刻音色生成的音频无声音如何排查?
确认音色状态
调用CosyVoice声音复刻/设计API接口,确认音色的
status是否为OK。检查模型版本一致性
确保复刻音色时使用的
target_model参数与语音合成时的model参数完全一致。例如:复刻时使用
cosyvoice-v3-plus合成时也必须使用
cosyvoice-v3-plus
验证源音频质量
检查复刻音色时使用的源音频是否符合CosyVoice声音复刻/设计API:
音频时长:10-20秒
音质清晰
无背景噪音
检查请求参数
确认语音合成请求中的
voice参数已设置为复刻音色的 ID。
Q:声音复刻后合成效果不稳定或语音不完整怎么办?
如果复刻音色后合成的语音出现以下问题:
语音播放不完整,只读出部分文字
合成效果不稳定,时好时坏
语音中包含异常停顿或静音段
可能原因:源音频质量不符合要求。
解决方案:检查源音频是否符合以下要求。建议按照录音操作指南重新录制。
检查音频连续性:确保源音频中语音内容连续,避免出现超过 2 秒的停顿或静音段。音频中的明显空白段会导致模型将静音或噪声误识别为音色特征,从而影响生成效果。
检查语音活动比例:确保有效语音占音频总时长的 60% 以上。背景噪声或非语音段过多会干扰音色特征提取。
验证音频质量细节:
音频时长:10~20 秒(推荐 15 秒左右)
发音清晰,语速平稳
无背景噪音、回音、杂音
语音能量集中,无长时间静音段
Q:为什么语音合成的实际时长与 WAV 文件显示的时长不一致?
语音合成采用流式机制,边合成边返回数据,因此保存的 WAV 文件头中的时长是预估值,存在一定误差。如需精确时长,可将 format 设置为 pcm,待获取完整合成结果后自行添加 WAV 文件头信息。
Q:为什么音频无法播放?
请按以下场景逐一排查:
音频保存为完整文件(如 xx.mp3)的情况
音频格式一致性:确保请求参数中设置的音频格式与文件后缀一致。例如,请求参数设置为 wav,但文件保存为 .mp3,可能导致播放失败。
播放器兼容性:确认播放器是否支持该音频文件的格式和采样率。部分播放器可能不支持高采样率或特定编码的音频文件。
流式播放音频的情况
将音频流保存为完整文件,尝试用播放器播放。如果文件无法播放,请参考场景 1 的排查方法。
如果文件可以正常播放,则问题可能出在流式播放的实现上。请确认播放器是否支持流式播放。常见的支持流式播放的工具和库包括:ffmpeg、pyaudio(Python)、AudioFormat(Java)、MediaSource(JavaScript)等。
Q:为什么音频播放卡顿?
请按以下步骤逐一排查:
检查文本发送速度:确保文本发送间隔合理,避免前一段音频播放完毕后下一段文本尚未发送。
检查回调函数性能:
确认回调函数中是否存在过多业务逻辑导致阻塞。
回调函数运行在 WebSocket 线程中,若被阻塞会影响网络数据包的接收,进而导致音频接收卡顿。
建议将音频数据写入独立的音频缓冲区(audio buffer),在其他线程中读取并处理,避免阻塞 WebSocket 线程。
检查网络稳定性:确保网络连接稳定,避免因网络波动导致音频传输中断或延迟。
Q:语音合成耗时较长是什么原因?
请按以下步骤排查:
检查输入间隔
如果是流式语音合成,请确认文本发送间隔是否过长(如上一段发出后延迟数秒才发送下一段),过长的间隔会导致合成总时长增加。
分析性能指标
首包延迟:正常约 500ms。
RTF(实时率 = 合成总耗时 / 音频时长):正常应小于 1.0。
Q:如何限制 API Key 仅用于语音合成服务(权限隔离)?
您可以通过新建业务空间并仅授权特定模型来限制 API Key 的使用范围。详情请参见业务空间管理。
Q:子业务空间的 API Key 能否调用 CosyVoice 模型?
默认业务空间下,所有模型均可调用。
子业务空间下,需要为 API Key 对应的子业务空间进行模型授权。详情请参见子业务空间的模型调用。