Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion genai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
"test": "c8 mocha -p -j 2 --timeout 2400000 test/*.test.js test/**/*.test.js"
},
"dependencies": {
"@google-cloud/storage": "^7.17.3",
"@google/genai": "1.20.0",
"axios": "^1.6.2",
"google-auth-library": "^10.3.0",
"luxon": "^3.7.1",
"proxyquire": "^2.1.3",
"node-fetch": "^3.3.2",
"openai": "^5.19.1",
"proxyquire": "^2.1.3",
"supertest": "^7.0.0"
},
"devDependencies": {
Expand Down
59 changes: 59 additions & 0 deletions genai/test/videogen-with-img.test.js
Original file line number Diff line number Diff line change
@@ -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('../video-generation/videogen-with-img.js');
const {delay} = require('./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 () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The describe callback function should not be async. Asynchronous operations should be handled within hooks (before, after, etc.) or test cases (it).

Suggested change
describe('videogen-with-img', async () => {
describe('videogen-with-img', () => {

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);
});
});
59 changes: 59 additions & 0 deletions genai/test/videogen-with-txt.test.js
Original file line number Diff line number Diff line change
@@ -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('../video-generation/videogen-with-txt.js');
const {delay} = require('./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()}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The GCS prefix text_output/ seems to be a copy-paste from a text generation sample. For clarity, it would be better to use a prefix that reflects the content being generated, such as video_output/.

Suggested change
const prefix = `text_output/${dt.toISOString()}`;
const prefix = `video_output/${dt.toISOString()}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Guiners you should change this if possible

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);
});
});
64 changes: 64 additions & 0 deletions genai/video-generation/videogen-with-img.js
Original file line number Diff line number Diff line change
@@ -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.0-generate-preview',
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.response.generatedVideos[0].video.uri;
}

// [END googlegenaisdk_videogen_with_img]

module.exports = {
generateVideo,
};
59 changes: 59 additions & 0 deletions genai/video-generation/videogen-with-txt.js
Original file line number Diff line number Diff line change
@@ -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.0-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.response.generatedVideos[0].video.uri;
}

// [END googlegenaisdk_videogen_with_txt]

module.exports = {
generateVideo,
};
Loading