diff --git a/genai/package.json b/genai/package.json index 9231c39c94..90ea78fd48 100644 --- a/genai/package.json +++ b/genai/package.json @@ -13,11 +13,13 @@ "test": "c8 mocha -p -j 2 --timeout 2400000 test/*.test.js test/**/*.test.js" }, "dependencies": { + "@google-cloud/storage": "^7.17.3", "@google/genai": "1.30.0", "axios": "^1.6.2", "canvas": "^3.2.0", "google-auth-library": "^10.3.0", "luxon": "^3.7.1", + "node-fetch": "^3.3.2", "openai": "^5.19.1", "proxyquire": "^2.1.3", "supertest": "^7.0.0" diff --git a/genai/video-generation/package.json b/genai/video-generation/package.json new file mode 100644 index 0000000000..7fa7f58d1c --- /dev/null +++ b/genai/video-generation/package.json @@ -0,0 +1,29 @@ +{ + "name": "nodejs-genai-video-generation-samples", + "version": "0.0.1", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "repository": { + "type": "git", + "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" + }, + "engines": { + "node": ">=16.0.0" + }, + "files": [ + "*.js" + ], + "scripts": { + "test": "c8 mocha -p -j 2 --timeout 2400000 test/*.test.js test/**/*.test.js" + }, + "dependencies": { + "@google-cloud/storage": "^7.17.3", + "@google/genai": "1.30.0" + }, + "devDependencies": { + "c8": "^10.0.0", + "chai": "^4.5.0", + "mocha": "^10.0.0" + } +} diff --git a/genai/video-generation/test/videogen-with-img.test.js b/genai/video-generation/test/videogen-with-img.test.js new file mode 100644 index 0000000000..0cf1c62efa --- /dev/null +++ b/genai/video-generation/test/videogen-with-img.test.js @@ -0,0 +1,59 @@ +// 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 {Storage} = require('@google-cloud/storage'); + +const location = process.env.GOOGLE_CLOUD_LOCATION || 'global'; +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../videogen-with-img.js'); +const {delay} = require('../../test/util'); + +const storage = new Storage(); + +const GCS_OUTPUT_BUCKET = 'nodejs-docs-samples-tests'; + +async function gcs_output_uri() { + const dt = new Date(); + const prefix = `video_output/${dt.toISOString()}`; + const fullUri = `gs://${GCS_OUTPUT_BUCKET}/${prefix}`; + + return { + uri: fullUri, + async cleanup() { + const [files] = await storage.bucket(GCS_OUTPUT_BUCKET).getFiles({ + prefix, + }); + for (const file of files) { + await file.delete(); + } + }, + }; +} + +describe('videogen-with-img', async () => { + it('should generate video content from an image', async function () { + this.timeout(180000); + this.retries(4); + await delay(this.test); + const gscOutput = gcs_output_uri(); + const gscUri = (await gscOutput).uri; + const output = await sample.generateVideo(gscUri, projectId, location); + console.log('output', output); + assert(output); + }); +}); diff --git a/genai/video-generation/test/videogen-with-txt.test.js b/genai/video-generation/test/videogen-with-txt.test.js new file mode 100644 index 0000000000..ba4c18b718 --- /dev/null +++ b/genai/video-generation/test/videogen-with-txt.test.js @@ -0,0 +1,59 @@ +// 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 {Storage} = require('@google-cloud/storage'); + +const location = process.env.GOOGLE_CLOUD_LOCATION || 'global'; +const projectId = process.env.CAIP_PROJECT_ID; +const sample = require('../videogen-with-txt.js'); +const {delay} = require('../../test/util'); + +const storage = new Storage(); + +const GCS_OUTPUT_BUCKET = 'nodejs-docs-samples-tests'; + +async function gcs_output_uri() { + const dt = new Date(); + const prefix = `text_output/${dt.toISOString()}`; + const fullUri = `gs://${GCS_OUTPUT_BUCKET}/${prefix}`; + + return { + uri: fullUri, + async cleanup() { + const [files] = await storage.bucket(GCS_OUTPUT_BUCKET).getFiles({ + prefix, + }); + for (const file of files) { + await file.delete(); + } + }, + }; +} + +describe('videogen-with-txt', async () => { + it('should generate video content from a text prompt', async function () { + this.timeout(180000); + this.retries(4); + await delay(this.test); + const gscOutput = gcs_output_uri(); + const gscUri = (await gscOutput).uri; + const output = await sample.generateVideo(gscUri, projectId, location); + console.log('output', output); + assert(output); + }); +}); diff --git a/genai/video-generation/videogen-with-img.js b/genai/video-generation/videogen-with-img.js new file mode 100644 index 0000000000..27f4e48457 --- /dev/null +++ b/genai/video-generation/videogen-with-img.js @@ -0,0 +1,64 @@ +// 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_videogen_with_img] +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 generateVideo( + outputGcsUri, + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + let operation = await client.models.generateVideos({ + model: 'veo-3.1-fast-generate-001', + prompt: + 'Extreme close-up of a cluster of vibrant wildflowers swaying gently in a sun-drenched meadow', + image: { + gcsUri: 'gs://cloud-samples-data/generative-ai/image/flowers.png', + mimeType: 'image/png', + }, + config: { + aspectRatio: '16:9', + outputGcsUri: outputGcsUri, + }, + }); + + while (!operation.done) { + await new Promise(resolve => setTimeout(resolve, 15000)); + operation = await client.operations.get({operation: operation}); + console.log(operation); + } + + if (operation.response) { + console.log(operation.response.generatedVideos[0].video.uri); + } + return operation; +} + +// [END googlegenaisdk_videogen_with_img] + +module.exports = { + generateVideo, +}; diff --git a/genai/video-generation/videogen-with-txt.js b/genai/video-generation/videogen-with-txt.js new file mode 100644 index 0000000000..26e4877308 --- /dev/null +++ b/genai/video-generation/videogen-with-txt.js @@ -0,0 +1,59 @@ +// 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_videogen_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 generateVideo( + outputGcsUri, + projectId = GOOGLE_CLOUD_PROJECT, + location = GOOGLE_CLOUD_LOCATION +) { + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + let operation = await client.models.generateVideos({ + model: 'veo-3.1-fast-generate-001', + prompt: 'a cat reading a book', + config: { + aspectRatio: '16:9', + outputGcsUri: outputGcsUri, + }, + }); + + while (!operation.done) { + await new Promise(resolve => setTimeout(resolve, 15000)); + operation = await client.operations.get({operation: operation}); + console.log(operation); + } + + if (operation.response) { + console.log(operation.response.generatedVideos[0].video.uri); + } + return operation; +} + +// [END googlegenaisdk_videogen_with_txt] + +module.exports = { + generateVideo, +};