From ae8d7f05faecb33da86ffc3af1384395c8339641 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 1 Sep 2025 13:23:17 +0200 Subject: [PATCH 01/18] adding samples, test, lints --- genai/live/live-transcribe-with-audio.js | 93 +++++++++++++++++++ genai/test/live-transcribe-with-audio.test.js | 0 2 files changed, 93 insertions(+) create mode 100644 genai/live/live-transcribe-with-audio.js create mode 100644 genai/test/live-transcribe-with-audio.test.js diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js new file mode 100644 index 0000000000..31a2ac67d1 --- /dev/null +++ b/genai/live/live-transcribe-with-audio.js @@ -0,0 +1,93 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START googlegenaisdk_live_transcribe_with_audio] + +'use strict'; + +const {GoogleGenAI, Modality} = require('@google/genai'); + +const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; +const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; + +async function generateContent( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const modelId = 'gemini-2.0-flash-live-preview-04-09'; + const config = {responseModalities: [Modality.TEXT]}; + + const responseQueue = []; + + async function waitMessage() { + while (responseQueue.length === 0) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + return responseQueue.shift(); + } + + async function handleTurn() { + const turns = []; + let done = false; + while (!done) { + const message = await waitMessage(); + turns.push(message); + if (message.serverContent && message.serverContent.turnComplete) { + done = true; + } + } + return turns; + } + + const session = await ai.live.connect({ + model: modelId, + config: config, + callbacks: { + onmessage: msg => responseQueue.push(msg), + onerror: e => console.error('Error:', e.message), + }, + }); + + const textInput = 'Hello? Gemini, are you there?'; + console.log('> ', textInput, '\n'); + + await session.sendClientContent({ + turns: [{role: 'user', parts: [{text: textInput}]}], + }); + + const turns = await handleTurn(); + for (const turn of turns) { + if (turn.text) { + console.log('Received text:', turn.text); + } + } + + session.close(); + return turns; +} +// Example output: +//> Hello? Gemini, are you there? +// Received text: Yes +// Received text: I'm here. How can I help you today? +// [END googlegenaisdk_live_transcribe_with_audio] + +module.exports = { + generateContent, +}; diff --git a/genai/test/live-transcribe-with-audio.test.js b/genai/test/live-transcribe-with-audio.test.js new file mode 100644 index 0000000000..e69de29bb2 From 268edd78d7222d4fbe1dfb1b97c10a02d173b724 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 1 Sep 2025 16:05:11 +0200 Subject: [PATCH 02/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 110 ++++++++++++++++++ genai/live/live-transcribe-with-audio.js | 44 ++++--- genai/test/live-audio-with-txt.test.js | 30 +++++ genai/test/live-transcribe-with-audio.test.js | 30 +++++ 4 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 genai/live/live-audio-with-txt.js create mode 100644 genai/test/live-audio-with-txt.test.js diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js new file mode 100644 index 0000000000..38e79bccb3 --- /dev/null +++ b/genai/live/live-audio-with-txt.js @@ -0,0 +1,110 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START googlegenaisdk_live_audio_with_txt] + +'use strict'; + +const {GoogleGenAI, Modality} = require('@google/genai'); +const fs = require('fs'); + +const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; +const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; + +async function generateContent( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const voiceName = 'Aoede'; + const modelId = 'gemini-2.0-flash-live-preview-04-09'; + const config = { + responseModalities: [Modality.AUDIO], + inputAudioTranscription: {}, + outputAudioTranscription: {}, + }; + + + const responseQueue = []; + + async function waitMessage() { + while (responseQueue.length === 0) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + return responseQueue.shift(); + } + + async function handleTurn(session) { + const turns = []; + let done = false; + let outputMessage = []; + while (!done) { + const message = await waitMessage(); + turns.push(message); + + const sc = message.serverContent; + if (sc?.modelTurn) { + console.log('Model turn:', sc.modelTurn); + } + if (sc?.inputTranscription) { + console.log('Input transcript:', sc.inputTranscription.text); + } + if (sc?.outputTranscription?.text) { + outputMessage.push(sc.outputTranscription.text); + } + + if (sc?.turnComplete) { + done = true; + } + } + console.log('Output transcript:', outputMessage.join('')); + return turns; + } + + const session = await ai.live.connect({ + model: modelId, + config: config, + callbacks: { + onmessage: msg => responseQueue.push(msg), + onerror: e => console.error('Error:', e.message), + }, + }); + + const inputTxt = 'Hello? Gemini, are you there?'; + console.log('> ', inputTxt, '\n'); + + await session.sendClientContent({ + turns: [{role: 'user', parts: [{text: inputTxt}]}], + }); + + const turns = await handleTurn(session); + + console.log('dupsko ', turns); + + session.close(); + return turns; +} +// Example output: +//> Hello? Gemini, are you there? +// Yes, I'm here. What would you like to talk about? +// [END googlegenaisdk_live_audio_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index 31a2ac67d1..2ff178e890 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -31,8 +31,12 @@ async function generateContent( location: location, }); - const modelId = 'gemini-2.0-flash-live-preview-04-09'; - const config = {responseModalities: [Modality.TEXT]}; + const modelId = 'gemini-live-2.5-flash-preview-native-audio'; + const config = { + responseModalities: [Modality.AUDIO], + inputAudioTranscription: {}, + outputAudioTranscription: {}, + }; const responseQueue = []; @@ -43,16 +47,30 @@ async function generateContent( return responseQueue.shift(); } - async function handleTurn() { + async function handleTurn(session) { const turns = []; let done = false; + let outputMessage = []; while (!done) { const message = await waitMessage(); turns.push(message); - if (message.serverContent && message.serverContent.turnComplete) { + + const sc = message.serverContent; + if (sc?.modelTurn) { + console.log('Model turn:', sc.modelTurn); + } + if (sc?.inputTranscription) { + console.log('Input transcript:', sc.inputTranscription.text); + } + if (sc?.outputTranscription?.text) { + outputMessage.push(sc.outputTranscription.text); + } + + if (sc?.turnComplete) { done = true; } } + console.log('Output transcript:', outputMessage.join('')); return turns; } @@ -65,27 +83,23 @@ async function generateContent( }, }); - const textInput = 'Hello? Gemini, are you there?'; - console.log('> ', textInput, '\n'); + const inputTxt = 'Hello? Gemini, are you there?'; + console.log('> ', inputTxt, '\n'); await session.sendClientContent({ - turns: [{role: 'user', parts: [{text: textInput}]}], + turns: [{role: 'user', parts: [{text: inputTxt}]}], }); - const turns = await handleTurn(); - for (const turn of turns) { - if (turn.text) { - console.log('Received text:', turn.text); - } - } + const turns = await handleTurn(session); + + console.log('dupsko ', turns); session.close(); return turns; } // Example output: //> Hello? Gemini, are you there? -// Received text: Yes -// Received text: I'm here. How can I help you today? +// Yes, I'm here. What would you like to talk about? // [END googlegenaisdk_live_transcribe_with_audio] module.exports = { diff --git a/genai/test/live-audio-with-txt.test.js b/genai/test/live-audio-with-txt.test.js new file mode 100644 index 0000000000..3291dea5c7 --- /dev/null +++ b/genai/test/live-audio-with-txt.test.js @@ -0,0 +1,30 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../live/live-audio-with-txt'); + +describe('live-audio-with-txt', () => { + it('should generate text content from a text prompt and multiple images', async function () { + this.timeout(180000); + const output = await sample.generateContent(projectId); + console.log('Generated output:', output); + assert(output.length > 0); + }); +}); diff --git a/genai/test/live-transcribe-with-audio.test.js b/genai/test/live-transcribe-with-audio.test.js index e69de29bb2..940f8e675b 100644 --- a/genai/test/live-transcribe-with-audio.test.js +++ b/genai/test/live-transcribe-with-audio.test.js @@ -0,0 +1,30 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../live/live-transcribe-with-audio'); + +describe('live-transcribe-with-audio', () => { + it('should generate text content from a text prompt and multiple images', async function () { + this.timeout(180000); + const output = await sample.generateContent(projectId); + console.log('Generated output:', output); + assert(output.length > 0); + }); +}); From 141c24413b37677dcf73d2141c2ae95d520d614e Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 1 Sep 2025 16:13:46 +0200 Subject: [PATCH 03/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 46 ++++++++++++------------ genai/live/live-transcribe-with-audio.js | 2 -- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index 38e79bccb3..73b522b152 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -36,8 +36,13 @@ async function generateContent( const modelId = 'gemini-2.0-flash-live-preview-04-09'; const config = { responseModalities: [Modality.AUDIO], - inputAudioTranscription: {}, - outputAudioTranscription: {}, + speechConfig: { + voiceConfig: { + prebuiltVoiceConfig: { + voiceName: voiceName, + }, + }, + }, }; @@ -51,51 +56,46 @@ async function generateContent( } async function handleTurn(session) { - const turns = []; + const audioChunks = []; let done = false; - let outputMessage = []; + while (!done) { const message = await waitMessage(); - turns.push(message); const sc = message.serverContent; - if (sc?.modelTurn) { - console.log('Model turn:', sc.modelTurn); - } - if (sc?.inputTranscription) { - console.log('Input transcript:', sc.inputTranscription.text); - } - if (sc?.outputTranscription?.text) { - outputMessage.push(sc.outputTranscription.text); + if (sc?.modelTurn?.parts) { + for (const part of sc.modelTurn.parts) { + if (part.inlineData?.data) { + audioChunks.push(Buffer.from(part.inlineData.data)); + } + } } if (sc?.turnComplete) { done = true; } } - console.log('Output transcript:', outputMessage.join('')); - return turns; + + return audioChunks; } const session = await ai.live.connect({ - model: modelId, - config: config, + model, + config, callbacks: { onmessage: msg => responseQueue.push(msg), onerror: e => console.error('Error:', e.message), }, }); - const inputTxt = 'Hello? Gemini, are you there?'; - console.log('> ', inputTxt, '\n'); + const textInput = 'Hello? Gemini are you there?'; + console.log('> ', textInput, '\n'); await session.sendClientContent({ - turns: [{role: 'user', parts: [{text: inputTxt}]}], + turns: [{ role: 'user', parts: [{ text: textInput }] }], }); - const turns = await handleTurn(session); - - console.log('dupsko ', turns); + const audioChunks = await handleTurn(session); session.close(); return turns; diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index 2ff178e890..a8b336d145 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -92,8 +92,6 @@ async function generateContent( const turns = await handleTurn(session); - console.log('dupsko ', turns); - session.close(); return turns; } From 823397a93cbd76932d4a33c8eb67cac709355aac Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 1 Sep 2025 16:24:52 +0200 Subject: [PATCH 04/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 15 +++++++++++---- genai/test/live-audio-with-txt.test.js | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index 73b522b152..dc36942207 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -80,8 +80,8 @@ async function generateContent( } const session = await ai.live.connect({ - model, - config, + model: modelId, + config: config, callbacks: { onmessage: msg => responseQueue.push(msg), onerror: e => console.error('Error:', e.message), @@ -98,11 +98,18 @@ async function generateContent( const audioChunks = await handleTurn(session); session.close(); - return turns; + + if (audioChunks.length > 0) { + const audioBuffer = Buffer.concat(audioChunks); + fs.writeFileSync('response.raw', audioBuffer); + console.log('Received audio answer (saved to response.raw)'); + } + + return audioChunks; } // Example output: //> Hello? Gemini, are you there? -// Yes, I'm here. What would you like to talk about? +// Received audio answer (saved to response.raw) // [END googlegenaisdk_live_audio_with_txt] module.exports = { diff --git a/genai/test/live-audio-with-txt.test.js b/genai/test/live-audio-with-txt.test.js index 3291dea5c7..daabe06e91 100644 --- a/genai/test/live-audio-with-txt.test.js +++ b/genai/test/live-audio-with-txt.test.js @@ -21,7 +21,7 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-audio-with-txt'); describe('live-audio-with-txt', () => { - it('should generate text content from a text prompt and multiple images', async function () { + it('should generate audio content from a text prompt', async function () { this.timeout(180000); const output = await sample.generateContent(projectId); console.log('Generated output:', output); From 862bdbabf08893026feeb9cc1d31bd0d6d78bd69 Mon Sep 17 00:00:00 2001 From: Guiners Date: Tue, 2 Sep 2025 15:47:50 +0200 Subject: [PATCH 05/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 11 +- genai/live/live-ground-ragengine-with-txt.js | 122 ++++++++++++++++++ genai/live/live-transcribe-with-audio.js | 12 +- genai/live/live-txt-with-audio.js | 110 ++++++++++++++++ genai/package.json | 3 +- .../live-ground-ragengine-with-txt.test.js | 62 +++++++++ genai/test/live-txt-with-audio.test.js | 30 +++++ 7 files changed, 337 insertions(+), 13 deletions(-) create mode 100644 genai/live/live-ground-ragengine-with-txt.js create mode 100644 genai/live/live-txt-with-audio.js create mode 100644 genai/test/live-ground-ragengine-with-txt.test.js create mode 100644 genai/test/live-txt-with-audio.test.js diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index dc36942207..e750598fcf 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -45,7 +45,6 @@ async function generateContent( }, }; - const responseQueue = []; async function waitMessage() { @@ -55,7 +54,7 @@ async function generateContent( return responseQueue.shift(); } - async function handleTurn(session) { + async function handleTurn() { const audioChunks = []; let done = false; @@ -63,15 +62,15 @@ async function generateContent( const message = await waitMessage(); const sc = message.serverContent; - if (sc?.modelTurn?.parts) { + if (sc.modelTurn.parts) { for (const part of sc.modelTurn.parts) { - if (part.inlineData?.data) { + if (part.inlineData.data) { audioChunks.push(Buffer.from(part.inlineData.data)); } } } - if (sc?.turnComplete) { + if (sc.turnComplete) { done = true; } } @@ -92,7 +91,7 @@ async function generateContent( console.log('> ', textInput, '\n'); await session.sendClientContent({ - turns: [{ role: 'user', parts: [{ text: textInput }] }], + turns: [{role: 'user', parts: [{text: textInput}]}], }); const audioChunks = await handleTurn(session); diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js new file mode 100644 index 0000000000..e67eeb2e11 --- /dev/null +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -0,0 +1,122 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START googlegenaisdk_live_audio_with_txt] + +'use strict'; + +const {GoogleGenAI, Modality} = require('@google/genai'); + +const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; +const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; + +// (DEVELOPER) put here your memory corpus +const MEMORY_CORPUS = + 'projects/cloud-ai-devrel-softserve/locations/us-central1/ragCorpora/2305843009213693952'; + +async function generateContent( + memoryCorpus = MEMORY_CORPUS, + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const modelId = 'gemini-2.0-flash-live-preview-04-09'; + + // RAG store config + const ragStore = { + ragResources: [ + { + ragCorpus: memoryCorpus, // Use memory corpus if you want to store context + }, + ], + storeContext: true, // sink context into your memory corpus + }; + + const config = { + responseModalities: [Modality.TEXT], + tools: [ + { + retrieval: { + vertexRagStore: ragStore, + }, + }, + ], + }; + + const responseQueue = []; + + async function waitMessage() { + while (responseQueue.length === 0) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + return responseQueue.shift(); + } + + async function handleTurn() { + const turns = []; + let done = false; + while (!done) { + const message = await waitMessage(); + turns.push(message); + if (message.serverContent && message.serverContent.turnComplete) { + done = true; + } + } + return turns; + } + + const session = await ai.live.connect({ + model: modelId, + config: config, + callbacks: { + onmessage: msg => responseQueue.push(msg), + onerror: e => console.error('Error:', e.message), + }, + }); + + const textInput = + "What year did Mariusz Pudzianowski win World's Strongest Man?"; + console.log('> ', textInput, '\n'); + + await session.sendClientContent({ + turns: [{role: 'user', parts: [{text: textInput}]}], + }); + + const turns = await handleTurn(); + const response = []; + + for (const turn of turns) { + if (turn.text) { + response.push(turn.text); + } + } + + console.log(response.join('')); + session.close(); + + return response; +} +// Example output: +// > What year did Mariusz Pudzianowski win World's Strongest Man? +// Mariusz Pudzianowski won World's Strongest Man in 2002, 2003, 2005, 2007, and 2008. +// [END googlegenaisdk_live_audio_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index a8b336d145..af29aeef5c 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -47,26 +47,26 @@ async function generateContent( return responseQueue.shift(); } - async function handleTurn(session) { + async function handleTurn() { const turns = []; let done = false; - let outputMessage = []; + const outputMessage = []; while (!done) { const message = await waitMessage(); turns.push(message); const sc = message.serverContent; - if (sc?.modelTurn) { + if (sc.modelTurn) { console.log('Model turn:', sc.modelTurn); } - if (sc?.inputTranscription) { + if (sc.inputTranscription) { console.log('Input transcript:', sc.inputTranscription.text); } - if (sc?.outputTranscription?.text) { + if (sc.outputTranscription.text) { outputMessage.push(sc.outputTranscription.text); } - if (sc?.turnComplete) { + if (sc.turnComplete) { done = true; } } diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js new file mode 100644 index 0000000000..c5aa9abaa6 --- /dev/null +++ b/genai/live/live-txt-with-audio.js @@ -0,0 +1,110 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START googlegenaisdk_live_txt_with_audio] + +'use strict'; + +const {GoogleGenAI, Modality} = require('@google/genai'); +const fetch = require('node-fetch'); + +const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; +const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; + +async function generateContent( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const modelId = 'gemini-2.0-flash-live-preview-04-09'; + const config = { + responseModalities: [Modality.TEXT], + }; + + const responseQueue = []; + + async function waitMessage() { + while (responseQueue.length === 0) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + return responseQueue.shift(); + } + + async function handleTurn() { + const turns = []; + let done = false; + while (!done) { + const message = await waitMessage(); + turns.push(message); + if (message.serverContent && message.serverContent.turnComplete) { + done = true; + } + } + return turns; + } + + const session = await ai.live.connect({ + model: modelId, + config: config, + callbacks: { + onmessage: msg => responseQueue.push(msg), + onerror: e => console.error('Error:', e.message), + }, + }); + + const audioUrl = + 'https://storage.googleapis.com/generativeai-downloads/data/16000.wav'; + + console.log('> Answer to this audio url', audioUrl); + + const res = await fetch(audioUrl); + if (!res.ok) throw new Error(`Failed to fetch audio: ${res.status}`); + const arrayBuffer = await res.arrayBuffer(); + const audioBytes = Buffer.from(arrayBuffer).toString('base64'); + + await session.sendRealtimeInput({ + media: { + data: audioBytes, + mimeType: 'audio/pcm;rate=16000', + }, + }); + + const turns = await handleTurn(); + + const response = []; + for (const turn of turns) { + if (turn.text) { + response.push(turn.text); + } + } + + console.log('Final response:', response.join('')); + session.close(); + + return response; +} + +// Example output: +//> Answer to this audio url https://storage.googleapis.com/generativeai-downloads/data/16000.wav +// Final response: Yes, I can hear you. How are you doing today? +// [END googlegenaisdk_live_txt_with_audio] + +module.exports = { + generateContent, +}; diff --git a/genai/package.json b/genai/package.json index 1f23438fc3..2c517de573 100644 --- a/genai/package.json +++ b/genai/package.json @@ -15,7 +15,8 @@ "dependencies": { "@google/genai": "1.12.0", "axios": "^1.6.2", - "supertest": "^7.0.0" + "supertest": "^7.0.0", + "node-fetch": "^3.3.2" }, "devDependencies": { "c8": "^10.0.0", diff --git a/genai/test/live-ground-ragengine-with-txt.test.js b/genai/test/live-ground-ragengine-with-txt.test.js new file mode 100644 index 0000000000..3a34a96b0c --- /dev/null +++ b/genai/test/live-ground-ragengine-with-txt.test.js @@ -0,0 +1,62 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const sinon = require('sinon'); +const {describe, it, beforeEach, afterEach} = require('mocha'); + +const sample = require('../live/live-ground-ragengine-with-txt'); + +describe('live-ground-ragengine-with-txt', () => { + let mockClient, mockSession; + + beforeEach(() => { + mockSession = { + async *receive() { + yield { + text: 'Mariusz Pudzianowski won in 2002, 2003, 2005, 2007, and 2008.', + }; + }, + sendClientContent: sinon.stub().resolves(), + close: sinon.stub().resolves(), + }; + + mockClient = { + aio: { + live: { + connect: sinon.stub().resolves(mockSession), + }, + }, + }; + + sinon.stub(require('@google/genai'), 'GoogleGenAI').returns(mockClient); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should return text from mocked RAG session', async function () { + this.timeout(5000); + + const output = await sample.generateContent(); + + console.log('Generated output:', output); + + assert.isArray(output); + assert.isNotEmpty(output); + }); +}); diff --git a/genai/test/live-txt-with-audio.test.js b/genai/test/live-txt-with-audio.test.js new file mode 100644 index 0000000000..2a34ef5e18 --- /dev/null +++ b/genai/test/live-txt-with-audio.test.js @@ -0,0 +1,30 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../live/live-txt-with-audio'); + +describe('live-txt-with-audio', () => { + it('should generate audio content from a text prompt', async function () { + this.timeout(18000); + const output = await sample.generateContent(projectId); + console.log('Generated output:', output); + assert(output.length > 0); + }); +}); From b659f40b682cc7fe429b977970c81fa5473fe10b Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 3 Sep 2025 11:57:15 +0200 Subject: [PATCH 06/18] adding samples, test, lints --- genai/live/live-structured-ouput-with-txt.js | 1 + genai/test/live-structured-ouput-with-txt.test.js | 1 + 2 files changed, 2 insertions(+) create mode 100644 genai/live/live-structured-ouput-with-txt.js create mode 100644 genai/test/live-structured-ouput-with-txt.test.js diff --git a/genai/live/live-structured-ouput-with-txt.js b/genai/live/live-structured-ouput-with-txt.js new file mode 100644 index 0000000000..8371f3a2d6 --- /dev/null +++ b/genai/live/live-structured-ouput-with-txt.js @@ -0,0 +1 @@ +//todo \ No newline at end of file diff --git a/genai/test/live-structured-ouput-with-txt.test.js b/genai/test/live-structured-ouput-with-txt.test.js new file mode 100644 index 0000000000..8371f3a2d6 --- /dev/null +++ b/genai/test/live-structured-ouput-with-txt.test.js @@ -0,0 +1 @@ +//todo \ No newline at end of file From a3d808b6eba94d4e064ede3efa929eebd9c99878 Mon Sep 17 00:00:00 2001 From: Guiners Date: Thu, 4 Sep 2025 12:01:06 +0200 Subject: [PATCH 07/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 8 +++++--- genai/live/live-ground-ragengine-with-txt.js | 9 ++++++--- genai/live/live-structured-ouput-with-txt.js | 2 +- genai/live/live-transcribe-with-audio.js | 8 +++++--- genai/live/live-txt-with-audio.js | 8 +++++--- genai/test/live-structured-ouput-with-txt.test.js | 2 +- package.json | 3 ++- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index e750598fcf..b2b5e69fac 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -104,11 +104,13 @@ async function generateContent( console.log('Received audio answer (saved to response.raw)'); } + // Example output: + //> Hello? Gemini, are you there? + // Received audio answer (saved to response.raw) + return audioChunks; } -// Example output: -//> Hello? Gemini, are you there? -// Received audio answer (saved to response.raw) + // [END googlegenaisdk_live_audio_with_txt] module.exports = { diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js index e67eeb2e11..e2bc247e20 100644 --- a/genai/live/live-ground-ragengine-with-txt.js +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -108,13 +108,16 @@ async function generateContent( } console.log(response.join('')); + + // Example output: + // > What year did Mariusz Pudzianowski win World's Strongest Man? + // Mariusz Pudzianowski won World's Strongest Man in 2002, 2003, 2005, 2007, and 2008. + session.close(); return response; } -// Example output: -// > What year did Mariusz Pudzianowski win World's Strongest Man? -// Mariusz Pudzianowski won World's Strongest Man in 2002, 2003, 2005, 2007, and 2008. + // [END googlegenaisdk_live_audio_with_txt] module.exports = { diff --git a/genai/live/live-structured-ouput-with-txt.js b/genai/live/live-structured-ouput-with-txt.js index 8371f3a2d6..593252c883 100644 --- a/genai/live/live-structured-ouput-with-txt.js +++ b/genai/live/live-structured-ouput-with-txt.js @@ -1 +1 @@ -//todo \ No newline at end of file +//todo diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index af29aeef5c..544e46cbf3 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -92,12 +92,14 @@ async function generateContent( const turns = await handleTurn(session); + // Example output: + //> Hello? Gemini, are you there? + // Yes, I'm here. What would you like to talk about? + session.close(); return turns; } -// Example output: -//> Hello? Gemini, are you there? -// Yes, I'm here. What would you like to talk about? + // [END googlegenaisdk_live_transcribe_with_audio] module.exports = { diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js index c5aa9abaa6..dfab85b154 100644 --- a/genai/live/live-txt-with-audio.js +++ b/genai/live/live-txt-with-audio.js @@ -95,14 +95,16 @@ async function generateContent( } console.log('Final response:', response.join('')); + + // Example output: + //> Answer to this audio url https://storage.googleapis.com/generativeai-downloads/data/16000.wav + // Final response: Yes, I can hear you. How are you doing today? + session.close(); return response; } -// Example output: -//> Answer to this audio url https://storage.googleapis.com/generativeai-downloads/data/16000.wav -// Final response: Yes, I can hear you. How are you doing today? // [END googlegenaisdk_live_txt_with_audio] module.exports = { diff --git a/genai/test/live-structured-ouput-with-txt.test.js b/genai/test/live-structured-ouput-with-txt.test.js index 8371f3a2d6..593252c883 100644 --- a/genai/test/live-structured-ouput-with-txt.test.js +++ b/genai/test/live-structured-ouput-with-txt.test.js @@ -1 +1 @@ -//todo \ No newline at end of file +//todo diff --git a/package.json b/package.json index b239c7ad54..e7f7f8217f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "commander": "^12.0.0", - "eslint": "^8.57.0" + "eslint": "^8.57.0", + "node-fetch": "^3.3.2" } } From 6fdf7140f5409962f5babb5e242293d239bae833 Mon Sep 17 00:00:00 2001 From: Guiners Date: Thu, 4 Sep 2025 15:17:59 +0200 Subject: [PATCH 08/18] adding samples, test, lints --- genai/live/live-structured-ouput-with-txt.js | 109 +++++++++++++++++- genai/package.json | 6 +- .../live-structured-ouput-with-txt.test.js | 31 ++++- 3 files changed, 142 insertions(+), 4 deletions(-) diff --git a/genai/live/live-structured-ouput-with-txt.js b/genai/live/live-structured-ouput-with-txt.js index 593252c883..f32346725c 100644 --- a/genai/live/live-structured-ouput-with-txt.js +++ b/genai/live/live-structured-ouput-with-txt.js @@ -1 +1,108 @@ -//todo +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START googlegenaisdk_live_structured_output_with_txt] + +'use strict'; +// todo not working +const {OpenAI} = require('openai'); +const {GoogleAuth} = require('google-auth-library'); + +const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; +const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1'; + +const CalendarEventSchema = { + type: 'object', + properties: { + name: {type: 'string'}, + date: {type: 'string'}, + participants: { + type: 'array', + items: {type: 'string'}, + }, + }, + required: ['name', 'date', 'participants'], +}; + +async function generateContent( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + console.log('[Init] Starting structured output sample...'); + console.log(`[Init] Project: ${projectId}, Location: ${location}`); + + const auth = new GoogleAuth({ + scopes: ['https://www.googleapis.com/auth/cloud-platform'], + }); + const client = await auth.getClient(); + const token = await client.getAccessToken(); + + const ENDPOINT_ID = 'openapi'; + const baseURL = `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/endpoints/${ENDPOINT_ID}`; + + console.log('[Auth] Successfully retrieved access token'); + + const ai = new OpenAI({ + apiKey: token, + baseURL: baseURL, + }); + + console.log('[Session] Sending structured output request...'); + + const completion = await ai.chat.completions.create({ + model: 'google/gemini-2.0-flash-001', + messages: [ + {role: 'system', content: 'Extract the event information.'}, + { + role: 'user', + content: 'Alice and Bob are going to a science fair on Friday.', + }, + ], + response_format: { + type: 'json_schema', + json_schema: { + name: 'CalendarEvent', + schema: CalendarEventSchema, + }, + }, + }); + + const response = completion.choices[0].message; + console.log('[Response] Raw structured output:', response); + + let parsed; + try { + parsed = JSON.parse(response.content[0].text); + } catch (err) { + console.error('[Error] Failed to parse structured response:', err); + throw err; + } + + console.log('[Parsed Response]', parsed); + + // Example expected output: + // { + // name: 'science fair', + // date: 'Friday', + // participants: ['Alice', 'Bob'] + // } + + return parsed; +} + +// [END googlegenaisdk_live_structured_output_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/package.json b/genai/package.json index 2c517de573..23848010a1 100644 --- a/genai/package.json +++ b/genai/package.json @@ -15,8 +15,10 @@ "dependencies": { "@google/genai": "1.12.0", "axios": "^1.6.2", - "supertest": "^7.0.0", - "node-fetch": "^3.3.2" + "google-auth-library": "^10.3.0", + "node-fetch": "^3.3.2", + "openai": "^5.19.1", + "supertest": "^7.0.0" }, "devDependencies": { "c8": "^10.0.0", diff --git a/genai/test/live-structured-ouput-with-txt.test.js b/genai/test/live-structured-ouput-with-txt.test.js index 593252c883..cab937fab7 100644 --- a/genai/test/live-structured-ouput-with-txt.test.js +++ b/genai/test/live-structured-ouput-with-txt.test.js @@ -1 +1,30 @@ -//todo +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../live/live-structured-ouput-with-txt'); + +describe('live-structured-ouput-with-txt', () => { + it('should generate audio content from a text prompt', async function () { + this.timeout(18000); + const output = await sample.generateContent(projectId); + console.log('Generated output:', output); + assert(output.length > 0); + }); +}); From ec83a6cfdf1565c174ce37a4801c97653d825dc5 Mon Sep 17 00:00:00 2001 From: Guiners Date: Fri, 5 Sep 2025 10:39:35 +0200 Subject: [PATCH 09/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 4 +-- genai/live/live-ground-ragengine-with-txt.js | 4 +-- genai/live/live-structured-ouput-with-txt.js | 35 ++++++-------------- genai/live/live-transcribe-with-audio.js | 4 +-- genai/live/live-txt-with-audio.js | 4 +-- 5 files changed, 18 insertions(+), 33 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index b2b5e69fac..ab18d0a008 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -26,7 +26,7 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -78,7 +78,7 @@ async function generateContent( return audioChunks; } - const session = await ai.live.connect({ + const session = await client.live.connect({ model: modelId, config: config, callbacks: { diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js index e2bc247e20..9821fde655 100644 --- a/genai/live/live-ground-ragengine-with-txt.js +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -30,7 +30,7 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -81,7 +81,7 @@ async function generateContent( return turns; } - const session = await ai.live.connect({ + const session = await client.live.connect({ model: modelId, config: config, callbacks: { diff --git a/genai/live/live-structured-ouput-with-txt.js b/genai/live/live-structured-ouput-with-txt.js index f32346725c..6a264a70c9 100644 --- a/genai/live/live-structured-ouput-with-txt.js +++ b/genai/live/live-structured-ouput-with-txt.js @@ -15,12 +15,12 @@ // [START googlegenaisdk_live_structured_output_with_txt] 'use strict'; -// todo not working const {OpenAI} = require('openai'); const {GoogleAuth} = require('google-auth-library'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; -const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'us-central1'; +const GOOGLE_CLOUD_LOCATION = + process.env.GOOGLE_CLOUD_LOCATION || 'us-central1'; const CalendarEventSchema = { type: 'object', @@ -39,28 +39,23 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - console.log('[Init] Starting structured output sample...'); - console.log(`[Init] Project: ${projectId}, Location: ${location}`); - const auth = new GoogleAuth({ scopes: ['https://www.googleapis.com/auth/cloud-platform'], }); const client = await auth.getClient(); - const token = await client.getAccessToken(); + const tokenResponse = await client.getAccessToken(); + + const token = tokenResponse.token; const ENDPOINT_ID = 'openapi'; const baseURL = `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/endpoints/${ENDPOINT_ID}`; - console.log('[Auth] Successfully retrieved access token'); - - const ai = new OpenAI({ + const openAI = new OpenAI({ apiKey: token, baseURL: baseURL, }); - console.log('[Session] Sending structured output request...'); - - const completion = await ai.chat.completions.create({ + const completion = await openAI.chat.completions.create({ model: 'google/gemini-2.0-flash-001', messages: [ {role: 'system', content: 'Extract the event information.'}, @@ -78,18 +73,8 @@ async function generateContent( }, }); - const response = completion.choices[0].message; - console.log('[Response] Raw structured output:', response); - - let parsed; - try { - parsed = JSON.parse(response.content[0].text); - } catch (err) { - console.error('[Error] Failed to parse structured response:', err); - throw err; - } - - console.log('[Parsed Response]', parsed); + const response = completion.choices[0].message.content; + console.log(response); // Example expected output: // { @@ -98,7 +83,7 @@ async function generateContent( // participants: ['Alice', 'Bob'] // } - return parsed; + return response; } // [END googlegenaisdk_live_structured_output_with_txt] diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index 544e46cbf3..50af7682f7 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -25,7 +25,7 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -74,7 +74,7 @@ async function generateContent( return turns; } - const session = await ai.live.connect({ + const session = await client.live.connect({ model: modelId, config: config, callbacks: { diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js index dfab85b154..609adb97c2 100644 --- a/genai/live/live-txt-with-audio.js +++ b/genai/live/live-txt-with-audio.js @@ -26,7 +26,7 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -59,7 +59,7 @@ async function generateContent( return turns; } - const session = await ai.live.connect({ + const session = await client.live.connect({ model: modelId, config: config, callbacks: { From 6e03ddb4448ac46784b82e34056cee3cc0bab57c Mon Sep 17 00:00:00 2001 From: Guiners Date: Fri, 5 Sep 2025 10:47:39 +0200 Subject: [PATCH 10/18] adding samples, test, lints --- genai/live/live-ground-ragengine-with-txt.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js index 9821fde655..6357ab16f5 100644 --- a/genai/live/live-ground-ragengine-with-txt.js +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START googlegenaisdk_live_audio_with_txt] +// [START googlegenaisdk_live_ground_ragengine_with_txt] 'use strict'; @@ -118,7 +118,7 @@ async function generateContent( return response; } -// [END googlegenaisdk_live_audio_with_txt] +// [END googlegenaisdk_live_ground_ragengine_with_txt] module.exports = { generateContent, From 8bde3622577a3033e607f46ab20913842c775545 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 8 Sep 2025 12:50:46 +0200 Subject: [PATCH 11/18] adding samples, test, lints --- genai/live/live-audio-with-txt.js | 6 +++--- genai/live/live-transcribe-with-audio.js | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index ab18d0a008..ce49b19d22 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -62,15 +62,15 @@ async function generateContent( const message = await waitMessage(); const sc = message.serverContent; - if (sc.modelTurn.parts) { + if (sc && sc.modelTurn && sc.modelTurn.parts) { for (const part of sc.modelTurn.parts) { - if (part.inlineData.data) { + if (part && part.inlineData && part.inlineData.data) { audioChunks.push(Buffer.from(part.inlineData.data)); } } } - if (sc.turnComplete) { + if (sc && sc.turnComplete) { done = true; } } diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index 50af7682f7..ade7f749d1 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -56,17 +56,16 @@ async function generateContent( turns.push(message); const sc = message.serverContent; - if (sc.modelTurn) { + if (sc && sc.modelTurn) { console.log('Model turn:', sc.modelTurn); } - if (sc.inputTranscription) { + if (sc && sc.inputTranscription) { console.log('Input transcript:', sc.inputTranscription.text); } - if (sc.outputTranscription.text) { + if (sc && sc.outputTranscription && sc.outputTranscription.text) { outputMessage.push(sc.outputTranscription.text); } - - if (sc.turnComplete) { + if (sc && sc.turnComplete) { done = true; } } From 41fe9ca97e6ae86b6572bedc8abf6355f1b3af29 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 8 Sep 2025 12:50:56 +0200 Subject: [PATCH 12/18] adding samples, test, lints --- genai/live/live-txt-with-audio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js index 609adb97c2..0f4e0ef7e6 100644 --- a/genai/live/live-txt-with-audio.js +++ b/genai/live/live-txt-with-audio.js @@ -18,7 +18,7 @@ const {GoogleGenAI, Modality} = require('@google/genai'); const fetch = require('node-fetch'); - +//todo const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; From 6f3a7105942f9763a2dc3e52b5db8acee22d8abb Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 10 Sep 2025 13:23:25 +0200 Subject: [PATCH 13/18] fixing functions names --- genai/live/live-audio-with-txt.js | 4 ++-- genai/live/live-ground-ragengine-with-txt.js | 4 ++-- genai/live/live-structured-ouput-with-txt.js | 4 ++-- genai/live/live-transcribe-with-audio.js | 4 ++-- genai/live/live-txt-with-audio.js | 8 ++++---- genai/test/live-audio-with-txt.test.js | 4 ++-- genai/test/live-ground-ragengine-with-txt.test.js | 2 +- genai/test/live-structured-ouput-with-txt.test.js | 4 ++-- genai/test/live-transcribe-with-audio.test.js | 4 ++-- genai/test/live-txt-with-audio.test.js | 4 ++-- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index ce49b19d22..70b8988e2b 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -22,7 +22,7 @@ const fs = require('fs'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; -async function generateContent( +async function generateLiveConversation( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { @@ -114,5 +114,5 @@ async function generateContent( // [END googlegenaisdk_live_audio_with_txt] module.exports = { - generateContent, + generateLiveConversation, }; diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js index 6357ab16f5..be7e7ea9e1 100644 --- a/genai/live/live-ground-ragengine-with-txt.js +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -25,7 +25,7 @@ const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; const MEMORY_CORPUS = 'projects/cloud-ai-devrel-softserve/locations/us-central1/ragCorpora/2305843009213693952'; -async function generateContent( +async function generateLiveRagTextResponse( memoryCorpus = MEMORY_CORPUS, projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION @@ -121,5 +121,5 @@ async function generateContent( // [END googlegenaisdk_live_ground_ragengine_with_txt] module.exports = { - generateContent, + generateLiveRagTextResponse, }; diff --git a/genai/live/live-structured-ouput-with-txt.js b/genai/live/live-structured-ouput-with-txt.js index 6a264a70c9..f77bba8f98 100644 --- a/genai/live/live-structured-ouput-with-txt.js +++ b/genai/live/live-structured-ouput-with-txt.js @@ -35,7 +35,7 @@ const CalendarEventSchema = { required: ['name', 'date', 'participants'], }; -async function generateContent( +async function generateStructuredTextResponse( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { @@ -89,5 +89,5 @@ async function generateContent( // [END googlegenaisdk_live_structured_output_with_txt] module.exports = { - generateContent, + generateStructuredTextResponse, }; diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index ade7f749d1..53673444e3 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -21,7 +21,7 @@ const {GoogleGenAI, Modality} = require('@google/genai'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; -async function generateContent( +async function generateLiveAudioTranscription( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { @@ -102,5 +102,5 @@ async function generateContent( // [END googlegenaisdk_live_transcribe_with_audio] module.exports = { - generateContent, + generateLiveAudioTranscription, }; diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js index 0f4e0ef7e6..573bc172aa 100644 --- a/genai/live/live-txt-with-audio.js +++ b/genai/live/live-txt-with-audio.js @@ -17,12 +17,12 @@ 'use strict'; const {GoogleGenAI, Modality} = require('@google/genai'); -const fetch = require('node-fetch'); -//todo +// const fetch = require('node-fetch'); +//todo try unittest and uncomment it if its needed const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; -async function generateContent( +async function generateLiveConversation( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { @@ -108,5 +108,5 @@ async function generateContent( // [END googlegenaisdk_live_txt_with_audio] module.exports = { - generateContent, + generateLiveConversation, }; diff --git a/genai/test/live-audio-with-txt.test.js b/genai/test/live-audio-with-txt.test.js index daabe06e91..9dca58c3fa 100644 --- a/genai/test/live-audio-with-txt.test.js +++ b/genai/test/live-audio-with-txt.test.js @@ -21,9 +21,9 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-audio-with-txt'); describe('live-audio-with-txt', () => { - it('should generate audio content from a text prompt', async function () { + it('should generate audio content in a live session conversation from a text prompt', async function () { this.timeout(180000); - const output = await sample.generateContent(projectId); + const output = await sample.generateLiveConversation(projectId); console.log('Generated output:', output); assert(output.length > 0); }); diff --git a/genai/test/live-ground-ragengine-with-txt.test.js b/genai/test/live-ground-ragengine-with-txt.test.js index 3a34a96b0c..837f3f1612 100644 --- a/genai/test/live-ground-ragengine-with-txt.test.js +++ b/genai/test/live-ground-ragengine-with-txt.test.js @@ -52,7 +52,7 @@ describe('live-ground-ragengine-with-txt', () => { it('should return text from mocked RAG session', async function () { this.timeout(5000); - const output = await sample.generateContent(); + const output = await sample.generateLiveRagTextResponse(); console.log('Generated output:', output); diff --git a/genai/test/live-structured-ouput-with-txt.test.js b/genai/test/live-structured-ouput-with-txt.test.js index cab937fab7..b26e1e3092 100644 --- a/genai/test/live-structured-ouput-with-txt.test.js +++ b/genai/test/live-structured-ouput-with-txt.test.js @@ -21,9 +21,9 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-structured-ouput-with-txt'); describe('live-structured-ouput-with-txt', () => { - it('should generate audio content from a text prompt', async function () { + it('should extract structured information from text input using the model', async function () { this.timeout(18000); - const output = await sample.generateContent(projectId); + const output = await sample.generateStructuredTextResponse(projectId); console.log('Generated output:', output); assert(output.length > 0); }); diff --git a/genai/test/live-transcribe-with-audio.test.js b/genai/test/live-transcribe-with-audio.test.js index 940f8e675b..250dafb5e5 100644 --- a/genai/test/live-transcribe-with-audio.test.js +++ b/genai/test/live-transcribe-with-audio.test.js @@ -21,9 +21,9 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-transcribe-with-audio'); describe('live-transcribe-with-audio', () => { - it('should generate text content from a text prompt and multiple images', async function () { + it('should transcribe audio input into text using the live model', async function () { this.timeout(180000); - const output = await sample.generateContent(projectId); + const output = await sample.generateLiveAudioTranscription(projectId); console.log('Generated output:', output); assert(output.length > 0); }); diff --git a/genai/test/live-txt-with-audio.test.js b/genai/test/live-txt-with-audio.test.js index 2a34ef5e18..0d655e9679 100644 --- a/genai/test/live-txt-with-audio.test.js +++ b/genai/test/live-txt-with-audio.test.js @@ -21,9 +21,9 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-txt-with-audio'); describe('live-txt-with-audio', () => { - it('should generate audio content from a text prompt', async function () { + it('should generate txt content in a live session from an audio', async function () { this.timeout(18000); - const output = await sample.generateContent(projectId); + const output = await sample.generateLiveConversation(projectId); console.log('Generated output:', output); assert(output.length > 0); }); From 0d7d240b6f4bbe1b94451a0d3c37c212ef2e9113 Mon Sep 17 00:00:00 2001 From: Guiners Date: Tue, 14 Oct 2025 15:55:57 +0200 Subject: [PATCH 14/18] linter changes and gemini code review fixes --- genai/live/live-audio-with-txt.js | 2 +- genai/live/live-ground-ragengine-with-txt.js | 7 +++---- genai/live/live-txt-with-audio.js | 3 +-- genai/test/live-ground-ragengine-with-txt.test.js | 5 ++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index 70b8988e2b..a4affeb20b 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -94,7 +94,7 @@ async function generateLiveConversation( turns: [{role: 'user', parts: [{text: textInput}]}], }); - const audioChunks = await handleTurn(session); + const audioChunks = await handleTurn(); session.close(); diff --git a/genai/live/live-ground-ragengine-with-txt.js b/genai/live/live-ground-ragengine-with-txt.js index be7e7ea9e1..04c83f34fc 100644 --- a/genai/live/live-ground-ragengine-with-txt.js +++ b/genai/live/live-ground-ragengine-with-txt.js @@ -90,8 +90,7 @@ async function generateLiveRagTextResponse( }, }); - const textInput = - "What year did Mariusz Pudzianowski win World's Strongest Man?"; + const textInput = 'What are newest gemini models?'; console.log('> ', textInput, '\n'); await session.sendClientContent({ @@ -110,8 +109,8 @@ async function generateLiveRagTextResponse( console.log(response.join('')); // Example output: - // > What year did Mariusz Pudzianowski win World's Strongest Man? - // Mariusz Pudzianowski won World's Strongest Man in 2002, 2003, 2005, 2007, and 2008. + // > What are newest gemini models? + // In December 2023, Google launched Gemini, their "most capable and general model". It's multimodal, meaning it understands and combines different types of information like text, code, audio, images, and video. session.close(); diff --git a/genai/live/live-txt-with-audio.js b/genai/live/live-txt-with-audio.js index 573bc172aa..92a5fdd594 100644 --- a/genai/live/live-txt-with-audio.js +++ b/genai/live/live-txt-with-audio.js @@ -17,8 +17,7 @@ 'use strict'; const {GoogleGenAI, Modality} = require('@google/genai'); -// const fetch = require('node-fetch'); -//todo try unittest and uncomment it if its needed +const fetch = require('node-fetch'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; diff --git a/genai/test/live-ground-ragengine-with-txt.test.js b/genai/test/live-ground-ragengine-with-txt.test.js index 837f3f1612..478779d8d0 100644 --- a/genai/test/live-ground-ragengine-with-txt.test.js +++ b/genai/test/live-ground-ragengine-with-txt.test.js @@ -27,7 +27,7 @@ describe('live-ground-ragengine-with-txt', () => { mockSession = { async *receive() { yield { - text: 'Mariusz Pudzianowski won in 2002, 2003, 2005, 2007, and 2008.', + text: 'In December 2023, Google launched Gemini, their "most capable and general model". It\'s multimodal, meaning it understands and combines different types of information like text, code, audio, images, and video.', }; }, sendClientContent: sinon.stub().resolves(), @@ -56,7 +56,6 @@ describe('live-ground-ragengine-with-txt', () => { console.log('Generated output:', output); - assert.isArray(output); - assert.isNotEmpty(output); + assert(output.length > 0); }); }); From 23919158bd7e64f56f8f3b20db8e9d87eb7fe016 Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 15 Oct 2025 14:08:16 +0200 Subject: [PATCH 15/18] renamed sc to serverContent --- genai/live/live-audio-with-txt.js | 12 ++++++++---- genai/live/live-transcribe-with-audio.js | 20 ++++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/genai/live/live-audio-with-txt.js b/genai/live/live-audio-with-txt.js index a4affeb20b..e6c257862d 100644 --- a/genai/live/live-audio-with-txt.js +++ b/genai/live/live-audio-with-txt.js @@ -61,16 +61,20 @@ async function generateLiveConversation( while (!done) { const message = await waitMessage(); - const sc = message.serverContent; - if (sc && sc.modelTurn && sc.modelTurn.parts) { - for (const part of sc.modelTurn.parts) { + const serverContent = message.serverContent; + if ( + serverContent && + serverContent.modelTurn && + serverContent.modelTurn.parts + ) { + for (const part of serverContent.modelTurn.parts) { if (part && part.inlineData && part.inlineData.data) { audioChunks.push(Buffer.from(part.inlineData.data)); } } } - if (sc && sc.turnComplete) { + if (serverContent && serverContent.turnComplete) { done = true; } } diff --git a/genai/live/live-transcribe-with-audio.js b/genai/live/live-transcribe-with-audio.js index 53673444e3..dcc23c1f0c 100644 --- a/genai/live/live-transcribe-with-audio.js +++ b/genai/live/live-transcribe-with-audio.js @@ -55,17 +55,21 @@ async function generateLiveAudioTranscription( const message = await waitMessage(); turns.push(message); - const sc = message.serverContent; - if (sc && sc.modelTurn) { - console.log('Model turn:', sc.modelTurn); + const serverContent = message.serverContent; + if (serverContent && serverContent.modelTurn) { + console.log('Model turn:', serverContent.modelTurn); } - if (sc && sc.inputTranscription) { - console.log('Input transcript:', sc.inputTranscription.text); + if (serverContent && serverContent.inputTranscription) { + console.log('Input transcript:', serverContent.inputTranscription.text); } - if (sc && sc.outputTranscription && sc.outputTranscription.text) { - outputMessage.push(sc.outputTranscription.text); + if ( + serverContent && + serverContent.outputTranscription && + serverContent.outputTranscription.text + ) { + outputMessage.push(serverContent.outputTranscription.text); } - if (sc && sc.turnComplete) { + if (serverContent && serverContent.turnComplete) { done = true; } } From dacada8924cee63957929403410b2efed46c4cca Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 15 Oct 2025 16:17:56 +0200 Subject: [PATCH 16/18] fixing package.json and adding delay to test --- genai/package.json | 3 ++- genai/test/live-ground-ragengine-with-txt.test.js | 5 ++++- genai/test/live-txt-with-audio.test.js | 5 ++++- package.json | 3 +-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/genai/package.json b/genai/package.json index c3d21c7033..029ff99594 100644 --- a/genai/package.json +++ b/genai/package.json @@ -27,6 +27,7 @@ "mocha": "^10.0.0", "sinon": "^18.0.0", "uuid": "^10.0.0", - "proxyquire": "^2.1.3" + "proxyquire": "^2.1.3", + "node-fetch": "^3.3.2" } } diff --git a/genai/test/live-ground-ragengine-with-txt.test.js b/genai/test/live-ground-ragengine-with-txt.test.js index 478779d8d0..36a42b49ce 100644 --- a/genai/test/live-ground-ragengine-with-txt.test.js +++ b/genai/test/live-ground-ragengine-with-txt.test.js @@ -19,6 +19,7 @@ const sinon = require('sinon'); const {describe, it, beforeEach, afterEach} = require('mocha'); const sample = require('../live/live-ground-ragengine-with-txt'); +const {delay} = require('./util'); describe('live-ground-ragengine-with-txt', () => { let mockClient, mockSession; @@ -50,7 +51,9 @@ describe('live-ground-ragengine-with-txt', () => { }); it('should return text from mocked RAG session', async function () { - this.timeout(5000); + this.timeout(180000); + this.retries(4); + await delay(this.test); const output = await sample.generateLiveRagTextResponse(); diff --git a/genai/test/live-txt-with-audio.test.js b/genai/test/live-txt-with-audio.test.js index 0d655e9679..755ccfae2e 100644 --- a/genai/test/live-txt-with-audio.test.js +++ b/genai/test/live-txt-with-audio.test.js @@ -19,10 +19,13 @@ const {describe, it} = require('mocha'); const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../live/live-txt-with-audio'); +const {delay} = require('./util'); describe('live-txt-with-audio', () => { it('should generate txt content in a live session from an audio', async function () { - this.timeout(18000); + this.timeout(180000); + this.retries(4); + await delay(this.test); const output = await sample.generateLiveConversation(projectId); console.log('Generated output:', output); assert(output.length > 0); diff --git a/package.json b/package.json index e7f7f8217f..b239c7ad54 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ }, "dependencies": { "commander": "^12.0.0", - "eslint": "^8.57.0", - "node-fetch": "^3.3.2" + "eslint": "^8.57.0" } } From 69e4614b8c6ee7081ec89a1b15fa6445844c9c38 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 27 Oct 2025 11:25:48 +0100 Subject: [PATCH 17/18] adding mock to live-txt-with-audio test --- genai/package.json | 8 ++-- genai/test/live-txt-with-audio.test.js | 55 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/genai/package.json b/genai/package.json index 029ff99594..fb2e402300 100644 --- a/genai/package.json +++ b/genai/package.json @@ -16,18 +16,18 @@ "@google/genai": "1.20.0", "axios": "^1.6.2", "google-auth-library": "^10.3.0", + "luxon": "^3.7.1", "node-fetch": "^3.3.2", "openai": "^5.19.1", - "luxon": "^3.7.1", "supertest": "^7.0.0" }, "devDependencies": { "c8": "^10.0.0", "chai": "^4.5.0", "mocha": "^10.0.0", - "sinon": "^18.0.0", - "uuid": "^10.0.0", + "node-fetch": "^3.3.2", "proxyquire": "^2.1.3", - "node-fetch": "^3.3.2" + "sinon": "^18.0.0", + "uuid": "^10.0.0" } } diff --git a/genai/test/live-txt-with-audio.test.js b/genai/test/live-txt-with-audio.test.js index 755ccfae2e..f648d3978a 100644 --- a/genai/test/live-txt-with-audio.test.js +++ b/genai/test/live-txt-with-audio.test.js @@ -18,11 +18,64 @@ const {assert} = require('chai'); const {describe, it} = require('mocha'); const projectId = process.env.CAIP_PROJECT_ID; -const sample = require('../live/live-txt-with-audio'); const {delay} = require('./util'); +const proxyquire = require('proxyquire'); + describe('live-txt-with-audio', () => { it('should generate txt content in a live session from an audio', async function () { + const fakeFetch = async () => ({ + ok: true, + arrayBuffer: async () => Buffer.from('fake audio'), + }); + + const fakeClient = { + live: { + connect: async (opts = {}) => { + console.log('Mock is called'); // <--- 👈 + + if ( + opts && + opts.callbacks && + typeof opts.callbacks.onmessage === 'function' + ) { + setImmediate(() => + opts.callbacks.onmessage({ + text: 'Yes, I can hear you.', + serverContent: { + turnComplete: false, + }, + }) + ); + + setImmediate(() => + opts.callbacks.onmessage({ + text: 'Here is the final response.', + serverContent: { + turnComplete: true, + }, + }) + ); + } + + return { + sendRealtimeInput: async () => {}, + close: async () => {}, + }; + }, + }, + }; + + const sample = proxyquire('../live/live-txt-with-audio', { + 'node-fetch': fakeFetch, + '@google/genai': { + GoogleGenAI: function () { + return fakeClient; + }, + Modality: {TEXT: 'TEXT'}, + }, + }); + this.timeout(180000); this.retries(4); await delay(this.test); From 049d08a5c52a5fc59f0f4e321c27ef7ea348f333 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 27 Oct 2025 11:50:15 +0100 Subject: [PATCH 18/18] adding mock to live-ground-ragengine-with-txt --- .../live-ground-ragengine-with-txt.test.js | 61 ++++++++++--------- genai/test/live-txt-with-audio.test.js | 2 +- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/genai/test/live-ground-ragengine-with-txt.test.js b/genai/test/live-ground-ragengine-with-txt.test.js index 36a42b49ce..c98fa71908 100644 --- a/genai/test/live-ground-ragengine-with-txt.test.js +++ b/genai/test/live-ground-ragengine-with-txt.test.js @@ -15,50 +15,53 @@ 'use strict'; const {assert} = require('chai'); -const sinon = require('sinon'); -const {describe, it, beforeEach, afterEach} = require('mocha'); +const {describe, it} = require('mocha'); +const proxyquire = require('proxyquire'); -const sample = require('../live/live-ground-ragengine-with-txt'); const {delay} = require('./util'); describe('live-ground-ragengine-with-txt', () => { - let mockClient, mockSession; - - beforeEach(() => { - mockSession = { - async *receive() { - yield { - text: 'In December 2023, Google launched Gemini, their "most capable and general model". It\'s multimodal, meaning it understands and combines different types of information like text, code, audio, images, and video.', - }; - }, - sendClientContent: sinon.stub().resolves(), - close: sinon.stub().resolves(), + it('should return text from mocked RAG session', async function () { + const fakeSession = { + sendClientContent: async () => {}, + close: async () => {}, }; - mockClient = { - aio: { - live: { - connect: sinon.stub().resolves(mockSession), + const mockClient = { + live: { + connect: async (opts = {}) => { + setImmediate(() => + opts.callbacks.onmessage({ + text: 'In December 2023, Google launched Gemini...', + serverContent: {turnComplete: false}, + }) + ); + setImmediate(() => + opts.callbacks.onmessage({ + text: 'Mock final message.', + serverContent: {turnComplete: true}, + }) + ); + + return fakeSession; }, }, }; - sinon.stub(require('@google/genai'), 'GoogleGenAI').returns(mockClient); - }); - - afterEach(() => { - sinon.restore(); - }); + const sample = proxyquire('../live/live-ground-ragengine-with-txt', { + '@google/genai': { + GoogleGenAI: function () { + return mockClient; + }, + Modality: {TEXT: 'TEXT'}, + }, + }); - it('should return text from mocked RAG session', async function () { - this.timeout(180000); + this.timeout(10000); this.retries(4); await delay(this.test); - const output = await sample.generateLiveRagTextResponse(); - console.log('Generated output:', output); - assert(output.length > 0); }); }); diff --git a/genai/test/live-txt-with-audio.test.js b/genai/test/live-txt-with-audio.test.js index f648d3978a..c7de558118 100644 --- a/genai/test/live-txt-with-audio.test.js +++ b/genai/test/live-txt-with-audio.test.js @@ -32,7 +32,7 @@ describe('live-txt-with-audio', () => { const fakeClient = { live: { connect: async (opts = {}) => { - console.log('Mock is called'); // <--- 👈 + console.log('Mock is called'); if ( opts &&