全部產品
Search
文件中心

Alibaba Cloud Model Studio:即時語音合成-千問

更新時間:Feb 12, 2026

即時語音合成-千問提供流式文本輸入與流式音訊輸出能力,提供多種擬人音色,支援多語種/方言合成,可在同一音色下輸出多語種,並能自適應調節語氣,流暢處理複雜文本。

核心功能

  • 即時產生高保真語音,支援中英等多語種自然發聲

  • 提供聲音複刻(Qwen)聲音設計(Qwen)兩種音色定製方式

  • 支援流式輸入輸出,低延遲響應即時互動情境

  • 可調節語速、語調、音量與碼率,精細控制語音表現

  • 相容主流音頻格式,最高支援48kHz採樣率輸出

  • 支援指令控制,可通過自然語言指令控制語音表現力

適用範圍

支援的模型:

國際

國際部署模式下,存取點與資料存放區均位於新加坡地區,模型推理計算資源在全球範圍內動態調度(不含中國內地)。

調用以下模型時,請選擇新加坡地區的API Key

  • 千問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-Realtimeqwen3-tts-vd-realtime-2026-01-15(最新快照版)、qwen3-tts-vd-realtime-2025-12-16(快照版)

  • 千問3-TTS-VC-Realtimeqwen3-tts-vc-realtime-2026-01-15(最新快照版)、qwen3-tts-vc-realtime-2025-11-27(快照版)

  • 千問3-TTS-Flash-Realtimeqwen3-tts-flash-realtime(穩定版,當前等同qwen3-tts-flash-realtime-2025-11-27)、qwen3-tts-flash-realtime-2025-11-27(最新快照版)、qwen3-tts-flash-realtime-2025-09-18(快照版)

中國內地

中國內地部署模式下,存取點與資料存放區均位於北京地區,模型推理計算資源僅限於中國內地。

調用以下模型時,請選擇北京地區的API Key

  • 千問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-Realtimeqwen3-tts-vd-realtime-2026-01-15(最新快照版)、qwen3-tts-vd-realtime-2025-12-16(快照版)

  • 千問3-TTS-VC-Realtimeqwen3-tts-vc-realtime-2026-01-15(最新快照版)、qwen3-tts-vc-realtime-2025-11-27(快照版)

  • 千問3-TTS-Flash-Realtimeqwen3-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-Realtimeqwen-tts-realtime(穩定版,當前等同qwen-tts-realtime-2025-07-15)、qwen-tts-realtime-latest(最新版,當前等同qwen-tts-realtime-2025-07-15)、qwen-tts-realtime-2025-07-15(快照版)

更多資訊請參見模型列表

模型選型

情境

推薦模型

推薦理由

品牌形象、專屬聲音、擴充系統音色等語音定製(基於文本描述)

qwen3-tts-vd-realtime-2026-01-15

支援聲音設計,無需音頻樣本,通過文本描述建立定製化音色,適合從零開始設計品牌專屬聲音

品牌形象、專屬聲音、擴充系統音色等語音定製(基於音頻樣本)

qwen3-tts-vc-realtime-2026-01-15

支援聲音複刻,基於真實音頻樣本快速複刻音色,打造擬人化品牌聲紋,確保音色高度還原與一致性

情感化內容生產(有聲書、廣播劇、遊戲/動畫配音)

qwen3-tts-instruct-flash-realtime

支援指令控制,通過自然語言描述精確控制音調、語速、情感、角色性格,適合需要豐富表現力和角色塑造的情境

專業播音(新聞、紀錄片、廣告宣傳)

qwen3-tts-instruct-flash-realtime

支援指令控制,可描述播音風格和語氣特點(如“莊重權威”、“輕鬆親切”),適合專業內容製作

智能客服與對話機器人

qwen3-tts-flash-realtime、qwen3-tts-instruct-flash-realtime

支援流式輸入輸出,可調節語速音高;instruct版本支援指令控制,可根據對話情境動態調整語氣(安撫、熱情、專業)

多語種內容播報

qwen3-tts-flash-realtime、qwen3-tts-instruct-flash-realtime

支援多種語言與中文方言,覆蓋全球化內容分發需求

有聲閱讀與常規內容生產

qwen3-tts-flash-realtime、qwen3-tts-instruct-flash-realtime

可調節音量、語速、音高,滿足有聲書、播客等內容精細化製作需求

電商直播與短視頻配音

qwen3-tts-flash-realtime、qwen3-tts-instruct-flash-realtime

支援 mp3/opus 壓縮格式,適合頻寬受限情境

更多說明請參見模型功能特性對比

快速開始

運行代碼前,需要擷取並配置 API Key。如果通過SDK調用,還需要安裝最新版DashScope SDK

使用系統音色進行語音合成

以下樣本示範如何使用系統音色(參見支援的音色)進行語音合成。

如需使用指令控制功能,請將model替換為qwen3-tts-instruct-flash-realtime,並通過instructions參數設定指令。

使用DashScope SDK

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://www.alibabacloud.com/help/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.aliyuncs.com/api-ws/v1/realtime
        url='wss://dashscope-intl.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://www.alibabacloud.com/help/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.aliyuncs.com/api-ws/v1/realtime
        url='wss://dashscope-intl.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.FileNotFoundException;
import java.io.IOException;
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 = {
            "對吧~我就特別喜歡這種超市",
            "尤其是過年的時候",
            "去逛超市",
            "就會覺得",
            "超級超級開心!",
            "想買好多好多的東西呢!"
    };

    // 即時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<>();

        // 建構函式初始化音頻格式和音頻線路
        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);
                        } 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();
            if (line != null && line.isRunning()) {
                line.drain();
                line.close();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException, LineUnavailableException, FileNotFoundException {
        QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
                // 如需使用指令控制功能,請將model替換為qwen3-tts-instruct-flash-realtime
                .model("qwen3-tts-flash-realtime")
                // 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime
                .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                // 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/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":
                        // 會話建立時的處理
                        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(QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT)
                .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.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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 commit {
    // 即時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<>();

        // 建構函式初始化音頻格式和音頻線路
        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);
                        } 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();
            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.aliyuncs.com/api-ws/v1/realtime
                .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                // 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/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(QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT)
                .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);
    }
}

使用WebSocket API

  1. 準備運行環境

    根據您的作業系統安裝 pyaudio。

    macOS

    brew install portaudio && pip install pyaudio

    Debian/Ubuntu

    sudo apt-get install python3-pyaudio
    
    或者
    
    pip install pyaudio

    CentOS

    sudo yum install -y portaudio portaudio-devel && pip install pyaudio

    Windows

    pip install pyaudio

    安裝完成後,通過 pip 安裝 websocket 相關的依賴:

    pip install websocket-client==1.8.0 websockets
  2. 建立用戶端

    在本地建立 Python 檔案,命名為tts_realtime_client.py並複製以下代碼到檔案中:

    tts_realtime_client.py

    # -- coding: utf-8 --
    
    import asyncio
    import websockets
    import json
    import base64
    import time
    from typing import Optional, Callable, Dict, Any
    from enum import Enum
    
    
    class SessionMode(Enum):
        SERVER_COMMIT = "server_commit"
        COMMIT = "commit"
    
    
    class TTSRealtimeClient:
        """
        與 TTS Realtime API 互動的用戶端。
    
        該類提供了串連 TTS Realtime API、發送文本資料、擷取音訊輸出以及管理 WebSocket 串連的相關方法。
    
        屬性說明:
            base_url (str):
                Realtime API 的基礎地址。
            api_key (str):
                用於身分識別驗證的 API Key。
            voice (str):
                伺服器合成語音所使用的聲音。
            mode (SessionMode):
                會話模式,可選 server_commit 或 commit。
            audio_callback (Callable[[bytes], None]):
                接收音頻資料的回呼函數。
            language_type(str)
                合成的語音的語種,可選值Chinese、English、German、Italian、Portuguese、Spanish、Japanese、Korean、French、Russian、Auto
        """
    
        def __init__(
                self,
                base_url: str,
                api_key: str,
                voice: str = "Cherry",
                mode: SessionMode = SessionMode.SERVER_COMMIT,
                audio_callback: Optional[Callable[[bytes], None]] = None,
            language_type: str = "Auto"):
            self.base_url = base_url
            self.api_key = api_key
            self.voice = voice
            self.mode = mode
            self.ws = None
            self.audio_callback = audio_callback
            self.language_type = language_type
    
            # 當前回複狀態
            self._current_response_id = None
            self._current_item_id = None
            self._is_responding = False
            self._response_done_future = None
    
    
        async def connect(self) -> None:
            """與 TTS Realtime API 建立 WebSocket 串連。"""
            headers = {
                "Authorization": f"Bearer {self.api_key}"
            }
    
            self.ws = await websockets.connect(self.base_url, additional_headers=headers)
    
            # 設定預設會話配置
            await self.update_session({
                "mode": self.mode.value,
                "voice": self.voice,
                # 如需使用指令控制功能,請取消下方注釋,並在server_commit.py或commit.py中將model替換為qwen3-tts-instruct-flash-realtime
                # "instructions": "語速較快,帶有明顯的上揚語調,適合介紹時尚產品。",
                # "optimize_instructions": true
                "language_type": self.language_type,
                "response_format": "pcm",
                "sample_rate": 24000
            })
    
    
        async def send_event(self, event) -> None:
            """發送事件到伺服器。"""
            event['event_id'] = "event_" + str(int(time.time() * 1000))
            print(f"發送事件: type={event['type']}, event_id={event['event_id']}")
            await self.ws.send(json.dumps(event))
    
    
        async def update_session(self, config: Dict[str, Any]) -> None:
            """更新會話配置。"""
            event = {
                "type": "session.update",
                "session": config
            }
            print("更新會話配置: ", event)
            await self.send_event(event)
    
    
        async def append_text(self, text: str) -> None:
            """向 API 發送文本資料。"""
            event = {
                "type": "input_text_buffer.append",
                "text": text
            }
            await self.send_event(event)
    
    
        async def commit_text_buffer(self) -> None:
            """提交文本緩衝區以觸發處理。"""
            event = {
                "type": "input_text_buffer.commit"
            }
            await self.send_event(event)
    
    
        async def clear_text_buffer(self) -> None:
            """清除文本緩衝區。"""
            event = {
                "type": "input_text_buffer.clear"
            }
            await self.send_event(event)
    
    
        async def finish_session(self) -> None:
            """結束會話。"""
            event = {
                "type": "session.finish"
            }
            await self.send_event(event)
    
    
        async def wait_for_response_done(self):
            """等待 response.done 事件"""
            if self._response_done_future:
                await self._response_done_future
    
    
        async def handle_messages(self) -> None:
            """處理來自伺服器的訊息。"""
            try:
                async for message in self.ws:
                    event = json.loads(message)
                    event_type = event.get("type")
    
                    if event_type != "response.audio.delta":
                        print(f"收到事件: {event_type}")
    
                    if event_type == "error":
                        print("錯誤: ", event.get('error', {}))
                        continue
                    elif event_type == "session.created":
                        print("會話建立,ID: ", event.get('session', {}).get('id'))
                    elif event_type == "session.updated":
                        print("會話更新,ID: ", event.get('session', {}).get('id'))
                    elif event_type == "input_text_buffer.committed":
                        print("文本緩衝區已提交,專案ID: ", event.get('item_id'))
                    elif event_type == "input_text_buffer.cleared":
                        print("文本緩衝區已清除")
                    elif event_type == "response.created":
                        self._current_response_id = event.get("response", {}).get("id")
                        self._is_responding = True
                        # 建立新的 future 來等待 response.done
                        self._response_done_future = asyncio.Future()
                        print("響應已建立,ID: ", self._current_response_id)
                    elif event_type == "response.output_item.added":
                        self._current_item_id = event.get("item", {}).get("id")
                        print("輸出項已添加,ID: ", self._current_item_id)
                    # 處理音頻增量
                    elif event_type == "response.audio.delta" and self.audio_callback:
                        audio_bytes = base64.b64decode(event.get("delta", ""))
                        self.audio_callback(audio_bytes)
                    elif event_type == "response.audio.done":
                        print("音頻產生完成")
                    elif event_type == "response.done":
                        self._is_responding = False
                        self._current_response_id = None
                        self._current_item_id = None
                        # 標記 future 完成
                        if self._response_done_future and not self._response_done_future.done():
                            self._response_done_future.set_result(True)
                        print("響應完成")
                    elif event_type == "session.finished":
                        print("會話已結束")
    
            except websockets.exceptions.ConnectionClosed:
                print("串連已關閉")
            except Exception as e:
                print("訊息處理出錯: ", str(e))
    
    
        async def close(self) -> None:
            """關閉 WebSocket 串連。"""
            if self.ws:
                await self.ws.close()
  3. 選擇語音合成模式

    Realtime API 支援以下兩種模式:

    • server_commit 模式

      用戶端僅發送文本。服務端會智能判斷文本分段方式與合成時機。適合低延遲且無需手動控制合成節奏的情境,例如 GPS 導航。

    • commit 模式

      用戶端先將文本添加至緩衝區,再主動觸發服務端合成指定文本。適合需精細控制斷句和停頓的情境,例如新聞播報。

    server_commit 模式

    tts_realtime_client.py的同級目錄下建立另一個 Python 檔案,命名為server_commit.py,並將以下代碼複製進檔案中:

    server_commit.py

    import os
    import asyncio
    import logging
    import wave
    from tts_realtime_client import TTSRealtimeClient, SessionMode
    import pyaudio
    
    # QwenTTS 服務配置
    # 如需使用指令控制功能,請將model替換為qwen3-tts-instruct-flash-realtime,並在tts_realtime_client.py中取消instructions的注釋
    # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3-tts-flash-realtime
    URL = "wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime?model=qwen3-tts-flash-realtime"
    # 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    # 若沒有配置環境變數,請用百鍊API Key將下行替換為:API_KEY="sk-xxx"
    API_KEY = os.getenv("DASHSCOPE_API_KEY")
    
    if not API_KEY:
        raise ValueError("Please set DASHSCOPE_API_KEY environment variable")
    
    # 收集音頻資料
    _audio_chunks = []
    # 即時播放相關
    _AUDIO_SAMPLE_RATE = 24000
    _audio_pyaudio = pyaudio.PyAudio()
    _audio_stream = None  # 將在運行時開啟
    
    def _audio_callback(audio_bytes: bytes):
        """TTSRealtimeClient 音頻回調: 即時播放並緩衝"""
        global _audio_stream
        if _audio_stream is not None:
            try:
                _audio_stream.write(audio_bytes)
            except Exception as exc:
                logging.error(f"PyAudio playback error: {exc}")
        _audio_chunks.append(audio_bytes)
        logging.info(f"Received audio chunk: {len(audio_bytes)} bytes")
    
    def _save_audio_to_file(filename: str = "output.wav", sample_rate: int = 24000) -> bool:
        """將收集到的音頻資料儲存為 WAV 檔案"""
        if not _audio_chunks:
            logging.warning("No audio data to save")
            return False
    
        try:
            audio_data = b"".join(_audio_chunks)
            with wave.open(filename, 'wb') as wav_file:
                wav_file.setnchannels(1)  # 單聲道
                wav_file.setsampwidth(2)  # 16-bit
                wav_file.setframerate(sample_rate)
                wav_file.writeframes(audio_data)
            logging.info(f"Audio saved to: {filename}")
            return True
        except Exception as exc:
            logging.error(f"Failed to save audio: {exc}")
            return False
    
    async def _produce_text(client: TTSRealtimeClient):
        """向伺服器發送文本片段"""
        text_fragments = [
            "阿里雲的大模型服務平台百鍊是一站式的大模型開發及應用構建平台。",
            "不論是開發人員還是業務人員,都能深入參與大模型應用的設計和構建。", 
            "您可以通過簡單的介面操作,在5分鐘內開發出一款大模型應用,",
            "或在幾小時內訓練出一個專屬模型,從而將更多精力專註於應用創新。",
        ]
    
        logging.info("Sending text fragments…")
        for text in text_fragments:
            logging.info(f"Sending fragment: {text}")
            await client.append_text(text)
            await asyncio.sleep(0.1)  # 片段間稍作延時
    
        # 等待伺服器完成內部處理後結束會話
        await asyncio.sleep(1.0)
        await client.finish_session()
    
    async def _run_demo():
        """運行完整 Demo"""
        global _audio_stream
        # 開啟 PyAudio 輸出資料流
        _audio_stream = _audio_pyaudio.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=_AUDIO_SAMPLE_RATE,
            output=True,
            frames_per_buffer=1024
        )
    
        client = TTSRealtimeClient(
            base_url=URL,
            api_key=API_KEY,
            voice="Cherry",
            mode=SessionMode.SERVER_COMMIT,
            audio_callback=_audio_callback
        )
    
        # 建立串連
        await client.connect()
    
        # 並存執行訊息處理與文本發送
        consumer_task = asyncio.create_task(client.handle_messages())
        producer_task = asyncio.create_task(_produce_text(client))
    
        await producer_task  # 等待文本發送完成
    
        # 等待 response.done
        await client.wait_for_response_done()
    
        # 關閉串連並取消消費者任務
        await client.close()
        consumer_task.cancel()
    
        # 關閉音頻流
        if _audio_stream is not None:
            _audio_stream.stop_stream()
            _audio_stream.close()
        _audio_pyaudio.terminate()
    
        # 儲存音頻資料
        os.makedirs("outputs", exist_ok=True)
        _save_audio_to_file(os.path.join("outputs", "qwen_tts_output.wav"))
    
    def main():
        """同步入口"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s [%(levelname)s] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        logging.info("Starting QwenTTS Realtime Client demo…")
        asyncio.run(_run_demo())
    
    if __name__ == "__main__":
        main() 

    運行server_commit.py,即可聽到 Realtime API 即時產生的音頻。

    commit 模式

    tts_realtime_client.py的同級目錄下建立另一個 python 檔案,命名為commit.py,並將以下代碼複製進檔案中:

    commit.py

    import os
    import asyncio
    import logging
    import wave
    from tts_realtime_client import TTSRealtimeClient, SessionMode
    import pyaudio
    
    # QwenTTS 服務配置
    # 如需使用指令控制功能,請將model替換為qwen3-tts-instruct-flash-realtime,並在tts_realtime_client.py中取消instructions的注釋
    # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime?model=qwen3-tts-flash-realtime
    URL = "wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime?model=qwen3-tts-flash-realtime"
    # 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    # 若沒有配置環境變數,請用百鍊API Key將下行替換為:API_KEY="sk-xxx"
    API_KEY = os.getenv("DASHSCOPE_API_KEY")
    
    if not API_KEY:
        raise ValueError("Please set DASHSCOPE_API_KEY environment variable")
    
    # 收集音頻資料
    _audio_chunks = []
    _AUDIO_SAMPLE_RATE = 24000
    _audio_pyaudio = pyaudio.PyAudio()
    _audio_stream = None
    
    def _audio_callback(audio_bytes: bytes):
        """TTSRealtimeClient 音頻回調: 即時播放並緩衝"""
        global _audio_stream
        if _audio_stream is not None:
            try:
                _audio_stream.write(audio_bytes)
            except Exception as exc:
                logging.error(f"PyAudio playback error: {exc}")
        _audio_chunks.append(audio_bytes)
        logging.info(f"Received audio chunk: {len(audio_bytes)} bytes")
    
    def _save_audio_to_file(filename: str = "output.wav", sample_rate: int = 24000) -> bool:
        """將收集到的音頻資料儲存為 WAV 檔案"""
        if not _audio_chunks:
            logging.warning("No audio data to save")
            return False
    
        try:
            audio_data = b"".join(_audio_chunks)
            with wave.open(filename, 'wb') as wav_file:
                wav_file.setnchannels(1)  # 單聲道
                wav_file.setsampwidth(2)  # 16-bit
                wav_file.setframerate(sample_rate)
                wav_file.writeframes(audio_data)
            logging.info(f"Audio saved to: {filename}")
            return True
        except Exception as exc:
            logging.error(f"Failed to save audio: {exc}")
            return False
    
    async def _user_input_loop(client: TTSRealtimeClient):
        """持續擷取使用者輸入並發送文本,當使用者輸入空文本時發送commit事件並結束本次會話"""
        print("請輸入文本(直接按Enter發送commit事件並結束本次會話,按Ctrl+C或Ctrl+D結束整個程式):")
        
        while True:
            try:
                user_text = input("> ")
                if not user_text:  # 使用者輸入為空白
                    # 空輸入視為一次對話的結束: 提交緩衝區 -> 結束會話 -> 跳出迴圈
                    logging.info("空輸入,發送 commit 事件並結束本次會話")
                    await client.commit_text_buffer()
                    # 適當等待伺服器處理 commit,防止過早結束會話導致丟失音頻
                    await asyncio.sleep(0.3)
                    await client.finish_session()
                    break  # 直接退出使用者輸入迴圈,無需再次斷行符號
                else:
                    logging.info(f"發送文本: {user_text}")
                    await client.append_text(user_text)
                    
            except EOFError:  # 使用者按下Ctrl+D
                break
            except KeyboardInterrupt:  # 使用者按下Ctrl+C
                break
        
        # 結束會話
        logging.info("結束會話...")
    async def _run_demo():
        """運行完整 Demo"""
        global _audio_stream
        # 開啟 PyAudio 輸出資料流
        _audio_stream = _audio_pyaudio.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=_AUDIO_SAMPLE_RATE,
            output=True,
            frames_per_buffer=1024
        )
    
        client = TTSRealtimeClient(
            base_url=URL,
            api_key=API_KEY,
            voice="Cherry",
            mode=SessionMode.COMMIT,  # 修改為COMMIT模式
            audio_callback=_audio_callback
        )
    
        # 建立串連
        await client.connect()
    
        # 並存執行訊息處理與使用者輸入
        consumer_task = asyncio.create_task(client.handle_messages())
        producer_task = asyncio.create_task(_user_input_loop(client))
    
        await producer_task  # 等待使用者輸入完成
    
        # 等待 response.done
        await client.wait_for_response_done()
    
        # 關閉串連並取消消費者任務
        await client.close()
        consumer_task.cancel()
    
        # 關閉音頻流
        if _audio_stream is not None:
            _audio_stream.stop_stream()
            _audio_stream.close()
        _audio_pyaudio.terminate()
    
        # 儲存音頻資料
        os.makedirs("outputs", exist_ok=True)
        _save_audio_to_file(os.path.join("outputs", "qwen_tts_output.wav"))
    
    def main():
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s [%(levelname)s] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        logging.info("Starting QwenTTS Realtime Client demo…")
        asyncio.run(_run_demo())
    
    if __name__ == "__main__":
        main() 

    運行commit.py,可多次輸入要合成的文本。在未輸入文本的情況下單擊 Enter 鍵,您將從擴音器聽到 Realtime API 返回的音頻。

使用聲音複刻音色進行語音合成

聲音複刻服務不提供預覽音頻,需通過語音合成介面試聽並評估效果。建議使用簡短文本進行初次測試。

以下樣本示範了如何在語音合成中使用聲音複刻產生的專屬音色,實現與原音高度相似的輸出效果。這裡參考了使用系統音色進行語音合成DashScope SDK的“server commit模式”範例程式碼,將voice參數替換為複刻產生的專屬音色進行語音合成。

  • 關鍵原則:聲音複刻時使用的模型 (target_model) 必須與後續進行語音合成時使用的模型 (model) 保持一致,否則會導致合成失敗。

  • 樣本使用本地音頻檔案 voice.mp3 進行聲音複刻,運行代碼時,請注意替換。

Python

# coding=utf-8
# Installation instructions for pyaudio:
# APPLE Mac OS X
#   brew install portaudio
#   pip install pyaudio
# Debian/Ubuntu
#   sudo apt-get install python-pyaudio python3-pyaudio
#   or
#   pip install pyaudio
# CentOS
#   sudo yum install -y portaudio portaudio-devel && pip install pyaudio
# Microsoft Windows
#   python -m pip install pyaudio

import pyaudio
import os
import requests
import base64
import pathlib
import threading
import time
import dashscope  # DashScope Python SDK 版本需要不低於1.23.9
from dashscope.audio.qwen_tts_realtime import QwenTtsRealtime, QwenTtsRealtimeCallback, AudioFormat

# ======= 常量配置 =======
DEFAULT_TARGET_MODEL = "qwen3-tts-vc-realtime-2026-01-15"  # 聲音複刻、語音合成要使用相同的模型
DEFAULT_PREFERRED_NAME = "guanyu"
DEFAULT_AUDIO_MIME_TYPE = "audio/mpeg"
VOICE_FILE_PATH = "voice.mp3"  # 用於聲音複刻的本地音頻檔案的相對路徑

TEXT_TO_SYNTHESIZE = [
    '對吧~我就特別喜歡這種超市,',
    '尤其是過年的時候',
    '去逛超市',
    '就會覺得',
    '超級超級開心!',
    '想買好多好多的東西呢!'
]

def create_voice(file_path: str,
                 target_model: str = DEFAULT_TARGET_MODEL,
                 preferred_name: str = DEFAULT_PREFERRED_NAME,
                 audio_mime_type: str = DEFAULT_AUDIO_MIME_TYPE) -> str:
    """
    建立音色,並返回 voice 參數
    """
    # 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    # 若沒有配置環境變數,請用百鍊API Key將下行替換為:api_key = "sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY")

    file_path_obj = pathlib.Path(file_path)
    if not file_path_obj.exists():
        raise FileNotFoundError(f"音頻檔案不存在: {file_path}")

    base64_str = base64.b64encode(file_path_obj.read_bytes()).decode()
    data_uri = f"data:{audio_mime_type};base64,{base64_str}"

    # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization
    url = "https://dashscope-intl.aliyuncs.com/api/v1/services/audio/tts/customization"
    payload = {
        "model": "qwen-voice-enrollment", # 不要修改該值
        "input": {
            "action": "create",
            "target_model": target_model,
            "preferred_name": preferred_name,
            "audio": {"data": data_uri}
        }
    }
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    resp = requests.post(url, json=payload, headers=headers)
    if resp.status_code != 200:
        raise RuntimeError(f"建立 voice 失敗: {resp.status_code}, {resp.text}")

    try:
        return resp.json()["output"]["voice"]
    except (KeyError, ValueError) as e:
        raise RuntimeError(f"解析 voice 響應失敗: {e}")

def init_dashscope_api_key():
    """
    初始化 dashscope SDK 的 API key
    """
    # 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
    # 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
    dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")

# ======= 回調類 =======
class MyCallback(QwenTtsRealtimeCallback):
    """
    自訂 TTS 流式回調
    """
    def __init__(self):
        self.complete_event = threading.Event()
        self._player = pyaudio.PyAudio()
        self._stream = self._player.open(
            format=pyaudio.paInt16, channels=1, rate=24000, output=True
        )

    def on_open(self) -> None:
        print('[TTS] 串連已建立')

    def on_close(self, close_status_code, close_msg) -> None:
        self._stream.stop_stream()
        self._stream.close()
        self._player.terminate()
        print(f'[TTS] 串連關閉 code={close_status_code}, msg={close_msg}')

    def on_event(self, response: dict) -> None:
        try:
            event_type = response.get('type', '')
            if event_type == 'session.created':
                print(f'[TTS] 會話開始: {response["session"]["id"]}')
            elif event_type == 'response.audio.delta':
                audio_data = base64.b64decode(response['delta'])
                self._stream.write(audio_data)
            elif event_type == 'response.done':
                print(f'[TTS] 響應完成, Response ID: {qwen_tts_realtime.get_last_response_id()}')
            elif event_type == 'session.finished':
                print('[TTS] 會話結束')
                self.complete_event.set()
        except Exception as e:
            print(f'[Error] 處理回調事件異常: {e}')

    def wait_for_finished(self):
        self.complete_event.wait()

# ======= 主執行邏輯 =======
if __name__ == '__main__':
    init_dashscope_api_key()
    print('[系統] 初始化 Qwen TTS Realtime ...')

    callback = MyCallback()
    qwen_tts_realtime = QwenTtsRealtime(
        model=DEFAULT_TARGET_MODEL,
        callback=callback,
        # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime
        url='wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime'
    )
    qwen_tts_realtime.connect()
    
    qwen_tts_realtime.update_session(
        voice=create_voice(VOICE_FILE_PATH), # 將voice參數替換為複刻產生的專屬音色
        response_format=AudioFormat.PCM_24000HZ_MONO_16BIT,
        mode='server_commit'
    )

    for text_chunk in TEXT_TO_SYNTHESIZE:
        print(f'[發送文本]: {text_chunk}')
        qwen_tts_realtime.append_text(text_chunk)
        time.sleep(0.1)

    qwen_tts_realtime.finish()
    callback.wait_for_finished()

    print(f'[Metric] session_id={qwen_tts_realtime.get_session_id()}, '
          f'first_audio_delay={qwen_tts_realtime.get_first_audio_delay()}s')

Java

需要匯入Gson依賴,若是使用Maven或者Gradle,添加依賴方式如下:

Maven

pom.xml中添加如下內容:

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.13.1</version>
</dependency>

Gradle

build.gradle中添加如下內容:

// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation("com.google.code.gson:gson:2.13.1")
import com.alibaba.dashscope.audio.qwen_tts_realtime.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import javax.sound.sampled.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
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 {
    // ===== 常量定義 =====
    // 聲音複刻、語音合成要使用相同的模型
    private static final String TARGET_MODEL = "qwen3-tts-vc-realtime-2026-01-15";
    private static final String PREFERRED_NAME = "guanyu";
    // 用於聲音複刻的本地音頻檔案的相對路徑
    private static final String AUDIO_FILE = "voice.mp3";
    private static final String AUDIO_MIME_TYPE = "audio/mpeg";
    private static String[] textToSynthesize = {
            "對吧~我就特別喜歡這種超市",
            "尤其是過年的時候",
            "去逛超市",
            "就會覺得",
            "超級超級開心!",
            "想買好多好多的東西呢!"
    };

    // 產生 data URI
    public static String toDataUrl(String filePath) throws IOException {
        byte[] bytes = Files.readAllBytes(Paths.get(filePath));
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return "data:" + AUDIO_MIME_TYPE + ";base64," + encoded;
    }

    // 調用 API 建立 voice
    public static String createVoice() throws Exception {
        // 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
        // 若沒有配置環境變數,請用百鍊API Key將下行替換為:String apiKey = "sk-xxx"
        String apiKey = System.getenv("DASHSCOPE_API_KEY");

        String jsonPayload =
                "{"
                        + "\"model\": \"qwen-voice-enrollment\"," // 不要修改該值
                        + "\"input\": {"
                        +     "\"action\": \"create\","
                        +     "\"target_model\": \"" + TARGET_MODEL + "\","
                        +     "\"preferred_name\": \"" + PREFERRED_NAME + "\","
                        +     "\"audio\": {"
                        +         "\"data\": \"" + toDataUrl(AUDIO_FILE) + "\""
                        +     "}"
                        + "}"
                        + "}";

        HttpURLConnection con = (HttpURLConnection) new URL("https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization").openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("Authorization", "Bearer " + apiKey);
        con.setRequestProperty("Content-Type", "application/json");
        con.setDoOutput(true);

        try (OutputStream os = con.getOutputStream()) {
            os.write(jsonPayload.getBytes(StandardCharsets.UTF_8));
        }

        int status = con.getResponseCode();
        System.out.println("HTTP 狀態代碼: " + status);

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(status >= 200 && status < 300 ? con.getInputStream() : con.getErrorStream(),
                        StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                response.append(line);
            }
            System.out.println("返回內容: " + response);

            if (status == 200) {
                JsonObject jsonObj = new Gson().fromJson(response.toString(), JsonObject.class);
                return jsonObj.getAsJsonObject("output").get("voice").getAsString();
            }
            throw new IOException("建立語音失敗: " + status + " - " + response);
        }
    }

    // 即時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<>();

        // 建構函式初始化音頻格式和音頻線路
        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);
                        } 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();
            if (line != null && line.isRunning()) {
                line.drain();
                line.close();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
                .model(TARGET_MODEL)
                // 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime
                .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                // 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
                // 若沒有配置環境變數,請用百鍊API Key將下行替換為:.apikey("sk-xxx")
                .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":
                        // 會話建立時的處理
                        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(createVoice()) // 將voice參數替換為複刻產生的專屬音色
                .responseFormat(QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT)
                .mode("server_commit")
                .build();
        qwenTtsRealtime.updateSession(config);
        for (String text:textToSynthesize) {
            qwenTtsRealtime.appendText(text);
            Thread.sleep(100);
        }
        qwenTtsRealtime.finish();
        completeLatch.get().await();

        // 等待音頻播放完成並關閉播放器
        audioPlayer.waitForComplete();
        audioPlayer.shutdown();
        System.exit(0);
    }
}

使用聲音設計音色進行語音合成

使用聲音設計功能時,服務會返回預覽音頻資料。建議先試聽該預覽音頻,確認效果符合預期後再用於語音合成,降低調用成本。

  1. 產生專屬音色並試聽效果,若對效果滿意,進行下一步;否則重建。

    Python

    import requests
    import base64
    import os
    
    def create_voice_and_play():
        # 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
        # 若沒有配置環境變數,請用百鍊API Key將下行替換為:api_key = "sk-xxx"
        api_key = os.getenv("DASHSCOPE_API_KEY")
        
        if not api_key:
            print("錯誤: 未找到DASHSCOPE_API_KEY環境變數,請先設定API Key")
            return None, None, None
        
        # 準備請求資料
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": "qwen-voice-design",
            "input": {
                "action": "create",
                "target_model": "qwen3-tts-vd-realtime-2026-01-15",
                "voice_prompt": "A composed middle-aged male announcer with a deep, rich and magnetic voice, a steady speaking speed and clear articulation, is suitable for news broadcasting or documentary commentary.",
                "preview_text": "Dear listeners, hello everyone. Welcome to the evening news.",
                "preferred_name": "announcer",
                "language": "en"
            },
            "parameters": {
                "sample_rate": 24000,
                "response_format": "wav"
            }
        }
        
        # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization
        url = "https://dashscope-intl.aliyuncs.com/api/v1/services/audio/tts/customization"
        
        try:
            # 發送請求
            response = requests.post(
                url,
                headers=headers,
                json=data,
                timeout=60  # 添加逾時設定
            )
            
            if response.status_code == 200:
                result = response.json()
                
                # 擷取音色名稱
                voice_name = result["output"]["voice"]
                print(f"音色名稱: {voice_name}")
                
                # 擷取預覽音頻資料
                base64_audio = result["output"]["preview_audio"]["data"]
                
                # 解碼Base64音頻資料
                audio_bytes = base64.b64decode(base64_audio)
                
                # 儲存音頻檔案到本地
                filename = f"{voice_name}_preview.wav"
                
                # 將音頻資料寫入本地檔案
                with open(filename, 'wb') as f:
                    f.write(audio_bytes)
                
                print(f"音頻已儲存到本地檔案: {filename}")
                print(f"檔案路徑: {os.path.abspath(filename)}")
                
                return voice_name, audio_bytes, filename
            else:
                print(f"請求失敗,狀態代碼: {response.status_code}")
                print(f"響應內容: {response.text}")
                return None, None, None
                
        except requests.exceptions.RequestException as e:
            print(f"網路請求發生錯誤: {e}")
            return None, None, None
        except KeyError as e:
            print(f"響應資料格式錯誤,缺少必要的欄位: {e}")
            print(f"響應內容: {response.text if 'response' in locals() else 'No response'}")
            return None, None, None
        except Exception as e:
            print(f"發生未知錯誤: {e}")
            return None, None, None
    
    if __name__ == "__main__":
        print("開始建立語音...")
        voice_name, audio_data, saved_filename = create_voice_and_play()
        
        if voice_name:
            print(f"\n成功建立音色 '{voice_name}'")
            print(f"音頻檔案已儲存: '{saved_filename}'")
            print(f"檔案大小: {os.path.getsize(saved_filename)} 位元組")
        else:
            print("\n音色建立失敗")

    Java

    需要匯入Gson依賴,若是使用Maven或者Gradle,添加依賴方式如下:

    Maven

    pom.xml中添加如下內容:

    <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.13.1</version>
    </dependency>

    Gradle

    build.gradle中添加如下內容:

    // https://mvnrepository.com/artifact/com.google.code.gson/gson
    implementation("com.google.code.gson:gson:2.13.1")
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Base64;
    
    public class Main {
        public static void main(String[] args) {
            Main example = new Main();
            example.createVoice();
        }
    
        public void createVoice() {
            // 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
            // 若沒有配置環境變數,請用百鍊API Key將下行替換為:String apiKey = "sk-xxx"
            String apiKey = System.getenv("DASHSCOPE_API_KEY");
    
            // 建立JSON請求體字串
            String jsonBody = "{\n" +
                    "    \"model\": \"qwen-voice-design\",\n" +
                    "    \"input\": {\n" +
                    "        \"action\": \"create\",\n" +
                    "        \"target_model\": \"qwen3-tts-vd-realtime-2026-01-15\",\n" +
                    "        \"voice_prompt\": \"A composed middle-aged male announcer with a deep, rich and magnetic voice, a steady speaking speed and clear articulation, is suitable for news broadcasting or documentary commentary.\",\n" +
                    "        \"preview_text\": \"Dear listeners, hello everyone. Welcome to the evening news.\",\n" +
                    "        \"preferred_name\": \"announcer\",\n" +
                    "        \"language\": \"en\"\n" +
                    "    },\n" +
                    "    \"parameters\": {\n" +
                    "        \"sample_rate\": 24000,\n" +
                    "        \"response_format\": \"wav\"\n" +
                    "    }\n" +
                    "}";
    
            HttpURLConnection connection = null;
            try {
                // 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization
                URL url = new URL("https://dashscope-intl.aliyuncs.com/api/v1/services/audio/tts/customization");
                connection = (HttpURLConnection) url.openConnection();
    
                // 佈建要求方法和頭部
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Authorization", "Bearer " + apiKey);
                connection.setRequestProperty("Content-Type", "application/json");
                connection.setDoOutput(true);
                connection.setDoInput(true);
    
                // 發送請求體
                try (OutputStream os = connection.getOutputStream()) {
                    byte[] input = jsonBody.getBytes("UTF-8");
                    os.write(input, 0, input.length);
                    os.flush();
                }
    
                // 擷取響應
                int responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    // 讀取響應內容
                    StringBuilder response = new StringBuilder();
                    try (BufferedReader br = new BufferedReader(
                            new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
                        String responseLine;
                        while ((responseLine = br.readLine()) != null) {
                            response.append(responseLine.trim());
                        }
                    }
    
                    // 解析JSON響應
                    JsonObject jsonResponse = JsonParser.parseString(response.toString()).getAsJsonObject();
                    JsonObject outputObj = jsonResponse.getAsJsonObject("output");
                    JsonObject previewAudioObj = outputObj.getAsJsonObject("preview_audio");
    
                    // 擷取音色名稱
                    String voiceName = outputObj.get("voice").getAsString();
                    System.out.println("音色名稱: " + voiceName);
    
                    // 擷取Base64編碼的音頻資料
                    String base64Audio = previewAudioObj.get("data").getAsString();
    
                    // 解碼Base64音頻資料
                    byte[] audioBytes = Base64.getDecoder().decode(base64Audio);
    
                    // 儲存音頻到本地檔案
                    String filename = voiceName + "_preview.wav";
                    saveAudioToFile(audioBytes, filename);
    
                    System.out.println("音頻已儲存到本地檔案: " + filename);
    
                } else {
                    // 讀取錯誤響應
                    StringBuilder errorResponse = new StringBuilder();
                    try (BufferedReader br = new BufferedReader(
                            new InputStreamReader(connection.getErrorStream(), "UTF-8"))) {
                        String responseLine;
                        while ((responseLine = br.readLine()) != null) {
                            errorResponse.append(responseLine.trim());
                        }
                    }
    
                    System.out.println("請求失敗,狀態代碼: " + responseCode);
                    System.out.println("錯誤響應: " + errorResponse.toString());
                }
    
            } catch (Exception e) {
                System.err.println("請求發生錯誤: " + e.getMessage());
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
    
        private void saveAudioToFile(byte[] audioBytes, String filename) {
            try {
                File file = new File(filename);
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    fos.write(audioBytes);
                }
                System.out.println("音頻已儲存到: " + file.getAbsolutePath());
            } catch (IOException e) {
                System.err.println("儲存音頻檔案時發生錯誤: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
  2. 使用上一步產生的專屬音色進行語音合成。

    這裡參考了使用系統音色進行語音合成DashScope SDK的“server commit模式”範例程式碼,將voice參數替換為聲音設計產生的專屬音色進行語音合成。

    關鍵原則:聲音設計時使用的模型 (target_model) 必須與後續進行語音合成時使用的模型 (model) 保持一致,否則會導致合成失敗。

    Python

    # coding=utf-8
    # Installation instructions for pyaudio:
    # APPLE Mac OS X
    #   brew install portaudio
    #   pip install pyaudio
    # Debian/Ubuntu
    #   sudo apt-get install python-pyaudio python3-pyaudio
    #   or
    #   pip install pyaudio
    # CentOS
    #   sudo yum install -y portaudio portaudio-devel && pip install pyaudio
    # Microsoft Windows
    #   python -m pip install pyaudio
    
    import pyaudio
    import os
    import base64
    import threading
    import time
    import dashscope  # DashScope Python SDK 版本需要不低於1.23.9
    from dashscope.audio.qwen_tts_realtime import QwenTtsRealtime, QwenTtsRealtimeCallback, AudioFormat
    
    # ======= 常量配置 =======
    TEXT_TO_SYNTHESIZE = [
        '對吧~我就特別喜歡這種超市,',
        '尤其是過年的時候',
        '去逛超市',
        '就會覺得',
        '超級超級開心!',
        '想買好多好多的東西呢!'
    ]
    
    def init_dashscope_api_key():
        """
        初始化 dashscope SDK 的 API key
        """
        # 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
        # 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
        dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
    
    # ======= 回調類 =======
    class MyCallback(QwenTtsRealtimeCallback):
        """
        自訂 TTS 流式回調
        """
        def __init__(self):
            self.complete_event = threading.Event()
            self._player = pyaudio.PyAudio()
            self._stream = self._player.open(
                format=pyaudio.paInt16, channels=1, rate=24000, output=True
            )
    
        def on_open(self) -> None:
            print('[TTS] 串連已建立')
    
        def on_close(self, close_status_code, close_msg) -> None:
            self._stream.stop_stream()
            self._stream.close()
            self._player.terminate()
            print(f'[TTS] 串連關閉 code={close_status_code}, msg={close_msg}')
    
        def on_event(self, response: dict) -> None:
            try:
                event_type = response.get('type', '')
                if event_type == 'session.created':
                    print(f'[TTS] 會話開始: {response["session"]["id"]}')
                elif event_type == 'response.audio.delta':
                    audio_data = base64.b64decode(response['delta'])
                    self._stream.write(audio_data)
                elif event_type == 'response.done':
                    print(f'[TTS] 響應完成, Response ID: {qwen_tts_realtime.get_last_response_id()}')
                elif event_type == 'session.finished':
                    print('[TTS] 會話結束')
                    self.complete_event.set()
            except Exception as e:
                print(f'[Error] 處理回調事件異常: {e}')
    
        def wait_for_finished(self):
            self.complete_event.wait()
    
    # ======= 主執行邏輯 =======
    if __name__ == '__main__':
        init_dashscope_api_key()
        print('[系統] 初始化 Qwen TTS Realtime ...')
    
        callback = MyCallback()
        qwen_tts_realtime = QwenTtsRealtime(
            # 聲音設計、語音合成要使用相同的模型
            model="qwen3-tts-vd-realtime-2026-01-15",
            callback=callback,
            # 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime
            url='wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime'
        )
        qwen_tts_realtime.connect()
        
        qwen_tts_realtime.update_session(
            voice="myvoice", # 將voice參數替換為聲音設計產生的專屬音色
            response_format=AudioFormat.PCM_24000HZ_MONO_16BIT,
            mode='server_commit'
        )
    
        for text_chunk in TEXT_TO_SYNTHESIZE:
            print(f'[發送文本]: {text_chunk}')
            qwen_tts_realtime.append_text(text_chunk)
            time.sleep(0.1)
    
        qwen_tts_realtime.finish()
        callback.wait_for_finished()
    
        print(f'[Metric] session_id={qwen_tts_realtime.get_session_id()}, '
              f'first_audio_delay={qwen_tts_realtime.get_first_audio_delay()}s')

    Java

    import com.alibaba.dashscope.audio.qwen_tts_realtime.*;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import com.google.gson.JsonObject;
    
    import javax.sound.sampled.*;
    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 {
        // ===== 常量定義 =====
        private static String[] textToSynthesize = {
                "對吧~我就特別喜歡這種超市",
                "尤其是過年的時候",
                "去逛超市",
                "就會覺得",
                "超級超級開心!",
                "想買好多好多的東西呢!"
        };
    
        // 即時音頻播放器類
        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<>();
    
            // 建構函式初始化音頻格式和音頻線路
            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);
                            } 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();
                if (line != null && line.isRunning()) {
                    line.drain();
                    line.close();
                }
            }
        }
    
        public static void main(String[] args) throws Exception {
            QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
                    // 聲音設計、語音合成要使用相同的模型
                    .model("qwen3-tts-vd-realtime-2026-01-15")
                    // 以下為新加坡地區url,若使用北京地區的模型,需將url替換為:wss://dashscope.aliyuncs.com/api-ws/v1/realtime
                    .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                    // 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
                    // 若沒有配置環境變數,請用百鍊API Key將下行替換為:.apikey("sk-xxx")
                    .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":
                            // 會話建立時的處理
                            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("myvoice") // 將voice參數替換為聲音設計產生的專屬音色
                    .responseFormat(QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT)
                    .mode("server_commit")
                    .build();
            qwenTtsRealtime.updateSession(config);
            for (String text:textToSynthesize) {
                qwenTtsRealtime.appendText(text);
                Thread.sleep(100);
            }
            qwenTtsRealtime.finish();
            completeLatch.get().await();
    
            // 等待音頻播放完成並關閉播放器
            audioPlayer.waitForComplete();
            audioPlayer.shutdown();
            System.exit(0);
        }
    }

更多範例程式碼請參見github

互動流程

server_commit 模式

session.update事件的session.mode 設為"server_commit"以啟用該模式,服務端會智能處理文本分段和合成時機。

互動流程如下:

  1. 用戶端發送session.update事件,服務端響應session.createdsession.updated事件。

  2. 用戶端發送 input_text_buffer.append 事件追加文本至服務端緩衝區。

  3. 服務端智能處理文本分段和合成時機,並返回response.createdresponse.output_item.addedresponse.content_part.addedresponse.audio.delta事件。

  4. 服務端響應完成後響應response.audio.doneresponse.content_part.doneresponse.output_item.doneresponse.done

  5. 服務端響應session.finished來結束會話。

生命週期

用戶端事件

伺服器事件

會話初始化

session.update

會話配置

session.created

會話已建立

session.updated

會話配置已更新

使用者文本輸入

input_text_buffer.append

添加文本到服務端

input_text_buffer.commit

立即合成服務端緩衝的文本

session.finish

通知服務端不再有文本輸入

input_text_buffer.committed

服務端收到提交的文本

伺服器音訊輸出

response.created

服務端開始產生響應

response.output_item.added

響應時有新的輸出內容

response.content_part.added

新的輸出內容添加到assistant message

response.audio.delta

模型增量產生的音頻

response.content_part.done

Assistant message 的文本或音頻內容流式輸出完成

response.output_item.done

Assistant message 的整個輸出項串流完成

response.audio.done

音頻產生完成

response.done

響應完成

commit 模式

session.update事件的session.mode 設為"commit"以啟用該模式,用戶端需主動提交文本緩衝區至服務端來擷取響應。

互動流程如下:

  1. 用戶端發送session.update事件,服務端響應session.createdsession.updated事件。

  2. 用戶端發送 input_text_buffer.append 事件追加文本至服務端緩衝區。

  3. 用戶端發送input_text_buffer.commit事件將緩衝區提交至服務端,並發送 session.finish事件表示後續無文本輸入。

  4. 服務端響應response.created,開始產生響應。

  5. 服務端響應response.output_item.addedresponse.content_part.addedresponse.audio.delta事件。

  6. 服務端響應完成後返回response.audio.doneresponse.content_part.doneresponse.output_item.doneresponse.done

  7. 服務端響應session.finished來結束會話。

生命週期

用戶端事件

伺服器事件

會話初始化

session.update

會話配置

session.created

會話已建立

session.updated

會話配置已更新

使用者文本輸入

input_text_buffer.append

添加文本到緩衝區

input_text_buffer.commit

提交緩衝區到服務端

input_text_buffer.clear

清除緩衝區

input_text_buffer.committed

伺服器收到提交的文本

伺服器音訊輸出

response.created

服務端開始產生響應

response.output_item.added

響應時有新的輸出內容

response.content_part.added

新的輸出內容添加到assistant message

response.audio.delta

模型增量產生的音頻

response.content_part.done

Assistant message 的文本或音頻內容流式輸出完成

response.output_item.done

Assistant message 的整個輸出項串流完成

response.audio.done

音頻產生完成

response.done

響應完成

指令控制

指令控制是一項進階語音合成功能,通過自然語言描述的方式精確控制語音的表達效果。您可以使用簡單的文字描述,讓合成語音呈現出特定的音調、語速、情感、音色特點,無需調整複雜的音頻參數。

支援的模型:僅支援千問3-TTS-Instruct-Flash-Realtime系列模型。

使用方式:通過instructions參數指定指令內容,例如“語速較快,帶有明顯的上揚語調,適合介紹時尚產品”。

支援語言:描述文本僅支援中文和英文。

長度限制:長度不得超過 1600 Token。

適用情境

  • 有聲書和廣播劇配音

  • 廣告和宣傳片配音

  • 遊戲角色和動畫配音

  • 情感化的智能語音助手

  • 紀錄片和新聞播報

如何編寫高品質的聲音描述:

  • 核心原則:

    1. 具體而非模糊:使用能夠描繪具體聲音特質的詞語,如“低沉”、“清脆”、“語速偏快”。避免使用“好聽”、“普通”等主觀且缺乏資訊量的詞彙。

    2. 多維而非單一:優秀的描述通常結合多個維度(如下文所述的音調、語速、情感等)。單一維度描述(如僅“高音”)過於寬泛,難以產生特色鮮明的效果。

    3. 客觀而非主觀:專註於聲音本身的物理和感知特徵,而不是個人的喜好。例如,用“音調偏高,帶有活力”代替“我最喜歡的聲音”。

    4. 原創而非模仿:請描述聲音的特質,而不是要求模仿特定人物(如名人、演員)。此類請求涉及著作權風險且模型不支援直接模仿。

    5. 簡潔而非冗餘:確保每個詞都有其意義。避免重複使用同義字或無意義的強調詞(如“非常非常棒的聲音”)。

  • 描述維度參考:可以組合多個維度,創造更豐富的表達效果。

    維度

    描述樣本

    音調

    高音、中音、低音、偏高、偏低

    語速

    快速、中速、緩慢、偏快、偏慢

    情感

    開朗、沉穩、溫柔、嚴肅、活潑、冷靜、治癒

    特點

    有磁性、清脆、沙啞、圓潤、甜美、渾厚、有力

    用途

    新聞播報、廣告配音、有聲書、動畫角色、語音助手、紀錄片解說

  • 樣本:

    • 標準播音風格:吐字清晰精準,字正腔圓

    • 情緒遞進效果:音量由正常對話迅速增強至高喊,性格直率,情緒易激動且外露

    • 特殊情感狀態:哭腔導致發音略微含糊,略顯沙啞,帶有明顯哭腔的緊張感

    • 廣告配音風格:音調偏高,語速中等,充滿活力和感染力,適合廣告配音

    • 溫柔治癒風格:語速偏慢,音調溫柔甜美,語氣治癒溫暖,像貼心朋友般關懷

API參考

即時語音合成-千問API參考

聲音複刻-API參考

聲音設計-API參考

模型功能特性對比

功能/特性

千問3-TTS-Instruct-Flash-Realtime

千問3-TTS-VD-Realtime

千問3-TTS-VC-Realtime

千問3-TTS-Flash-Realtime

千問-TTS-Realtime

支援語言

中文(普通話)、英文、西班牙語、俄語、意大利語、法語、韓語、日語、德語、葡萄牙語

中文(普通話)、英文、西班牙語、俄語、意大利語、法語、韓語、日語、德語、葡萄牙語

中文(普通話、北京、上海、四川、南京、陝西、閩南、天津、粵語,因音色而異)、英文、西班牙語、俄語、意大利語、法語、韓語、日語、德語、葡萄牙語

中文、英文

音頻格式

pcm、wav、mp3、opus

pcm

音頻採樣率

8kHz、16kHz、24kHz、48kHz

24kHz

聲音複刻

不支援

支援

不支援

聲音設計

不支援

支援

不支援

SSML

不支援

LaTeX

不支援

音量大小

支援

不支援

語速調節

支援

不支援

語調(音高)調節

支援

不支援

碼率調節

支援

不支援

時間戳記

不支援

指令控制(Instruct)

支援

不支援

流式輸入

支援

流式輸出

支援

限流

每分鐘調用次數(RPM):180

qwen3-tts-flash-realtime、qwen3-tts-flash-realtime-2025-11-27每分鐘調用次數(RPM):180

qwen3-tts-flash-realtime-2025-09-18每分鐘調用次數(RPM):10

每分鐘調用次數(RPM):10

每分鐘消耗Token數(TPM):100,000

接入方式

Java/Python SDK、WebSocket API

價格

國際:$0.143/萬字元

中國內地:$0.143/萬字元

國際:$0.143353/萬字元

中國內地:$0.143353/萬字元

國際:$0.13/萬字元

中國內地:$0.143353/萬字元

中國內地:

  • 輸入成本:$0.345/千Token

  • 輸出成本:$1.721/千Token

支援的音色

不同模型支援的音色有所差異,使用時將請求參數voice設定為音色列表中voice參數列對應的值。

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

Ebona

音色名:詭婆婆

描述:她的低語像一把生鏽的鑰匙,緩慢轉動你內心最深處的幽暗角落——那裡藏著所有你不敢承認的童年陰影與未知恐懼(女性)

中文(普通話)、英語、法語、德語、俄語、意大利語、西班牙語、葡萄牙語、日語、韓語

  • 千問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