gemini/multimodal-live-api/websocket-demo-app/frontend/script.js (209 lines of code) (raw):

window.addEventListener("load", (event) => { console.log("Hello Gemini Realtime Demo!"); setAvailableCamerasOptions(); setAvailableMicrophoneOptions(); }); const PROXY_URL = "wss://[THE_URL_YOU_COPIED_WITHOUT_HTTP]"; const PROJECT_ID = "your project id"; const MODEL = "gemini-2.0-flash-live-preview-04-09"; const API_HOST = "us-central1-aiplatform.googleapis.com"; const accessTokenInput = document.getElementById("token"); const projectInput = document.getElementById("project"); const systemInstructionsInput = document.getElementById("systemInstructions"); CookieJar.init("token"); CookieJar.init("project"); CookieJar.init("systemInstructions"); const disconnected = document.getElementById("disconnected"); const connecting = document.getElementById("connecting"); const connected = document.getElementById("connected"); const speaking = document.getElementById("speaking"); const micBtn = document.getElementById("micBtn"); const micOffBtn = document.getElementById("micOffBtn"); const cameraBtn = document.getElementById("cameraBtn"); const screenBtn = document.getElementById("screenBtn"); const cameraSelect = document.getElementById("cameraSource"); const micSelect = document.getElementById("audioSource"); const geminiLiveApi = new GeminiLiveAPI(PROXY_URL, PROJECT_ID, MODEL, API_HOST); geminiLiveApi.onErrorMessage = (message) => { showDialogWithMessage(message); setAppStatus("disconnected"); }; function getSelectedResponseModality() { // return "AUDIO"; const radioButtons = document.querySelectorAll( 'md-radio[name="responseModality"]', ); let selectedValue; for (const radioButton of radioButtons) { if (radioButton.checked) { selectedValue = radioButton.value; break; } } return selectedValue; } function getSystemInstructions() { return systemInstructionsInput.value; } function connectBtnClick() { setAppStatus("connecting"); geminiLiveApi.responseModalities = getSelectedResponseModality(); geminiLiveApi.systemInstructions = getSystemInstructions(); geminiLiveApi.onConnectionStarted = () => { setAppStatus("connected"); startAudioInput(); }; geminiLiveApi.setProjectId(projectInput.value); geminiLiveApi.connect(accessTokenInput.value); } const liveAudioOutputManager = new LiveAudioOutputManager(); geminiLiveApi.onReceiveResponse = (messageResponse) => { if (messageResponse.type == "AUDIO") { liveAudioOutputManager.playAudioChunk(messageResponse.data); } else if (messageResponse.type == "TEXT") { console.log("Gemini said: ", messageResponse.data); newModelMessage(messageResponse.data); } }; const liveAudioInputManager = new LiveAudioInputManager(); liveAudioInputManager.onNewAudioRecordingChunk = (audioData) => { geminiLiveApi.sendAudioMessage(audioData); }; function addMessageToChat(message) { const textChat = document.getElementById("text-chat"); const newParagraph = document.createElement("p"); newParagraph.textContent = message; textChat.appendChild(newParagraph); } function newModelMessage(message) { addMessageToChat(">> " + message); } function newUserMessage() { const textMessage = document.getElementById("text-message"); addMessageToChat("User: " + textMessage.value); geminiLiveApi.sendTextMessage(textMessage.value); textMessage.value = ""; } function startAudioInput() { liveAudioInputManager.connectMicrophone(); } function stopAudioInput() { liveAudioInputManager.disconnectMicrophone(); } function micBtnClick() { console.log("micBtnClick"); stopAudioInput(); micBtn.hidden = true; micOffBtn.hidden = false; } function micOffBtnClick() { console.log("micOffBtnClick"); startAudioInput(); micBtn.hidden = false; micOffBtn.hidden = true; } const videoElement = document.getElementById("video"); const canvasElement = document.getElementById("canvas"); const liveVideoManager = new LiveVideoManager(videoElement, canvasElement); const liveScreenManager = new LiveScreenManager(videoElement, canvasElement); liveVideoManager.onNewFrame = (b64Image) => { geminiLiveApi.sendImageMessage(b64Image); }; liveScreenManager.onNewFrame = (b64Image) => { geminiLiveApi.sendImageMessage(b64Image); }; function startCameraCapture() { liveScreenManager.stopCapture(); liveVideoManager.startWebcam(); } function startScreenCapture() { liveVideoManager.stopWebcam(); liveScreenManager.startCapture(); } function cameraBtnClick() { startCameraCapture(); console.log("cameraBtnClick"); } function screenShareBtnClick() { startScreenCapture(); console.log("screenShareBtnClick"); } function newCameraSelected() { console.log("newCameraSelected ", cameraSelect.value); liveVideoManager.updateWebcamDevice(cameraSelect.value); } function newMicSelected() { console.log("newMicSelected", micSelect.value); liveAudioInputManager.updateMicrophoneDevice(micSelect.value); } function disconnectBtnClick() { setAppStatus("disconnected"); geminiLiveApi.disconnect(); stopAudioInput(); } function showDialogWithMessage(messageText) { const dialog = document.getElementById("dialog"); const dialogMessage = document.getElementById("dialogMessage"); dialogMessage.innerHTML = messageText; dialog.show(); } async function getAvailableDevices(deviceType) { const allDevices = await navigator.mediaDevices.enumerateDevices(); const devices = []; allDevices.forEach((device) => { if (device.kind === deviceType) { devices.push({ id: device.deviceId, name: device.label || device.deviceId, }); } }); return devices; } async function getAvailableCameras() { return await this.getAvailableDevices("videoinput"); } async function getAvailableAudioInputs() { return await this.getAvailableDevices("audioinput"); } function setMaterialSelect(allOptions, selectElement) { allOptions.forEach((optionData) => { const option = document.createElement("md-select-option"); option.value = optionData.id; const slotDiv = document.createElement("div"); slotDiv.slot = "headline"; slotDiv.innerHTML = optionData.name; option.appendChild(slotDiv); selectElement.appendChild(option); }); } async function setAvailableCamerasOptions() { const cameras = await getAvailableCameras(); const videoSelect = document.getElementById("cameraSource"); setMaterialSelect(cameras, videoSelect); } async function setAvailableMicrophoneOptions() { const mics = await getAvailableAudioInputs(); const audioSelect = document.getElementById("audioSource"); setMaterialSelect(mics, audioSelect); } function setAppStatus(status) { disconnected.hidden = true; connecting.hidden = true; connected.hidden = true; speaking.hidden = true; switch (status) { case "disconnected": disconnected.hidden = false; break; case "connecting": connecting.hidden = false; break; case "connected": connected.hidden = false; break; case "speaking": speaking.hidden = false; break; default: } }