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:
}
}