Qwen-ASR-Realtime Python SDK - API reference

Updated at:

Stream audio to Qwen-ASR-Realtime over WebSocket and receive real-time transcription results via the DashScope Python SDK.

Prerequisites

Before you begin, make sure that you have:

ImportantAlibaba Cloud Model Studio has released workspace-specific domains for the China (Beijing) and Singapore regions. The new dedicated domains deliver superior performance and higher stability for inference requests. We recommend migrating to the new domains:

  • China (Beijing): from dashscope.aliyuncs.com to {WorkspaceId}.cn-beijing.maas.aliyuncs.com
  • Singapore: from dashscope-intl.aliyuncs.com to {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

Replace {WorkspaceId} with your actual Workspace ID. The existing domains remain fully functional.

Complete example

NoteThe example code reads your_audio_file.pcm (PCM16, 16 kHz, mono). If you only have an MP3, WAV, or similar format, convert it with ffmpeg:

ffmpeg -i your_audio.mp3 -ar 16000 -ac 1 -f s16le your_audio_file.pcm
import logging
import os
import base64
import signal
import sys
import time
import dashscope
from dashscope.audio.qwen_omni import *
from dashscope.audio.qwen_omni.omni_realtime import TranscriptionParams

def setup_logging():
    """Configure log output"""
    logger = logging.getLogger('dashscope')
    logger.setLevel(logging.DEBUG)
    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.propagate = False
    return logger

def init_api_key():
    """Initialize the API Key"""
    # The API Key differs between the Singapore and Beijing regions. Get your API Key: https://help.aliyun.com/zh/model-studio/get-api-key
    # If you have not configured the environment variable, replace the following line with your Alibaba Cloud Model Studio API Key: dashscope.api_key = "sk-xxx"
    dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY', 'YOUR_API_KEY')
    if dashscope.api_key == 'YOUR_API_KEY':
        print('[Warning] Using placeholder API key, set DASHSCOPE_API_KEY environment variable.')

class MyCallback(OmniRealtimeCallback):
    """Real-time recognition callback handler"""
    def __init__(self, conversation):
        self.conversation = conversation
        self.handlers = {
            'session.created': self._handle_session_created,
            'conversation.item.input_audio_transcription.completed': self._handle_final_text,
            'conversation.item.input_audio_transcription.text': self._handle_transcription_text,
            'input_audio_buffer.speech_started': lambda r: print('======Speech Start======'),
            'input_audio_buffer.speech_stopped': lambda r: print('======Speech Stop======')
        }

    def on_open(self):
        print('Connection opened')

    def on_close(self, code, msg):
        print(f'Connection closed, code: {code}, msg: {msg}')

    def on_event(self, response):
        try:
            handler = self.handlers.get(response['type'])
            if handler:
                handler(response)
        except Exception as e:
            print(f'[Error] {e}')

    def _handle_session_created(self, response):
        print(f"Start session: {response['session']['id']}")

    def _handle_final_text(self, response):
        print(f"Final recognized text: {response['transcript']}")

    def _handle_transcription_text(self, response):
        print(f"Got transcription result: {response['text'] + response['stash']}")

def read_audio_chunks(file_path, chunk_size=3200):
    """Read the audio file in chunks"""
    with open(file_path, 'rb') as f:
        while chunk := f.read(chunk_size):
            yield chunk

def send_audio(conversation, file_path, delay=0.1):
    """Send audio data"""
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"Audio file {file_path} does not exist.")

    print("Processing audio file... Press 'Ctrl+C' to stop.")
    for chunk in read_audio_chunks(file_path):
        audio_b64 = base64.b64encode(chunk).decode('ascii')
        conversation.append_audio(audio_b64)
        time.sleep(delay)

def main():
    setup_logging()
    init_api_key()

    audio_file_path = "./your_audio_file.pcm"
    callback = MyCallback(conversation=None)
    conversation = OmniRealtimeConversation(
        model='qwen3-asr-flash-realtime',
        # The following is the configuration for the China (Beijing) region. When calling, replace "{WorkspaceId}" with your actual workspace ID. Configurations differ by region.
        url='wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime',
        callback=callback,
    )
    callback.conversation = conversation  # Inject conversation into the callback so its methods can be called within the callback

    def handle_exit(sig, frame):
        print('Ctrl+C pressed, exiting...')
        conversation.close()
        sys.exit(0)

    signal.signal(signal.SIGINT, handle_exit)

    conversation.connect()

    transcription_params = TranscriptionParams(
        language='zh',
        sample_rate=16000,
        input_audio_format="pcm"
    )

    conversation.update_session(
        output_modalities=[MultiModality.TEXT],
        enable_input_audio_transcription=True,
        transcription_params=transcription_params
    )

    try:
        send_audio(conversation, audio_file_path)
        # send session.finish and wait for finished and close
        conversation.end_session()
    except Exception as e:
        print(f"Error occurred: {e}")
    finally:
        conversation.close()
        print("Audio processing completed.")

if __name__ == '__main__':
    main()

Request parameters

OmniRealtimeConversation constructor

Create an OmniRealtimeConversation instance with the following parameters.

Click to view sample code

from dashscope.audio.qwen_omni import OmniRealtimeConversation, OmniRealtimeCallback

class MyCallback(OmniRealtimeCallback):
    """Callback for real-time recognition"""
    def __init__(self, conversation):
        self.conversation = conversation
        self.handlers = {
            'session.created': self._handle_session_created,
            'conversation.item.input_audio_transcription.completed': self._handle_final_text,
            'conversation.item.input_audio_transcription.text': self._handle_stash_text,
            'input_audio_buffer.speech_started': lambda r: print('======Speech Start======'),
            'input_audio_buffer.speech_stopped': lambda r: print('======Speech Stop======')
        }

    def on_open(self):
        print('Connection opened')

    def on_close(self, code, msg):
        print(f'Connection closed, code: {code}, msg: {msg}')

    def on_event(self, response):
        try:
            handler = self.handlers.get(response['type'])
            if handler:
                handler(response)
        except Exception as e:
            print(f'[Error] {e}')

    def _handle_session_created(self, response):
        print(f"Start session: {response['session']['id']}")

    def _handle_final_text(self, response):
        print(f"Final recognized text: {response['transcript']}")

    def _handle_stash_text(self, response):
        print(f"Got stash result: {response['stash']}")

conversation = OmniRealtimeConversation(
        model='qwen3-asr-flash-realtime',
        # The following URL is for the Chinese mainland. For regions outside
        # the Chinese mainland, use
        # wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime instead.
        url='wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime',
        callback=MyCallback(conversation=None)  # Temporarily pass None and inject it later.
    )
# Inject self into the callback.
conversation.callback.conversation = conversation
ParameterTypeRequiredDescription
modelstrYesModel to use.
callbackOmniRealtimeCallbackYesCallback object that handles server-side events.
urlstrYesWebSocket endpoint.
China (Beijing): wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime
Singapore: wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime. Replace {WorkspaceId} with your actual Workspace ID.






















Session configuration

After connecting, call update_session to configure session parameters.

Click to view sample code

from dashscope.audio.qwen_omni import TranscriptionParams, MultiModality

transcription_params = TranscriptionParams(
    language='zh',
    sample_rate=16000,
    input_audio_format="pcm"
)

conversation.update_session(
    output_modalities=[MultiModality.TEXT],
    enable_turn_detection=True,
    turn_detection_type="server_vad",
    turn_detection_threshold=0.0,
    turn_detection_silence_duration_ms=400,
    enable_input_audio_transcription=True,
    transcription_params=transcription_params
)
ParameterTypeRequiredDescription
output_modalitiesList[MultiModality]YesOutput modality. Fixed to [MultiModality.TEXT].
enable_turn_detectionboolNoEnables server-side Voice Activity Detection (VAD). Default: True. When False, call commit() manually to trigger recognition.
turn_detection_typestrNoServer-side VAD type. Fixed to server_vad.
turn_detection_thresholdfloatNoVAD sensitivity threshold. Default: 0.2. Recommended: 0.0. Valid range: [-1, 1].
Lower values = higher sensitivity (may trigger on background noise). Higher values = fewer false triggers in noisy environments.







turn_detection_silence_duration_msintNoSilence duration (ms) that marks the end of a statement. Default: 800. Recommended: 400. Valid range: [200, 6000].
Lower values (e.g., 300 ms) = faster response but may split natural pauses. Higher values (e.g., 1200 ms) = better handling of long-sentence pauses but higher latency.







transcription_paramsTranscriptionParamsNoSpeech recognition configurations. See TranscriptionParams.

TranscriptionParams

Configure speech recognition settings with the TranscriptionParams constructor.

Click to view sample code

transcription_params = TranscriptionParams(
    language='zh',
    sample_rate=16000,
    input_audio_format="pcm"
)
ParameterTypeRequiredDescription
languagestrNoSource language of the audio. Supported values:
zh (Chinese: Mandarin, Sichuanese, Minnan, Wu), yue (Cantonese), en (English), ja (Japanese), ko (Korean), de (German), fr (French), es (Spanish), pt (Portuguese), it (Italian), ru (Russian), ar (Arabic), hi (Hindi), id (Indonesian), th (Thai), tr (Turkish), uk (Ukrainian), vi (Vietnamese), cs (Czech), da (Danish), fi (Finnish), fil (Filipino), is (Icelandic), ms (Malay), no (Norwegian), pl (Polish), sv (Swedish)







sample_rateintNoAudio sampling rate in Hz. Default: 16000. Supported: 16000, 8000. With 8000, the server upsamples to 16,000 Hz before recognition, which may add minor latency. Use 8000 only for 8 kHz source audio like telephone recordings.
input_audio_formatstrNoAudio format. Default: pcm. Supported: pcm, opus.
corpus_textstrNoBackground text, entity vocabularies, or other reference information for contextual biasing. Max: 10,000 tokens. For details, see Contextual biasing.

Key interfaces

OmniRealtimeConversation class

from dashscope.audio.qwen_omni import OmniRealtimeConversation
MethodServer response eventDescription
connect()session.created, session.updatedOpens a WebSocket connection to the server.
update_session(...)session.updatedConfigures the session. Call after connect(). If omitted, defaults apply. See Session configuration for parameters.
append_audio(audio_b64: str)NoneSends a Base64-encoded audio chunk to the server input buffer. With enable_turn_detection=True, the server detects speech boundaries and commits automatically. With enable_turn_detection=False, the client controls commit timing (max 15 MiB per event). Smaller chunks improve VAD responsiveness.
commit()input_audio_buffer.committedCommits buffered audio for recognition. Returns an error if the buffer is empty. Disabled when enable_turn_detection=True.
end_session(timeout: int = 20)session.finishedEnds the session after the server completes final recognition. In VAD mode (default), call after sending all audio. In Manual mode, call after commit(). Async variant: end_session_async().
close()NoneTerminates the task and closes the connection.
get_session_id()NoneReturns the current session ID.
get_last_response_id()NoneReturns the most recent response ID.

OmniRealtimeCallback interface

Subclass OmniRealtimeCallback and implement its methods to handle server events.

from dashscope.audio.qwen_omni import OmniRealtimeCallback
MethodParametersDescription
on_open()NoneCalled when the WebSocket connection is established.
on_event(message: dict)message: a server eventCalled when a server event is received.
on_close(close_status_code, close_msg)close_status_code: status code; close_msg: log messageCalled when the WebSocket connection is closed.