0
# Video Generation
1
2
The Models module provides video generation capabilities using Veo models, supporting text-to-video, image-to-video, and video-to-video generation as long-running operations.
3
4
## Capabilities
5
6
### generateVideos
7
8
Generate videos from text, images, or existing videos using Veo models. This is a long-running operation that requires polling for completion.
9
10
```typescript { .api }
11
/**
12
* Generate videos from text/images (returns long-running operation)
13
* @param params - Video generation parameters
14
* @returns Promise resolving to video generation operation
15
*/
16
function generateVideos(
17
params: GenerateVideosParameters
18
): Promise<GenerateVideosOperation>;
19
20
interface GenerateVideosParameters {
21
/** Model name (e.g., 'veo-2.0-generate-001') */
22
model: string;
23
/** Text prompt for video generation */
24
prompt?: string;
25
/** Source image for image-to-video */
26
image?: BlobImageUnion;
27
/** Source video for video-to-video */
28
video?: BlobVideoUnion;
29
/** Source reference */
30
source?: SourceUnion;
31
/** Video generation configuration */
32
config?: GenerateVideosConfig;
33
}
34
35
interface GenerateVideosOperation {
36
/** Operation name (used for polling status) */
37
name?: string;
38
/** Whether operation is complete */
39
done?: boolean;
40
/** Response when operation completes successfully */
41
response?: GenerateVideosResponse;
42
/** Error if operation failed */
43
error?: Status;
44
/** Operation metadata */
45
metadata?: GenerateVideosMetadata;
46
}
47
```
48
49
**Usage Examples:**
50
51
```typescript
52
import { GoogleGenAI } from '@google/genai';
53
54
const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });
55
56
// Text-to-video generation
57
const operation = await client.models.generateVideos({
58
model: 'veo-2.0-generate-001',
59
prompt: 'A serene lake with mountains in the background, sunrise time lapse'
60
});
61
62
console.log('Operation started:', operation.name);
63
64
// Poll for completion
65
while (!operation.done) {
66
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
67
const updated = await client.operations.getVideosOperation({
68
operation: operation.name!
69
});
70
71
if (updated.done) {
72
if (updated.response) {
73
console.log('Video generated successfully');
74
const videoUri = updated.response.generatedVideos?.[0]?.video?.uri;
75
console.log('Video URI:', videoUri);
76
} else if (updated.error) {
77
console.error('Video generation failed:', updated.error);
78
}
79
break;
80
}
81
}
82
83
// With configuration
84
const configuredOp = await client.models.generateVideos({
85
model: 'veo-2.0-generate-001',
86
prompt: 'A robot walking through a futuristic city',
87
config: {
88
aspectRatio: '16:9',
89
durationSeconds: 8
90
}
91
});
92
```
93
94
### Operations Management
95
96
Poll and manage video generation operations.
97
98
```typescript { .api }
99
/**
100
* Get video generation operation status
101
* @param params - Operation parameters
102
* @returns Promise resolving to operation status
103
*/
104
function getVideosOperation(
105
params: OperationGetParameters<GenerateVideosResponse, GenerateVideosOperation>
106
): Promise<GenerateVideosOperation>;
107
108
interface OperationGetParameters<T, U> {
109
/** Operation name from initial generateVideos call */
110
operation: string;
111
}
112
```
113
114
**Usage Examples:**
115
116
```typescript
117
// Start video generation
118
const operation = await client.models.generateVideos({
119
model: 'veo-2.0-generate-001',
120
prompt: 'Waves crashing on a beach'
121
});
122
123
// Poll operation status
124
const pollOperation = async (opName: string) => {
125
let op = await client.operations.getVideosOperation({
126
operation: opName
127
});
128
129
while (!op.done) {
130
console.log('Operation in progress...');
131
if (op.metadata) {
132
console.log('Progress:', op.metadata);
133
}
134
135
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10s
136
137
op = await client.operations.getVideosOperation({
138
operation: opName
139
});
140
}
141
142
return op;
143
};
144
145
const result = await pollOperation(operation.name!);
146
147
if (result.response?.generatedVideos) {
148
result.response.generatedVideos.forEach((genVideo, index) => {
149
console.log(`Video ${index}:`, genVideo.video?.uri);
150
});
151
}
152
```
153
154
## Types
155
156
### GenerateVideosConfig
157
158
Configuration options for video generation.
159
160
```typescript { .api }
161
interface GenerateVideosConfig {
162
/** Aspect ratio (e.g., '16:9', '9:16', '1:1') */
163
aspectRatio?: string;
164
/** Video duration in seconds */
165
durationSeconds?: number;
166
/** Number of videos to generate */
167
numberOfVideos?: number;
168
/** Negative prompt (things to avoid) */
169
negativePrompt?: string;
170
/** Frame rate (fps) */
171
frameRate?: number;
172
/** Guidance scale */
173
guidanceScale?: number;
174
/** Random seed for reproducibility */
175
seed?: number;
176
/** Safety filter level */
177
safetyFilterLevel?: SafetyFilterLevel;
178
/** Include RAI information */
179
includeRaiReason?: boolean;
180
/** Output video codec */
181
outputVideoType?: string;
182
}
183
```
184
185
### GenerateVideosResponse
186
187
Response from completed video generation operation.
188
189
```typescript { .api }
190
interface GenerateVideosResponse {
191
/** Generated videos */
192
generatedVideos?: GeneratedVideo[];
193
}
194
195
interface GeneratedVideo {
196
/** Video data */
197
video?: Video;
198
/** RAI (Responsible AI) information */
199
rai?: Rai;
200
}
201
202
interface Video {
203
/** Video URI (GCS path or download URI) */
204
uri?: string;
205
/** Processing state */
206
state?: FileState;
207
}
208
```
209
210
### GenerateVideosMetadata
211
212
Metadata about the video generation operation.
213
214
```typescript { .api }
215
interface GenerateVideosMetadata {
216
/** Operation create time */
217
createTime?: string;
218
/** Operation start time */
219
startTime?: string;
220
/** Operation update time */
221
updateTime?: string;
222
/** Progress percentage (0-100) */
223
progressPercentage?: number;
224
}
225
```
226
227
### Status
228
229
Error information if operation failed.
230
231
```typescript { .api }
232
interface Status {
233
/** Error code */
234
code?: number;
235
/** Error message */
236
message?: string;
237
/** Additional error details */
238
details?: unknown[];
239
}
240
```
241
242
### BlobImageUnion and BlobVideoUnion
243
244
Input media types.
245
246
```typescript { .api }
247
/** Image blob for image-to-video */
248
type BlobImageUnion = Blob;
249
250
/** Video blob for video-to-video */
251
type BlobVideoUnion = Blob;
252
253
interface Blob {
254
/** MIME type (e.g., 'image/png', 'video/mp4') */
255
mimeType?: string;
256
/** Base64-encoded data */
257
data?: string;
258
}
259
```
260
261
### Enumerations
262
263
```typescript { .api }
264
enum FileState {
265
STATE_UNSPECIFIED = 'STATE_UNSPECIFIED',
266
PROCESSING = 'PROCESSING',
267
ACTIVE = 'ACTIVE',
268
FAILED = 'FAILED'
269
}
270
271
enum SafetyFilterLevel {
272
BLOCK_LOW_AND_ABOVE = 'BLOCK_LOW_AND_ABOVE',
273
BLOCK_MEDIUM_AND_ABOVE = 'BLOCK_MEDIUM_AND_ABOVE',
274
BLOCK_ONLY_HIGH = 'BLOCK_ONLY_HIGH',
275
BLOCK_NONE = 'BLOCK_NONE'
276
}
277
```
278
279
## Complete Examples
280
281
### Text-to-Video with Polling Helper
282
283
```typescript
284
import { GoogleGenAI, GenerateVideosOperation } from '@google/genai';
285
286
const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });
287
288
// Helper function to poll until completion
289
async function pollVideoOperation(
290
client: GoogleGenAI,
291
operationName: string,
292
pollIntervalMs: number = 10000
293
): Promise<GenerateVideosOperation> {
294
let operation = await client.operations.getVideosOperation({
295
operation: operationName
296
});
297
298
while (!operation.done) {
299
console.log(`Polling operation... ${operation.metadata?.progressPercentage || 0}%`);
300
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
301
302
operation = await client.operations.getVideosOperation({
303
operation: operationName
304
});
305
}
306
307
return operation;
308
}
309
310
// Generate video
311
const operation = await client.models.generateVideos({
312
model: 'veo-2.0-generate-001',
313
prompt: 'A time-lapse of a flower blooming in spring',
314
config: {
315
aspectRatio: '16:9',
316
durationSeconds: 5,
317
numberOfVideos: 1
318
}
319
});
320
321
console.log('Video generation started:', operation.name);
322
323
// Wait for completion
324
const completed = await pollVideoOperation(client, operation.name!);
325
326
if (completed.response?.generatedVideos?.[0]?.video?.uri) {
327
console.log('Video ready:', completed.response.generatedVideos[0].video.uri);
328
} else if (completed.error) {
329
console.error('Video generation failed:', completed.error.message);
330
}
331
```
332
333
### Image-to-Video Generation
334
335
```typescript
336
import { GoogleGenAI } from '@google/genai';
337
import * as fs from 'fs';
338
339
const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });
340
341
// Read image as base64
342
const imageData = fs.readFileSync('./start_frame.png', 'base64');
343
344
// Generate video from image
345
const operation = await client.models.generateVideos({
346
model: 'veo-2.0-generate-001',
347
prompt: 'Animate this scene with gentle camera movement',
348
image: {
349
data: imageData,
350
mimeType: 'image/png'
351
},
352
config: {
353
aspectRatio: '16:9',
354
durationSeconds: 8,
355
frameRate: 24
356
}
357
});
358
359
console.log('Image-to-video generation started:', operation.name);
360
```
361
362
### Video-to-Video (Style Transfer)
363
364
```typescript
365
const videoData = fs.readFileSync('./source_video.mp4', 'base64');
366
367
const operation = await client.models.generateVideos({
368
model: 'veo-2.0-generate-001',
369
prompt: 'Transform this video into an animated cartoon style',
370
video: {
371
data: videoData,
372
mimeType: 'video/mp4'
373
},
374
config: {
375
durationSeconds: 10,
376
guidanceScale: 7.5
377
}
378
});
379
380
console.log('Video-to-video generation started:', operation.name);
381
```
382
383
### Multiple Video Variants
384
385
```typescript
386
// Generate multiple variations
387
const operation = await client.models.generateVideos({
388
model: 'veo-2.0-generate-001',
389
prompt: 'A cat playing with a ball of yarn',
390
config: {
391
aspectRatio: '9:16',
392
durationSeconds: 6,
393
numberOfVideos: 4,
394
negativePrompt: 'blurry, low quality, distorted'
395
}
396
});
397
398
// Wait for completion
399
const completed = await pollVideoOperation(client, operation.name!);
400
401
// Process all generated videos
402
completed.response?.generatedVideos?.forEach((genVideo, index) => {
403
if (genVideo.video?.uri) {
404
console.log(`Video ${index + 1}:`, genVideo.video.uri);
405
406
if (genVideo.rai) {
407
console.log(` RAI info:`, genVideo.rai);
408
}
409
}
410
});
411
```
412
413
### Reproducible Generation with Seeds
414
415
```typescript
416
// Generate with specific seed for reproducibility
417
const operation1 = await client.models.generateVideos({
418
model: 'veo-2.0-generate-001',
419
prompt: 'A sunset over the ocean',
420
config: {
421
seed: 12345,
422
aspectRatio: '16:9',
423
durationSeconds: 5
424
}
425
});
426
427
// Same seed will produce similar results
428
const operation2 = await client.models.generateVideos({
429
model: 'veo-2.0-generate-001',
430
prompt: 'A sunset over the ocean',
431
config: {
432
seed: 12345,
433
aspectRatio: '16:9',
434
durationSeconds: 5
435
}
436
});
437
```
438
439
### Download Generated Video
440
441
```typescript
442
import * as fs from 'fs';
443
import * as https from 'https';
444
445
// Wait for video generation
446
const completed = await pollVideoOperation(client, operation.name!);
447
448
const videoUri = completed.response?.generatedVideos?.[0]?.video?.uri;
449
450
if (videoUri) {
451
// Download video from URI
452
const downloadVideo = (uri: string, outputPath: string): Promise<void> => {
453
return new Promise((resolve, reject) => {
454
const file = fs.createWriteStream(outputPath);
455
https.get(uri, (response) => {
456
response.pipe(file);
457
file.on('finish', () => {
458
file.close();
459
resolve();
460
});
461
}).on('error', (err) => {
462
fs.unlink(outputPath, () => {});
463
reject(err);
464
});
465
});
466
};
467
468
await downloadVideo(videoUri, './generated_video.mp4');
469
console.log('Video downloaded to ./generated_video.mp4');
470
}
471
```
472
473
### Advanced Configuration
474
475
```typescript
476
const operation = await client.models.generateVideos({
477
model: 'veo-2.0-generate-001',
478
prompt: 'A bustling street market with colorful stalls and people',
479
config: {
480
// Video settings
481
aspectRatio: '16:9',
482
durationSeconds: 10,
483
frameRate: 30,
484
485
// Quality and style
486
guidanceScale: 8.0,
487
negativePrompt: 'static, boring, low quality, artifacts',
488
489
// Safety
490
safetyFilterLevel: SafetyFilterLevel.BLOCK_MEDIUM_AND_ABOVE,
491
includeRaiReason: true,
492
493
// Generation
494
numberOfVideos: 2,
495
seed: 42,
496
497
// Output
498
outputVideoType: 'video/mp4'
499
}
500
});
501
```
502
503
### Error Handling and Retry Logic
504
505
```typescript
506
async function generateVideoWithRetry(
507
client: GoogleGenAI,
508
params: GenerateVideosParameters,
509
maxRetries: number = 3
510
): Promise<GenerateVideosOperation> {
511
let lastError: Error | null = null;
512
513
for (let attempt = 1; attempt <= maxRetries; attempt++) {
514
try {
515
console.log(`Attempt ${attempt}/${maxRetries}`);
516
517
const operation = await client.models.generateVideos(params);
518
const completed = await pollVideoOperation(client, operation.name!);
519
520
if (completed.error) {
521
throw new Error(`Operation failed: ${completed.error.message}`);
522
}
523
524
if (completed.response?.generatedVideos?.[0]?.video?.uri) {
525
console.log('Video generation successful');
526
return completed;
527
}
528
529
throw new Error('No video generated');
530
} catch (error) {
531
lastError = error as Error;
532
console.error(`Attempt ${attempt} failed:`, error);
533
534
if (attempt < maxRetries) {
535
const backoffMs = Math.pow(2, attempt) * 1000;
536
console.log(`Retrying in ${backoffMs}ms...`);
537
await new Promise(resolve => setTimeout(resolve, backoffMs));
538
}
539
}
540
}
541
542
throw lastError || new Error('Max retries exceeded');
543
}
544
545
// Use with retry logic
546
try {
547
const result = await generateVideoWithRetry(client, {
548
model: 'veo-2.0-generate-001',
549
prompt: 'A peaceful forest scene',
550
config: {
551
aspectRatio: '16:9',
552
durationSeconds: 5
553
}
554
});
555
556
console.log('Final video:', result.response?.generatedVideos?.[0]?.video?.uri);
557
} catch (error) {
558
console.error('Video generation failed after retries:', error);
559
}
560
```
561
562
### Monitoring Multiple Operations
563
564
```typescript
565
// Start multiple video generations
566
const operations = await Promise.all([
567
client.models.generateVideos({
568
model: 'veo-2.0-generate-001',
569
prompt: 'A sunrise over mountains'
570
}),
571
client.models.generateVideos({
572
model: 'veo-2.0-generate-001',
573
prompt: 'A waterfall in a tropical forest'
574
}),
575
client.models.generateVideos({
576
model: 'veo-2.0-generate-001',
577
prompt: 'City traffic at night'
578
})
579
]);
580
581
console.log(`Started ${operations.length} video generation operations`);
582
583
// Poll all operations
584
const results = await Promise.all(
585
operations.map(op => pollVideoOperation(client, op.name!))
586
);
587
588
// Process results
589
results.forEach((result, index) => {
590
if (result.response?.generatedVideos?.[0]?.video?.uri) {
591
console.log(`Video ${index + 1}: ${result.response.generatedVideos[0].video.uri}`);
592
} else {
593
console.log(`Video ${index + 1}: Failed`);
594
}
595
});
596
```
597
598
### Using Files Module for Large Videos
599
600
```typescript
601
// For video-to-video with large source files, upload first
602
const uploadedVideo = await client.files.upload({
603
file: './large_video.mp4',
604
mimeType: 'video/mp4'
605
});
606
607
// Wait for processing
608
while (uploadedVideo.state === FileState.PROCESSING) {
609
await new Promise(resolve => setTimeout(resolve, 5000));
610
const file = await client.files.get({ file: uploadedVideo.name! });
611
if (file.state === FileState.ACTIVE) {
612
break;
613
}
614
}
615
616
// Use uploaded video URI
617
const operation = await client.models.generateVideos({
618
model: 'veo-2.0-generate-001',
619
prompt: 'Add dramatic music visualization effects',
620
source: {
621
videoUri: uploadedVideo.uri
622
},
623
config: {
624
durationSeconds: 15
625
}
626
});
627
```
628