@ai-sdk/google-vertex 5.0.49 → 5.0.50

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.
@@ -0,0 +1,188 @@
1
+ import type { SharedV4Warning, SpeechModelV4 } from '@ai-sdk/provider';
2
+ import {
3
+ combineHeaders,
4
+ convertBase64ToUint8Array,
5
+ createJsonResponseHandler,
6
+ postJsonToApi,
7
+ resolve,
8
+ serializeModelOptions,
9
+ WORKFLOW_DESERIALIZE,
10
+ WORKFLOW_SERIALIZE,
11
+ type FetchFunction,
12
+ type Resolvable,
13
+ } from '@ai-sdk/provider-utils';
14
+ import { z } from 'zod/v4';
15
+ import { googleVertexFailedResponseHandler } from './google-vertex-error';
16
+ import type { GoogleVertexSpeechModelId } from './google-vertex-speech-model-options';
17
+
18
+ interface GoogleVertexCloudTTSSpeechModelConfig {
19
+ provider: string;
20
+ headers?: Resolvable<Record<string, string | undefined>>;
21
+ fetch?: FetchFunction;
22
+ _internal?: {
23
+ currentDate?: () => Date;
24
+ };
25
+ }
26
+
27
+ const DEFAULT_VOICE = 'Kore';
28
+ const DEFAULT_LANGUAGE = 'en-US';
29
+
30
+ // Chirp 3: HD voice names are `<locale>-Chirp3-HD-<voice>`,
31
+ // e.g. `en-US-Chirp3-HD-Kore`.
32
+ // https://cloud.google.com/text-to-speech/docs/chirp3-hd
33
+ const CHIRP3_HD_VOICE_INFIX = 'Chirp3-HD';
34
+
35
+ // Cloud Text-to-Speech uses a single non-regional host for standard
36
+ // synthesis (unlike Speech-to-Text and Vertex AI, which are regional).
37
+ // https://cloud.google.com/text-to-speech/docs/reference/rest/v1/text/synthesize
38
+ const CLOUD_TTS_SYNTHESIZE_URL =
39
+ 'https://texttospeech.googleapis.com/v1/text:synthesize';
40
+
41
+ /**
42
+ * Speech model for Chirp 3: HD voices on the Google Cloud Text-to-Speech API.
43
+ *
44
+ * Unlike the Gemini TTS models (which go through the Vertex
45
+ * `generateContent` endpoint via `GoogleSpeechModel`), Chirp 3: HD voices are
46
+ * served by the dedicated Cloud Text-to-Speech `text:synthesize` endpoint,
47
+ * reusing the provider's Google Cloud credentials.
48
+ */
49
+ export class GoogleVertexCloudTTSSpeechModel implements SpeechModelV4 {
50
+ readonly specificationVersion = 'v4';
51
+
52
+ static [WORKFLOW_SERIALIZE](model: GoogleVertexCloudTTSSpeechModel) {
53
+ return serializeModelOptions({
54
+ modelId: model.modelId,
55
+ config: model.config,
56
+ });
57
+ }
58
+
59
+ static [WORKFLOW_DESERIALIZE](options: {
60
+ modelId: GoogleVertexSpeechModelId;
61
+ config: GoogleVertexCloudTTSSpeechModelConfig;
62
+ }) {
63
+ return new GoogleVertexCloudTTSSpeechModel(options.modelId, options.config);
64
+ }
65
+
66
+ get provider(): string {
67
+ return this.config.provider;
68
+ }
69
+
70
+ constructor(
71
+ readonly modelId: GoogleVertexSpeechModelId,
72
+ private readonly config: GoogleVertexCloudTTSSpeechModelConfig,
73
+ ) {}
74
+
75
+ async doGenerate(
76
+ options: Parameters<SpeechModelV4['doGenerate']>[0],
77
+ ): Promise<Awaited<ReturnType<SpeechModelV4['doGenerate']>>> {
78
+ const currentDate = this.config._internal?.currentDate?.() ?? new Date();
79
+ const warnings: SharedV4Warning[] = [];
80
+
81
+ const {
82
+ text,
83
+ voice = DEFAULT_VOICE,
84
+ outputFormat,
85
+ instructions,
86
+ speed,
87
+ language,
88
+ } = options;
89
+
90
+ // Compose the voice name. A fully-qualified Chirp 3: HD voice name
91
+ // (e.g. `en-US-Chirp3-HD-Kore`) is passed through verbatim, with its
92
+ // locale prefix as the language code; otherwise the name is composed
93
+ // from the language (BCP-47 locale, e.g. `en-US`) and the plain voice
94
+ // name (e.g. `Kore`).
95
+ let voiceName: string;
96
+ let languageCode: string;
97
+ if (voice.includes(CHIRP3_HD_VOICE_INFIX)) {
98
+ voiceName = voice;
99
+ // The locale prefix may be missing (e.g. `Chirp3-HD-Kore`), in which
100
+ // case the extracted prefix is empty and the default language is used.
101
+ const localePrefix = voice
102
+ .split(CHIRP3_HD_VOICE_INFIX)[0]
103
+ .replace(/-$/, '');
104
+ languageCode = language ?? (localePrefix || DEFAULT_LANGUAGE);
105
+ } else {
106
+ languageCode = language ?? DEFAULT_LANGUAGE;
107
+ voiceName = `${languageCode}-${CHIRP3_HD_VOICE_INFIX}-${voice}`;
108
+ }
109
+
110
+ if (instructions != null) {
111
+ warnings.push({
112
+ type: 'unsupported',
113
+ feature: 'instructions',
114
+ details:
115
+ 'Google Cloud Text-to-Speech Chirp 3: HD voices do not support the `instructions` option. It was ignored.',
116
+ });
117
+ }
118
+
119
+ // LINEAR16 responses are WAV (RIFF) files, so only `wav` is supported.
120
+ if (outputFormat != null && outputFormat !== 'wav') {
121
+ warnings.push({
122
+ type: 'unsupported',
123
+ feature: 'outputFormat',
124
+ details: `Unsupported output format: ${outputFormat}. Using wav instead.`,
125
+ });
126
+ }
127
+
128
+ const requestBody = {
129
+ input: { text },
130
+ voice: { languageCode, name: voiceName },
131
+ audioConfig: {
132
+ audioEncoding: 'LINEAR16',
133
+ ...(speed != null ? { speakingRate: speed } : {}),
134
+ },
135
+ };
136
+
137
+ const {
138
+ value: response,
139
+ responseHeaders,
140
+ rawValue: rawResponse,
141
+ } = await postJsonToApi({
142
+ url: CLOUD_TTS_SYNTHESIZE_URL,
143
+ headers: combineHeaders(
144
+ this.config.headers ? await resolve(this.config.headers) : undefined,
145
+ options.headers,
146
+ ),
147
+ body: requestBody,
148
+ failedResponseHandler: googleVertexFailedResponseHandler,
149
+ successfulResponseHandler: createJsonResponseHandler(
150
+ googleVertexCloudTTSResponseSchema,
151
+ ),
152
+ abortSignal: options.abortSignal,
153
+ fetch: this.config.fetch,
154
+ });
155
+
156
+ // Empty audio is returned as-is so the core layer throws
157
+ // NoSpeechGeneratedError.
158
+ const audio =
159
+ response.audioContent != null
160
+ ? convertBase64ToUint8Array(response.audioContent)
161
+ : new Uint8Array(0);
162
+
163
+ return {
164
+ audio,
165
+ warnings,
166
+ request: {
167
+ body: JSON.stringify(requestBody),
168
+ },
169
+ response: {
170
+ timestamp: currentDate,
171
+ modelId: this.modelId,
172
+ headers: responseHeaders,
173
+ body: rawResponse,
174
+ },
175
+ providerMetadata: {
176
+ google: {
177
+ mimeType: 'audio/wav',
178
+ },
179
+ },
180
+ };
181
+ }
182
+ }
183
+
184
+ // Minimal schema: only the fields the implementation reads, with `.nullish()`
185
+ // so provider API changes don't break parsing.
186
+ const googleVertexCloudTTSResponseSchema = z.object({
187
+ audioContent: z.string().nullish(),
188
+ });
@@ -32,6 +32,7 @@ import type { GoogleVertexEmbeddingModelId } from './google-vertex-embedding-mod
32
32
  import { GoogleVertexImageModel } from './google-vertex-image-model';
33
33
  import type { GoogleVertexImageModelId } from './google-vertex-image-settings';
34
34
  import type { GoogleVertexModelId } from './google-vertex-options';
35
+ import { GoogleVertexCloudTTSSpeechModel } from './google-vertex-cloud-tts-speech-model';
35
36
  import { googleVertexTools } from './google-vertex-tools';
36
37
  import { GoogleVertexTranscriptionModel } from './google-vertex-transcription-model';
37
38
  import type { GoogleVertexTranscriptionModelId } from './google-vertex-transcription-model-options';
@@ -327,8 +328,24 @@ export function createGoogleVertex(
327
328
  generateId: options.generateId ?? generateId,
328
329
  });
329
330
 
330
- const createSpeechModel = (modelId: GoogleVertexSpeechModelId) =>
331
- new GoogleSpeechModel(modelId, createConfig('speech'));
331
+ const createSpeechModel = (modelId: GoogleVertexSpeechModelId) => {
332
+ if (modelId.startsWith('chirp')) {
333
+ if (apiKey) {
334
+ throw new Error(
335
+ 'Google Vertex Chirp speech models do not support Express Mode API keys. Use standard Google Cloud credentials instead.',
336
+ );
337
+ }
338
+
339
+ const config = createConfig('speech');
340
+ return new GoogleVertexCloudTTSSpeechModel(modelId, {
341
+ provider: config.provider,
342
+ headers: config.headers,
343
+ fetch: config.fetch,
344
+ });
345
+ }
346
+
347
+ return new GoogleSpeechModel(modelId, createConfig('speech'));
348
+ };
332
349
 
333
350
  // Cloud Speech-to-Text reuses the Vertex auth headers from createConfig, but
334
351
  // targets the Speech-to-Text API.
@@ -1,11 +1,15 @@
1
1
  import type { GoogleSpeechModelOptions } from '@ai-sdk/google';
2
2
 
3
+ // Gemini TTS models (Vertex `generateContent` endpoint):
3
4
  // https://docs.cloud.google.com/text-to-speech/docs/gemini-tts
5
+ // Chirp 3: HD voices (Cloud Text-to-Speech `text:synthesize` endpoint):
6
+ // https://docs.cloud.google.com/text-to-speech/docs/chirp3-hd
4
7
  export type GoogleVertexSpeechModelId =
5
8
  | 'gemini-2.5-flash-tts'
6
9
  | 'gemini-2.5-pro-tts'
7
10
  | 'gemini-2.5-flash-lite-preview-tts'
8
11
  | 'gemini-3.1-flash-tts-preview'
12
+ | 'chirp-3-hd'
9
13
  | (string & {});
10
14
 
11
15
  export type GoogleVertexSpeechModelOptions = GoogleSpeechModelOptions;