AGTCloud API Docs
ガイドAPIリファレンス連携とリソース更新とヘルプ
音声処理Muse Voice Transcribe

リアルタイム文字起こし

Muse Voice Transcribe WebSocketを使用してPCM音声を継続的に送信し、リアルタイムの文字起こしイベントを受信します。

Muse Voice TranscribeのリアルタイムAPIは、永続的なWebSocketを介して生のPCM音声を受信し、進捗、発話ターン、文字起こしの各イベントを継続的に返します。このAPIはテキストのみを生成し、音声応答は生成しません。

WSS
wss://api.agtcloud.cn/v1/asr/realtime

認証と接続

WebSocket接続を確立したら、10秒以内に最初のJSONテキストフレームを送信してください。Bearer API KeyはWebSocketハンドシェイクHeaderではなく、authorization.accessTokenに指定します。

項目値
接続先wss://api.agtcloud.cn/v1/asr/realtime
認証情報の指定位置最初のJSONテキストフレームのauthorization.accessToken
モデルmuse-voice-transcribe-1.0
任意のクエリパラメーターsessionId。セッション識別子としてそのまま転送されるだけで、切断後の再開や過去のセッション取得には対応しません

最初のフレームにはtypeを含めず、サイズは最大64 KiBです。sessionIdを含む成功レスポンスを受信してから音声の送信を開始してください。WebSocketのアップグレードに成功しても、最初のフレームの認証が成功したことにはなりません。

セッションの流れ

  1. WebSocket接続を確立します。
  2. 認証、モデル、音声設定を含む最初のフレームを送信します。
  3. サーバーからsessionIdが返されるまで待機します。
  4. 生のPCMバイナリフレームをリアルタイムの速度で送信しながら、イベントを継続的に受信します。
  5. 音声の送信が完了したら{"type":"endStream"}を送信します。
  6. 接続が閉じられるまで、末尾の文字起こしイベントと終了メッセージを受信し続けます。

speechCompleteは1回の発話ターンが完了したことだけを示し、セッション全体の終了を意味しません。endStreamを送信した後も、接続が閉じられるまでサーバーイベントを読み取り続けてください。

最初のフレームのパラメーター

フィールド型説明
authorization.accessTokenstring必須。形式はBearer your-api-keyです
modelstring必須。muse-voice-transcribe-1.0を使用します
audioEncodingstring必須。リアルタイム音声ではPCM_16KHZまたはPCM_24KHZを使用します
modestring任意:PUSH_TO_TALK、ENDPOINTING、DIARIZATION
partialModestring任意:CUMULATIVEは累積テキストを返し、DELTAは新しく追加されたテキストを返します
keywordsstring[]任意。専門用語や固有名詞のヒントです
languageBiasstring[]任意。想定する言語のヒントです
emitAudioProgressboolean任意。音声処理の進捗イベントを返すかどうかを指定します
zdrOverrideboolean任意のデータ処理オプションです。利用可否は現在のサービスとアカウント権限によって異なります

音声入力

音声はWAVヘッダーを含まないPCM16 little-endianのモノラルデータで、最初のフレームで宣言した16 kHzまたは24 kHzのサンプリングレートと一致する必要があります。各音声フレームは1 MiB以下で、バイト数は偶数である必要があります。

100 msを1つの音声チャンクとして、リアルタイムの速度で送信することを推奨します。24 kHzでは4800バイト、16 kHzでは3200バイトに相当します。無音中も連続したタイムラインを維持する必要がある場合は、同じ形式のPCM無音データを送信してください。

# 24 kHz、モノラル、PCM16の生音声を生成
ffmpeg -i input.mp3 -ac 1 -ar 24000 -c:a pcm_s16le -f s16le audio.pcm

Pythonの例

WebSocketクライアントをインストールし、audio.pcmを準備してからサンプルを実行します。音声のアップロードによってサーバーイベントの処理が妨げられないように、送信と受信は別々のスレッドで行います。

python -m pip install websocket-client
WSSMuseリアルタイム文字起こし接続
import json
import sys
import threading
import websocket

url = "wss://api.agtcloud.cn/v1/asr/realtime"
stop = threading.Event()
sender = None
ws = websocket.create_connection(url, timeout=40, enable_multithread=True)

def send_audio():
    try:
        with open(sys.argv[1], "rb") as audio:
            while not stop.is_set():
                chunk = audio.read(4800)
                if not chunk:
                    break
                if len(chunk) % 2:
                    raise ValueError("PCMのバイト数は偶数である必要があります")
                ws.send_binary(chunk)
                if stop.wait(len(chunk) / 48000):
                    return
        if not stop.is_set():
            silence = bytes(4800)
            for _ in range(10):
                ws.send_binary(silence)
                if stop.wait(0.1):
                    return
            ws.send(json.dumps({"type": "endStream"}))
    except Exception as exc:
        print("送信が中断されました:", exc)
        stop.set()
        ws.close()

try:
    ws.send(json.dumps({
        "authorization": {"accessToken": "Bearer your-api-key"},
        "model": "muse-voice-transcribe-1.0",
        "audioEncoding": "PCM_24KHZ",
        "mode": "ENDPOINTING",
        "partialMode": "CUMULATIVE",
        "languageBias": ["Mandarin Chinese"],
        "emitAudioProgress": True
    }))
    ack = json.loads(ws.recv())
    if ack.get("type") == "error" or not ack.get("sessionId"):
        raise RuntimeError("接続の初期化に失敗しました: " + json.dumps(ack, ensure_ascii=False))
    print("sessionId:", ack["sessionId"])
    sender = threading.Thread(target=send_audio, daemon=True)
    sender.start()
    while not stop.is_set():
        message = ws.recv()
        if not message:
            break
        event = json.loads(message)
        print(json.dumps(event, ensure_ascii=False))
        if event.get("type") == "error":
            break
finally:
    stop.set()
    ws.close()
    if sender is not None:
        sender.join(timeout=2)

イベントReference

audioProcessedMsは累積処理の進捗を表すため、複数のイベントの値を加算しないでください。CUMULATIVEでは、新しい部分テキストが前回の累積結果を置き換えます。DELTAでは、増分テキストを追加してください。

サーバーイベント · 進捗

audioProgress

現在までに処理された音声の累積進捗を返します。

フィールド型必須説明例
typestringはい常に`audioProgress`です。audioProgress
audioProcessedMsintegerはい処理済み音声の累積時間(ミリ秒)です。1600
JSONの例
{
  "type": "audioProgress",
  "audioProcessedMs": 1600
}

speechComplete.transcriptには、現在の発話ターンの完全な文字起こし結果が含まれます。セッション終了時には、final: trueのtranscriptイベントにテキストが含まれない場合があります。クライアントは空文字列で、保存済みの累積テキストまたはspeechComplete.transcriptを上書きしないでください。

セッション制限とエラー処理

セッションの最長時間は約60分です。クライアントからのメッセージが15秒間連続して届かない場合、入力の終了処理が開始されることがあります。ネットワークやサーバーの状態によって接続が早期に終了する場合もあります。クライアントでは、全体の時間制限、読み取りタイムアウト、回数を制限した再試行を設定してください。

終了コード意味対処方法
1008ポリシーまたはプロトコルエラー最初のフレームの構造、認証、パラメーター、後続の制御メッセージを確認します
1011サーバーまたはアップストリームの中断sessionId、エラーイベント、終了理由を保存してから、再試行するかどうかを判断します
1013サービスの一時的な利用不可またはレート制限バックオフ戦略を使用して、回数を制限した再試行を行います

課金

リアルタイム文字起こしは処理済みの音声時間に基づいて課金されます。具体的な料金は、現在のサイトのモデル一覧を参照してください。進捗イベントのミリ秒値は処理タイムラインを表すものであり、個別の請求額としてイベントごとに加算しないでください。

参考資料