メインコンテンツまでスキップ

リアルタイム ASR​(WebSocket)

リアルタイム ASR は、​WebSocket 経由で​音声を​ストリーミングし、​発話中に​文字起こしを​返します。​音声が​まだ​流れている​間は​暫定的な​**部​分​(partial)結果を、​発話ごとに​確定的な確定​(final)​**結果を​返します。​ライブ字幕、​会議の​文字起こし、​音声インターフェースに​利用できます。

完全な​音声ファイルを​一度に​文字起こしする​場合は、​代わりにバッチ ASR エンドポイントを​使用してください。

エンドポイント

wss://api.shisa.ai/ws/asr/realtime

WebSocket ハンドシェイク時に、​ASR 用の​ベアラートークンで​認証します:

Authorization: Bearer YOUR_API_KEY
リアルタイムアクセスが必要です

API キーには​ shisa/asr-realtime サービスへの​明示的な​アクセス権が​必要です。​バッチ ASR、​チャット、​翻訳、​TTS への​アクセス権が​あっても、​リアルタイム ASR への​アクセス権は​付与されません。​キーが​サービス許可リストを​使用している​場合は、shisa/asr-realtime を​追加してください。​追加されていないと、​ハンドシェイクは​拒否されます。

サーバーサイド専用

リアルタイム ASR は​バックエンドでの​利用を​想定しています。​API キーは​サーバーサイドに​保管してください。​ブラウザから​自前の​サーバーへ​音声を​中継し、​そこから​ Shisa に​接続します。

仕組み

  1. Authorization ヘッダーを​付けて​エンドポイントに​ WebSocket を​開きます。
  2. session.update メッセージを​ 1 回送信し、​音声形式と​言語を​設定します。
  3. session.created を​待ちます。
  4. 生の​音声を​ base64 の​ input_audio.append メッセージと​して​ストリーミングします​(1 チャンクあたり 50〜250 ms が​目安です)。
  5. asr.partial_result を​ライブの​暫定テキストと​して​表示し、asr.final_result が​届いたら​置き換えます。
  6. 完了したら​ session.close を​送信します。

音声の​要件

生の​ PCM を​送信してください。​コンテナや​圧縮は​使用しません:

プロパティ
エンコーディングpcm_s16le(符号付き 16 ビットリトルエンディアン)
サンプルレート16000 Hz
チャンネル1(モノラル)
チャンク間隔50〜250 ms 推奨​(例では​ 100 ms)

送信前に​クライアント側で​リサンプリングと​ダウンミックスを​行ってください。​WAV ヘッダー、​Ogg、​MP3、​データ URL、​浮動小数点 PCM、​ステレオ音声は​送信しないでください。

クライアントメッセージ

session.update

音声を​送信する​前に、session.update を​必ず 1 回送信します。​言語を​固定する​セッションが​最も​シンプルです:

{
"type": "session.update",
"session": {
"input_audio_format": "pcm_s16le",
"sample_rate": 16000,
"channels": 1,
"language": "ja"
}
}
フィールド必須備​考
input_audio_formatは​いpcm_s16le生の​符号付き 16 ビットリトルエンディアン PCM。
sample_rateは​い16000送信前に​ 16 kHz に​リサンプリングします。
channelsは​い1モノラルのみ。​ステレオは​先に​ダウンミックスします。
languageは​いjaenzhauto言語が​分かっている​場合は​固定します。​自動言語識別には​ auto を​使用します​(後述)。
default_languageauto 時のみjaenzh検出が​確信できない​場合の​フォールバック。
language_detection_modeauto 時のみsessionutterancesession は​一度だけ検出、utterance は​セグメントごとに​検出​(応用 — 後述)。

input_audio.append

音声チャンクを​ base64 エンコードした​ PCM と​して​ストリーミングします:

{
"type": "input_audio.append",
"audio": "<base64 pcm_s16le bytes>"
}

session.close

完了したら、​セッションを​正常に​クローズします:

{ "type": "session.close" }

言語​識別​(任意)

発話される​言語が​事前に​分からない​場合は、language: "auto" を​設定します。​2 つの​モードが​あります。

セッション検出は、​開始直後に​一度だけ言語を​識別し、​セッション全体で​その​言語を​使用します:

{
"type": "session.update",
"session": {
"input_audio_format": "pcm_s16le",
"sample_rate": 16000,
"channels": 1,
"language": "auto",
"default_language": "en",
"language_detection_mode": "session"
}
}

セッションは​ session.language_detecting を​発行し、​続いて​選択された​ language を​含む session.language_detected を​ 1 回発行します。

発話単位の​検出language_detection_mode: "utterance")は、​発話ごとに​個別に​言語を​検出する​ため、​複数言語が​混在する​音声に​便利です。​発話ごとに​ utterance.language_detected を​発行します。​この​モードは​バックエンドで​有効化されている​必要が​あり、​有効でない​場合、​セッションは​ code: "invalid_config" の​ error を​返します。​その​場合は、​固定言語または​セッション検出に​フォールバックしてください。

検出が​確信を​持って選択できない​場合は​ default_language に​フォールバックし、​イベントには​ source: "default" と​ reason(例: no_speechshort_utteranceinconclusivetimeout)が​含まれます。asr.final_result.text を​常に​権威ある​結果と​して​扱い、​言語イベントだけを​根拠に​文字起こしを​書き換えないでください。

ルーター管理の​翻訳​(任意)

ルーターは、​空でない​各asr.final_resultを​非同期で​翻訳できます。​APIキーにはshisa/asr-realtimeshisa/translateの​両方​への​アクセス権が​必要です。​翻訳は​WebSocketセッションごとに​明示的に​有効化するまで​無効です。

session.updateの​後に​次を​送信します。

{
"type": "router.translation.update",
"id": "translate-en",
"enabled": true,
"target_langs": ["en"]
}
フィールド必須説明
enabled必須boolean。​翻訳を​無効に​する​場合はfalseを​指定し、​対象言語は​省略します。
target_langs有​効化​時一意かつ​有効な​言語コードを​1〜3個指定します。
id任意制御レスポンスに​エコーされる​クライアント相関ID。​最大36文字。
context任意各翻訳に​渡す文脈。​最大2,000 Unicodeコードポイント。
keywords任意用語集の​配列。​最大20件、​各項目100バイトまで。

更新が​受け付けられると、​次の​レスポンスが​返ります。

{
"type": "router.translation.updated",
"id": "translate-en",
"enabled": true,
"target_langs": ["en"]
}

設定が​不正な​場合はrouter.translation.errorが​返ります。

{
"type": "router.translation.error",
"id": "translate-en",
"code": "too_many_target_langs",
"message": "At most 3 target languages are allowed"
}

設定エラーの​コードには、invalid_jsoninvalid_message_typeinvalid_idid_too_longinvalid_enabledmissing_target_langstoo_many_target_langsduplicate_target_langinvalid_target_langcontext_too_longtoo_many_keywordskeyword_too_longtranslation_access_deniedtranslation_service_unavailableが​あります。​その​他の​予約済みrouter.*メッセージにはrouter.errorが​返り、​コードはunknown_router_messageまたはrouter_message_too_largeです。

翻訳元言語の解決

ルーターは​各確定結果の​翻訳元言語を、​(1) asr.final_result.language、​(2) 最新のsession.language_detected、(3) session.update.session.languageで​指定した​固定言語、の​優先順で​解決します。​単独のutterance.language_detectedイベントは​翻訳元言語と​して​直接利用しません。​確定結果の​到着時に​有効な​言語が​ない​場合、​その​対象言語にはcode: "source_language_unknown"translation.errorが​返ります。

サービスイベント

すべての​イベントは​ JSON テキストメッセージです。​セッション作成後、​ASRバックエンドの​イベントにはsession_idと​単調増加するseqが​含まれます。​ルーターが​生成するrouter.*およびtranslation.*イベントには​これらの​フィールドが​ないため、​翻訳結果と​翻訳エラーはsource_result_idで​ASR確定結果に​関連付けてください。

session.created

セッションが​受け入れられ、​音声の​送信を​開始できます:

{
"type": "session.created",
"session_id": "asr_sess_...",
"seq": 1,
"format": { "encoding": "pcm_s16le", "sample_rate": 16000, "channels": 1 }
}

発話境界

speech_started と​ speech_stopped は、​各発話の​音声区間検出​(VAD)の​境界を​示します:

{
"type": "speech_started",
"session_id": "asr_sess_...",
"seq": 4,
"utterance_id": "utt_0001",
"audio_start_ms": 420
}
{
"type": "speech_stopped",
"session_id": "asr_sess_...",
"seq": 9,
"utterance_id": "utt_0001",
"audio_start_ms": 420,
"audio_end_ms": 2860,
"reason": "vad_endpoint"
}

一般的な​停止理由は​ vad_endpointmax_buffersession_close です。

asr.partial_result

進行中の​発話の​暫定テキストです。utterance_id ごとに​最新の​部分結果を​表示し、​前の​ものを​置き換えてください。​すべての​部分結果を​履歴に​追加しないでください​:

{
"type": "asr.partial_result",
"session_id": "asr_sess_...",
"seq": 7,
"utterance_id": "utt_0001",
"result_id": "utt_0001:p3",
"text": "今日の会議は3時から",
"is_final": false,
"audio_start_ms": 420,
"audio_end_ms": 2260
}

asr.final_result

発話の​確定テキストです。​表示していた​暫定の​部分結果を​破棄するには​ replaces を​使用します:

{
"type": "asr.final_result",
"session_id": "asr_sess_...",
"seq": 12,
"utterance_id": "utt_0001",
"result_id": "utt_0001:final",
"replaces": ["utt_0001:p1", "utt_0001:p2", "utt_0001:p3"],
"replaces_audio_range_ms": [420, 2860],
"text": "今日の会議は3時からです。",
"language": "ja",
"is_final": true,
"audio_start_ms": 420,
"audio_end_ms": 2860
}

確定結果は​非同期であり、​後続の​音声イベントより​遅れて​届く​ことがあります。​非常に​長い​発話は、​追加の​ continuation_of と​ overlap_mode メタデータを​持つ継続確定結果に​分割される​場合が​あります。​表示は​論理的な​ audio_start_msaudio_end_ms の​範囲のみと​してください。

translation.final_result

翻訳が​有効な​場合、​ルーターは​翻訳可能な​ASR確定結果​ごとに、​対象言語ごとの​結果を​1件発行します。

{
"type": "translation.final_result",
"utterance_id": "utt_0001",
"source_result_id": "utt_0001:final",
"source_text": "今日の会議は3時からです。",
"text": "Today's meeting starts at 3 o'clock.",
"source_lang": "ja",
"target_lang": "en",
"model": "shisa-v2.1-unphi4-14b"
}

source_result_idで​示される​正確な​ASR確定結果に​翻訳を​関連付けてください。​翻訳は​非同期であり、​複数の​対象言語の​結果は​任意の​順序で​到着します。modelは​バックエンドが​レスポンスで​報告した​モデルIDであり、​翻訳リクエストに​使われる​デフォルトエイリアスshisa-ai/chottoと​異なる​場合が​あります。

translation.error

対象言語の​翻訳に​失敗した​場合、​ASRセッションを​閉じずに​対象別の​エラーが​発行されます。

{
"type": "translation.error",
"code": "source_language_unknown",
"message": "Cannot translate ASR final result before source language is known",
"utterance_id": "utt_0001",
"source_result_id": "utt_0001:final",
"target_lang": "en"
}

その​他の​一般的な​コードには、same_source_target_langtranslation_access_deniedtranslation_service_unavailabletranslation_rate_limitedtranslation_rate_limiter_unavailabletranslation_failedsource_text_too_longが​あります。​空の​確定テキストは​翻訳されず、​翻訳結果も​翻訳エラーも​発行されません。

session.usage

利用量は​累積です。​課金は​最新の​イベントを​使用します。billable_duration は​整数秒です:

{
"type": "session.usage",
"session_id": "asr_sess_...",
"seq": 20,
"final": true,
"usage": {
"input_duration": 18.3036875,
"billable_duration": 19,
"utterance_count": 3,
"final_result_count": 3,
"status": "completed",
"final": true
}
}

error

{
"type": "error",
"code": "finalization_failed",
"message": "Finalization failed",
"fatal": false,
"session_id": "asr_sess_...",
"seq": 18,
"utterance_id": "utt_0002"
}

致命的​(fatal)​エラーの​後は​クローズが​続きます。​致命的でない​発話エラーの​場合、​セッションは​継続できます。

文字起こしの​取り扱い

  • 暫定テキストは​ utterance_id を​キーと​して​保持します。
  • より​新しい​ asr.partial_result が​届いたら、​アクティブな​部分結果を​置き換えます。
  • asr.final_result を​受け取ったら、replaces の​ ID を​削除し、​確定テキストを​確定します。
  • 翻訳はsource_result_idで​関連付け、​対象言語の​結果​順序を​前提に​しないでください。
  • 空の​確定テキストは​表示上は​無視します​(診断用には​保持します)。
  • session.usage を​文字起こしテキストと​して​表示しないでください。

次の​ステップ