Panduan ini memberikan petunjuk dan praktik terbaik bagi engineer yang membangun pengalaman pemesanan makanan dengan metode RPC FoodOrderingService.BidiProcessOrder.
API streaming dua arah real-time ini adalah inti dari Agen AI Pemesanan Makanan, yang memungkinkan pengambilan pesanan secara dinamis dan percakapan di berbagai aplikasi seperti aplikasi seluler, asisten suara, layanan drive-thru, dan kios.
Ringkasan BidiProcessOrder
Metode BidiProcessOrder membuat saluran komunikasi dua arah yang persisten antara aplikasi klien Anda dan Agen AI Pemesanan Makanan. Tidak seperti RPC permintaan dan respons unary standar, pendekatan streaming ini memungkinkan:
- Interaksi latensi rendah: Pertukaran informasi berkelanjutan tanpa overhead permintaan HTTP berulang.
- Input multimodal: Penanganan aliran audio (untuk pemesanan suara), input teks, dan peristiwa sisi klien.
- Respons real-time: Agen dapat mengirim kembali audio, teks, pembaruan pesanan, dan sinyal lainnya saat percakapan berlangsung.
BidiProcessOrder tidak dapat dipanggil menggunakan REST. Integrasi harus menggunakan protokol berorientasi koneksi:
- gRPC (Direkomendasikan): Menyediakan framework yang andal dan efisien untuk streaming dua arah.
- WebSocket: Cocok untuk klien atau lingkungan yang tidak sesuai dengan gRPC karena batasan bahasa pemrograman atau jaringan.
Lihat Referensi API BidiProcessOrder untuk mengetahui definisi jenis yang mendetail. Integrasi WebSocket menggunakan representasi JSON dari jenis ini, seperti yang dijelaskan di bagian WebSocket.
Prasyarat
Sebelum mengintegrasikan dengan BidiProcessOrder:
Aktifkan API: Pastikan Food Ordering AI Agent API diaktifkan di project Google Cloud Anda.
bash gcloud services enable foodorderingaiagent.googleapis.com --project=PROJECT_IDAutentikasi: Tentukan pendekatan autentikasi Anda dan siapkan akun layanan serta peran IAM yang diperlukan, seperti yang dijelaskan dalam Autentikasi.
Penyerapan Menu: Menu yang valid harus diserap dan dikaitkan dengan
Store. Lihat Mengintegrasikan Data Menu untuk mengetahui detailnya.
Autentikasi
Untuk terhubung dengan aman ke RPC BidiProcessOrder, aplikasi Anda harus
mengautentikasi menggunakan Akun Layanan Google Cloud .
1. Mengonfigurasi Akun Layanan
- Buat Akun Layanan: Di project Google Cloud Anda, buat Akun Layanan yang akan digunakan aplikasi Anda untuk mengautentikasi ke Food Ordering AI Agent API. Lihat Membuat dan mengelola akun layanan.
Berikan Peran IAM: Berikan peran IAM yang diperlukan ke akun layanan ini. Peran utama yang diperlukan untuk memanggil
BidiProcessOrderadalah:- Pengguna Agen Pemesanan Makanan (
roles/foodorderingaiagent.agentUser): Memungkinkan akun layanan terhubung ke layanan pemesanan dan memproses sesi.
Anda dapat memberikan peran ini menggunakan konsol Google Cloud atau
gcloud:bash gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \ --role="roles/foodorderingaiagent.agentUser"- Pengguna Agen Pemesanan Makanan (
2. Alur Autentikasi Aplikasi
Alur autentikasi yang tepat bergantung pada arsitektur aplikasi Anda, terutama apakah aplikasi klien (misalnya, aplikasi seluler, software kios) terhubung secara langsung atau melalui backend Anda sendiri.
Skenario Umum: Mengautentikasi aplikasi klien yang berinteraksi dengan konsumen
Berikut adalah pola umum untuk aplikasi seluler atau web:
- Client-to-YourAuth: Aplikasi klien pengguna akhir (seluler, web) melakukan autentikasi dengan sistem autentikasi pengguna yang sudah ada milik Anda (bisa berupa Firebase Authentication, server OAuth Anda sendiri, dll.).
- Pertukaran Token: Aplikasi klien, setelah mengautentikasi pengguna, meminta token berdurasi singkat dari layanan backend aman yang Anda kontrol (misalnya, "Layanan Token API").
Pembuatan Token Akses: Layanan backend Anda, menggunakan kredensial akun utama Google Cloud Akun Layanan yang dikonfigurasi di Langkah 1, menghasilkan token akses OAuth 2.0 standar untuk cakupan
https://www.googleapis.com/auth/cloud-platform. Hal ini dapat dilakukan menggunakan library klien autentikasiGoogle Cloud .- Keamanan: Kunci atau kredensial akun layanan yang digunakan untuk membuat token ini harus disimpan dan dikelola dengan aman di backend Anda. Jangan pernah mengekspos kunci pribadi akun layanan secara langsung ke aplikasi klien pengguna akhir. Lihat Praktik terbaik untuk mengelola kunci akun layanan.
Token ke Klien: Layanan backend Anda menampilkan token akses Google yang dibuat ke aplikasi klien.
Panggilan API: Aplikasi klien menggunakan token akses Google ini untuk mengautentikasi koneksi gRPC atau WebSocket-nya ke RPC
BidiProcessOrder.
3. Menggunakan Token
- gRPC: Library klien gRPC Google biasanya menangani perpanjangan masa berlaku token dan penyertaan dalam metadata panggilan saat diberikan kredensial akun layanan.
- WebSocket (Non-Browser): Sertakan token di header
Authorization: Bearer TOKEN. - WebSocket (Browser): Seperti yang disebutkan di bagian WebSocket, koneksi WebSocket browser langsung tidak dapat menggunakan header Otorisasi. Proxy streaming sisi server diperlukan untuk mengautentikasi koneksi klien Anda ke Google Cloud.
Menghubungkan ke API
Anda dapat membuat streaming menggunakan library klien gRPC atau koneksi WebSocket.
gRPC
Menggunakan gRPC adalah pendekatan yang direkomendasikan. Anda akan menggunakan library klien untuk bahasa pilihan Anda (misalnya, Node.js) yang didasarkan pada Referensi API BidiProcessOrder.
Langkah-langkah dasarnya meliputi:
- Buat saluran gRPC ke endpoint API Agen AI Pemesanan Makanan (misalnya,
foodorderingaiagent.googleapis.com). - Dapatkan stub klien untuk
FoodOrderingService. - Panggil metode
BidiProcessOrder, yang menampilkan objek stream untuk mengirim permintaan dan menerima respons. - Terapkan logika bisnis sesuai dengan kasus penggunaan Anda yang secara bersamaan:
- Mengirimkan input audio, teks, dan peristiwa dari pengguna akhir.
- Menangani pesan dari agen, termasuk audio, teks, dan peristiwa.
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
Untuk koneksi WebSocket, jalur URL-nya adalah:
wss://foodorderingaiagent.googleapis.com/ws/google.cloud.foodorderingaiagent.v1beta.FoodOrderingService/BidiProcessOrder/locations/LOCATION
LOCATION: misalnya,us
Header yang Wajib Ada:
Authorization:Bearer TOKEN- DenganTOKENadalah token akses OAuth 2.0 yang diperoleh untuk akun layanan Anda.
Format Pesan:
- Klien ke Server: Pesan yang dikirim ke API (misalnya,
Config,AudioInput,TextInput,EventInput) harus berupa representasi JSON dari protoBidiProcessOrderRequest, yang dikirim sebagaiwebsocket.TextMessage. - Server ke Klien: Pesan yang diterima dari API
(
BidiProcessOrderResponse) akan dikirim sebagaiwebsocket.BinaryMessage, tetapi konten pesan biner ini adalah payload JSON. - Data Biner: Data biner dalam payload JSON (misalnya,
customerAudiodalamAudioInput,agentAudiodalamAgentAudio) harus dienkode base64.
Contoh WebSocket Node.js
Berikut contoh cara menghubungkan dan berinteraksi dengan API menggunakan WebSockets di Node.js dengan library 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');
});
Siklus Proses Sesi
Setiap panggilan ke BidiProcessOrder memulai sesi. Sesi tetap aktif
selama aliran terbuka.
1. Inisiasi (Pesan Konfigurasi)
- Setelah koneksi dibuat, pesan pertama yang dikirim oleh klien harus berupa
BidiProcessOrderRequestyang berisi pesanConfig. - Kolom Wajib Diisi di
Config:session: ID sesi unik yang dibuat klien. Format:projects/PROJECT/locations/LOCATION/sessions/SESSION_ID.store: Nama resourceStore. Format:projects/PROJECT/locations/LOCATION/brands/BRAND/stores/STORE.- Agen menggunakan
storeuntuk memuat menu dan konfigurasi yang sesuai.
- Agen menggunakan
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. Mengirim Input
- Setelah
Configawal, klien dapat mengirimkan aliran pesanBidiProcessOrderRequestyang berisi salah satu input berikut:AudioInput: Data audio mentah (biasanya PCM linear 16-bit pada 16000 Hz, tanpa header). Digunakan untuk interaksi suara.TextInput: Pesan teks dari pengguna.EventInput: Sinyal untuk peristiwa sepertiDriveOffEvent(untuk kasus penggunaan layanan pesan antar mobil saat kendaraan berangkat),CrewInterjectionEvent(untuk situasi apa pun saat manusia mengambil alih peran pengambilan pesanan di tengah percakapan), atauOrderStateUpdateEvent(jika pesanan diubah di sisi klien, misalnya, menggunakan antarmuka sentuh).
Node.js
// Stream user inputs over the active connection
stream.write({textInput: {text: 'Hi, I\'d like to order a cheeseburger.'}});
3. Menerima Respons
- Secara bersamaan, agen mengirim kembali aliran pesan
BidiProcessOrderResponse. Klien Anda harus siap menangani berbagai jenis respons dalam kolomoneof response:AgentAudio: Byte audio yang disintesis untuk diputar kepada pengguna, digunakan untuk interaksi suara.AgentText: Versi teks respons agen.SpeechRecognition: Transkrip ucapan pengguna yang dikenali.UpdatedOrderState: Berisi status lengkap saat ini dariOrderpelanggan setiap kali diperbarui oleh agen. Gunakan ini untuk memperbarui representasi pesanan aplikasi Anda. Hal ini biasanya akan menghasilkan pembaruan pada antarmuka pengguna atau sistem pencatatan untuk informasi status pesanan, seperti sistem point of sale.InterruptionSignal: Menunjukkan bahwa pengguna menginterupsi ucapan agen. Klien harus segera berhenti memutarAgentAudiokeluar.AgentEvent: Acara khusus, sepertiRestartOrder, yang memerlukan tindakan klien.SuggestedOptions: Menyediakan opsi yang relevan secara kontekstual yang mungkin dipilih pengguna berikutnya, berguna untuk ditampilkan di layar.EndSession: Menandakan bahwa sesi telah dihentikan oleh agen (misalnya, pesanan selesai, pengguna pergi, atau eskalasi agen).
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. Menutup Streaming
- Aliran dapat ditutup oleh klien atau server. Biasanya, server
menandakan akhir percakapan menggunakan pesan
EndSession. Klien harus menutup streaming saat pesan ini diterima.
Menangani Jenis Pesan Tertentu
Bagian berikut menjelaskan cara menangani jenis respons tertentu yang akan diterima klien Anda saat memanggil BidiProcessOrder.
AudioInput
- Streaming audio dalam potongan-potongan saat tersedia.
- Format: PCM linear 16-bit, frekuensi sampel 16000 Hz.
- Chunk audio tidak menyertakan header audio yang biasanya diawali dengan file WAV.
- Untuk skenario drive-thru dengan peredam gema diaktifkan
(
enable_echo_cancellationdiConfig), berikancustomer_audiodancrew_audio.
UpdatedOrderState
- Pesan ini memberikan status lengkap pesanan setiap kali dikirim.
Ganti cache lokal pesanan dengan konten pesan
Orderyang diterima. - Gunakan
custom_integration_attributesdalam item dan pengubahOrderuntuk memetakan kontenOrderke entitas yang setara dalam sistem pencatatan aplikasi Anda.
InterruptionSignal
- Setelah menerima, segera hentikan pemutaran
AgentAudioapa pun dan hapus audio agen yang di-buffer. Hal ini memastikan alur percakapan yang alami saat pengguna menyela ucapan agen.
EndSession
- Periksa
EndType(misalnya,DRIVE_OFF,AGENT_ESCALATION). - Aplikasi Anda harus menutup koneksi dengan baik dan mengalihkan pengguna dengan tepat (misalnya, memberi tahu supervisor manusia jika terjadi
AGENT_ESCALATION, atau beralih ke status konfirmasi pesanan).
Praktik Terbaik
- Menangani Pesan Secara Asinkron: Minimalkan latensi dengan menggunakan thread atau I/O non-blocking untuk mengirim permintaan dan memproses respons masuk secara bersamaan.
- Logika Koneksi Ulang: Terapkan logika koneksi ulang yang andal jika terjadi masalah jaringan, dengan mengingat untuk mengirim pesan
Configawal dengan ID sesi yang sama untuk mencoba melanjutkan. - Penanganan Error: Pantau error pada stream. Library gRPC dan WebSocket menyediakan mekanisme untuk mendeteksi penutupan stream atau error transportasi. Mencatat peristiwa ini dan menanganinya dengan lancar.
- Buffering Audio: Kelola buffer audio dengan cermat, terapkan buffering jika perlu, untuk memastikan pemutaran
AgentAudioyang lancar dan pengirimanAudioInputtepat waktu. Pertimbangkan dengan cermat keseimbangan antara latensi dan kualitas pemutaran saat memutuskan skema buffering Anda. - Pengelolaan ID Sesi: Pastikan ID sesi unik untuk setiap pesanan/percakapan yang berbeda.
- Pengelolaan Resource: Tutup aliran dan lepaskan resource saat sesi selesai atau jika terjadi error yang tidak dapat dipulihkan.
- Waktu tunggu: Meskipun streaming itu sendiri dapat berlangsung lama (hingga 15 menit secara default), pertimbangkan waktu tunggu tingkat aplikasi untuk status tertentu jika diperlukan.
Contoh Alur Integrasi (Konseptual)
- Aplikasi Klien (misalnya, Aplikasi Seluler) memulai pesanan.
- Buat koneksi gRPC/WebSocket ke
BidiProcessOrder. - Kirim
BidiProcessOrderRequestdenganConfig(ID sesi, ID toko). - Menerima
AgentAudioawal (misalnya, pesan selamat datang) dan memutarnya. - Pengguna berbicara: Merekam audio, melakukan streaming di pesan
AudioInput. - Menerima
SpeechRecognition(menampilkan transkrip),AgentAudio(memutar respons), dan berpotensiUpdatedOrderState(memperbarui keranjang UI). - Jika pengguna mengganggu, terima
InterruptionSignal, hentikan pemutaran. - Melanjutkan pertukaran input audio atau teks dan respons agen.
- Pengguna mengonfirmasi pesanan: Agen mengirimkan
UpdatedOrderStateakhir. - Agen mengirim
EndSession: Klien menutup streaming dan menyelesaikan pesanan dalam sistem POS menggunakan data dariUpdatedOrderStateterakhir.
Contoh End-to-End
Meskipun petunjuk di atas menguraikan konsep streaming langkah demi langkah, berikut tampilan alur integrasi menyeluruh yang lengkap.
Node.js
Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Node.js di Panduan memulai Agen AI Pemesanan Makanan menggunakan library klien.
Untuk melakukan autentikasi ke Agen AI Pemesanan Makanan, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, lihat Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
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.'}});
}