WebSocket を介して音声を Qwen-ASR-Realtime にストリーミングし、DashScope Python SDK を使ってリアルタイムの文字起こし結果を受信します。
前提条件
作業を開始する前に、以下の項目が準備済みであることを確認してください。
- DashScope SDK 2.0.1 以降
- API キー
- インタラクションフロー の理解
重要Alibaba Cloud Model Studio は、中国 (北京) リージョンおよびシンガポールリージョン向けにワークスペース専用ドメインをリリースしました。この新しい専用ドメインは、推論リクエストに対して優れたパフォーマンスと高い安定性を提供します。新しいドメインへの移行を推奨します。
- 中国 (北京):
dashscope.aliyuncs.comから{WorkspaceId}.cn-beijing.maas.aliyuncs.comへ - シンガポール:
dashscope-intl.aliyuncs.comから{WorkspaceId}.ap-southeast-1.maas.aliyuncs.comへ
{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。既存のドメインは引き続き完全に機能します。
完全な例
注記サンプルコードは your_audio_file.pcm (PCM16、16 kHz、モノラル) を読み込みます。MP3 や WAV などのフォーマットしかない場合は、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
# API キーは、シンガポールリージョンと北京リージョンで異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
# 環境変数を設定していない場合は、次の行を Model Studio API キーに置き換えてください: api_key="sk-xxx"
client = dashscope.Client(
api_key=os.environ.get('DASHSCOPE_API_KEY'),
# 以下はシンガポール (ap-southeast-1) リージョンの設定です。呼び出す際に、"{WorkspaceId}" を実際のワークスペース ID に置き換えてください。設定はリージョンによって異なります。
workspace="{WorkspaceId}",
region="ap-southeast-1",
)
def setup_logging():
"""ログ出力を設定"""
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):
"""サーバー側イベントを処理"""
kind = event.get('type')
if kind == 'session.created':
print(f"Start session: {event['session']['id']}")
elif kind == 'conversation.item.input_audio_transcription.completed':
print(f"Final recognized text: {event['transcript']}")
elif kind == 'conversation.item.input_audio_transcription.text':
print(f"Got transcription result: {event['text'] + event['stash']}")
elif kind == 'input_audio_buffer.speech_started':
print('======Speech Start======')
elif kind == 'input_audio_buffer.speech_stopped':
print('======Speech Stop======')
def receive_events(session):
"""サーバー側イベントを受信して処理"""
for event in session.events():
handle_event(event)
def read_audio_chunks(file_path, chunk_size=3200):
"""音声ファイルをチャンク単位で読み込む"""
with open(file_path, 'rb') as f:
while chunk := f.read(chunk_size):
yield chunk
def send_audio(session, file_path, delay=0.1):
"""音声データを送信"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"音声ファイル {file_path} が存在しません。")
print("Processing audio file... Press 'Ctrl+C' to stop.")
for chunk in read_audio_chunks(file_path):
session.append_audio(chunk) # bytes は送信前に自動的に Base64 エンコードされます
time.sleep(delay)
def main():
setup_logging()
audio_file_path = "./your_audio_file.pcm"
# with コンテキストに入ると自動的に接続が確立されます
with client.audio.realtime.connect(
model='qwen3-asr-flash-realtime',
) as session:
def handle_exit(sig, frame):
print('Ctrl+C pressed, exiting...')
session.close()
sys.exit(0)
signal.signal(signal.SIGINT, handle_exit)
# セッション設定を更新します:テキスト出力のみ、入力音声の文字起こしを有効化
session.update_session(
output_modalities=['text'],
enable_input_audio_transcription=True,
transcription_params={
'language': 'zh',
'sample_rate': 16000,
'input_audio_format': 'pcm',
},
)
# session.updated が返されるまで読み取り、設定が反映されたことを確認します
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)
# session.finish を送信し、finished の受信とクローズを待ちます
session.end_session()
receiver.result()
finally:
# close はレシーバーのブロックを解除するため、プールのコンテキスト内で実行する必要があります
session.close()
print("Audio processing completed.")
if __name__ == '__main__':
main()
リクエストパラメーター
client.audio.realtime.connect
以下のパラメーターは client.audio.realtime.connect を使用して設定します。
サンプルコードを表示
# API キーは、シンガポールリージョンと北京リージョンで異なります。API キーの取得: https://www.alibabacloud.com/help/model-studio/get-api-key
# 環境変数を設定していない場合は、次の行を Model Studio API キーに置き換えてください: api_key="sk-xxx"
client = dashscope.Client(
api_key=os.environ.get('DASHSCOPE_API_KEY'),
# 以下はシンガポール (ap-southeast-1) リージョンの設定です。呼び出す際に、"{WorkspaceId}" を実際のワークスペース ID に置き換えてください。設定はリージョンによって異なります。
workspace="{WorkspaceId}",
region="ap-southeast-1",
)
# リアルタイム認識セッションを作成します:with コンテキストに入ると自動的に接続が確立されます
session = client.audio.realtime.connect(
model='qwen3-asr-flash-realtime',
)
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
model | str | はい | 使用する モデル を指定します。 |
ws_url | str | いいえ | 完全な WebSocket エンドポイントです。未指定の場合、Client の workspace と region に基づいてエンドポイントが自動的に選択されます:中国(北京): wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime シンガポール: wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime。{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。 |
セッション構成
接続後、update_session を呼び出してセッションパラメーターを構成します。
サンプルコードを表示
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',
},
)
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
output_modalities | List[str] | はい | 出力モダリティです。固定値:["text"]。 |
enable_turn_detection | bool | いいえ | サーバー側の音声アクティビティ検出 (VAD) を有効にします。デフォルト:True。False の場合、認識をトリガーするために commit() を手動で呼び出す必要があります。 |
turn_detection_type | str | いいえ | サーバー側 VAD のタイプです。固定値:server_vad。 |
turn_detection_threshold | float | いいえ | VAD 検出しきい値です。デフォルト:0.5。推奨値:0.0。有効範囲:[-1, 1]。値が低いほど VAD の感度が高くなり(背景ノイズでもトリガーされる可能性あり)、値が高いほどノイズ環境での誤トリガーが少なくなります。 |
turn_detection_silence_duration_ms | int | いいえ | 文の終了を示すサイレンス持続時間 (ミリ秒) です。デフォルト:800。推奨値:400。有効範囲:[200, 6000]。値が小さい (例:300 ms) ほど応答が速くなりますが、自然なポーズが分割される可能性があります。値が大きい (例:1200 ms) ほど長文のポーズを適切に処理できますが、レイテンシが高くなります。 |
transcription_params | dict | いいえ | 音声認識の構成です。「transcription_params」をご参照ください。 |
transcription_params
update_session の transcription_params 辞書を使用して音声認識設定を構成します。
サンプルコードを表示
session.update_session(
output_modalities=['text'],
enable_input_audio_transcription=True,
transcription_params={
'language': 'zh',
'sample_rate': 16000,
'input_audio_format': 'pcm',
},
)
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
language | str | いいえ | 音声のソース言語です。サポートされる値:zh (中国語:普通話、四川語、閩南語、呉語)、yue (広東語)、en (英語)、ja (日本語)、ko (韓国語)、de (ドイツ語)、fr (フランス語)、es (スペイン語)、pt (ポルトガル語)、it (イタリア語)、ru (ロシア語)、ar (アラビア語)、hi (ヒンディー語)、id (インドネシア語)、th (タイ語)、tr (トルコ語)、uk (ウクライナ語)、vi (ベトナム語)、cs (チェコ語)、da (デンマーク語)、fi (フィンランド語)、fil (フィリピン語)、is (アイスランド語)、ms (マレー語)、no (ノルウェー語)、pl (ポーランド語)、sv (スウェーデン語) |
sample_rate | int | いいえ | 音声のサンプリングレート (Hz) です。デフォルト:16000。サポートされる値:16000、8000。8000 を使用すると、サーバーが認識前に 16,000 Hz にアップサンプリングするため、わずかなレイテンシが発生する可能性があります。電話録音など 8 kHz ソース音声の場合のみ、8000 を使用してください。 |
input_audio_format | str | いいえ | 音声フォーマットです。デフォルト:pcm。サポートされる値:pcm、opus。 |
corpus_text | str | いいえ | コンテキストバイアシング用の背景テキスト、エンティティ語彙、またはその他のリファレンス情報。最大:10,000 トークン。詳細については、「コンテキストバイアシング」をご参照ください。 |
主要インターフェイス
RealtimeSession クラス
リアルタイム認識セッションは client.audio.realtime.connect(model=...) で作成されます:with コンテキストに入る(またはセッションの connect() メソッドを呼び出す)と接続が確立されます。
| メソッド | サーバー応答イベント (events() で配信) | 説明 |
|---|---|---|
connect() | session.created、session.updated | サーバーへの WebSocket 接続を開きます。with コンテキストに入ると自動的に呼び出されます。先に connect() を呼び出してから同じセッションの with コンテキストに入らないでください。 |
update_session(...) | session.updated | セッション設定を更新します。connect() 後に呼び出してください。省略した場合はデフォルト値が適用されます。パラメーターの詳細については、「セッション構成」をご参照ください。 |
append_audio(audio: Union[str, bytes]) | なし | 音声データのチャンクをサーバーの入力バッファーに追加します。str は Base64 エンコード済みとみなされ、bytes は自動的に Base64 エンコードされます。enable_turn_detection=True の場合、サーバーが音声境界を検出し自動的にコミットします。enable_turn_detection=False の場合、クライアントがコミットタイミングを制御します (1 イベントあたり最大 15 MiB)。チャンクサイズを小さくすると VAD の応答性が向上します。 |
commit() | input_audio_buffer.committed | バッファリングされた音声を認識のためにコミットします。入力バッファーが空の場合はエラーが返されます。enable_turn_detection=True の場合は無効になります。 |
end_session() | session.finished | サーバーが最終認識を完了した後にセッションを終了します。VAD モード (デフォルト) の場合はすべての音声送信後に、マニュアルモード の場合は commit() 後に呼び出します。 |
close() | なし | タスクを終了し、接続を閉じます(冪等。session.finish は送信しません)。 |
events() | サーバーイベント (イベントタイプは event["type"]) | サーバーイベントを継続的に読み取ります。session.finished が返された後に反復が終了します。イベントは単一の受信スレッドで消費し、複数の並行リーダーを作成しないでください。 |
session.session_id、session.last_response_id | なし | 現在のタスクの session_id、最新の response の response_id(属性)。 |
イベント反復(events())
サーバーは、サーバー応答イベントとデータをイベントとしてクライアントに返します。受信スレッドでセッションの events() を反復処理し、event["type"] に基づいて振り分け処理してください(完全なイベントリストはサーバーイベントをご参照ください)。
def receive_events(session):
for event in session.events():
kind = event.get('type')
if kind == 'session.created':
print(f"Start session: {event['session']['id']}")
elif kind == 'conversation.item.input_audio_transcription.completed':
print(f"Final recognized text: {event['transcript']}")
elif kind == 'conversation.item.input_audio_transcription.text':
print(f"Got transcription result: {event['text'] + event['stash']}")
| メソッド | パラメーター | 説明 |
|---|---|---|
events() | event: サーバーイベント | サーバーイベント (dict) を継続的に読み取り、1 つずつ返します。接続が閉じられるか session.finished を受信すると反復が終了します。 |
recv_event() | なし | 単一のサーバーイベントをブロッキングで読み取ります(自動ループなし)。イベントがない場合(接続が閉じられている場合)は None を返します。 |