MiniCPM-o Docs
Realtime API

视频双工

Realtime API 的视频全双工协议

视频双工模式用于实时音视频对话。客户端持续发送 16 kHz 音频,可在每个输入包中携带 JPEG 视频帧;服务端以 response.output.delta 返回 listen、文本和音频输出。

连接

wss://host/v1/realtime?mode=video
项目
帧格式JSON 文本帧
上行音频16 kHz,单声道,float32 PCM,base64 编码
上行视频JPEG,base64 编码,字段为 input.video_frames
下行音频24 kHz,单声道,float32 PCM,base64 编码
会话总时长上限300 秒

初始化

连接后等待 session.queue_done,然后发送 session.init

{
  "type": "session.init",
  "payload": {
    "system_prompt": "你是一个有用的视频语音助手",
    "config": {
      "length_penalty": 1.1
    },
    "voice": {
      "ref_audio_base64": "<base64 float32 PCM>",
      "tts_ref_audio_base64": "<base64 float32 PCM>"
    }
  }
}
字段类型必填说明
system_promptstring系统提示词。也可使用 instructions
configobject双工推理配置;当前常用 length_penalty
voice.ref_audio_base64stringLLM 参考音频
voice.tts_ref_audio_base64stringTTS 参考音频;未提供时可复用 LLM 参考音频

初始化完成后服务端发送 session.created

发送输入

{
  "type": "input.append",
  "input": {
    "audio": "<base64 float32 PCM, 16 kHz mono>",
    "video_frames": ["<base64 JPEG>"],
    "force_listen": false,
    "max_slice_nums": 1
  }
}
字段类型必填说明
audiostring16 kHz 单声道 float32 PCM。浏览器 demo 通常每秒发送一个 chunk
video_framesstring[]JPEG 帧列表。视频模式建议随输入持续携带
force_listenbool强制模型回到 listen 状态
max_slice_numsint本次输入的视频切片数,默认 1
hints.force_listenboolforce_listen 的等价位置
hints.max_slice_numsintmax_slice_nums 的等价位置

接收输出

模型继续听时:

{
  "type": "response.output.delta",
  "kind": "listen",
  "session_id": "sess_xxx",
  "metrics": {
    "kv_cache_length": 1024,
    "vision_slices": 1,
    "vision_tokens": 64
  }
}

文本增量:

{
  "type": "response.output.delta",
  "kind": "text",
  "text": "我看到了",
  "response_id": "resp_xxx",
  "metrics": {}
}

音频增量:

{
  "type": "response.output.delta",
  "kind": "audio",
  "audio": "<base64 float32 PCM, 24 kHz mono>",
  "response_id": "resp_xxx",
  "metrics": {}
}

文本和音频是独立 delta,不保证一一对应。客户端应分别更新字幕和音频播放队列;收到 kind=listen 可视为模型回到听用户输入的状态。

时序

Client connects
  <- session.queued / session.queue_update   optional
  <- session.queue_done
  -> session.init { payload: {...} }
  <- session.created
  -> input.append { input: { audio, video_frames } }
  -> input.append { input: { audio, video_frames } }
  <- response.output.delta { kind: "listen" }
  -> input.append { input: { audio, video_frames } }
  <- response.output.delta { kind: "text", text: "..." }
  <- response.output.delta { kind: "audio", audio: "..." }
  <- response.output.delta { kind: "listen" }
  -> session.close
  <- session.closed

视频双工不使用 response.done 表示每轮结束;输出边界由 kind=listen、后续输入和 session.closed 表达。

关闭

{
  "type": "session.close",
  "reason": "user_stop"
}

服务端会尽力返回 session.closed。如果达到 300 秒上限,gateway 会发送:

{
  "type": "session.closed",
  "reason": "timeout"
}

On this page