@ai-sdk/google-vertex 4.0.40 → 4.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/anthropic/edge/index.js +1 -1
- package/dist/anthropic/edge/index.mjs +1 -1
- package/dist/edge/index.d.mts +7 -1
- package/dist/edge/index.d.ts +7 -1
- package/dist/edge/index.js +282 -20
- package/dist/edge/index.js.map +1 -1
- package/dist/edge/index.mjs +279 -5
- package/dist/edge/index.mjs.map +1 -1
- package/dist/index.d.mts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +276 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +279 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/google-vertex-provider.ts +20 -1
- package/src/google-vertex-video-model.ts +374 -0
- package/src/google-vertex-video-settings.ts +16 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AISDKError,
|
|
3
|
+
type Experimental_VideoModelV3,
|
|
4
|
+
type SharedV3Warning,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
import {
|
|
7
|
+
combineHeaders,
|
|
8
|
+
convertUint8ArrayToBase64,
|
|
9
|
+
createJsonResponseHandler,
|
|
10
|
+
delay,
|
|
11
|
+
type FetchFunction,
|
|
12
|
+
lazySchema,
|
|
13
|
+
parseProviderOptions,
|
|
14
|
+
postJsonToApi,
|
|
15
|
+
type Resolvable,
|
|
16
|
+
resolve,
|
|
17
|
+
zodSchema,
|
|
18
|
+
} from '@ai-sdk/provider-utils';
|
|
19
|
+
import { z } from 'zod/v4';
|
|
20
|
+
import { googleVertexFailedResponseHandler } from './google-vertex-error';
|
|
21
|
+
import type { GoogleVertexVideoModelId } from './google-vertex-video-settings';
|
|
22
|
+
|
|
23
|
+
export type GoogleVertexVideoProviderOptions = {
|
|
24
|
+
// Polling configuration
|
|
25
|
+
pollIntervalMs?: number | null;
|
|
26
|
+
pollTimeoutMs?: number | null;
|
|
27
|
+
|
|
28
|
+
// Video generation options
|
|
29
|
+
personGeneration?: 'dont_allow' | 'allow_adult' | 'allow_all' | null;
|
|
30
|
+
negativePrompt?: string | null;
|
|
31
|
+
generateAudio?: boolean | null;
|
|
32
|
+
|
|
33
|
+
// Output configuration
|
|
34
|
+
gcsOutputDirectory?: string | null;
|
|
35
|
+
|
|
36
|
+
// Reference images (for style/asset reference)
|
|
37
|
+
referenceImages?: Array<{
|
|
38
|
+
bytesBase64Encoded?: string;
|
|
39
|
+
gcsUri?: string;
|
|
40
|
+
}> | null;
|
|
41
|
+
|
|
42
|
+
[key: string]: unknown; // For passthrough
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
interface GoogleVertexVideoModelConfig {
|
|
46
|
+
provider: string;
|
|
47
|
+
baseURL: string;
|
|
48
|
+
headers?: Resolvable<Record<string, string | undefined>>;
|
|
49
|
+
fetch?: FetchFunction;
|
|
50
|
+
generateId?: () => string;
|
|
51
|
+
_internal?: {
|
|
52
|
+
currentDate?: () => Date;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class GoogleVertexVideoModel implements Experimental_VideoModelV3 {
|
|
57
|
+
readonly specificationVersion = 'v3';
|
|
58
|
+
|
|
59
|
+
get provider(): string {
|
|
60
|
+
return this.config.provider;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get maxVideosPerCall(): number {
|
|
64
|
+
// Vertex supports multiple videos via sampleCount
|
|
65
|
+
return 4;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
readonly modelId: GoogleVertexVideoModelId,
|
|
70
|
+
private readonly config: GoogleVertexVideoModelConfig,
|
|
71
|
+
) {}
|
|
72
|
+
|
|
73
|
+
async doGenerate(
|
|
74
|
+
options: Parameters<Experimental_VideoModelV3['doGenerate']>[0],
|
|
75
|
+
): Promise<Awaited<ReturnType<Experimental_VideoModelV3['doGenerate']>>> {
|
|
76
|
+
const currentDate = this.config._internal?.currentDate?.() ?? new Date();
|
|
77
|
+
const warnings: SharedV3Warning[] = [];
|
|
78
|
+
|
|
79
|
+
const vertexOptions = (await parseProviderOptions({
|
|
80
|
+
provider: 'vertex',
|
|
81
|
+
providerOptions: options.providerOptions,
|
|
82
|
+
schema: vertexVideoProviderOptionsSchema,
|
|
83
|
+
})) as GoogleVertexVideoProviderOptions | undefined;
|
|
84
|
+
|
|
85
|
+
const instances: Array<Record<string, unknown>> = [{}];
|
|
86
|
+
const instance = instances[0];
|
|
87
|
+
|
|
88
|
+
if (options.prompt != null) {
|
|
89
|
+
instance.prompt = options.prompt;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (options.image != null) {
|
|
93
|
+
if (options.image.type === 'url') {
|
|
94
|
+
warnings.push({
|
|
95
|
+
type: 'unsupported',
|
|
96
|
+
feature: 'URL-based image input',
|
|
97
|
+
details:
|
|
98
|
+
'Vertex AI video models require base64-encoded images or GCS URIs. URL will be ignored.',
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
const base64Data =
|
|
102
|
+
typeof options.image.data === 'string'
|
|
103
|
+
? options.image.data
|
|
104
|
+
: convertUint8ArrayToBase64(options.image.data);
|
|
105
|
+
|
|
106
|
+
instance.image = {
|
|
107
|
+
bytesBase64Encoded: base64Data,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (vertexOptions?.referenceImages != null) {
|
|
113
|
+
instance.referenceImages = vertexOptions.referenceImages;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const parameters: Record<string, unknown> = {
|
|
117
|
+
sampleCount: options.n,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (options.aspectRatio) {
|
|
121
|
+
parameters.aspectRatio = options.aspectRatio;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (options.resolution) {
|
|
125
|
+
const resolutionMap: Record<string, string> = {
|
|
126
|
+
'1280x720': '720p',
|
|
127
|
+
'1920x1080': '1080p',
|
|
128
|
+
'3840x2160': '4k',
|
|
129
|
+
};
|
|
130
|
+
parameters.resolution =
|
|
131
|
+
resolutionMap[options.resolution] || options.resolution;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (options.duration) {
|
|
135
|
+
parameters.durationSeconds = options.duration;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (options.seed) {
|
|
139
|
+
parameters.seed = options.seed;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (vertexOptions != null) {
|
|
143
|
+
const opts = vertexOptions;
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
opts.personGeneration !== undefined &&
|
|
147
|
+
opts.personGeneration !== null
|
|
148
|
+
) {
|
|
149
|
+
parameters.personGeneration = opts.personGeneration;
|
|
150
|
+
}
|
|
151
|
+
if (opts.negativePrompt !== undefined && opts.negativePrompt !== null) {
|
|
152
|
+
parameters.negativePrompt = opts.negativePrompt;
|
|
153
|
+
}
|
|
154
|
+
if (opts.generateAudio !== undefined && opts.generateAudio !== null) {
|
|
155
|
+
parameters.generateAudio = opts.generateAudio;
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
opts.gcsOutputDirectory !== undefined &&
|
|
159
|
+
opts.gcsOutputDirectory !== null
|
|
160
|
+
) {
|
|
161
|
+
parameters.gcsOutputDirectory = opts.gcsOutputDirectory;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const [key, value] of Object.entries(opts)) {
|
|
165
|
+
if (
|
|
166
|
+
![
|
|
167
|
+
'pollIntervalMs',
|
|
168
|
+
'pollTimeoutMs',
|
|
169
|
+
'personGeneration',
|
|
170
|
+
'negativePrompt',
|
|
171
|
+
'generateAudio',
|
|
172
|
+
'gcsOutputDirectory',
|
|
173
|
+
'referenceImages',
|
|
174
|
+
].includes(key)
|
|
175
|
+
) {
|
|
176
|
+
parameters[key] = value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const { value: operation } = await postJsonToApi({
|
|
182
|
+
url: `${this.config.baseURL}/models/${this.modelId}:predictLongRunning`,
|
|
183
|
+
headers: combineHeaders(
|
|
184
|
+
await resolve(this.config.headers),
|
|
185
|
+
options.headers,
|
|
186
|
+
),
|
|
187
|
+
body: {
|
|
188
|
+
instances,
|
|
189
|
+
parameters,
|
|
190
|
+
},
|
|
191
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
192
|
+
vertexOperationSchema,
|
|
193
|
+
),
|
|
194
|
+
failedResponseHandler: googleVertexFailedResponseHandler,
|
|
195
|
+
abortSignal: options.abortSignal,
|
|
196
|
+
fetch: this.config.fetch,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const operationName = operation.name;
|
|
200
|
+
if (!operationName) {
|
|
201
|
+
throw new AISDKError({
|
|
202
|
+
name: 'VERTEX_VIDEO_GENERATION_ERROR',
|
|
203
|
+
message: 'No operation name returned from API',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const pollIntervalMs = vertexOptions?.pollIntervalMs ?? 10000; // 10 seconds
|
|
208
|
+
const pollTimeoutMs = vertexOptions?.pollTimeoutMs ?? 600000; // 10 minutes
|
|
209
|
+
|
|
210
|
+
const startTime = Date.now();
|
|
211
|
+
let finalOperation = operation;
|
|
212
|
+
let responseHeaders: Record<string, string> | undefined;
|
|
213
|
+
|
|
214
|
+
while (!finalOperation.done) {
|
|
215
|
+
if (Date.now() - startTime > pollTimeoutMs) {
|
|
216
|
+
throw new AISDKError({
|
|
217
|
+
name: 'VERTEX_VIDEO_GENERATION_TIMEOUT',
|
|
218
|
+
message: `Video generation timed out after ${pollTimeoutMs}ms`,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await delay(pollIntervalMs);
|
|
223
|
+
|
|
224
|
+
if (options.abortSignal?.aborted) {
|
|
225
|
+
throw new AISDKError({
|
|
226
|
+
name: 'VERTEX_VIDEO_GENERATION_ABORTED',
|
|
227
|
+
message: 'Video generation request was aborted',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const { value: statusOperation, responseHeaders: pollHeaders } =
|
|
232
|
+
await postJsonToApi({
|
|
233
|
+
url: `${this.config.baseURL}/models/${this.modelId}:fetchPredictOperation`,
|
|
234
|
+
headers: combineHeaders(
|
|
235
|
+
await resolve(this.config.headers),
|
|
236
|
+
options.headers,
|
|
237
|
+
),
|
|
238
|
+
body: {
|
|
239
|
+
operationName,
|
|
240
|
+
},
|
|
241
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
242
|
+
vertexOperationSchema,
|
|
243
|
+
),
|
|
244
|
+
failedResponseHandler: googleVertexFailedResponseHandler,
|
|
245
|
+
abortSignal: options.abortSignal,
|
|
246
|
+
fetch: this.config.fetch,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
finalOperation = statusOperation;
|
|
250
|
+
responseHeaders = pollHeaders;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (finalOperation.error) {
|
|
254
|
+
throw new AISDKError({
|
|
255
|
+
name: 'VERTEX_VIDEO_GENERATION_FAILED',
|
|
256
|
+
message: `Video generation failed: ${finalOperation.error.message}`,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const response = finalOperation.response;
|
|
261
|
+
if (!response?.videos || response.videos.length === 0) {
|
|
262
|
+
throw new AISDKError({
|
|
263
|
+
name: 'VERTEX_VIDEO_GENERATION_ERROR',
|
|
264
|
+
message: `No videos in response. Response: ${JSON.stringify(finalOperation)}`,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Process videos - Vertex returns base64 encoded videos or GCS URIs
|
|
269
|
+
const videos: Array<
|
|
270
|
+
| { type: 'base64'; data: string; mediaType: string }
|
|
271
|
+
| { type: 'url'; url: string; mediaType: string }
|
|
272
|
+
> = [];
|
|
273
|
+
const videoMetadata: Array<{
|
|
274
|
+
gcsUri?: string | null | undefined;
|
|
275
|
+
mimeType?: string | null | undefined;
|
|
276
|
+
}> = [];
|
|
277
|
+
|
|
278
|
+
for (const video of response.videos) {
|
|
279
|
+
if (video.bytesBase64Encoded) {
|
|
280
|
+
videos.push({
|
|
281
|
+
type: 'base64',
|
|
282
|
+
data: video.bytesBase64Encoded,
|
|
283
|
+
mediaType: video.mimeType || 'video/mp4',
|
|
284
|
+
});
|
|
285
|
+
videoMetadata.push({
|
|
286
|
+
mimeType: video.mimeType,
|
|
287
|
+
});
|
|
288
|
+
} else if (video.gcsUri) {
|
|
289
|
+
videos.push({
|
|
290
|
+
type: 'url',
|
|
291
|
+
url: video.gcsUri,
|
|
292
|
+
mediaType: video.mimeType || 'video/mp4',
|
|
293
|
+
});
|
|
294
|
+
videoMetadata.push({
|
|
295
|
+
gcsUri: video.gcsUri,
|
|
296
|
+
mimeType: video.mimeType,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (videos.length === 0) {
|
|
302
|
+
throw new AISDKError({
|
|
303
|
+
name: 'VERTEX_VIDEO_GENERATION_ERROR',
|
|
304
|
+
message: 'No valid videos in response',
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
videos,
|
|
310
|
+
warnings,
|
|
311
|
+
response: {
|
|
312
|
+
timestamp: currentDate,
|
|
313
|
+
modelId: this.modelId,
|
|
314
|
+
headers: responseHeaders,
|
|
315
|
+
},
|
|
316
|
+
providerMetadata: {
|
|
317
|
+
'google-vertex': {
|
|
318
|
+
videos: videoMetadata,
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const vertexOperationSchema = z.object({
|
|
326
|
+
name: z.string().nullish(),
|
|
327
|
+
done: z.boolean().nullish(),
|
|
328
|
+
error: z
|
|
329
|
+
.object({
|
|
330
|
+
code: z.number().nullish(),
|
|
331
|
+
message: z.string(),
|
|
332
|
+
status: z.string().nullish(),
|
|
333
|
+
})
|
|
334
|
+
.nullish(),
|
|
335
|
+
response: z
|
|
336
|
+
.object({
|
|
337
|
+
videos: z
|
|
338
|
+
.array(
|
|
339
|
+
z.object({
|
|
340
|
+
bytesBase64Encoded: z.string().nullish(),
|
|
341
|
+
gcsUri: z.string().nullish(),
|
|
342
|
+
mimeType: z.string().nullish(),
|
|
343
|
+
}),
|
|
344
|
+
)
|
|
345
|
+
.nullish(),
|
|
346
|
+
raiMediaFilteredCount: z.number().nullish(),
|
|
347
|
+
})
|
|
348
|
+
.nullish(),
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const vertexVideoProviderOptionsSchema = lazySchema(() =>
|
|
352
|
+
zodSchema(
|
|
353
|
+
z
|
|
354
|
+
.object({
|
|
355
|
+
pollIntervalMs: z.number().positive().nullish(),
|
|
356
|
+
pollTimeoutMs: z.number().positive().nullish(),
|
|
357
|
+
personGeneration: z
|
|
358
|
+
.enum(['dont_allow', 'allow_adult', 'allow_all'])
|
|
359
|
+
.nullish(),
|
|
360
|
+
negativePrompt: z.string().nullish(),
|
|
361
|
+
generateAudio: z.boolean().nullish(),
|
|
362
|
+
gcsOutputDirectory: z.string().nullish(),
|
|
363
|
+
referenceImages: z
|
|
364
|
+
.array(
|
|
365
|
+
z.object({
|
|
366
|
+
bytesBase64Encoded: z.string().nullish(),
|
|
367
|
+
gcsUri: z.string().nullish(),
|
|
368
|
+
}),
|
|
369
|
+
)
|
|
370
|
+
.nullish(),
|
|
371
|
+
})
|
|
372
|
+
.passthrough(),
|
|
373
|
+
),
|
|
374
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type GoogleVertexVideoModelId =
|
|
2
|
+
| 'veo-001'
|
|
3
|
+
| 'veo-002'
|
|
4
|
+
| 'veo-003'
|
|
5
|
+
| 'veo-2.0-generate-001'
|
|
6
|
+
| 'veo-2.0-generate-exp'
|
|
7
|
+
| 'veo-2.0-generate-preview'
|
|
8
|
+
| 'veo-3.0-generate-001'
|
|
9
|
+
| 'veo-3.0-fast-generate-001'
|
|
10
|
+
| 'veo-3.0-generate-preview'
|
|
11
|
+
| 'veo-3.0-fast-generate-preview'
|
|
12
|
+
| 'veo-3.1-generate-001'
|
|
13
|
+
| 'veo-3.1-fast-generate-001'
|
|
14
|
+
| 'veo-3.1-generate-preview'
|
|
15
|
+
| 'veo-3.1-fast-generate-preview'
|
|
16
|
+
| (string & {});
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type { GoogleVertexImageProviderOptions } from './google-vertex-image-model';
|
|
2
|
+
export type { GoogleVertexVideoProviderOptions } from './google-vertex-video-model';
|
|
3
|
+
export type { GoogleVertexVideoModelId } from './google-vertex-video-settings';
|
|
2
4
|
export { createVertex, vertex } from './google-vertex-provider-node';
|
|
3
5
|
export type {
|
|
4
6
|
GoogleVertexProvider,
|