diff --git a/genai/controlled-generation/ctrlgen-with-class-schema.js b/genai/controlled-generation/ctrlgen-with-class-schema.js new file mode 100644 index 0000000000..a1584c4e4d --- /dev/null +++ b/genai/controlled-generation/ctrlgen-with-class-schema.js @@ -0,0 +1,79 @@ +// 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_ctrlgen_with_class_schema] +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 generateClassSchema( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + class Recipe { + /** + * @param {string} recipeName + * @param {string[]} ingredients + */ + constructor(recipeName, ingredients) { + this.recipeName = recipeName; + this.ingredients = ingredients; + } + } + + const response = await client.models.generateContent({ + model: 'gemini-2.5-flash', + contents: 'List a few popular cookie recipes?', + config: { + responseMimeType: 'application/json', + responseSchema: Recipe, + }, + }); + + console.log(response.text); + + // Example output: + // [Recipe(recipe_name='Chocolate Chip Cookies', ingredients=['2 1/4 cups all-purpose flour' + // { + // "ingredients": [ + // "2 1/4 cups all-purpose flour", + // "1 teaspoon baking soda", + // "1 teaspoon salt", + // "1 cup (2 sticks) unsalted butter, softened", + // "3/4 cup granulated sugar", + // "3/4 cup packed brown sugar", + // "1 teaspoon vanilla extract", + // "2 large eggs", + // "2 cups chocolate chips" + // ], + // "recipe_name": "Classic Chocolate Chip Cookies" + // }, ... ] + + return response.text; +} + +// [END googlegenaisdk_ctrlgen_with_class_schema] + +module.exports = { + generateClassSchema, +}; diff --git a/genai/controlled-generation/ctrlgen-with-enum-class-schema.js b/genai/controlled-generation/ctrlgen-with-enum-class-schema.js new file mode 100644 index 0000000000..bb59dd6aae --- /dev/null +++ b/genai/controlled-generation/ctrlgen-with-enum-class-schema.js @@ -0,0 +1,77 @@ +// 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_ctrlgen_with_enum_class_schema] +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 generateEnumClassSchema( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + class InstrumentClass { + static values() { + return [ + InstrumentClass.PERCUSSION, + InstrumentClass.STRING, + InstrumentClass.WOODWIND, + InstrumentClass.BRASS, + InstrumentClass.KEYBOARD, + ]; + } + } + + InstrumentClass.PERCUSSION = 'Percussion'; + InstrumentClass.STRING = 'String'; + InstrumentClass.WOODWIND = 'Woodwind'; + InstrumentClass.BRASS = 'Brass'; + InstrumentClass.KEYBOARD = 'Keyboard'; + + const responseSchema = { + type: 'string', + enum: InstrumentClass.values(), + }; + + const response = await client.models.generateContent({ + model: 'gemini-2.5-flash', + contents: 'What type of instrument is a guitar?', + config: { + responseMimeType: 'text/x.enum', + responseSchema: responseSchema, + }, + }); + + console.log(response.text); + + // Example output: + // String + + return response.text; +} + +// [END googlegenaisdk_ctrlgen_with_enum_class_schema] + +module.exports = { + generateEnumClassSchema, +}; diff --git a/genai/controlled-generation/ctrlgen-with-enum-schema.js b/genai/controlled-generation/ctrlgen-with-enum-schema.js index b87c513aab..32cdc9a3d7 100644 --- a/genai/controlled-generation/ctrlgen-with-enum-schema.js +++ b/genai/controlled-generation/ctrlgen-with-enum-schema.js @@ -24,7 +24,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, @@ -35,7 +35,7 @@ async function generateContent( enum: ['Percussion', 'String', 'Woodwind', 'Brass', 'Keyboard'], }; - const response = await ai.models.generateContent({ + const response = await client.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What type of instrument is an oboe?', config: { @@ -45,9 +45,11 @@ async function generateContent( }); console.log(response.text); - + // Example output: + // Woodwind return response.text; } + // [END googlegenaisdk_ctrlgen_with_enum_schema] module.exports = { diff --git a/genai/controlled-generation/ctrlgen-with-nested-class-schema.js b/genai/controlled-generation/ctrlgen-with-nested-class-schema.js new file mode 100644 index 0000000000..46e7277d52 --- /dev/null +++ b/genai/controlled-generation/ctrlgen-with-nested-class-schema.js @@ -0,0 +1,78 @@ +// 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_ctrlgen_with_nested_class_schema] +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 generateNestedClassSchema( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const Grade = Object.freeze({ + A_PLUS: 'a+', + A: 'a', + B: 'b', + C: 'c', + D: 'd', + F: 'f', + }); + + class Recipe { + /** + * @param {string} recipeName + * @param {string} rating - Must be one of Grade enum values + */ + constructor(recipeName, rating) { + if (!Object.values(Grade).includes(rating)) { + throw new Error(`Invalid rating: ${rating}`); + } + this.recipeName = recipeName; + this.rating = rating; + } + } + + const response = await client.models.generateContent({ + model: 'gemini-2.5-flash', + contents: + 'List about 10 home-baked cookies and give them grades based on tastiness.', + config: { + responseMimeType: 'application/json', + responseSchema: Recipe, + }, + }); + + console.log(response.text); + + // Example output: + // [{"rating": "a+", "recipe_name": "Classic Chocolate Chip Cookies"}, ...] + + return response.text; +} + +// [END googlegenaisdk_ctrlgen_with_nested_class_schema] + +module.exports = { + generateNestedClassSchema, +}; diff --git a/genai/controlled-generation/ctrlgen-with-nullable-schema.js b/genai/controlled-generation/ctrlgen-with-nullable-schema.js new file mode 100644 index 0000000000..d302f7e85f --- /dev/null +++ b/genai/controlled-generation/ctrlgen-with-nullable-schema.js @@ -0,0 +1,90 @@ +// 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_ctrlgen_with_nullable_schema] +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 generateNullableSchema( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const prompt = ` + The week ahead brings a mix of weather conditions. + Sunday is expected to be sunny with a temperature of 77°F and a humidity level of 50%. Winds will be light at around 10 km/h. + Monday will see partly cloudy skies with a slightly cooler temperature of 72°F and the winds will pick up slightly to around 15 km/h. + Tuesday brings rain showers, with temperatures dropping to 64°F and humidity rising to 70%. + Wednesday may see thunderstorms, with a temperature of 68°F. + Thursday will be cloudy with a temperature of 66°F and moderate humidity at 60%. + Friday returns to partly cloudy conditions, with a temperature of 73°F and the Winds will be light at 12 km/h. + Finally, Saturday rounds off the week with sunny skies, a temperature of 80°F, and a humidity level of 40%. Winds will be gentle at 8 km/h. +`; + + const responseSchema = { + type: 'object', + properties: { + forecast: { + type: 'array', + items: { + type: 'object', + properties: { + Day: {type: 'string', nullable: true}, + Forecast: {type: 'string', nullable: true}, + Temperature: {type: 'integer', nullable: true}, + Humidity: {type: 'string', nullable: true}, + WindSpeed: {type: 'integer', nullable: true}, + }, + required: ['Day', 'Temperature', 'Forecast', 'WindSpeed'], + }, + }, + }, + }; + + const response = await client.models.generateContent({ + model: 'gemini-2.5-flash', + contents: prompt, + config: { + responseMimeType: 'application/json', + responseSchema: responseSchema, + }, + }); + console.log(response.text); + + // Example output: + // {"forecast": [{"Day": "Sunday", "Forecast": "sunny", "Temperature": 77, "Wind Speed": 10, "Humidity": "50%"}, + // {"Day": "Monday", "Forecast": "partly cloudy", "Temperature": 72, "Wind Speed": 15}, + // {"Day": "Tuesday", "Forecast": "rain showers", "Temperature": 64, "Wind Speed": null, "Humidity": "70%"}, + // {"Day": "Wednesday", "Forecast": "thunderstorms", "Temperature": 68, "Wind Speed": null}, + // {"Day": "Thursday", "Forecast": "cloudy", "Temperature": 66, "Wind Speed": null, "Humidity": "60%"}, + // {"Day": "Friday", "Forecast": "partly cloudy", "Temperature": 73, "Wind Speed": 12}, + // {"Day": "Saturday", "Forecast": "sunny", "Temperature": 80, "Wind Speed": 8, "Humidity": "40%"}]} + + return response.text; +} + +// [END googlegenaisdk_ctrlgen_with_nullable_schema] + +module.exports = { + generateNullableSchema, +}; diff --git a/genai/controlled-generation/ctrlgen-with-resp-schema.js b/genai/controlled-generation/ctrlgen-with-resp-schema.js new file mode 100644 index 0000000000..a9508189e8 --- /dev/null +++ b/genai/controlled-generation/ctrlgen-with-resp-schema.js @@ -0,0 +1,86 @@ +// 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_ctrlgen_with_resp_schema] +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 generateResponseSchema( + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const prompt = 'List a few popular cookie recipes.'; + + const responseSchema = { + type: 'ARRAY', + items: { + type: 'OBJECT', + properties: { + recipeName: {type: 'STRING'}, + ingredients: { + type: 'ARRAY', + items: {type: 'STRING'}, + }, + }, + required: ['recipeName', 'ingredients'], + }, + }; + + const response = await client.models.generateContent({ + model: 'gemini-2.5-flash', + contents: prompt, + config: { + responseMimeType: 'application/json', + responseSchema: responseSchema, + }, + }); + + console.log(response.text); + + // Example output: + // [ + // { + // "ingredients": [ + // "2 1/4 cups all-purpose flour", + // "1 teaspoon baking soda", + // "1 teaspoon salt", + // "1 cup (2 sticks) unsalted butter, softened", + // "3/4 cup granulated sugar", + // "3/4 cup packed brown sugar", + // "1 teaspoon vanilla extract", + // "2 large eggs", + // "2 cups chocolate chips", + // ], + // "recipe_name": "Chocolate Chip Cookies", + // } + // ] + + return response.text; +} + +// [END googlegenaisdk_ctrlgen_with_resp_schema] + +module.exports = { + generateResponseSchema, +}; diff --git a/genai/test/ctrlgen-with-class-schema.test.js b/genai/test/ctrlgen-with-class-schema.test.js new file mode 100644 index 0000000000..10acd5d676 --- /dev/null +++ b/genai/test/ctrlgen-with-class-schema.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('../controlled-generation/ctrlgen-with-class-schema.js'); + +describe('ctrlgen-with-class-schema', () => { + it('should generate text content in Json', async function () { + this.timeout(10000); + const output = await sample.generateClassSchema(projectId); + assert(output.length > 0 && output.includes('Cookies')); + }); +}); diff --git a/genai/test/ctrlgen-with-enum-class-schema.test.js b/genai/test/ctrlgen-with-enum-class-schema.test.js new file mode 100644 index 0000000000..7c54e6b82e --- /dev/null +++ b/genai/test/ctrlgen-with-enum-class-schema.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('../controlled-generation/ctrlgen-with-enum-class-schema.js'); + +describe('ctrlgen-with-enum-class-schema', () => { + it('should generate text content matching enum schema', async function () { + this.timeout(10000); + const output = await sample.generateEnumClassSchema(projectId); + assert(output.length > 0 && output.includes('String')); + }); +}); diff --git a/genai/test/ctrlgen-with-nested-class-schema.test.js b/genai/test/ctrlgen-with-nested-class-schema.test.js new file mode 100644 index 0000000000..8bb16e3f62 --- /dev/null +++ b/genai/test/ctrlgen-with-nested-class-schema.test.js @@ -0,0 +1,32 @@ +// 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('../controlled-generation/ctrlgen-with-nested-class-schema.js'); +const {delay} = require('./util'); + +describe('ctrlgen-with-nested-class-schema', () => { + it('should generate text content using nested schema', async function () { + this.timeout(180000); + this.retries(4); + await delay(this.test); + const output = await sample.generateNestedClassSchema(projectId); + assert(output.length > 0); + }); +}); diff --git a/genai/test/ctrlgen-with-nullable-schema.test.js b/genai/test/ctrlgen-with-nullable-schema.test.js new file mode 100644 index 0000000000..7edf7055b5 --- /dev/null +++ b/genai/test/ctrlgen-with-nullable-schema.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('../controlled-generation/ctrlgen-with-nullable-schema.js'); + +describe('ctrlgen-with-nullable-schema', () => { + it('should generate text content using nullable schema', async function () { + this.timeout(10000); + const output = await sample.generateNullableSchema(projectId); + assert(output.length > 0); + }); +}); diff --git a/genai/test/ctrlgen-with-resp-schema.test.js b/genai/test/ctrlgen-with-resp-schema.test.js new file mode 100644 index 0000000000..3e0a4e2608 --- /dev/null +++ b/genai/test/ctrlgen-with-resp-schema.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('../controlled-generation/ctrlgen-with-resp-schema.js'); + +describe('ctrlgen-with-resp-schema', () => { + it('should generate text content in given schema', async function () { + this.timeout(10000); + const output = await sample.generateResponseSchema(projectId); + assert(output.length > 0 && output.includes('Cookies')); + }); +}); diff --git a/genai/test/imggen-mmflash-with-txt.test.js b/genai/test/imggen-mmflash-with-txt.test.js index 908adabe3b..44f109b269 100644 --- a/genai/test/imggen-mmflash-with-txt.test.js +++ b/genai/test/imggen-mmflash-with-txt.test.js @@ -24,7 +24,7 @@ const {delay} = require('./util'); describe('imggen-mmflash-with-txt', async () => { it('should generate images from a text prompt', async function () { this.timeout(180000); - this.retries(4); + this.retries(10); await delay(this.test); const generatedFileNames = await sample.generateContent(projectId); assert(Array.isArray(generatedFileNames));