En esta guía, se proporcionan instrucciones y prácticas recomendadas para los ingenieros que crean experiencias de pedidos de comida con el método RPC FoodOrderingService.BidiProcessOrder.
Esta API de transmisión bidireccional en tiempo real es el núcleo del agente de IA de pedidos de comida, lo que permite la toma de pedidos conversacionales y dinámicos en varias aplicaciones, como apps para dispositivos móviles, asistentes de voz, autoservicios y quioscos.
Descripción general de BidiProcessOrder
El método BidiProcessOrder establece un canal de comunicación bidireccional persistente entre tu aplicación cliente y el agente de IA de pedidos de comida. A diferencia de las RPC de solicitud y respuesta unarias estándar, este enfoque de transmisión permite lo siguiente:
- Interacción de baja latencia: Intercambio continuo de información sin la sobrecarga de solicitudes HTTP repetidas.
- Entrada multimodal: Manejo de transmisiones de audio (para pedidos por voz), entradas de texto y eventos del cliente.
- Respuestas en tiempo real: El agente puede enviar audio, texto, actualizaciones de pedidos y otros indicadores a medida que se desarrolla la conversación.
BidiProcessOrder No se puede invocar con REST. Las integraciones deben usar un protocolo orientado a la conexión:
- gRPC (recomendado): Proporciona un framework sólido y eficiente para la transmisión bidireccional.
- WebSocket: Adecuado para clientes o entornos en los que gRPC no es adecuado debido a restricciones de lenguaje de programación o de red.
Consulta la referencia de la API de BidiProcessOrder para obtener definiciones de tipos detalladas. Las integraciones de WebSocket usan representaciones JSON de estos tipos, como se describe en la sección WebSocket.
Requisitos previos
Antes de realizar la integración con BidiProcessOrder, haz lo siguiente:
Habilita la API: Asegúrate de que la API del agente de IA de pedidos de comida esté habilitada en tu Google Cloud proyecto.
bash gcloud services enable foodorderingaiagent.googleapis.com --project=PROJECT_IDAutenticación: Decide tu enfoque de autenticación y configura las cuentas de servicio y los roles de IAM necesarios, como se describe en Autenticación.
Ingesta de menú: Se debe ingerir un menú válido y asociarlo con un
Store. Consulta Integra datos de menú Data para obtener más detalles.
Autenticación
Para conectarte de forma segura a la BidiProcessOrder RPC, tu aplicación debe
autenticarse con una Google Cloud cuenta de servicio.
1. Configura una cuenta de servicio
- Crea una cuenta de servicio: En tu Google Cloud proyecto, crea una cuenta de servicio que tu aplicación usará para autenticarse en la API del agente de IA de pedidos de comida. Consulta Crea y administra cuentas de servicio.
Otorga roles de IAM: Otorga los roles de IAM necesarios a esta cuenta de servicio. El rol principal necesario para llamar a
BidiProcessOrderes el siguiente:- Usuario del agente de pedidos de comida (
roles/foodorderingaiagent.agentUser): Permite que la cuenta de servicio se conecte al servicio de pedidos y procese sesiones.
Puedes otorgar este rol con la Google Cloud consola de o
gcloud:bash gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \ --role="roles/foodorderingaiagent.agentUser"- Usuario del agente de pedidos de comida (
2. Flujo de autenticación de la aplicación
El flujo de autenticación exacto depende de la arquitectura de tu aplicación, en especial si la aplicación cliente (p.ej., app para dispositivos móviles, software de quiosco) se conecta directamente o a través de tu propio backend.
Situación común: Autenticación de una aplicación cliente para el consumidor
Este es un patrón típico para aplicaciones web o para dispositivos móviles:
- Client-to-YourAuth: La app cliente del usuario final (para dispositivos móviles o web) se autentica con tu sistema de autenticación de usuarios existente (puede ser Firebase Authentication, tu propio servidor de OAuth, etcétera).
- Intercambio de tokens: Después de autenticar al usuario, la app cliente solicita un token de corta duración de un servicio de backend seguro que tú controlas (p.ej., un "servicio de tokens de API").
Generación de tokens de acceso: Tu servicio de backend, con las credenciales de la Google Cloud principal de la cuenta de servicio configurada en el paso 1, genera un token de acceso estándar de OAuth 2.0 para el
https://www.googleapis.com/auth/cloud-platformalcance. Esto se puede hacer con las Google Cloud bibliotecas cliente de Authentication.- Seguridad: Las claves o credenciales de la cuenta de servicio que se usan para generar estos tokens deben almacenarse y administrarse de forma segura en tu backend. Nunca expongas las claves privadas de la cuenta de servicio directamente a las aplicaciones cliente del usuario final. Consulta las prácticas recomendadas para administrar claves de cuenta de servicio.
Token para el cliente: Tu servicio de backend devuelve el token de acceso de Google generado a la app cliente.
Llamada a la API: La app cliente usa este token de acceso de Google para autenticar su conexión gRPC o WebSocket a la RPC
BidiProcessOrder.
3. Usa el token de
- gRPC: Por lo general, las bibliotecas cliente de gRPC de Google controlan la actualización de tokens y la inclusión en los metadatos de la llamada cuando se proporcionan credenciales de cuenta de servicio.
- WebSocket (no navegador): Incluye el token en el encabezado
Authorization: Bearer TOKEN. - WebSocket (navegador): Como se indicó en la sección WebSocket, las conexiones directas de WebSocket del navegador no pueden usar encabezados de autorización. Se necesita un proxy de transmisión del servidor para autenticar la conexión de tus clientes a Google Cloud.
Conéctate a la API
Puedes establecer una transmisión con las bibliotecas cliente de gRPC o una conexión WebSocket.
gRPC
Se recomienda usar gRPC. Usarás las bibliotecas cliente para el lenguaje que elijas (p.ej., Node.js), que se basan en la referencia de la API de BidiProcessOrder.
Los pasos básicos son los siguientes:
- Crea un canal gRPC para el extremo de API del agente de IA de Pedidos de comida (p.ej.,
foodorderingaiagent.googleapis.com). - Obtén un stub de cliente para
FoodOrderingService. - Invoca el método
BidiProcessOrder, que devuelve un objeto de transmisión para enviar solicitudes y recibir respuestas. - Implementa la lógica empresarial según tu caso de uso, que se ejecuta de forma simultánea:
- Envía audio, texto y entrada de eventos del usuario final.
- Maneja mensajes del agente, incluidos audio, texto y eventos.
Node.js
const {FoodOrderingServiceClient} = require('@google-cloud/foodorderingaiagent');
const client = new FoodOrderingServiceClient();
// The stream is initialized immediately. You can now write commands and attach listeners.
const stream = client.bidiProcessOrder();
WebSocket
Para las conexiones WebSocket, la ruta de URL es la siguiente:
wss://foodorderingaiagent.googleapis.com/ws/google.cloud.foodorderingaiagent.v1beta.FoodOrderingService/BidiProcessOrder/locations/LOCATION
LOCATION: p.ej.,us
Encabezados obligatorios:
Authorization:Bearer TOKEN(dondeTOKENes un token de acceso de OAuth 2.0 obtenido para tu cuenta de servicio)
Formato del mensaje:
- Cliente a servidor: Los mensajes enviados a la API (p.ej.,
Config,AudioInput,TextInput,EventInput) deben ser representaciones JSON del protoBidiProcessOrderRequest, que se envían comowebsocket.TextMessage. - Servidor a cliente: Los mensajes recibidos de la API (
BidiProcessOrderResponse) se enviarán comowebsocket.BinaryMessage, pero el contenido de estos mensajes binarios es una carga útil de JSON. - Datos binarios: Los datos binarios dentro de las cargas útiles de JSON (p.ej.,
customerAudioenAudioInput,agentAudioenAgentAudio) deben estar codificados en base64.
Ejemplo de WebSocket de Node.js
A continuación, se muestra un ejemplo de cómo conectarse e interactuar con la API mediante WebSockets en Node.js con la biblioteca ws:
const WebSocket = require('ws');
// Replace with your actual values
const location = 'LOCATION';
const projectId = 'PROJECT_ID';
const sessionId = 'SESSION_ID';
const brandId = 'BRAND_ID';
const storeId = 'STORE_ID';
const token = 'OAUTH_TOKEN';
const wsUrl = `wss://foodorderingaiagent.googleapis.com/ws/google.cloud.foodorderingaiagent.v1beta.FoodOrderingService/BidiProcessOrder/locations/${location}`;
const ws = new WebSocket(wsUrl, {
headers: {
'Authorization': `Bearer ${token}`
}
});
ws.on('open', () => {
console.log('Connected to WebSocket');
// 1. Send the required initial Config message
const configRequest = {
config: {
session: `projects/${projectId}/locations/${location}/sessions/${sessionId}`,
store: `projects/${projectId}/locations/${location}/brands/${brandId}/stores/${storeId}`
}
};
// Client-to-server messages are sent as TextMessage
ws.send(JSON.stringify(configRequest));
console.log('Sent Config message');
});
ws.on('message', (data, isBinary) => {
// The documentation specifies that server-to-client messages
// are sent as BinaryMessage containing a JSON payload.
if (isBinary) {
try {
const response = JSON.parse(data.toString('utf8'));
console.log('Received response:', response);
if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
}
if (response.agentAudio) {
const audioBytes = Buffer.from(response.agentAudio.agentAudio, 'base64');
console.log(`Received ${audioBytes.length} bytes of agent audio.`);
// Play or process the audio bytes here
}
if (response.endSession) {
console.log('Session ended by agent.');
ws.close();
}
} catch (e) {
console.error('Failed to parse JSON response:', e);
}
}
});
ws.on('close', () => {
console.log('Connection closed');
});
Ciclo de vida de la sesión
Cada llamada a BidiProcessOrder inicia una sesión. La sesión permanece activa mientras la transmisión esté abierta.
1. Inicio (mensaje de configuración)
- Al establecer la conexión, el primer mensaje que envía el cliente
debe ser un
BidiProcessOrderRequestque contenga elConfigmensaje. - Campos obligatorios en
Config:session: Un identificador de sesión único generado por el cliente. Formato:projects/PROJECT/locations/LOCATION/sessions/SESSION_ID.store: El nombre del recurso deStore. Formato:projects/PROJECT/locations/LOCATION/brands/BRAND/stores/STORE.- El agente usa el
storepara cargar el menú y la configuración adecuados.
- El agente usa el
mode(opcional paraBidiProcessOrder): El valor predeterminado esHYBRID(voz y texto). Ten en cuenta que, si usas la API de REST o gRPC unariaProcessOrderen lugar deBidiProcessOrder,modedebe establecerse de forma explícita enTEXT.
Node.js
// Send the first message containing Config
stream.write({
config: {
session: client.sessionPath(projectId, location, sessionId),
store: client.storePath(projectId, location, brandId, storeId),
}
});
2. Envía entradas
- Después de la
Configinicial, el cliente puede enviar una transmisión de mensajesBidiProcessOrderRequestque contenga una de las siguientes entradas:AudioInput: Datos de audio sin procesar (por lo general, PCM lineal de 16 bits a 16,000 Hz, sin encabezados). Se usa para interacciones de voz.TextInput: Mensajes de texto del usuario.EventInput: Indicadores para eventos comoDriveOffEvent(para casos de uso de autoservicio cuando el vehículo se va),CrewInterjectionEvent(para cualquier situación en la que un humano asume el rol de toma de pedidos en medio de la conversación) oOrderStateUpdateEvent(si el pedido se modifica en el cliente, p.ej., con una interfaz táctil).
Node.js
// Stream user inputs over the active connection
stream.write({textInput: {text: 'Hi, I\'d like to order a cheeseburger.'}});
3. Recibe respuestas
- De forma simultánea, el agente envía una transmisión de mensajes
BidiProcessOrderResponse. Tu cliente debe estar preparado para controlar varios tipos de respuesta dentro del campooneof response:AgentAudio: Bytes de audio sintetizados para reproducir al usuario, que se usan para interacciones de voz.AgentText: Versión de texto de la respuesta del agente.SpeechRecognition: Transcripción del discurso reconocido del usuario.UpdatedOrderState: Contiene el estado actual completo del clienteOrdercada vez que el agente lo actualiza. Úsalo para actualizar la representación del pedido de tu aplicación. Por lo general, esto debería generar una actualización de una interfaz de usuario o un sistema de registro para la información del estado del pedido, como un sistema de punto de venta.InterruptionSignal: Indica que el usuario interrumpió el discurso del agente. El cliente debe dejar de reproducir de inmediato cualquierAgentAudiosaliente.AgentEvent:Eventos especiales, comoRestartOrder,que requieren la acción del cliente.SuggestedOptions: Proporciona opciones contextualmente relevantes que un usuario podría seleccionar a continuación, lo que es útil para mostrar en una pantalla.EndSession: Indica que el agente finalizó la sesión (p.ej., pedido completado, el usuario se fue o escalamiento del agente).
Node.js
// Attach event listeners to handle responses sequentially
stream.on('data', (response) => {
if (response.agentAudio) {
console.log(`Received ${response.agentAudio.agentAudio.length} bytes of agent audio.`);
} else if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
} else if (response.speechRecognition) {
console.log(`Recognized User Speech: ${response.speechRecognition.transcript}`);
} else if (response.updatedOrderState) {
console.log('Order updated.');
} else if (response.interruptionSignal) {
console.log('User interrupted the agent. Stop playing audio!');
} else if (response.endSession) {
console.log(`Session ended. Type: ${response.endSession.type}, Reason: ${response.endSession.reason}`);
stream.end();
}
});
stream.on('error', (err) => {
console.error('Stream error:', err);
});
4. Cierra la transmisión
- El cliente o el servidor pueden cerrar la transmisión. Por lo general, el servidor indica el final de una conversación con un mensaje
EndSession. El cliente debe cerrar la transmisión cuando se recibe este mensaje.
Maneja tipos de mensajes específicos
En las siguientes secciones, se describe cómo manejar tipos de respuesta específicos que recibirá tu cliente cuando llame a BidiProcessOrder.
AudioInput
- Transmite audio en fragmentos a medida que esté disponible.
- Formato: PCM lineal de 16 bits, tasa de muestreo de 16,000 Hz.
- Los fragmentos de audio no incluyen los encabezados de audio que suelen preceder a un archivo WAV.
- Para situaciones de autoservicio con cancelación de eco habilitada (
enable_echo_cancellationenConfig), proporcionacustomer_audioycrew_audio.
UpdatedOrderState
- Este mensaje proporciona el estado completo del pedido cada vez que se envía.
Reemplaza cualquier caché local del pedido por el contenido del mensaje
Orderrecibido. - Usa los
custom_integration_attributesdentro de los elementos y modificadoresOrderpara asignar el contenidoOrdera entidades equivalentes dentro del sistema de registro de tu aplicación.
InterruptionSignal
- Al recibirlo, detén de inmediato la reproducción de cualquier
AgentAudioy borra cualquier audio del agente almacenado en búfer. Esto garantiza un flujo conversacional natural cuando el usuario interrumpe el discurso del agente.
EndSession
- Verifica el
EndType(p.ej.,DRIVE_OFF,AGENT_ESCALATION). - Tu aplicación debe cerrar la conexión correctamente y realizar la transición del usuario de forma adecuada (p.ej., notificar a un supervisor humano en el caso de
AGENT_ESCALATIONo realizar la transición a un estado de confirmación del pedido).
Prácticas recomendadas
- Maneja mensajes de forma asíncrona: Minimiza la latencia con subprocesos o E/S sin bloqueo para enviar solicitudes y procesar respuestas entrantes de forma simultánea.
- Lógica de reconexión: Implementa una lógica de reconexión sólida en caso de problemas de red. Recuerda enviar el mensaje
Configinicial con el mismo ID de sesión para intentar reanudar la conexión. - Manejo de errores: Supervisa la transmisión en busca de errores. Las bibliotecas de gRPC y WebSocket proporcionan mecanismos para detectar el cierre de la transmisión o errores de transporte. Registra estos eventos y manéjalos correctamente.
- Almacenamiento en búfer de audio: Administra los búferes de audio con cuidado. Implementa el almacenamiento en búfer si es necesario para garantizar la reproducción fluida de
AgentAudioy la entrega oportuna deAudioInput. Considera cuidadosamente la compensación entre la latencia y la calidad de reproducción cuando decidas tu esquema de almacenamiento en búfer. - Administración de ID de sesión: Asegúrate de que los IDs de sesión sean únicos para cada pedido o conversación distintos.
- Administración de recursos: Cierra las transmisiones y libera recursos cuando se complete la sesión o si se producen errores irrecuperables.
- Tiempos de espera: Si bien la transmisión en sí puede ser de larga duración (hasta 15 minutos de forma predeterminada), considera los tiempos de espera a nivel de la aplicación para estados específicos si es necesario.
Ejemplo de flujo de integración (conceptual)
- La app cliente (p.ej., app para dispositivos móviles) inicia un pedido.
- Establece la conexión gRPC o WebSocket a
BidiProcessOrder. - Envía
BidiProcessOrderRequestconConfig(ID de sesión, ID de tienda). - Recibe el
AgentAudioinicial (p.ej., mensaje de bienvenida) y reprodúcelo. - El usuario habla: Captura el audio y transmítelo en mensajes
AudioInput. - Recibe
SpeechRecognition(muestra la transcripción),AgentAudio(reproduce la respuesta) y, posiblemente,UpdatedOrderState(actualiza el carrito de la IU). - Si el usuario interrumpe, recibe
InterruptionSignaly detiene la reproducción. - Continúa el intercambio de entradas de audio o texto y respuestas del agente.
- El usuario confirma el pedido: El agente envía el
UpdatedOrderStatefinal. - El agente envía
EndSession: El cliente cierra la transmisión y finaliza el pedido en el sistema de PdV con los datos del últimoUpdatedOrderState.
Ejemplo de extremo a extremo
Si bien las instrucciones anteriores desglosan los conceptos de transmisión paso a paso, a continuación, se muestra cómo es un flujo de integración completo de extremo a extremo.
Node.js
Antes de probar este ejemplo, sigue las instrucciones de configuración que se encuentran en la guía de inicio rápido del agente de IA de pedidos de comida sobre el uso de bibliotecas cliente.Node.js
Para autenticarte en el agente de IA de pedidos de comida, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.
const {FoodOrderingServiceClient} = require('@google-cloud/foodorderingaiagent');
async function bidiProcessOrderSample(projectId, location, brand, store, sessionId) {
const client = new FoodOrderingServiceClient();
// Create the resource names
const sessionPath = client.sessionPath(projectId, location, sessionId);
const storePath = client.storePath(projectId, location, brand, store);
// Initialize the stream using gRPC. See the WebSocket section for the equivalent WebSocket implementation.
const stream = client.bidiProcessOrder();
// Attach event listeners to handle responses sequentially
stream.on('data', (response) => {
if (response.agentAudio) {
console.log(`Received ${response.agentAudio.agentAudio.length} bytes of agent audio.`);
} else if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
} else if (response.speechRecognition) {
console.log(`Recognized User Speech: ${response.speechRecognition.transcript}`);
} else if (response.updatedOrderState) {
console.log('Order updated.');
} else if (response.interruptionSignal) {
console.log('User interrupted the agent. Stop playing audio!');
} else if (response.endSession) {
console.log(`Session ended. Type: ${response.endSession.type}, Reason: ${response.endSession.reason}`);
stream.end();
}
});
stream.on('error', (err) => {
console.error('Stream error:', err);
});
// 1. Send the first message containing Config
stream.write({
config: {
session: sessionPath,
store: storePath,
}
});
// 2. Stream user inputs over the active connection
stream.write({textInput: {text: 'Hi, I\'d like to order a cheeseburger.'}});
}