diff --git a/ai-platform/snippets/imagen-edit-image-inpainting-insert-mask.js b/ai-platform/snippets/imagen-edit-image-inpainting-insert-mask.js new file mode 100644 index 0000000000..843ddb663c --- /dev/null +++ b/ai-platform/snippets/imagen-edit-image-inpainting-insert-mask.js @@ -0,0 +1,121 @@ +/* + * 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 + * + * 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'; + +async function main() { + // [START generativeaionvertexai_imagen_edit_image_inpainting_insert_mask] + /** + * TODO(developer): Update these variables before running the sample. + */ + const projectId = process.env.CAIP_PROJECT_ID; + const location = 'us-central1'; + const inputFile = 'resources/woman.png'; + const maskFile = 'resources/woman_inpainting_insert_mask.png'; + const prompt = 'hat'; + + const aiplatform = require('@google-cloud/aiplatform'); + + // Imports the Google Cloud Prediction Service Client library + const {PredictionServiceClient} = aiplatform.v1; + + // Import the helper module for converting arbitrary protobuf.Value objects + const {helpers} = aiplatform; + + // Specifies the location of the api endpoint + const clientOptions = { + apiEndpoint: `${location}-aiplatform.googleapis.com`, + }; + + // Instantiates a client + const predictionServiceClient = new PredictionServiceClient(clientOptions); + + async function editImageInpaintingInsertMask() { + const fs = require('fs'); + const util = require('util'); + // Configure the parent resource + const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/imagegeneration@006`; + + const imageFile = fs.readFileSync(inputFile); + // Convert the image data to a Buffer and base64 encode it. + const encodedImage = Buffer.from(imageFile).toString('base64'); + + const maskImageFile = fs.readFileSync(maskFile); + // Convert the image mask data to a Buffer and base64 encode it. + const encodedMask = Buffer.from(maskImageFile).toString('base64'); + + const promptObj = { + prompt: prompt, // The text prompt describing what you want to see inserted + editMode: 'inpainting-insert', + image: { + bytesBase64Encoded: encodedImage, + }, + mask: { + image: { + bytesBase64Encoded: encodedMask, + }, + }, + }; + const instanceValue = helpers.toValue(promptObj); + const instances = [instanceValue]; + + const parameter = { + // Optional parameters + seed: 100, + // Controls the strength of the prompt + // 0-9 (low strength), 10-20 (medium strength), 21+ (high strength) + guidanceScale: 21, + sampleCount: 1, + }; + const parameters = helpers.toValue(parameter); + + const request = { + endpoint, + instances, + parameters, + }; + + // Predict request + const [response] = await predictionServiceClient.predict(request); + const predictions = response.predictions; + if (predictions.length === 0) { + console.log( + 'No image was generated. Check the request parameters and prompt.' + ); + } else { + let i = 1; + for (const prediction of predictions) { + const buff = Buffer.from( + prediction.structValue.fields.bytesBase64Encoded.stringValue, + 'base64' + ); + // Write image content to the output file + const writeFile = util.promisify(fs.writeFile); + const filename = `output${i}.png`; + await writeFile(filename, buff); + console.log(`Saved image ${filename}`); + i++; + } + } + } + await editImageInpaintingInsertMask(); + // [END generativeaionvertexai_imagen_edit_image_inpainting_insert_mask] +} + +main().catch(err => { + console.error(err); + process.exitcode = 1; +}); diff --git a/ai-platform/snippets/imagen-edit-image-inpainting-remove-mask.js b/ai-platform/snippets/imagen-edit-image-inpainting-remove-mask.js new file mode 100644 index 0000000000..01901422af --- /dev/null +++ b/ai-platform/snippets/imagen-edit-image-inpainting-remove-mask.js @@ -0,0 +1,121 @@ +/* + * 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 + * + * 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'; + +async function main() { + // [START generativeaionvertexai_imagen_edit_image_inpainting_remove_mask] + /** + * TODO(developer): Update these variables before running the sample. + */ + const projectId = process.env.CAIP_PROJECT_ID; + const location = 'us-central1'; + const inputFile = 'resources/volleyball_game.png'; + const maskFile = 'resources/volleyball_game_inpainting_remove_mask.png'; + const prompt = 'volleyball game'; + + const aiplatform = require('@google-cloud/aiplatform'); + + // Imports the Google Cloud Prediction Service Client library + const {PredictionServiceClient} = aiplatform.v1; + + // Import the helper module for converting arbitrary protobuf.Value objects + const {helpers} = aiplatform; + + // Specifies the location of the api endpoint + const clientOptions = { + apiEndpoint: `${location}-aiplatform.googleapis.com`, + }; + + // Instantiates a client + const predictionServiceClient = new PredictionServiceClient(clientOptions); + + async function editImageInpaintingRemoveMask() { + const fs = require('fs'); + const util = require('util'); + // Configure the parent resource + const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/imagegeneration@006`; + + const imageFile = fs.readFileSync(inputFile); + // Convert the image data to a Buffer and base64 encode it. + const encodedImage = Buffer.from(imageFile).toString('base64'); + + const maskImageFile = fs.readFileSync(maskFile); + // Convert the image mask data to a Buffer and base64 encode it. + const encodedMask = Buffer.from(maskImageFile).toString('base64'); + + const promptObj = { + prompt: prompt, // The text prompt describing the entire image + editMode: 'inpainting-remove', + image: { + bytesBase64Encoded: encodedImage, + }, + mask: { + image: { + bytesBase64Encoded: encodedMask, + }, + }, + }; + const instanceValue = helpers.toValue(promptObj); + const instances = [instanceValue]; + + const parameter = { + // Optional parameters + seed: 100, + // Controls the strength of the prompt + // 0-9 (low strength), 10-20 (medium strength), 21+ (high strength) + guidanceScale: 21, + sampleCount: 1, + }; + const parameters = helpers.toValue(parameter); + + const request = { + endpoint, + instances, + parameters, + }; + + // Predict request + const [response] = await predictionServiceClient.predict(request); + const predictions = response.predictions; + if (predictions.length === 0) { + console.log( + 'No image was generated. Check the request parameters and prompt.' + ); + } else { + let i = 1; + for (const prediction of predictions) { + const buff = Buffer.from( + prediction.structValue.fields.bytesBase64Encoded.stringValue, + 'base64' + ); + // Write image content to the output file + const writeFile = util.promisify(fs.writeFile); + const filename = `output${i}.png`; + await writeFile(filename, buff); + console.log(`Saved image ${filename}`); + i++; + } + } + } + await editImageInpaintingRemoveMask(); + // [END generativeaionvertexai_imagen_edit_image_inpainting_remove_mask] +} + +main().catch(err => { + console.error(err); + process.exitcode = 1; +}); diff --git a/ai-platform/snippets/imagen-edit-image-mask-free.js b/ai-platform/snippets/imagen-edit-image-mask-free.js new file mode 100644 index 0000000000..f5b58ada60 --- /dev/null +++ b/ai-platform/snippets/imagen-edit-image-mask-free.js @@ -0,0 +1,110 @@ +/* + * 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 + * + * 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'; + +async function main() { + // [START generativeaionvertexai_imagen_edit_image_mask_free] + /** + * TODO(developer): Update these variables before running the sample. + */ + const projectId = process.env.CAIP_PROJECT_ID; + const location = 'us-central1'; + const inputFile = 'resources/cat.png'; + const prompt = 'dog'; + + const aiplatform = require('@google-cloud/aiplatform'); + + // Imports the Google Cloud Prediction Service Client library + const {PredictionServiceClient} = aiplatform.v1; + + // Import the helper module for converting arbitrary protobuf.Value objects + const {helpers} = aiplatform; + + // Specifies the location of the api endpoint + const clientOptions = { + apiEndpoint: `${location}-aiplatform.googleapis.com`, + }; + + // Instantiates a client + const predictionServiceClient = new PredictionServiceClient(clientOptions); + + async function editImageMaskFree() { + const fs = require('fs'); + const util = require('util'); + // Configure the parent resource + const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/imagegeneration@002`; + + const imageFile = fs.readFileSync(inputFile); + // Convert the image data to a Buffer and base64 encode it. + const encodedImage = Buffer.from(imageFile).toString('base64'); + + const promptObj = { + prompt: prompt, // The text prompt describing what you want to see + image: { + bytesBase64Encoded: encodedImage, + }, + }; + const instanceValue = helpers.toValue(promptObj); + const instances = [instanceValue]; + + const parameter = { + // Optional parameters + seed: 100, + // Controls the strength of the prompt + // 0-9 (low strength), 10-20 (medium strength), 21+ (high strength) + guidanceScale: 21, + sampleCount: 1, + }; + const parameters = helpers.toValue(parameter); + + const request = { + endpoint, + instances, + parameters, + }; + + // Predict request + const [response] = await predictionServiceClient.predict(request); + const predictions = response.predictions; + if (predictions.length === 0) { + console.log( + 'No image was generated. Check the request parameters and prompt.' + ); + } else { + let i = 1; + for (const prediction of predictions) { + const buff = Buffer.from( + prediction.structValue.fields.bytesBase64Encoded.stringValue, + 'base64' + ); + // Write image content to the output file + const writeFile = util.promisify(fs.writeFile); + const filename = `output${i}.png`; + await writeFile(filename, buff); + console.log(`Saved image ${filename}`); + i++; + } + } + } + await editImageMaskFree(); + // [END generativeaionvertexai_imagen_edit_image_mask_free] +} + +main().catch(err => { + console.error(err); + process.exitcode = 1; +}); diff --git a/ai-platform/snippets/imagen-edit-image-outpainting-mask.js b/ai-platform/snippets/imagen-edit-image-outpainting-mask.js new file mode 100644 index 0000000000..458d2fb206 --- /dev/null +++ b/ai-platform/snippets/imagen-edit-image-outpainting-mask.js @@ -0,0 +1,121 @@ +/* + * 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 + * + * 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'; + +async function main() { + // [START generativeaionvertexai_imagen_edit_image_outpainting_mask] + /** + * TODO(developer): Update these variables before running the sample. + */ + const projectId = process.env.CAIP_PROJECT_ID; + const location = 'us-central1'; + const inputFile = 'resources/roller_skaters.png'; + const maskFile = 'resources/roller_skaters_mask.png'; + const prompt = 'city with skyscrapers'; + + const aiplatform = require('@google-cloud/aiplatform'); + + // Imports the Google Cloud Prediction Service Client library + const {PredictionServiceClient} = aiplatform.v1; + + // Import the helper module for converting arbitrary protobuf.Value objects + const {helpers} = aiplatform; + + // Specifies the location of the api endpoint + const clientOptions = { + apiEndpoint: `${location}-aiplatform.googleapis.com`, + }; + + // Instantiates a client + const predictionServiceClient = new PredictionServiceClient(clientOptions); + + async function editImageOutpaintingMask() { + const fs = require('fs'); + const util = require('util'); + // Configure the parent resource + const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/imagegeneration@006`; + + const imageFile = fs.readFileSync(inputFile); + // Convert the image data to a Buffer and base64 encode it. + const encodedImage = Buffer.from(imageFile).toString('base64'); + + const maskImageFile = fs.readFileSync(maskFile); + // Convert the image mask data to a Buffer and base64 encode it. + const encodedMask = Buffer.from(maskImageFile).toString('base64'); + + const promptObj = { + prompt: prompt, // The optional text prompt describing what you want to see inserted + editMode: 'outpainting', + image: { + bytesBase64Encoded: encodedImage, + }, + mask: { + image: { + bytesBase64Encoded: encodedMask, + }, + }, + }; + const instanceValue = helpers.toValue(promptObj); + const instances = [instanceValue]; + + const parameter = { + // Optional parameters + seed: 100, + // Controls the strength of the prompt + // 0-9 (low strength), 10-20 (medium strength), 21+ (high strength) + guidanceScale: 21, + sampleCount: 1, + }; + const parameters = helpers.toValue(parameter); + + const request = { + endpoint, + instances, + parameters, + }; + + // Predict request + const [response] = await predictionServiceClient.predict(request); + const predictions = response.predictions; + if (predictions.length === 0) { + console.log( + 'No image was generated. Check the request parameters and prompt.' + ); + } else { + let i = 1; + for (const prediction of predictions) { + const buff = Buffer.from( + prediction.structValue.fields.bytesBase64Encoded.stringValue, + 'base64' + ); + // Write image content to the output file + const writeFile = util.promisify(fs.writeFile); + const filename = `output${i}.png`; + await writeFile(filename, buff); + console.log(`Saved image ${filename}`); + i++; + } + } + } + await editImageOutpaintingMask(); + // [END generativeaionvertexai_imagen_edit_image_outpainting_mask] +} + +main().catch(err => { + console.error(err); + process.exitcode = 1; +}); diff --git a/ai-platform/snippets/imagen/generateImage.js b/ai-platform/snippets/imagen-generate-image.js similarity index 88% rename from ai-platform/snippets/imagen/generateImage.js rename to ai-platform/snippets/imagen-generate-image.js index 546b72b744..5601fb0079 100644 --- a/ai-platform/snippets/imagen/generateImage.js +++ b/ai-platform/snippets/imagen-generate-image.js @@ -16,15 +16,14 @@ 'use strict'; -const main = async () => { +async function main() { // [START generativeaionvertexai_imagen_generate_image] /** * TODO(developer): Update these variables before running the sample. */ const projectId = process.env.CAIP_PROJECT_ID; - const outputFile = 'my-output'; - const prompt = 'a dog reading a newspaper'; // The text prompt describing what you want to see const location = 'us-central1'; + const prompt = 'a dog reading a newspaper'; const aiplatform = require('@google-cloud/aiplatform'); @@ -42,15 +41,14 @@ const main = async () => { // Instantiates a client const predictionServiceClient = new PredictionServiceClient(clientOptions); - const fs = require('fs'); - const util = require('util'); - async function generateImage() { + const fs = require('fs'); + const util = require('util'); // Configure the parent resource const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/imagen-3.0-generate-001`; const promptText = { - prompt: prompt, + prompt: prompt, // The text prompt describing what you want to see }; const instanceValue = helpers.toValue(promptText); const instances = [instanceValue]; @@ -88,7 +86,7 @@ const main = async () => { ); // Write image content to the output file const writeFile = util.promisify(fs.writeFile); - const filename = `${outputFile}${i}.png`; + const filename = `output${i}.png`; await writeFile(filename, buff); console.log(`Saved image ${filename}`); i++; @@ -97,10 +95,9 @@ const main = async () => { } await generateImage(); // [END generativeaionvertexai_imagen_generate_image] -}; +} -// node generateImage.js main().catch(err => { - console.log(err); - process.exitCode = 1; + console.error(err); + process.exitcode = 1; }); diff --git a/ai-platform/snippets/package.json b/ai-platform/snippets/package.json index 49c852c5fd..4d7ad0964f 100644 --- a/ai-platform/snippets/package.json +++ b/ai-platform/snippets/package.json @@ -10,7 +10,7 @@ "*.js" ], "scripts": { - "test": "c8 mocha -p -j 2 --timeout 2400000 test/*.js test/**/*.test.js" + "test": "c8 mocha -p -j 2 --timeout 2400000 test/*.js" }, "dependencies": { "@google-cloud/aiplatform": "^3.0.0", diff --git a/ai-platform/snippets/resources/cat.png b/ai-platform/snippets/resources/cat.png new file mode 100644 index 0000000000..67f2b55a6f Binary files /dev/null and b/ai-platform/snippets/resources/cat.png differ diff --git a/ai-platform/snippets/resources/roller_skaters.png b/ai-platform/snippets/resources/roller_skaters.png new file mode 100644 index 0000000000..e63adbfdce Binary files /dev/null and b/ai-platform/snippets/resources/roller_skaters.png differ diff --git a/ai-platform/snippets/resources/roller_skaters_mask.png b/ai-platform/snippets/resources/roller_skaters_mask.png new file mode 100644 index 0000000000..333da89897 Binary files /dev/null and b/ai-platform/snippets/resources/roller_skaters_mask.png differ diff --git a/ai-platform/snippets/resources/volleyball_game.png b/ai-platform/snippets/resources/volleyball_game.png new file mode 100644 index 0000000000..2a335ef4fb Binary files /dev/null and b/ai-platform/snippets/resources/volleyball_game.png differ diff --git a/ai-platform/snippets/resources/volleyball_game_inpainting_remove_mask.png b/ai-platform/snippets/resources/volleyball_game_inpainting_remove_mask.png new file mode 100644 index 0000000000..784c1f5a42 Binary files /dev/null and b/ai-platform/snippets/resources/volleyball_game_inpainting_remove_mask.png differ diff --git a/ai-platform/snippets/resources/woman.png b/ai-platform/snippets/resources/woman.png new file mode 100644 index 0000000000..f232924368 Binary files /dev/null and b/ai-platform/snippets/resources/woman.png differ diff --git a/ai-platform/snippets/resources/woman_inpainting_insert_mask.png b/ai-platform/snippets/resources/woman_inpainting_insert_mask.png new file mode 100644 index 0000000000..d5399635b0 Binary files /dev/null and b/ai-platform/snippets/resources/woman_inpainting_insert_mask.png differ diff --git a/ai-platform/snippets/test/imagen.test.js b/ai-platform/snippets/test/imagen.test.js new file mode 100644 index 0000000000..e302bce0ec --- /dev/null +++ b/ai-platform/snippets/test/imagen.test.js @@ -0,0 +1,67 @@ +/* + * 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 + * + * 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 path = require('path'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const cp = require('child_process'); +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('AI platform generate and edit an image using Imagen', () => { + it('should generate an image', async () => { + const stdout = execSync('node ./imagen-generate-image.js', { + cwd, + }); + assert.match(stdout, /Saved image output1.png/); + }); + it('should edit an image without using a mask', async () => { + const stdout = execSync('node ./imagen-edit-image-mask-free.js', { + cwd, + }); + assert.match(stdout, /Saved image output1.png/); + }); +}); + +describe('AI platform edit image using Imagen inpainting and outpainting', () => { + it('should edit an image using a mask image and inpainting insert', async () => { + const stdout = execSync( + 'node ./imagen-edit-image-inpainting-insert-mask.js', + { + cwd, + } + ); + assert.match(stdout, /Saved image output1.png/); + }); + it('should edit an image using a mask image and inpainting remove', async () => { + const stdout = execSync( + 'node ./imagen-edit-image-inpainting-remove-mask.js', + { + cwd, + } + ); + assert.match(stdout, /Saved image output1.png/); + }); + it('should edit an image using a mask image and outpainting', async () => { + const stdout = execSync('node ./imagen-edit-image-outpainting-mask.js', { + cwd, + }); + assert.match(stdout, /Saved image output1.png/); + }); +}); diff --git a/ai-platform/snippets/test/imagen/generateImage.test.js b/ai-platform/snippets/test/imagen/generateImage.test.js deleted file mode 100644 index 3e460a95a5..0000000000 --- a/ai-platform/snippets/test/imagen/generateImage.test.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 - * - * 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 path = require('path'); -const {assert} = require('chai'); -const {describe, it} = require('mocha'); - -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -describe('AI platform generate image', () => { - it('should generate an image using the Imagen model', async () => { - const stdout = execSync('node ./imagen/generateImage.js', { - cwd, - }); - assert.match(stdout, /Saved image my-output1.png/); - }); -});