Transmita áudio para o Qwen-ASR-Realtime via WebSocket e receba resultados de transcrição em tempo real pelo DashScope Python SDK.
Pré-requisitos
Antes de começar, verifique se você tem:
- DashScope SDK 2.0.1 ou posterior
- Uma chave de API
- Conhecimento do fluxo de interação
ImportanteAlibaba 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.comto{WorkspaceId}.cn-beijing.maas.aliyuncs.com - Singapore: from
dashscope-intl.aliyuncs.comto{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
Replace {WorkspaceId} with your actual Workspace ID. The existing domains remain fully functional.
Exemplo completo
ObservaçãoO código de exemplo lê o arquivo your_audio_file.pcm (PCM16, 16 kHz, mono). Caso você possua apenas arquivos em MP3, WAV ou formatos similares, converta-os usando o ffmpeg:
ffmpeg -i your_audio.mp3 -ar 16000 -ac 1 -f s16le your_audio_file.pcm
import logging
import os
import signal
import sys
import time
import dashscope
from concurrent.futures import ThreadPoolExecutor
# A API Key da região Singapura é diferente da da região Pequim. Obtenha sua API Key: https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# Se a variável de ambiente não estiver configurada, substitua a linha abaixo pela sua API Key do Alibaba Cloud Model Studio: api_key="sk-xxx"
client = dashscope.Client(
api_key=os.environ.get('DASHSCOPE_API_KEY'),
# A configuração abaixo refere-se à região Singapura (ap-southeast-1). Substitua {WorkspaceId} pelo ID real do seu workspace. O valor de region varia conforme a região.
workspace="{WorkspaceId}",
region="ap-southeast-1",
)
def setup_logging():
"""Configura a saída de log"""
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 handle_event(event):
"""Trata um evento do servidor"""
kind = event.get('type')
if kind == 'session.created':
print(f"Sessão iniciada: {event['session']['id']}")
elif kind == 'conversation.item.input_audio_transcription.completed':
print(f"Texto final reconhecido: {event['transcript']}")
elif kind == 'conversation.item.input_audio_transcription.text':
print(f"Resultado da transcrição recebido: {event['text'] + event['stash']}")
elif kind == 'input_audio_buffer.speech_started':
print('======Início da fala======')
elif kind == 'input_audio_buffer.speech_stopped':
print('======Fim da fala======')
def receive_events(session):
"""Recebe e processa eventos do servidor"""
for event in session.events():
handle_event(event)
def read_audio_chunks(file_path, chunk_size=3200):
"""Lê o arquivo de áudio em blocos"""
with open(file_path, 'rb') as f:
while chunk := f.read(chunk_size):
yield chunk
def send_audio(session, file_path, delay=0.1):
"""Envia dados de áudio"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"O arquivo de áudio {file_path} não existe.")
print("Processando o arquivo de áudio... Pressione 'Ctrl+C' para interromper.")
for chunk in read_audio_chunks(file_path):
session.append_audio(chunk) # os bytes são codificados automaticamente em Base64 antes do envio
time.sleep(delay)
def main():
setup_logging()
audio_file_path = "./your_audio_file.pcm"
# Entrar no contexto with estabelece a conexão automaticamente
with client.audio.realtime.connect(
model='qwen3-asr-flash-realtime',
) as session:
def handle_exit(sig, frame):
print('Ctrl+C pressionado, encerrando...')
session.close()
sys.exit(0)
signal.signal(signal.SIGINT, handle_exit)
# Atualiza a configuração da sessão: apenas saída de texto, com transcrição do áudio de entrada ativada
session.update_session(
output_modalities=['text'],
enable_input_audio_transcription=True,
transcription_params={
'language': 'zh',
'sample_rate': 16000,
'input_audio_format': 'pcm',
},
)
# Lê até session.updated para confirmar que a configuração entrou em vigor
for event in session.events():
if event.get('type') == 'session.updated':
break
with ThreadPoolExecutor(max_workers=1) as pool:
receiver = pool.submit(receive_events, session)
try:
send_audio(session, audio_file_path)
# envia session.finish e aguarda finished e o fechamento
session.end_session()
receiver.result()
finally:
# close deve ser executado dentro do contexto do pool para desbloquear o receptor
session.close()
print("Processamento de áudio concluído.")
if __name__ == '__main__':
main()
Parâmetros da solicitação
Criação da sessão (client.audio.realtime.connect)
Os parâmetros a seguir são definidos por meio do método client.audio.realtime.connect.
Clique para visualizar o código de exemplo
# A API Key da região Singapura é diferente da da região Pequim. Obtenha sua API Key: https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# Se a variável de ambiente não estiver configurada, substitua a linha abaixo pela sua API Key do Alibaba Cloud Model Studio: api_key="sk-xxx"
client = dashscope.Client(
api_key=os.environ.get('DASHSCOPE_API_KEY'),
# A configuração abaixo refere-se à região Singapura (ap-southeast-1). Substitua {WorkspaceId} pelo ID real do seu workspace. O valor de region varia conforme a região.
workspace="{WorkspaceId}",
region="ap-southeast-1",
)
# Cria a sessão de reconhecimento em tempo real: entrar no contexto with estabelece a conexão automaticamente
session = client.audio.realtime.connect(
model='qwen3-asr-flash-realtime',
)
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
model | str | Sim | Nome do modelo a ser usado. |
ws_url | str | Não | Endpoint WebSocket completo. Quando não especificado, o endpoint é selecionado automaticamente conforme o workspace e o region do Client: China (Pequim): wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime Singapura: wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime. Substitua {WorkspaceId} pelo seu Workspace ID real. |
Configuração da sessão
Após a conexão ser estabelecida, chame o método update_session da sessão (RealtimeSession) para configurar os seguintes parâmetros.
Clique para visualizar o código de exemplo
session.update_session(
output_modalities=['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={
'language': 'zh',
'sample_rate': 16000,
'input_audio_format': 'pcm',
},
)
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
output_modalities | List[str] | Sim | Modalidade de saída do modelo, fixada como ["text"]. |
enable_turn_detection | bool | Não | Ativa a detecção de atividade de voz (VAD) no servidor. Padrão: True. Quando False, chame commit() manualmente para acionar o reconhecimento. |
turn_detection_type | str | Não | Tipo de VAD no servidor. Fixo como server_vad. |
turn_detection_threshold | float | Não | Limiar de sensibilidade do VAD. Padrão: 0.5. Recomendado: 0.0. Intervalo válido: [-1, 1]. Valores menores = maior sensibilidade (pode ser acionado por ruído ambiente). Valores maiores = menos acionamentos falsos em ambientes ruidosos. |
turn_detection_silence_duration_ms | int | Não | Duração do silêncio (ms) que marca o fim de uma fala. Padrão: 800. Recomendado: 400. Intervalo válido: [200, 6000]. Valores menores (ex.: 300 ms) = resposta mais rápida, mas pode dividir pausas naturais. Valores maiores (ex.: 1200 ms) = melhor tratamento de pausas em frases longas, porém com maior latência. |
transcription_params | dict | Não | Configurações de reconhecimento de fala. Consulte os parâmetros de transcription_params. |
Parâmetros de transcription_params
Configure as definições de reconhecimento de fala por meio do dicionário transcription_params do método update_session.
Clique para visualizar o código de exemplo
session.update_session(
output_modalities=['text'],
enable_input_audio_transcription=True,
transcription_params={
'language': 'zh',
'sample_rate': 16000,
'input_audio_format': 'pcm',
},
)
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
language | str | Não | Idioma de origem do áudio. Valores compatíveis: zh (chinês: mandarim, sichuanês, minnan, wu), yue (cantonês), en (inglês), ja (japonês), ko (coreano), de (alemão), fr (francês), es (espanhol), pt (português), it (italiano), ru (russo), ar (árabe), hi (hindi), id (indonésio), th (tailandês), tr (turco), uk (ucraniano), vi (vietnamita), cs (tcheco), da (dinamarquês), fi (finlandês), fil (filipino), is (islandês), ms (malaio), no (norueguês), pl (polonês), sv (sueco) |
sample_rate | int | Não | Taxa de amostragem de áudio em Hz. Padrão: 16000. Compatível: 16000, 8000. Com 8000, o servidor faz upsampling para 16.000 Hz antes do reconhecimento, o que pode adicionar uma pequena latência. Use 8000 apenas para áudio de origem de 8 kHz, como gravações telefônicas. |
input_audio_format | str | Não | Formato de áudio. Padrão: pcm. Compatível: pcm, opus. |
corpus_text | str | Não | Texto de contexto, vocabulários de entidades ou outras informações de referência para viés contextual. Máximo: 10.000 tokens. Para detalhes, consulte Viés contextual. |
Interfaces principais
Sessão RealtimeSession (client.audio.realtime.connect)
A sessão de reconhecimento em tempo real é criada por meio de client.audio.realtime.connect(model=...): a conexão é estabelecida ao entrar no contexto with (ou ao chamar o método connect() da sessão).
| Método | Evento de resposta do servidor | Descrição |
|---|---|---|
connect() | session.created, session.updated | Cria a conexão com o servidor. Chamado automaticamente ao entrar no contexto with; não chame connect() explicitamente e depois entre no with da mesma sessão. |
update_session(...) | session.updated | Atualiza a configuração da sessão; recomenda-se chamá-lo primeiro após a conexão ser estabelecida. Se omitido, são aplicadas as configurações padrão. Consulte Configuração da sessão para os parâmetros. |
append_audio(audio_b64: Union[str, bytes]) | Nenhum | Anexa fragmentos de dados de áudio ao buffer de entrada do servidor. Um valor str é tratado como Base64 já codificado; valores bytes são codificados automaticamente em Base64. Com enable_turn_detection=True, o servidor detecta os limites de fala e faz o commit automaticamente. Com enable_turn_detection=False, o cliente controla o momento do commit (máximo de 15 MiB por evento). Blocos menores melhoram a responsividade do VAD. |
commit() | input_audio_buffer.committed | Faz o commit do áudio armazenado no buffer para reconhecimento. Retorna um erro se o buffer estiver vazio. Desativado quando enable_turn_detection=True. |
end_session() | session.finished | Notifica o servidor de que a sessão deve ser encerrada; após receber a notificação, o servidor conclui o reconhecimento final da fala. No modo VAD (padrão), chame após enviar todo o áudio. No modo manual, chame após commit(). |
close() | Nenhum | Encerra a tarefa e fecha a conexão (idempotente; não envia session.finish). |
session.session_id / session.last_response_id | Nenhum | Obtém o session_id da tarefa atual e o response_id da resposta mais recente (atributos). |
Iteração de eventos (events())
O servidor retorna os eventos e dados de resposta ao cliente por meio de eventos. Você precisa iterar os events() da sessão na thread de recepção e fazer o despacho por event["type"] (a lista completa de eventos está em eventos do servidor).
def receive_events(session):
for event in session.events():
kind = event.get('type')
if kind == 'session.created':
print(f"Sessão iniciada: {event['session']['id']}")
elif kind == 'conversation.item.input_audio_transcription.completed':
print(f"Texto final reconhecido: {event['transcript']}")
elif kind == 'conversation.item.input_audio_transcription.text':
print(f"Resultado da transcrição recebido: {event['text'] + event['stash']}")
| Assinatura do método | Parâmetros | Descrição |
|---|---|---|
def events(self) -> Iterator[Dict] | event: um evento do servidor | Lê continuamente e produz os eventos do servidor (dict) um a um. A iteração termina quando a conexão é fechada ou quando session.finished é recebido. |
def recv_event(self) -> Optional[Dict] | Nenhum | Lê de forma bloqueante um único evento do servidor, sem laço automático; retorna None quando não há eventos (conexão fechada). |