From 25111cdaabcbb307db2ee865c13858c17fb533d5 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:09:32 -0700 Subject: [PATCH 1/7] added function calling --- samples/node/function_calling.js | 96 ++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 samples/node/function_calling.js diff --git a/samples/node/function_calling.js b/samples/node/function_calling.js new file mode 100644 index 00000000..e1e4b2a7 --- /dev/null +++ b/samples/node/function_calling.js @@ -0,0 +1,96 @@ +/** + * @license + * Copyright 2024 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 + * + * http://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. + */ + +import { GoogleGenerativeAI } from "@google/generative-ai"; + +async function functionCalling() { + // [START function_calling] + async function setLightValues(brightness, colorTemperature) { + // This mock API returns the requested lighting values + return { + brightness, + colorTemperature, + }; + } + + const controlLightFunctionDeclaration = { + name: "controlLight", + parameters: { + type: "OBJECT", + description: "Set the brightness and color temperature of a room light.", + properties: { + brightness: { + type: "NUMBER", + description: + "Light level from 0 to 100. Zero is off and 100 is full brightness.", + }, + colorTemperature: { + type: "STRING", + description: + "Color temperature of the light fixture which can be `daylight`, `cool` or `warm`.", + }, + }, + required: ["brightness", "colorTemperature"], + }, + }; + + // Executable function code. Put it in a map keyed by the function name + // so that you can call it once you get the name string from the model. + const functions = { + controlLight: ({ brightness, colorTemperature }) => { + return setLightValues(brightness, colorTemperature); + }, + }; + + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + tools: { functionDeclarations: [controlLightFunctionDeclaration] }, + }); + const chat = model.startChat(); + const prompt = "Dim the lights so the room feels cozy and warm."; + + // Send the message to the model. + const result = await chat.sendMessage(prompt); + + // For simplicity, this uses the first function call found. + const call = result.response.functionCalls()[0]; + + if (call) { + // Call the executable function named in the function call + // with the arguments specified in the function call and + // let it call the hypothetical API. + const apiResponse = await functions[call.name](call.args); + + // Send the API response back to the model so it can generate + // a text response that can be displayed to the user. + const result2 = await chat.sendMessage([ + { + functionResponse: { + name: "controlLight", + response: apiResponse, + }, + }, + ]); + + // Log the text response. + console.log(result2.response.text()); + } + // [END function_calling] +} + +functionCalling(); \ No newline at end of file From d849e72ea594c567626b8044dc939c0014981460 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:33:35 -0700 Subject: [PATCH 2/7] added controlled_generation --- samples/node/README.md | 16 +++++- samples/node/controlled_generation.js | 81 +++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 samples/node/controlled_generation.js diff --git a/samples/node/README.md b/samples/node/README.md index 30d1e6e5..3f51380d 100644 --- a/samples/node/README.md +++ b/samples/node/README.md @@ -1,9 +1,9 @@ # Google Generative AI Sample for Node.js (Javascript) -This sample demonstrates how to use state-of-the-art +These samples demonstrate how to use state-of-the-art generative AI models (like Gemini) to build AI-powered features and applications. -To try out this sample, you'll need Node.js v18+. +To try out these samples, you'll need Node.js v18+. ## Requirements @@ -13,6 +13,18 @@ It’s strongly recommended that you do not check an API key into your version c This sample assumes that you're providing an `API_KEY` environment variable. +## Instructions + +Each of these sample files can be run in Node.js from the command line, for +example: + +``` +node function_calling.js +``` + +Some of these files run multiple example cases sequentially, and you may want +to comment out cases you do not want to run. + ## Documentation - [Quickstart: Get started with the Gemini API in Node.js applications](https://ai.google.dev/tutorials/node_quickstart) diff --git a/samples/node/controlled_generation.js b/samples/node/controlled_generation.js new file mode 100644 index 00000000..b940e946 --- /dev/null +++ b/samples/node/controlled_generation.js @@ -0,0 +1,81 @@ +/** + * @license + * Copyright 2024 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 + * + * http://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. + */ + +import { + FunctionDeclarationSchemaType, + GoogleGenerativeAI, +} from "@google/generative-ai"; + +async function jsonControlledGeneration() { + // [START json_controlled_generation] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + + const schema = { + description: "List of recipes", + type: FunctionDeclarationSchemaType.ARRAY, + items: { + type: FunctionDeclarationSchemaType.OBJECT, + properties: { + recipeName: { + type: FunctionDeclarationSchemaType.STRING, + description: "Name of the recipe", + nullable: false + }, + }, + required: ["recipeName"], + }, + }; + + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-pro", + generationConfig: { + responseMimeType: "application/json", + responseSchema: schema, + }, + }); + + const result = await model.generateContent( + "List a few popular cookie recipes.", + ); + console.log(result.response.text()); + // [END json_controlled_generation] +} + +async function jsonNoSchema() { + // [START json_no_schema] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + }); + + const prompt = `List a few popular cookie recipes using this JSON schema: + + Recipe = {'recipeName': string} + Return: Array`; + + const result = await model.generateContent(prompt); + console.log(result.response.text()); + // [END json_no_schema] +} + +async function run() { + await jsonControlledGeneration(); + await jsonNoSchema(); +} + +run(); From bfdbf6a3cc756145901a548a118484c854a95546 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:38:26 -0700 Subject: [PATCH 3/7] Add model_configuration --- samples/node/controlled_generation.js | 2 +- samples/node/function_calling.js | 2 +- samples/node/model_configuration.js | 40 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 samples/node/model_configuration.js diff --git a/samples/node/controlled_generation.js b/samples/node/controlled_generation.js index b940e946..c6854541 100644 --- a/samples/node/controlled_generation.js +++ b/samples/node/controlled_generation.js @@ -33,7 +33,7 @@ async function jsonControlledGeneration() { recipeName: { type: FunctionDeclarationSchemaType.STRING, description: "Name of the recipe", - nullable: false + nullable: false, }, }, required: ["recipeName"], diff --git a/samples/node/function_calling.js b/samples/node/function_calling.js index e1e4b2a7..98e34fb3 100644 --- a/samples/node/function_calling.js +++ b/samples/node/function_calling.js @@ -93,4 +93,4 @@ async function functionCalling() { // [END function_calling] } -functionCalling(); \ No newline at end of file +functionCalling(); diff --git a/samples/node/model_configuration.js b/samples/node/model_configuration.js new file mode 100644 index 00000000..a2b76910 --- /dev/null +++ b/samples/node/model_configuration.js @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2024 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 + * + * http://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. + */ + +import { GoogleGenerativeAI } from "@google/generative-ai"; + +async function configureModel() { + // [START configure_model] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + generationConfig: { + candidateCount: 1, + stopSequences: ["x"], + maxOutputTokens: 20, + temperature: 1.0, + }, + }); + + const result = await model.generateContent( + "Tell me a story about a magic backpack.", + ); + console.log(result.response.text()); + // [END configure_model] +} + +configureModel(); From 0a5084e7bedeb651d394a740bf23d78ba522a164 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:46:57 -0700 Subject: [PATCH 4/7] add safety_settings --- samples/node/safety_settings.js | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 samples/node/safety_settings.js diff --git a/samples/node/safety_settings.js b/samples/node/safety_settings.js new file mode 100644 index 00000000..3c69cf14 --- /dev/null +++ b/samples/node/safety_settings.js @@ -0,0 +1,89 @@ +/** + * @license + * Copyright 2024 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 + * + * http://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. + */ + +import { + GoogleGenerativeAI, + HarmBlockThreshold, + HarmCategory, +} from "@google/generative-ai"; + +async function safetySettings() { + // [START safety_settings] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + safetySettings: [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, + }, + ], + }); + + const unsafePrompt = + "I support Martians Soccer Club and I think " + + "Jupiterians Football Club sucks! Write a ironic phrase about them."; + + const result = await model.generateContent(unsafePrompt); + + try { + result.response.text(); + } catch (e) { + console.error(e); + console.log(result.response.candidates[0].safetyRatings); + } + // [END safety_settings] +} + +async function safetySettingsMulti() { + // [START safety_settings_multi] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + safetySettings: [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, + }, + ], + }); + + const unsafePrompt = + "I support Martians Soccer Club and I think " + + "Jupiterians Football Club sucks! Write a ironic phrase about them."; + + const result = await model.generateContent(unsafePrompt); + + try { + result.response.text(); + } catch (e) { + console.error(e); + console.log(result.response.candidates[0].safetyRatings); + } + // [END safety_settings_multi] +} + +async function run() { + // await safetySettings(); + await safetySettingsMulti(); +} + +run(); From 1c2cd723b9d916785d8c6324877fd302cffe289c Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:49:05 -0700 Subject: [PATCH 5/7] add system_instruction --- ...simple-config.js => system_instruction.js} | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) rename samples/node/{simple-config.js => system_instruction.js} (53%) diff --git a/samples/node/simple-config.js b/samples/node/system_instruction.js similarity index 53% rename from samples/node/simple-config.js rename to samples/node/system_instruction.js index 9f3f63dc..8a7b682b 100644 --- a/samples/node/simple-config.js +++ b/samples/node/system_instruction.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,22 +15,23 @@ * limitations under the License. */ -import { genAI } from "./utils/common.js"; +import { GoogleGenerativeAI } from "@google/generative-ai"; -async function run(options = {}) { - const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash-latest", ...options }); +async function systemInstruction() { + // [START system_instruction] + const genAI = new GoogleGenerativeAI(process.env.API_KEY); + const model = genAI.getGenerativeModel({ + model: "gemini-1.5-flash", + systemInstruction: "You are a cat. Your name is Neko.", + }); - const prompt = "One, two, three, "; + const prompt = "Good morning! How are you?"; const result = await model.generateContent(prompt); - console.log(options, "\n" + result.response.text() + "\n"); + const response = result.response; + const text = response.text(); + console.log(text); + // [END system_instruction] } -async function runAll() { - await run(); - await run({ generationConfig: { maxOutputTokens: 3 } }); - await run({ generationConfig: { stopSequences: ["seven"] } }); - await run({ generationConfig: { temperature: 0 } }); -} - -runAll(); +systemInstruction(); \ No newline at end of file From dff2078899291855990142d5369779e16453e465 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 3 Jul 2024 12:50:48 -0700 Subject: [PATCH 6/7] Clean up redundant files --- samples/node/advanced-function-calling.js | 110 ---------------------- samples/node/advanced-text-and-images.js | 54 ----------- 2 files changed, 164 deletions(-) delete mode 100644 samples/node/advanced-function-calling.js delete mode 100644 samples/node/advanced-text-and-images.js diff --git a/samples/node/advanced-function-calling.js b/samples/node/advanced-function-calling.js deleted file mode 100644 index c7295342..00000000 --- a/samples/node/advanced-function-calling.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright 2024 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 - * - * http://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. - */ - -import { FunctionDeclarationSchemaType } from "@google/generative-ai"; -import { genAI } from "./utils/common.js"; - -async function run() { - const functions = { - convertCtoF: ({ value }) => { - const num = typeof value === "string" ? parseFloat(value) : value; - if (!Number.isFinite(num)) { - throw new Error("Value should finite number"); - } - return (num * 9) / 5 + 32; - }, - }; - const tools = [ - { - functionDeclarations: [ - { - name: "convertCtoF", - description: "Convert temperature from Celsius to Fahrenheit", - parameters: { - type: FunctionDeclarationSchemaType.OBJECT, - properties: { - value: { type: FunctionDeclarationSchemaType.NUMBER }, - }, - required: ["value"], - }, - }, - ], - }, - ]; - - const model = genAI.getGenerativeModel( - { model: "gemini-1.5-flash-latest", tools }, - { apiVersion: "v1beta" }, - ); - - const prompt = { - role: "user", - parts: [ - { - text: "Convert 15 Celsius to Fahrenheit", - }, - ], - }; - - const result = await model.generateContent({ - contents: [prompt], - }); - const response = result.response; - console.dir(response, { depth: null }); - - if (response.candidates.length === 0) { - throw new Error("No candidates"); - } - - const content = result.response.candidates[0].content; - if (content.parts.length === 0) { - throw new Error("No parts"); - } - const fc = content.parts[0].functionCall; - const text = content.parts.map(({ text }) => text).join(""); - if (fc) { - const { name, args } = fc; - const fn = functions[name]; - if (!fn) { - throw new Error(`Unknown function "${name}"`); - } - const fr = { - role: "function", - parts: [ - { - functionResponse: { - name, - response: { - name, - content: functions[name](args), - }, - }, - }, - ], - }; - const request2 = { - contents: [prompt, content, fr], - }; - const response2 = await model.generateContent(request2); - const result2 = response2.response; - console.log(result2.text()); - } else if (text) { - console.log(text); - } -} - -run(); diff --git a/samples/node/advanced-text-and-images.js b/samples/node/advanced-text-and-images.js deleted file mode 100644 index 9abcade6..00000000 --- a/samples/node/advanced-text-and-images.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @license - * Copyright 2023 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 - * - * http://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. - */ - -import { - genAI, - fileToGenerativePart, - displayTokenCount, - streamToStdout, -} from "./utils/common.js"; - -async function run() { - const model = genAI.getGenerativeModel({ - model: "gemini-1.5-flash-latest", - generationConfig: { - temperature: 0, - }, - }); - - const prompt = - "What do you see? Use lists. Start with a headline for each image."; - - // Note: The only accepted mime types are some image types, image/*. - const imageParts = [ - fileToGenerativePart("./utils/cat.jpg", "image/jpeg"), - fileToGenerativePart("./utils/scones.jpg", "image/jpeg"), - ]; - - displayTokenCount(model, [prompt, ...imageParts]); - - const result = await model.generateContentStream([prompt, ...imageParts]); - - // Stream the first candidate text - await streamToStdout(result.stream); - - // Display the aggregated response - const response = await result.response; - console.log(JSON.stringify(response, null, 2)); -} - -run(); From 8f041a0dce100aeeae598553f999c3b67814f261 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 8 Jul 2024 12:56:41 -0700 Subject: [PATCH 7/7] Update safety settings sample for better success rate. --- samples/node/safety_settings.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/node/safety_settings.js b/samples/node/safety_settings.js index 3c69cf14..f39f1eef 100644 --- a/samples/node/safety_settings.js +++ b/samples/node/safety_settings.js @@ -36,7 +36,8 @@ async function safetySettings() { const unsafePrompt = "I support Martians Soccer Club and I think " + - "Jupiterians Football Club sucks! Write a ironic phrase about them."; + "Jupiterians Football Club sucks! Write an ironic phrase telling " + + "them how I feel about them."; const result = await model.generateContent(unsafePrompt); @@ -68,7 +69,8 @@ async function safetySettingsMulti() { const unsafePrompt = "I support Martians Soccer Club and I think " + - "Jupiterians Football Club sucks! Write a ironic phrase about them."; + "Jupiterians Football Club sucks! Write an ironic phrase telling " + + "them how I feel about them."; const result = await model.generateContent(unsafePrompt); @@ -82,7 +84,7 @@ async function safetySettingsMulti() { } async function run() { - // await safetySettings(); + await safetySettings(); await safetySettingsMulti(); }