Multimodal: Entrada de Vídeo
Um agente em tempo real pode ver. Juntamente com o fluxo de áudio, você pode enviar quadros de imagem de uma câmera (ou tela) para o modelo, para que o usuário possa mostrar algo ao agente — um produto danificado para devolução, um erro em uma tela, um documento — em vez de descrevê-lo.
A API
Um método no runner, espelhando send_audio:
runner.send_video_frame("image/jpeg", &base64_jpeg).await?;
Também está disponível no RealtimeRunner de nível inferior e diretamente no RealtimeSession. A implementação de trait padrão é uma no-op, então provedores/modelos que não aceitam entrada visual simplesmente ignoram os quadros.
Como cada provedor lida com os quadros
Os dois backends tratam a visão de forma diferente, e isso deve moldar a frequência com que você envia os quadros:
| Provedor | Mecanismo | Cadência |
|---|---|---|
| Gemini Live | Contínuos realtimeInput blocos de mídia | Transmita-os — ~1–2 fps é natural |
| OpenAI Realtime | Uma input_image parte em um item de conversa | Snapshots — limitar a ~1 a cada poucos segundos |
Gemini é construído para vídeo contínuo: os quadros fluem como áudio e o modelo raciocina sobre a imagem em movimento. A visão em tempo real da OpenAI é imagem-em-contexto: cada quadro se torna um item de conversação, então enviar muitos por segundo inunda o contexto e custa mais. Envie um quadro para a OpenAI quando for útil (por exemplo, o usuário disse "olhe para isto"), não a cada tick.
As UIs de exemplo codificam isso:
const intervalMs = provider === 'gemini' ? 700 : 2500; // ~1.4 fps vs ~0.4 fps
Capturando quadros em um navegador
Pegue a câmera, desenhe o <video> para uma tela, e envie quadros JPEG pelo seu WebSocket (a ponte do lado do servidor os encaminha para send_video_frame):
const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 640, height: 480 } });
video.srcObject = stream;
const canvas = document.createElement('canvas');
setInterval(() => {
if (ws.readyState !== WebSocket.OPEN) return;
canvas.width = 640; canvas.height = 480;
canvas.getContext('2d').drawImage(video, 0, 0, 640, 480);
const data = canvas.toDataURL('image/jpeg', 0.6).split(',')[1]; // strip data: prefix
ws.send(JSON.stringify({ type: 'video_frame', mime: 'image/jpeg', data }));
}, intervalMs);
No servidor, encaminhe para o modelo:
ClientMsg::VideoFrame { mime, data } => {
let _ = runner.send_video_frame(&mime, &data).await; // non-fatal on error
}
Mantenha os quadros modestos (640×480, qualidade JPEG ~0.6) — a visão não precisa de resolução total, e quadros menores significam menor latência e custo.
Prompting para visão
Diga ao agente que ele pode ver, para que ele use a câmera naturalmente:
You can hear the customer and SEE what they show their camera. When they show
you an item (e.g. a damaged product for a return), briefly describe what you see
and use it to help resolve the issue.
Experimente
O exemplo customer_service possui um painel de câmera:
inicie a câmera, segure um objeto e diga "Quero devolver isso — você consegue
ver?". Funciona melhor no Gemini (vídeo contínuo); no OpenAI o agent raciocina
sobre os instantâneos periódicos.
Próximo: Diálogo afetivo →