From 7b72387dc2b43f9551418e1234f3e10c1a8e2df9 Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 13 Aug 2025 12:20:04 +0200 Subject: [PATCH 01/10] adding samples, test, lints --- .../embeddings-docretrieval-with-txt.js | 53 +++++++++++++++++ genai/express-mode/api-key-example.js | 40 +++++++++++++ genai/package.json | 3 +- .../provisionedthroughput-with-txt.js | 58 +++++++++++++++++++ genai/test/api-key-example.test.js | 49 ++++++++++++++++ .../embeddings-docretrieval-with-txt.test.js | 28 +++++++++ .../provisionedthroughput-with-txt.test.js | 28 +++++++++ package.json | 3 +- 8 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 genai/embeddings/embeddings-docretrieval-with-txt.js create mode 100644 genai/express-mode/api-key-example.js create mode 100644 genai/provisioned-throughput/provisionedthroughput-with-txt.js create mode 100644 genai/test/api-key-example.test.js create mode 100644 genai/test/embeddings-docretrieval-with-txt.test.js create mode 100644 genai/test/provisionedthroughput-with-txt.test.js diff --git a/genai/embeddings/embeddings-docretrieval-with-txt.js b/genai/embeddings/embeddings-docretrieval-with-txt.js new file mode 100644 index 0000000000..15984e0ac3 --- /dev/null +++ b/genai/embeddings/embeddings-docretrieval-with-txt.js @@ -0,0 +1,53 @@ +// 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'; + +// [START googlegenaisdk_embeddings_docretrieval_with_txt] +const {GoogleGenAI} = 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(projectId); + + const prompt = [ + "How do I get a driver's license/learner's permit?", + "How long is my driver's license valid for?", + "Driver's knowledge test study guide", + ]; + + const response = await ai.models.embedContent({ + model: 'gemini-embedding-001', + contents: prompt, + config: { + taskType: 'RETRIEVAL_DOCUMENT', // Optional + outputDimensionality: 3072, // Optional + title: "Driver's License" // Optional + } + }); + + console.log(response); + + return response; +} +// [END googlegenaisdk_embeddings_docretrieval_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/express-mode/api-key-example.js b/genai/express-mode/api-key-example.js new file mode 100644 index 0000000000..117dd681ee --- /dev/null +++ b/genai/express-mode/api-key-example.js @@ -0,0 +1,40 @@ +// 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'; + +// [START googlegenaisdk_vertexai_express_mode] +const {GoogleGenAI} = require('@google/genai'); +const API_KEY = 'PUT HERE YOUR API KEY'; + +async function generateContent(apiKey = API_KEY) { + const ai = new GoogleGenAI({ + vertexai: true, + apiKey: apiKey, + }); + + const response = await ai.models.generateContentStream({ + model: 'gemini-2.5-flash', + contents: 'Explain bubble sort to me.', + }); + + console.log(response.text); + + return response; +} +// [END googlegenaisdk_vertexai_express_mode] + +module.exports = { + generateContent, +}; diff --git a/genai/package.json b/genai/package.json index 1786d292d9..5d39963af6 100644 --- a/genai/package.json +++ b/genai/package.json @@ -22,6 +22,7 @@ "chai": "^4.5.0", "mocha": "^10.0.0", "sinon": "^18.0.0", - "uuid": "^10.0.0" + "uuid": "^10.0.0", + "proxyquire": "^2.1.3" } } diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js new file mode 100644 index 0000000000..1ac7fb8dce --- /dev/null +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -0,0 +1,58 @@ +// 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'; + +// [START googlegenaisdk_googlegenaisdk_provisionedthroughput_with_txt] +const {GoogleGenAI} = 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 +) { + + //todo not working + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + httpOptions: { + apiVersion: 'v1', + headers: { + // Options: + // - "dedicated": Use Provisioned Throughput + // - "shared": Use pay-as-you-go + // https://cloud.google.com/vertex-ai/generative-ai/docs/use-provisioned-throughput + "X-Vertex-AI-LLM-Request-Type": "shared" + } + } + }); + + const response = await ai.models.embedContent({ + model: 'gemini-2.5-flash', + contents: 'How does AI work?' + }); + + console.log(response.text); + + return response.text; +} +// [END googlegenaisdk_googlegenaisdk_provisionedthroughput_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/test/api-key-example.test.js b/genai/test/api-key-example.test.js new file mode 100644 index 0000000000..a77f1024fb --- /dev/null +++ b/genai/test/api-key-example.test.js @@ -0,0 +1,49 @@ +// 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 proxyquire = require('proxyquire').noCallThru(); + +describe('vertexai-express-mode', () => { + it('should call generateContentStream and return the mocked response', async function () { + this.timeout(10000); + + const mockGenerateContentStreamResult = { + text: 'Bubble sort works by repeatedly swapping adjacent elements until sorted.', + }; + + class MockModels { + async generateContentStream() { + return mockGenerateContentStreamResult; + } + } + + class MockGoogleGenAI { + constructor() { + this.models = new MockModels(); + } + } + + const sample = proxyquire('../express-mode/api-key-example.js', { + '@google/genai': {GoogleGenAI: MockGoogleGenAI}, + }); + + const response = await sample.generateContent('FAKE_API_KEY'); + + assert.strictEqual(response.text, mockGenerateContentStreamResult.text); + }); +}); diff --git a/genai/test/embeddings-docretrieval-with-txt.test.js b/genai/test/embeddings-docretrieval-with-txt.test.js new file mode 100644 index 0000000000..e65cf63349 --- /dev/null +++ b/genai/test/embeddings-docretrieval-with-txt.test.js @@ -0,0 +1,28 @@ +// 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('../embeddings/embeddings-docretrieval-with-txt.js'); + +describe('embeddings-docretrieval-with-txt', async () => { + it('embeddings-docretrieval-with-txt', async () => { + const generatedFileNames = await sample.generateContent(projectId); + assert.containsAllKeys(generatedFileNames, ['embeddings', 'metadata']); + }); +}); diff --git a/genai/test/provisionedthroughput-with-txt.test.js b/genai/test/provisionedthroughput-with-txt.test.js new file mode 100644 index 0000000000..4d0f2b89b7 --- /dev/null +++ b/genai/test/provisionedthroughput-with-txt.test.js @@ -0,0 +1,28 @@ +// 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('../provisioned-throughput/provisionedthroughput-with-txt.js'); + +describe('provisionedthroughput-with-txt', async () => { + it('provisionedthroughput-with-txt', async () => { + const generatedFileNames = await sample.generateContent(projectId); + + }); +}); diff --git a/package.json b/package.json index b239c7ad54..9d95ae2790 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "commander": "^12.0.0", - "eslint": "^8.57.0" + "eslint": "^8.57.0", + "proxyquire": "^2.1.3" } } From 88ff0cea9b670ed5df4f943d591f58daa523d8fe Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 13 Aug 2025 16:16:37 +0200 Subject: [PATCH 02/10] adding samples, test, lints --- .../embeddings-docretrieval-with-txt.js | 12 +-- .../provisionedthroughput-with-txt.js | 20 ++--- genai/safety/safety-with-txt.js | 84 +++++++++++++++++++ .../embeddings-docretrieval-with-txt.test.js | 2 +- .../provisionedthroughput-with-txt.test.js | 9 +- genai/test/safety-with-txt.test.js | 29 +++++++ 6 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 genai/safety/safety-with-txt.js create mode 100644 genai/test/safety-with-txt.test.js diff --git a/genai/embeddings/embeddings-docretrieval-with-txt.js b/genai/embeddings/embeddings-docretrieval-with-txt.js index 15984e0ac3..77c87833b2 100644 --- a/genai/embeddings/embeddings-docretrieval-with-txt.js +++ b/genai/embeddings/embeddings-docretrieval-with-txt.js @@ -18,12 +18,8 @@ const {GoogleGenAI} = 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 -) { +async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { const ai = new GoogleGenAI(projectId); const prompt = [ @@ -37,9 +33,9 @@ async function generateContent( contents: prompt, config: { taskType: 'RETRIEVAL_DOCUMENT', // Optional - outputDimensionality: 3072, // Optional - title: "Driver's License" // Optional - } + outputDimensionality: 3072, // Optional + title: "Driver's License", // Optional + }, }); console.log(response); diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js index 1ac7fb8dce..5ac1d5ec2e 100644 --- a/genai/provisioned-throughput/provisionedthroughput-with-txt.js +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -24,8 +24,6 @@ async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - - //todo not working const ai = new GoogleGenAI({ vertexai: true, project: projectId, @@ -33,18 +31,18 @@ async function generateContent( httpOptions: { apiVersion: 'v1', headers: { - // Options: - // - "dedicated": Use Provisioned Throughput - // - "shared": Use pay-as-you-go - // https://cloud.google.com/vertex-ai/generative-ai/docs/use-provisioned-throughput - "X-Vertex-AI-LLM-Request-Type": "shared" - } - } + // Options: + // - "dedicated": Use Provisioned Throughput + // - "shared": Use pay-as-you-go + // https://cloud.google.com/vertex-ai/generative-ai/docs/use-provisioned-throughput + 'X-Vertex-AI-LLM-Request-Type': 'shared', + }, + }, }); - const response = await ai.models.embedContent({ + const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', - contents: 'How does AI work?' + contents: 'How does AI work?', }); console.log(response.text); diff --git a/genai/safety/safety-with-txt.js b/genai/safety/safety-with-txt.js new file mode 100644 index 0000000000..936e66601f --- /dev/null +++ b/genai/safety/safety-with-txt.js @@ -0,0 +1,84 @@ +// 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'; + +// [START googlegenaisdk_safety_with_txt] +const {GoogleGenAI} = 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 systemInstruction = 'Be as mean as possible.'; + + const prompt = + 'Write a list of 5 disrespectful things that I might say to the universe after stubbing my toe in the dark.'; + + const safetySettings = [ + { + category: 'HARM_CATEGORY_DANGEROUS_CONTENT', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + { + category: 'HARM_CATEGORY_HARASSMENT', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + { + category: 'HARM_CATEGORY_HATE_SPEECH', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + { + category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + ]; + + const response = await ai.models.generateContent({ + model: 'gemini-2.5-flash', + contents: prompt, + config: { + systemInstruction: systemInstruction, + safetySettings: safetySettings, + }, + }); + + console.log(response.text); + console.log(response.candidates[0].finishMessage); + + for (const each of response.candidates[0].safetyRatings) { + console.log('\nCategory:', String(each.category)); + console.log('Is Blocked:', each.blocked); + console.log('Probability:', each.probability); + console.log('Probability Score:', each.probabilityScore); + console.log('Severity:', each.severity); + console.log('Severity Score:', each.severityScore); + } + + return response; +} +// [END googlegenaisdk_safety_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/test/embeddings-docretrieval-with-txt.test.js b/genai/test/embeddings-docretrieval-with-txt.test.js index e65cf63349..0e9146dfe8 100644 --- a/genai/test/embeddings-docretrieval-with-txt.test.js +++ b/genai/test/embeddings-docretrieval-with-txt.test.js @@ -21,7 +21,7 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../embeddings/embeddings-docretrieval-with-txt.js'); describe('embeddings-docretrieval-with-txt', async () => { - it('embeddings-docretrieval-with-txt', async () => { + it('should return an object containing embeddings and metadata', async () => { const generatedFileNames = await sample.generateContent(projectId); assert.containsAllKeys(generatedFileNames, ['embeddings', 'metadata']); }); diff --git a/genai/test/provisionedthroughput-with-txt.test.js b/genai/test/provisionedthroughput-with-txt.test.js index 4d0f2b89b7..3e0189b389 100644 --- a/genai/test/provisionedthroughput-with-txt.test.js +++ b/genai/test/provisionedthroughput-with-txt.test.js @@ -20,9 +20,10 @@ const {describe, it} = require('mocha'); const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../provisioned-throughput/provisionedthroughput-with-txt.js'); -describe('provisionedthroughput-with-txt', async () => { - it('provisionedthroughput-with-txt', async () => { - const generatedFileNames = await sample.generateContent(projectId); - +describe('provisionedthroughput-with-txt', () => { + it('should return provisioned throughput result', async function () { + this.timeout(50000); + const output = await sample.generateContent(projectId); + assert(output.length > 0); }); }); diff --git a/genai/test/safety-with-txt.test.js b/genai/test/safety-with-txt.test.js new file mode 100644 index 0000000000..3929f68fb8 --- /dev/null +++ b/genai/test/safety-with-txt.test.js @@ -0,0 +1,29 @@ +// 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('../safety/safety-with-txt.js'); + +describe('safety-with-txt', () => { + it('should call generateContentStream with safety instructions', async function () { + this.timeout(50000); + const output = await sample.generateContent(projectId); + assert(output.text.length > 0); + }); +}); From 7aa2a1635d6fa8558da483bc737ebf04b26b5b32 Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 13 Aug 2025 17:06:17 +0200 Subject: [PATCH 03/10] adding samples, test, lints --- .../bounding-box/boundingbox-with-txt-img.js | 75 +++++++++++++++++++ genai/test/boundingbox-with-txt-img.test.js | 28 +++++++ 2 files changed, 103 insertions(+) create mode 100644 genai/bounding-box/boundingbox-with-txt-img.js create mode 100644 genai/test/boundingbox-with-txt-img.test.js diff --git a/genai/bounding-box/boundingbox-with-txt-img.js b/genai/bounding-box/boundingbox-with-txt-img.js new file mode 100644 index 0000000000..1c61797975 --- /dev/null +++ b/genai/bounding-box/boundingbox-with-txt-img.js @@ -0,0 +1,75 @@ +// 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'; + +// [START googlegenaisdk_embeddings_docretrieval_with_txt] +const {GoogleGenAI} = 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 +) { + + + /** + * Represents a bounding box with its 2D coordinates and associated label. + */ + class BoundingBox { + /** + * @param {number[]} box2d - A list of integers representing the 2D coordinates of the bounding box + * in the format [y_min, x_min, y_max, x_max]. + * @param {string} label - The label or class associated with the object in the bounding box. + */ + constructor(box2d, label) { + if (!Array.isArray(box2d) || box2d.length !== 4 || !box2d.every(Number.isInteger)) { + throw new Error('box2d must be an array of 4 integers'); + } + if (typeof label !== 'string') { + throw new Error('label must be a string'); + } + this.box2d = box2d; + this.label = label; + } + } + + const ai = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + + const response = await ai.models.embedContent({ + model: 'gemini-embedding-001', + contents: prompt, + config: { + taskType: 'RETRIEVAL_DOCUMENT', // Optional + outputDimensionality: 3072, // Optional + title: "Driver's License" // Optional + } + }); + + console.log(response); + + return response; +} +// [END googlegenaisdk_embeddings_docretrieval_with_txt] + +module.exports = { + generateContent, +}; diff --git a/genai/test/boundingbox-with-txt-img.test.js b/genai/test/boundingbox-with-txt-img.test.js new file mode 100644 index 0000000000..e87dc8c11b --- /dev/null +++ b/genai/test/boundingbox-with-txt-img.test.js @@ -0,0 +1,28 @@ +// 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('../bounding-box/boundingbox-with-txt-img'); + +describe('boundingbox-with-txt-img', async () => { + it('should return the total token count for a text prompt', async () => { + const output = await sample.generateContent(projectId); + assert(output > 0); + }); +}); From a5d633310973910ea615c8d369390592dd29fc16 Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 18 Aug 2025 08:30:07 +0200 Subject: [PATCH 04/10] adding samples, test, lints --- .../bounding-box/boundingbox-with-txt-img.js | 89 ++++++++++++++++--- genai/test/boundingbox-with-txt-img.test.js | 3 +- package.json | 2 + 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/genai/bounding-box/boundingbox-with-txt-img.js b/genai/bounding-box/boundingbox-with-txt-img.js index 1c61797975..28d48d01a9 100644 --- a/genai/bounding-box/boundingbox-with-txt-img.js +++ b/genai/bounding-box/boundingbox-with-txt-img.js @@ -19,13 +19,12 @@ const {GoogleGenAI} = require('@google/genai'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; - +//todo notworking async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - /** * Represents a bounding box with its 2D coordinates and associated label. */ @@ -47,24 +46,94 @@ async function generateContent( } } + /** + * Helper function to plot bounding boxes on an image + * @param {string} imageUri + * @param {BoundingBox[]} boundingBoxes + */ + async function plotBoundingBoxes(imageUri, boundingBoxes) { + const image = await loadImage(imageUri); + const width = image.width; + const height = image.height; + + const canvas = createCanvas(width, height); + const ctx = canvas.getContext('2d'); + + ctx.drawImage(image, 0, 0, width, height); + + const colors = ['red', 'green', 'blue', 'orange', 'purple', 'yellow', 'cyan', 'magenta', 'lime', 'pink']; + + boundingBoxes.forEach((bbox, i) => { + const absYMin = Math.floor((bbox.box2d[0] / 1000) * height); + const absXMin = Math.floor((bbox.box2d[1] / 1000) * width); + const absYMax = Math.floor((bbox.box2d[2] / 1000) * height); + const absXMax = Math.floor((bbox.box2d[3] / 1000) * width); + + const color = colors[i % colors.length]; + + ctx.strokeStyle = color; + ctx.lineWidth = 4; + ctx.strokeRect(absXMin, absYMin, absXMax - absXMin, absYMax - absYMin); + + if (bbox.label) { + ctx.fillStyle = color; + ctx.font = '20px Arial'; + ctx.fillText(bbox.label, absXMin + 8, absYMin + 20); + } + }); + + // Save or return buffer + return canvas.toBuffer('image/png'); + } + const ai = new GoogleGenAI({ vertexai: true, project: projectId, location: location, }); + const systemInstructions = 'Return bounding boxes as an array with labels.\n' + + ' Never return masks. Limit to 25 objects.\n' + + ' If an object is present multiple times, give each object a unique label\n' + + ' according to its distinct characteristics (colors, size, position, etc..).' + + const imageUri = "https://storage.googleapis.com/generativeai-downloads/images/socks.jpg"; + + const prompt = [ + { file_uri: imageUri, mime_type: 'image/jpeg' }, // zamiast Part.fromUri + "Output the positions of the socks with a face. Label according to position in the image." + ]; + + const config = { + systemInstructions: systemInstructions, + temperature: 0.5, + safetySettings: [ + { + category: 'HARM_CATEGORY_DANGEROUS_CONTENT', + threshold: 'BLOCK_ONLY_HIGH', + }, + ], + responseMimeType: 'application/json' + }; - const response = await ai.models.embedContent({ - model: 'gemini-embedding-001', + + const response = await ai.models.generateContent({ + model: 'gemini-2.5-flash', contents: prompt, - config: { - taskType: 'RETRIEVAL_DOCUMENT', // Optional - outputDimensionality: 3072, // Optional - title: "Driver's License" // Optional - } + config: config }); - console.log(response); + console.log(response.text); + + let boundingBoxes = []; + try { + boundingBoxes = JSON.parse(response.text).map(b => new BoundingBox(b.box_2d, b.label)); + } catch (err) { + console.error('Failed to parse response:', err); + } + + await plotBoundingBoxes(imageUri, boundingBoxes); + return response; } diff --git a/genai/test/boundingbox-with-txt-img.test.js b/genai/test/boundingbox-with-txt-img.test.js index e87dc8c11b..8cd29c1f2c 100644 --- a/genai/test/boundingbox-with-txt-img.test.js +++ b/genai/test/boundingbox-with-txt-img.test.js @@ -21,7 +21,8 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../bounding-box/boundingbox-with-txt-img'); describe('boundingbox-with-txt-img', async () => { - it('should return the total token count for a text prompt', async () => { + it('should return the total token count for a text prompt', async function (){ + this.timeout(10000); const output = await sample.generateContent(projectId); assert(output > 0); }); diff --git a/package.json b/package.json index 9d95ae2790..471dbb3139 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,10 @@ "typescript": "^5.0.4" }, "dependencies": { + "canvas": "^3.1.2", "commander": "^12.0.0", "eslint": "^8.57.0", + "node-fetch": "^3.3.2", "proxyquire": "^2.1.3" } } From 7cc334d5484f845082ce3457dc671ce74685546f Mon Sep 17 00:00:00 2001 From: Guiners Date: Mon, 18 Aug 2025 15:12:11 +0200 Subject: [PATCH 05/10] adding samples, test, lints --- .../bounding-box/boundingbox-with-txt-img.js | 213 ++++++++++-------- genai/package.json | 4 +- genai/test/boundingbox-with-txt-img.test.js | 6 +- 3 files changed, 119 insertions(+), 104 deletions(-) diff --git a/genai/bounding-box/boundingbox-with-txt-img.js b/genai/bounding-box/boundingbox-with-txt-img.js index 28d48d01a9..7e7288f3cb 100644 --- a/genai/bounding-box/boundingbox-with-txt-img.js +++ b/genai/bounding-box/boundingbox-with-txt-img.js @@ -14,131 +14,144 @@ 'use strict'; -// [START googlegenaisdk_embeddings_docretrieval_with_txt] +// [START googlegenaisdk_boundingbox_with_txt_img] const {GoogleGenAI} = require('@google/genai'); +const {createCanvas, loadImage} = require('canvas'); +const fetch = require('node-fetch'); +const fs = require('fs'); + const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; const GOOGLE_CLOUD_LOCATION = process.env.GOOGLE_CLOUD_LOCATION || 'global'; -//todo notworking + +async function fetchImageAsBase64(uri) { + const response = await fetch(uri); + const buffer = await response.buffer(); + return buffer.toString('base64'); +} + +async function plotBoundingBoxes(imageUri, boundingBoxes) { + console.log('Creating bounding boxes'); + const image = await loadImage(imageUri); + const canvas = createCanvas(image.width, image.height); + const ctx = canvas.getContext('2d'); + + ctx.drawImage(image, 0, 0); + + const colors = ['red', 'blue', 'green', 'orange']; + + boundingBoxes.forEach((bbox, i) => { + const [yMin, xMin, yMax, xMax] = bbox.box_2d; + + const absYMin = Math.floor((yMin / 1000) * image.height); + const absXMin = Math.floor((xMin / 1000) * image.width); + const absYMax = Math.floor((yMax / 1000) * image.height); + const absXMax = Math.floor((xMax / 1000) * image.width); + + ctx.strokeStyle = colors[i % colors.length]; + ctx.lineWidth = 4; + ctx.strokeRect(absXMin, absYMin, absXMax - absXMin, absYMax - absYMin); + + ctx.fillStyle = colors[i % colors.length]; + ctx.font = '20px Arial'; + ctx.fillText(bbox.label, absXMin + 8, absYMin + 20); + }); + + fs.writeFileSync('output.png', canvas.toBuffer('image/png')); + console.log('Saved output to file: output.png'); +} + async function generateContent( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - - /** - * Represents a bounding box with its 2D coordinates and associated label. - */ - class BoundingBox { - /** - * @param {number[]} box2d - A list of integers representing the 2D coordinates of the bounding box - * in the format [y_min, x_min, y_max, x_max]. - * @param {string} label - The label or class associated with the object in the bounding box. - */ - constructor(box2d, label) { - if (!Array.isArray(box2d) || box2d.length !== 4 || !box2d.every(Number.isInteger)) { - throw new Error('box2d must be an array of 4 integers'); - } - if (typeof label !== 'string') { - throw new Error('label must be a string'); - } - this.box2d = box2d; - this.label = label; - } - } - - /** - * Helper function to plot bounding boxes on an image - * @param {string} imageUri - * @param {BoundingBox[]} boundingBoxes - */ - async function plotBoundingBoxes(imageUri, boundingBoxes) { - const image = await loadImage(imageUri); - const width = image.width; - const height = image.height; - - const canvas = createCanvas(width, height); - const ctx = canvas.getContext('2d'); - - ctx.drawImage(image, 0, 0, width, height); - - const colors = ['red', 'green', 'blue', 'orange', 'purple', 'yellow', 'cyan', 'magenta', 'lime', 'pink']; - - boundingBoxes.forEach((bbox, i) => { - const absYMin = Math.floor((bbox.box2d[0] / 1000) * height); - const absXMin = Math.floor((bbox.box2d[1] / 1000) * width); - const absYMax = Math.floor((bbox.box2d[2] / 1000) * height); - const absXMax = Math.floor((bbox.box2d[3] / 1000) * width); - - const color = colors[i % colors.length]; - - ctx.strokeStyle = color; - ctx.lineWidth = 4; - ctx.strokeRect(absXMin, absYMin, absXMax - absXMin, absYMax - absYMin); - - if (bbox.label) { - ctx.fillStyle = color; - ctx.font = '20px Arial'; - ctx.fillText(bbox.label, absXMin + 8, absYMin + 20); - } - }); - - // Save or return buffer - return canvas.toBuffer('image/png'); - } - const ai = new GoogleGenAI({ vertexai: true, project: projectId, location: location, }); - const systemInstructions = 'Return bounding boxes as an array with labels.\n' + - ' Never return masks. Limit to 25 objects.\n' + - ' If an object is present multiple times, give each object a unique label\n' + - ' according to its distinct characteristics (colors, size, position, etc..).' - - const imageUri = "https://storage.googleapis.com/generativeai-downloads/images/socks.jpg"; - - const prompt = [ - { file_uri: imageUri, mime_type: 'image/jpeg' }, // zamiast Part.fromUri - "Output the positions of the socks with a face. Label according to position in the image." + const systemInstruction = ` + Return bounding boxes as an array with labels. + Never return masks. Limit to 25 objects. + If an object is present multiple times, give each object a unique label + according to its distinct characteristics (colors, size, position, etc.). + `; + + const safetySettings = [ + { + category: 'HARM_CATEGORY_DANGEROUS_CONTENT', + threshold: 'BLOCK_ONLY_HIGH', + }, ]; - const config = { - systemInstructions: systemInstructions, - temperature: 0.5, - safetySettings: [ - { - category: 'HARM_CATEGORY_DANGEROUS_CONTENT', - threshold: 'BLOCK_ONLY_HIGH', + const imageUri = + 'https://storage.googleapis.com/generativeai-downloads/images/socks.jpg'; + const base64Image = await fetchImageAsBase64(imageUri); + + const boundingBoxSchema = { + type: 'ARRAY', + description: 'List of bounding boxes for detected objects', + items: { + type: 'OBJECT', + title: 'BoundingBox', + description: 'Represents a bounding box with coordinates and label', + properties: { + box_2d: { + type: 'ARRAY', + description: + 'Bounding box coordinates in format [y_min, x_min, y_max, x_max]', + items: { + type: 'INTEGER', + format: 'int32', + }, + minItems: '4', + maxItems: '4', + }, + label: { + type: 'STRING', + description: 'Label describing the object within the bounding box', + }, }, - ], - responseMimeType: 'application/json' + required: ['box_2d', 'label'], + }, }; - const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', - contents: prompt, - config: config + contents: [ + { + role: 'user', + parts: [ + { + text: 'Output the positions of the socks with a face. Label according to position in the image.', + }, + { + inlineData: { + data: base64Image, + mimeType: 'image/jpeg', + }, + }, + ], + }, + ], + config: { + systemInstruction: systemInstruction, + safetySettings: safetySettings, + responseMimeType: 'application/json', + temperature: 0.5, + responseSchema: boundingBoxSchema, + }, }); - console.log(response.text); + const candidate = response.candidates[0].content.parts[0].text; + const boundingBoxes = JSON.parse(candidate); - let boundingBoxes = []; - try { - boundingBoxes = JSON.parse(response.text).map(b => new BoundingBox(b.box_2d, b.label)); - } catch (err) { - console.error('Failed to parse response:', err); - } + console.log('Bounding boxes:', boundingBoxes); await plotBoundingBoxes(imageUri, boundingBoxes); - - - return response; + return boundingBoxes; } -// [END googlegenaisdk_embeddings_docretrieval_with_txt] +// [END googlegenaisdk_boundingbox_with_txt_img] -module.exports = { - generateContent, -}; +module.exports = {generateContent}; diff --git a/genai/package.json b/genai/package.json index 5d39963af6..f64b2e88fa 100644 --- a/genai/package.json +++ b/genai/package.json @@ -23,6 +23,8 @@ "mocha": "^10.0.0", "sinon": "^18.0.0", "uuid": "^10.0.0", - "proxyquire": "^2.1.3" + "proxyquire": "^2.1.3", + "canvas": "^3.1.0", + "node-fetch": "^2.7.0" } } diff --git a/genai/test/boundingbox-with-txt-img.test.js b/genai/test/boundingbox-with-txt-img.test.js index 8cd29c1f2c..18f4ac19ad 100644 --- a/genai/test/boundingbox-with-txt-img.test.js +++ b/genai/test/boundingbox-with-txt-img.test.js @@ -21,9 +21,9 @@ const projectId = process.env.CAIP_PROJECT_ID; const sample = require('../bounding-box/boundingbox-with-txt-img'); describe('boundingbox-with-txt-img', async () => { - it('should return the total token count for a text prompt', async function (){ - this.timeout(10000); + it('should return the bounding box', async function () { + this.timeout(100000); const output = await sample.generateContent(projectId); - assert(output > 0); + assert(output.length > 0); }); }); From e20d7fd06ec14db6598388822d6f2c51e4da2aec Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 20 Aug 2025 13:20:10 +0200 Subject: [PATCH 06/10] adding samples, test, lints --- .../embeddings-docretrieval-with-txt.js | 5 +++- genai/express-mode/api-key-example.js | 2 ++ .../provisionedthroughput-with-txt.js | 8 +++-- genai/safety/safety-with-txt.js | 30 +++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/genai/embeddings/embeddings-docretrieval-with-txt.js b/genai/embeddings/embeddings-docretrieval-with-txt.js index 77c87833b2..28bc1e0120 100644 --- a/genai/embeddings/embeddings-docretrieval-with-txt.js +++ b/genai/embeddings/embeddings-docretrieval-with-txt.js @@ -39,7 +39,10 @@ async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { }); console.log(response); - + // Example response: + // embeddings=[ContentEmbedding(values=[-0.06302902102470398, 0.00928034819662571, 0.014716853387653828, -0.028747491538524628, ... ], + // statistics=ContentEmbeddingStatistics(truncated=False, token_count=13.0))] + // metadata=EmbedContentMetadata(billable_character_count=112) return response; } // [END googlegenaisdk_embeddings_docretrieval_with_txt] diff --git a/genai/express-mode/api-key-example.js b/genai/express-mode/api-key-example.js index 117dd681ee..678f080c3b 100644 --- a/genai/express-mode/api-key-example.js +++ b/genai/express-mode/api-key-example.js @@ -33,6 +33,8 @@ async function generateContent(apiKey = API_KEY) { return response; } +// Example response: +// Bubble Sort is a simple sorting algorithm that repeatedly steps through the list // [END googlegenaisdk_vertexai_express_mode] module.exports = { diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js index 5ac1d5ec2e..255da58d16 100644 --- a/genai/provisioned-throughput/provisionedthroughput-with-txt.js +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -14,7 +14,7 @@ 'use strict'; -// [START googlegenaisdk_googlegenaisdk_provisionedthroughput_with_txt] +// [START googlegenaisdk_provisionedthroughput_with_txt] const {GoogleGenAI} = require('@google/genai'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; @@ -49,7 +49,11 @@ async function generateContent( return response.text; } -// [END googlegenaisdk_googlegenaisdk_provisionedthroughput_with_txt] +// Example response: +// Okay, let's break down how AI works. It's a broad field, so I'll focus on the ... +// Here's a simplified overview: +// ... +// [END googlegenaisdk_provisionedthroughput_with_txt] module.exports = { generateContent, diff --git a/genai/safety/safety-with-txt.js b/genai/safety/safety-with-txt.js index 936e66601f..e91984fe4f 100644 --- a/genai/safety/safety-with-txt.js +++ b/genai/safety/safety-with-txt.js @@ -77,6 +77,36 @@ async function generateContent( return response; } +// Example response: +// +// Category: HarmCategory.HARM_CATEGORY_HATE_SPEECH +// Is Blocked: False +// Probability: HarmProbability.NEGLIGIBLE +// Probability Score: 2.547714e-05 +// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE +// Severity Score: None +// +// Category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT +// Is Blocked: False +// Probability: HarmProbability.NEGLIGIBLE +// Probability Score: 3.6103818e-06 +// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE +// Severity Score: None +// +// Category: HarmCategory.HARM_CATEGORY_HARASSMENT +// Is Blocked: True +// Probability: HarmProbability.MEDIUM +// Probability Score: 0.71599233 +// Severity: HarmSeverity.HARM_SEVERITY_MEDIUM +// Severity Score: 0.30782545 +// +// Category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT +// Is Blocked: False +// Probability: HarmProbability.NEGLIGIBLE +// Probability Score: 1.5624657e-05 +// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE +// Severity Score: None + // [END googlegenaisdk_safety_with_txt] module.exports = { From 9577b8e64331d762eee7eca8363e1a3e0170685e Mon Sep 17 00:00:00 2001 From: Guiners Date: Thu, 4 Sep 2025 11:19:16 +0200 Subject: [PATCH 07/10] adding samples, test, lints --- .../embeddings-docretrieval-with-txt.js | 2 + genai/express-mode/api-key-example.js | 5 +- .../provisionedthroughput-with-txt.js | 10 ++-- genai/safety/safety-with-txt.js | 59 ++++++++++--------- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/genai/embeddings/embeddings-docretrieval-with-txt.js b/genai/embeddings/embeddings-docretrieval-with-txt.js index 28bc1e0120..e6d916a8db 100644 --- a/genai/embeddings/embeddings-docretrieval-with-txt.js +++ b/genai/embeddings/embeddings-docretrieval-with-txt.js @@ -39,10 +39,12 @@ async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { }); console.log(response); + // Example response: // embeddings=[ContentEmbedding(values=[-0.06302902102470398, 0.00928034819662571, 0.014716853387653828, -0.028747491538524628, ... ], // statistics=ContentEmbeddingStatistics(truncated=False, token_count=13.0))] // metadata=EmbedContentMetadata(billable_character_count=112) + return response; } // [END googlegenaisdk_embeddings_docretrieval_with_txt] diff --git a/genai/express-mode/api-key-example.js b/genai/express-mode/api-key-example.js index 678f080c3b..fb8daaab99 100644 --- a/genai/express-mode/api-key-example.js +++ b/genai/express-mode/api-key-example.js @@ -31,10 +31,11 @@ async function generateContent(apiKey = API_KEY) { console.log(response.text); + // Example response: + // Bubble Sort is a simple sorting algorithm that repeatedly steps through the list + return response; } -// Example response: -// Bubble Sort is a simple sorting algorithm that repeatedly steps through the list // [END googlegenaisdk_vertexai_express_mode] module.exports = { diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js index 255da58d16..827ceff58b 100644 --- a/genai/provisioned-throughput/provisionedthroughput-with-txt.js +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -46,13 +46,13 @@ async function generateContent( }); console.log(response.text); - + // Example response: + // Okay, let's break down how AI works. It's a broad field, so I'll focus on the ... + // Here's a simplified overview: + // ... return response.text; } -// Example response: -// Okay, let's break down how AI works. It's a broad field, so I'll focus on the ... -// Here's a simplified overview: -// ... + // [END googlegenaisdk_provisionedthroughput_with_txt] module.exports = { diff --git a/genai/safety/safety-with-txt.js b/genai/safety/safety-with-txt.js index e91984fe4f..322f636d9d 100644 --- a/genai/safety/safety-with-txt.js +++ b/genai/safety/safety-with-txt.js @@ -75,37 +75,38 @@ async function generateContent( console.log('Severity Score:', each.severityScore); } + // Example response: + // + // Category: HarmCategory.HARM_CATEGORY_HATE_SPEECH + // Is Blocked: False + // Probability: HarmProbability.NEGLIGIBLE + // Probability Score: 2.547714e-05 + // Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE + // Severity Score: None + // + // Category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT + // Is Blocked: False + // Probability: HarmProbability.NEGLIGIBLE + // Probability Score: 3.6103818e-06 + // Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE + // Severity Score: None + // + // Category: HarmCategory.HARM_CATEGORY_HARASSMENT + // Is Blocked: True + // Probability: HarmProbability.MEDIUM + // Probability Score: 0.71599233 + // Severity: HarmSeverity.HARM_SEVERITY_MEDIUM + // Severity Score: 0.30782545 + // + // Category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT + // Is Blocked: False + // Probability: HarmProbability.NEGLIGIBLE + // Probability Score: 1.5624657e-05 + // Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE + // Severity Score: None + return response; } -// Example response: -// -// Category: HarmCategory.HARM_CATEGORY_HATE_SPEECH -// Is Blocked: False -// Probability: HarmProbability.NEGLIGIBLE -// Probability Score: 2.547714e-05 -// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE -// Severity Score: None -// -// Category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT -// Is Blocked: False -// Probability: HarmProbability.NEGLIGIBLE -// Probability Score: 3.6103818e-06 -// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE -// Severity Score: None -// -// Category: HarmCategory.HARM_CATEGORY_HARASSMENT -// Is Blocked: True -// Probability: HarmProbability.MEDIUM -// Probability Score: 0.71599233 -// Severity: HarmSeverity.HARM_SEVERITY_MEDIUM -// Severity Score: 0.30782545 -// -// Category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT -// Is Blocked: False -// Probability: HarmProbability.NEGLIGIBLE -// Probability Score: 1.5624657e-05 -// Severity: HarmSeverity.HARM_SEVERITY_NEGLIGIBLE -// Severity Score: None // [END googlegenaisdk_safety_with_txt] From 79f65d50676b0668119454fc3ed8fc0edd3833f4 Mon Sep 17 00:00:00 2001 From: Guiners Date: Thu, 4 Sep 2025 11:30:15 +0200 Subject: [PATCH 08/10] adding samples, test, lints --- genai/provisioned-throughput/provisionedthroughput-with-txt.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js index 827ceff58b..b80fa26707 100644 --- a/genai/provisioned-throughput/provisionedthroughput-with-txt.js +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -46,10 +46,12 @@ async function generateContent( }); console.log(response.text); + // Example response: // Okay, let's break down how AI works. It's a broad field, so I'll focus on the ... // Here's a simplified overview: // ... + return response.text; } From 23f5a05ff06b623fd36edb8afa650c9ffec92002 Mon Sep 17 00:00:00 2001 From: Guiners Date: Wed, 10 Sep 2025 12:46:44 +0200 Subject: [PATCH 09/10] fixing functions names --- genai/bounding-box/boundingbox-with-txt-img.js | 10 ++++++---- genai/embeddings/embeddings-docretrieval-with-txt.js | 10 ++++++---- genai/express-mode/api-key-example.js | 8 ++++---- .../provisionedthroughput-with-txt.js | 8 ++++---- genai/safety/safety-with-txt.js | 8 ++++---- genai/test/api-key-example.test.js | 2 +- genai/test/boundingbox-with-txt-img.test.js | 2 +- genai/test/embeddings-docretrieval-with-txt.test.js | 3 ++- genai/test/provisionedthroughput-with-txt.test.js | 2 +- genai/test/safety-with-txt.test.js | 2 +- 10 files changed, 30 insertions(+), 25 deletions(-) diff --git a/genai/bounding-box/boundingbox-with-txt-img.js b/genai/bounding-box/boundingbox-with-txt-img.js index 7e7288f3cb..cd2f874d49 100644 --- a/genai/bounding-box/boundingbox-with-txt-img.js +++ b/genai/bounding-box/boundingbox-with-txt-img.js @@ -61,11 +61,11 @@ async function plotBoundingBoxes(imageUri, boundingBoxes) { console.log('Saved output to file: output.png'); } -async function generateContent( +async function createBoundingBox( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -117,7 +117,7 @@ async function generateContent( }, }; - const response = await ai.models.generateContent({ + const response = await client.models.generateContent({ model: 'gemini-2.5-flash', contents: [ { @@ -154,4 +154,6 @@ async function generateContent( } // [END googlegenaisdk_boundingbox_with_txt_img] -module.exports = {generateContent}; +module.exports = { + createBoundingBox, +}; diff --git a/genai/embeddings/embeddings-docretrieval-with-txt.js b/genai/embeddings/embeddings-docretrieval-with-txt.js index e6d916a8db..c7b59d0385 100644 --- a/genai/embeddings/embeddings-docretrieval-with-txt.js +++ b/genai/embeddings/embeddings-docretrieval-with-txt.js @@ -19,8 +19,10 @@ const {GoogleGenAI} = require('@google/genai'); const GOOGLE_CLOUD_PROJECT = process.env.GOOGLE_CLOUD_PROJECT; -async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { - const ai = new GoogleGenAI(projectId); +async function generateEmbeddingsForRetrieval( + projectId = GOOGLE_CLOUD_PROJECT +) { + const client = new GoogleGenAI(projectId); const prompt = [ "How do I get a driver's license/learner's permit?", @@ -28,7 +30,7 @@ async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { "Driver's knowledge test study guide", ]; - const response = await ai.models.embedContent({ + const response = await client.models.embedContent({ model: 'gemini-embedding-001', contents: prompt, config: { @@ -50,5 +52,5 @@ async function generateContent(projectId = GOOGLE_CLOUD_PROJECT) { // [END googlegenaisdk_embeddings_docretrieval_with_txt] module.exports = { - generateContent, + generateEmbeddingsForRetrieval, }; diff --git a/genai/express-mode/api-key-example.js b/genai/express-mode/api-key-example.js index fb8daaab99..4cfc91e2f9 100644 --- a/genai/express-mode/api-key-example.js +++ b/genai/express-mode/api-key-example.js @@ -18,13 +18,13 @@ const {GoogleGenAI} = require('@google/genai'); const API_KEY = 'PUT HERE YOUR API KEY'; -async function generateContent(apiKey = API_KEY) { - const ai = new GoogleGenAI({ +async function generateWithApiKey(apiKey = API_KEY) { + const client = new GoogleGenAI({ vertexai: true, apiKey: apiKey, }); - const response = await ai.models.generateContentStream({ + const response = await client.models.generateContentStream({ model: 'gemini-2.5-flash', contents: 'Explain bubble sort to me.', }); @@ -39,5 +39,5 @@ async function generateContent(apiKey = API_KEY) { // [END googlegenaisdk_vertexai_express_mode] module.exports = { - generateContent, + generateWithApiKey, }; diff --git a/genai/provisioned-throughput/provisionedthroughput-with-txt.js b/genai/provisioned-throughput/provisionedthroughput-with-txt.js index b80fa26707..6463284272 100644 --- a/genai/provisioned-throughput/provisionedthroughput-with-txt.js +++ b/genai/provisioned-throughput/provisionedthroughput-with-txt.js @@ -20,11 +20,11 @@ const {GoogleGenAI} = 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 generateWithProvisionedThroughput( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -40,7 +40,7 @@ async function generateContent( }, }); - const response = await ai.models.generateContent({ + const response = await client.models.generateContent({ model: 'gemini-2.5-flash', contents: 'How does AI work?', }); @@ -58,5 +58,5 @@ async function generateContent( // [END googlegenaisdk_provisionedthroughput_with_txt] module.exports = { - generateContent, + generateWithProvisionedThroughput, }; diff --git a/genai/safety/safety-with-txt.js b/genai/safety/safety-with-txt.js index 322f636d9d..986f9b6781 100644 --- a/genai/safety/safety-with-txt.js +++ b/genai/safety/safety-with-txt.js @@ -20,11 +20,11 @@ const {GoogleGenAI} = 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 generateWithSafetySettings( projectId = GOOGLE_CLOUD_PROJECT, location = GOOGLE_CLOUD_LOCATION ) { - const ai = new GoogleGenAI({ + const client = new GoogleGenAI({ vertexai: true, project: projectId, location: location, @@ -54,7 +54,7 @@ async function generateContent( }, ]; - const response = await ai.models.generateContent({ + const response = await client.models.generateContent({ model: 'gemini-2.5-flash', contents: prompt, config: { @@ -111,5 +111,5 @@ async function generateContent( // [END googlegenaisdk_safety_with_txt] module.exports = { - generateContent, + generateWithSafetySettings, }; diff --git a/genai/test/api-key-example.test.js b/genai/test/api-key-example.test.js index a77f1024fb..021886fe57 100644 --- a/genai/test/api-key-example.test.js +++ b/genai/test/api-key-example.test.js @@ -42,7 +42,7 @@ describe('vertexai-express-mode', () => { '@google/genai': {GoogleGenAI: MockGoogleGenAI}, }); - const response = await sample.generateContent('FAKE_API_KEY'); + const response = await sample.generateWithApiKey('FAKE_API_KEY'); assert.strictEqual(response.text, mockGenerateContentStreamResult.text); }); diff --git a/genai/test/boundingbox-with-txt-img.test.js b/genai/test/boundingbox-with-txt-img.test.js index 18f4ac19ad..fb2950e150 100644 --- a/genai/test/boundingbox-with-txt-img.test.js +++ b/genai/test/boundingbox-with-txt-img.test.js @@ -23,7 +23,7 @@ const sample = require('../bounding-box/boundingbox-with-txt-img'); describe('boundingbox-with-txt-img', async () => { it('should return the bounding box', async function () { this.timeout(100000); - const output = await sample.generateContent(projectId); + const output = await sample.createBoundingBox(projectId); assert(output.length > 0); }); }); diff --git a/genai/test/embeddings-docretrieval-with-txt.test.js b/genai/test/embeddings-docretrieval-with-txt.test.js index 0e9146dfe8..08d2edbc7f 100644 --- a/genai/test/embeddings-docretrieval-with-txt.test.js +++ b/genai/test/embeddings-docretrieval-with-txt.test.js @@ -22,7 +22,8 @@ const sample = require('../embeddings/embeddings-docretrieval-with-txt.js'); describe('embeddings-docretrieval-with-txt', async () => { it('should return an object containing embeddings and metadata', async () => { - const generatedFileNames = await sample.generateContent(projectId); + const generatedFileNames = + await sample.generateEmbeddingsForRetrieval(projectId); assert.containsAllKeys(generatedFileNames, ['embeddings', 'metadata']); }); }); diff --git a/genai/test/provisionedthroughput-with-txt.test.js b/genai/test/provisionedthroughput-with-txt.test.js index 3e0189b389..f036a890d5 100644 --- a/genai/test/provisionedthroughput-with-txt.test.js +++ b/genai/test/provisionedthroughput-with-txt.test.js @@ -23,7 +23,7 @@ const sample = require('../provisioned-throughput/provisionedthroughput-with-txt describe('provisionedthroughput-with-txt', () => { it('should return provisioned throughput result', async function () { this.timeout(50000); - const output = await sample.generateContent(projectId); + const output = await sample.generateWithProvisionedThroughput(projectId); assert(output.length > 0); }); }); diff --git a/genai/test/safety-with-txt.test.js b/genai/test/safety-with-txt.test.js index 3929f68fb8..40fdbd2faf 100644 --- a/genai/test/safety-with-txt.test.js +++ b/genai/test/safety-with-txt.test.js @@ -23,7 +23,7 @@ const sample = require('../safety/safety-with-txt.js'); describe('safety-with-txt', () => { it('should call generateContentStream with safety instructions', async function () { this.timeout(50000); - const output = await sample.generateContent(projectId); + const output = await sample.generateWithSafetySettings(projectId); assert(output.text.length > 0); }); }); From 42b4fc47e842341ffcf0006a83c0592ce8f39319 Mon Sep 17 00:00:00 2001 From: Guiners Date: Thu, 20 Nov 2025 11:08:59 +0100 Subject: [PATCH 10/10] adding count token samples --- genai/bounding-box/boundingbox-with-txt-img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genai/bounding-box/boundingbox-with-txt-img.js b/genai/bounding-box/boundingbox-with-txt-img.js index cd2f874d49..2eb6852c5d 100644 --- a/genai/bounding-box/boundingbox-with-txt-img.js +++ b/genai/bounding-box/boundingbox-with-txt-img.js @@ -75,7 +75,7 @@ async function createBoundingBox( Return bounding boxes as an array with labels. Never return masks. Limit to 25 objects. If an object is present multiple times, give each object a unique label - according to its distinct characteristics (colors, size, position, etc.). + according to its distinct characteristics (colors, size, position, etc). `; const safetySettings = [