リアルタイムインタラクション
MOSS-Liveを使用して、1本のWebSocketでリアルタイム音声対話を行い、カメラや画面共有と組み合わせて映像を理解します。
/v1/realtimemoss-live-1.0APIキーを作成
APIキー管理プラットフォームでキーを作成し、サーバー側の環境変数でのみ使用してください。
環境変数 MOSS_API_KEY=<your_api_key_here>接続と認証
サーバー側のWebSocketクライアントでAPIに接続します。クエリパラメータでモデルを指定し、ハンドシェイクのリクエストヘッダーでAPIキーを渡します。
フィールド型必須説明モデルIDです。moss-live-1.0で固定です。WebSocket接続URLのクエリパラメータに指定します。
Bearer
<API Key>。WebSocketハンドシェイクのリクエストヘッダーにのみ指定できます。接続URL wss://api.mosi.cn/v1/realtime?model=moss-live-1.0 Authorization: Bearer $MOSS_API_KEYセッションを設定
接続に成功したら
attach_sessionを送信します。session_attachedを受信してsession_idを保存した後、session.updateでペルソナと業務ルールを設定します。session.updatedを待ってdata.errorを確認します。空文字列であれば設定は成功です。その後でメディアを有効にします。フィールド型必須説明デフォルトのペルソナを置き換えます。最大8000文字です。
アシスタントの名前と別名です。呼びかけの認識と文字起こしの補正に使用します。
業務ルールです。ペルソナは変更しません。このフィールドのみを渡した場合、元のペルソナが保持されます。
ペルソナと業務指示を設定 { "action": "session.update", "session": { "persona": { "name": "アン", "aliases": [ "アンちゃん" ], "prompt": "あなたはフレンドリーなアシスタントのアンです。口調は穏やかで簡潔です。" }, "instructions": "中国語の短い一文で答えてください。" } }リアルタイム音声と映像を送信
音声と映像は1本のWebSocketを共有します。セッションの設定に成功したら、まず必要な入力を有効にします。
入力を有効化 · 制御イベント // マイクをオンにします {"action":"mic_state","enabled":true} // 映像が必要な場合は、先にtagged-v1を有効にします {"action":"media.mode","binary_protocol":"tagged-v1"} // カメラをオンにします。画面共有の場合はsourceをscreenに変更します {"action":"video.state","source":"camera","enabled":true}音声はリアルタイムの速度で継続的に送信します。形式は16 kHz、モノラルのPCM S16LEです。発話が終わった後も無音フレームを送信し続けます。tagged-v1を有効にした後は、各音声メッセージの先頭に0x00を付けます。
映像は1フレームずつJPEGとして個別に送信します。tagged-v1を有効にした後は、カメラのフレームの先頭に0x01、画面のフレームの先頭に0x02を付けます。
Node.js ws · メディアを送信 // wsは確立済みの接続、pcmBytes / jpegBytesはキャプチャしたBufferです。 ws.send(Buffer.concat([Buffer.from([0x00]), pcmBytes])); // 音声 ws.send(Buffer.concat([Buffer.from([0x01]), jpegBytes])); // カメラ ws.send(Buffer.concat([Buffer.from([0x02]), jpegBytes])); // 画面注目するソースを選択します:camera、screen、またはauto。autoは、両方の映像に入力がある場合にカメラを優先します。
注目する映像を選択 { "action": "video.stream_focus", "source": "screen" }回答の受信と表示
input.transcript.doneのユーザーの文字起こしとoutput.transcript.doneの回答テキストを表示し、48 kHz、モノラルのPCM S16LEを順番に再生して、response.audio.contextとの対応関係を保持します。各音声チャンクの再生が実際に終わったらplayback.chunk.completedを送信します。response.audio.doneを受信し、このターンの再生がすべて完了したらplayback.completedを送信します。再生の確認は、回答テキストの終了を待たずに行ってください。response.audio.stopを受信したら該当する再生を停止し、playback.stoppedを送信して、まだ確認していない現在の音声チャンクを実際に再生した長さを返します。回答が割り込まれるとresponse.interruptedを受信します。response.endedのdata.statusがcompleted、aborted、failedのいずれの場合も、このターンは終了しています。音声チャンクの再生完了 { "action": "playback.chunk.completed", "chunk_id": "<chunk_id>", "run_id": "<run_id>", "turn_id": "<turn_id>" }このターンの再生完了 { "action": "playback.completed", "run_id": "<run_id>", "turn_id": "<turn_id>" }再生を停止 { "action": "playback.stopped", "run_id": "<run_id>", "turn_id": "<turn_id>", "played_audio_ms": 1200 }対話を終了
画面を停止する場合はsourceをscreenに変更し、同時にそのソースのJPEGの送信も停止します。映像を停止するだけでは、セッションは終了せず、課金も停止しません。音声は引き続き0x00プレフィックスを使用します。課金は
session_attachedから接続が閉じるまでが対象で、終了後に非同期で精算されます。通話中に料金がリアルタイムで差し引かれることはなく、残高の変化を理由に通話が中断されることもありません。カメラを停止 { "action": "video.state", "source": "camera", "enabled": false }セッションを終了 ws.close(); stream?.getTracks().forEach(track => track.stop()); // 音声キューをクリアし、キャプチャと再生のリソースを解放します。成功を確認
input.transcript.done、output.transcript.done、音声を受信し、実際の再生確認を完了して、最終的にdata.status=completedのresponse.endedを受信します。この間、errorは一度も発生しません。