@mastra/voice-google 0.14.0 → 0.14.1

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/dist/index.js CHANGED
@@ -1,542 +1,559 @@
1
- import { PassThrough } from 'stream';
2
- import { SpeechClient, v2 } from '@google-cloud/speech';
3
- import { TextToSpeechClient } from '@google-cloud/text-to-speech';
4
-
5
- // src/index.ts
6
-
7
- // ../../packages/_internal-core/dist/chunk-3M4SEWMI.js
8
- var RegisteredLogger = {
9
- LLM: "LLM"};
10
- var LogLevel = {
11
- DEBUG: "debug",
12
- INFO: "info",
13
- WARN: "warn",
14
- ERROR: "error"};
1
+ import { PassThrough } from "stream";
2
+ import { SpeechClient, v2 } from "@google-cloud/speech";
3
+ import { TextToSpeechClient } from "@google-cloud/text-to-speech";
4
+ //#region ../../packages/_internal-core/dist/logger/index.js
5
+ const RegisteredLogger = {
6
+ AGENT: "AGENT",
7
+ OBSERVABILITY: "OBSERVABILITY",
8
+ AUTH: "AUTH",
9
+ BROWSER: "BROWSER",
10
+ NETWORK: "NETWORK",
11
+ WORKFLOW: "WORKFLOW",
12
+ LLM: "LLM",
13
+ TTS: "TTS",
14
+ VOICE: "VOICE",
15
+ VECTOR: "VECTOR",
16
+ BUNDLER: "BUNDLER",
17
+ DEPLOYER: "DEPLOYER",
18
+ MEMORY: "MEMORY",
19
+ STORAGE: "STORAGE",
20
+ EMBEDDINGS: "EMBEDDINGS",
21
+ MCP_SERVER: "MCP_SERVER",
22
+ SERVER_CACHE: "SERVER_CACHE",
23
+ SERVER: "SERVER",
24
+ WORKSPACE: "WORKSPACE",
25
+ CHANNEL: "CHANNEL"
26
+ };
27
+ const LogLevel = {
28
+ DEBUG: "debug",
29
+ INFO: "info",
30
+ WARN: "warn",
31
+ ERROR: "error",
32
+ NONE: "silent"
33
+ };
15
34
  var MastraLogger = class {
16
- name;
17
- level;
18
- transports;
19
- constructor(options = {}) {
20
- this.name = options.name || "Mastra";
21
- this.level = options.level || LogLevel.ERROR;
22
- this.transports = new Map(Object.entries(options.transports || {}));
23
- }
24
- getTransports() {
25
- return this.transports;
26
- }
27
- trackException(_error, _metadata) {
28
- }
29
- async listLogs(transportId, params) {
30
- if (!transportId || !this.transports.has(transportId)) {
31
- return { logs: [], total: 0, page: params?.page ?? 1, perPage: params?.perPage ?? 100, hasMore: false };
32
- }
33
- return this.transports.get(transportId).listLogs?.(params) ?? {
34
- logs: [],
35
- total: 0,
36
- page: params?.page ?? 1,
37
- perPage: params?.perPage ?? 100,
38
- hasMore: false
39
- };
40
- }
41
- async listLogsByRunId({
42
- transportId,
43
- runId,
44
- fromDate,
45
- toDate,
46
- logLevel,
47
- filters,
48
- page,
49
- perPage
50
- }) {
51
- if (!transportId || !this.transports.has(transportId) || !runId) {
52
- return { logs: [], total: 0, page: page ?? 1, perPage: perPage ?? 100, hasMore: false };
53
- }
54
- return this.transports.get(transportId).listLogsByRunId?.({ runId, fromDate, toDate, logLevel, filters, page, perPage }) ?? {
55
- logs: [],
56
- total: 0,
57
- page: page ?? 1,
58
- perPage: perPage ?? 100,
59
- hasMore: false
60
- };
61
- }
35
+ name;
36
+ level;
37
+ transports;
38
+ constructor(options = {}) {
39
+ this.name = options.name || "Mastra";
40
+ this.level = options.level || LogLevel.ERROR;
41
+ this.transports = new Map(Object.entries(options.transports || {}));
42
+ }
43
+ getTransports() {
44
+ return this.transports;
45
+ }
46
+ trackException(_error, _metadata) {}
47
+ async listLogs(transportId, params) {
48
+ if (!transportId || !this.transports.has(transportId)) return {
49
+ logs: [],
50
+ total: 0,
51
+ page: params?.page ?? 1,
52
+ perPage: params?.perPage ?? 100,
53
+ hasMore: false
54
+ };
55
+ return this.transports.get(transportId).listLogs?.(params) ?? {
56
+ logs: [],
57
+ total: 0,
58
+ page: params?.page ?? 1,
59
+ perPage: params?.perPage ?? 100,
60
+ hasMore: false
61
+ };
62
+ }
63
+ async listLogsByRunId({ transportId, runId, fromDate, toDate, logLevel, filters, page, perPage }) {
64
+ if (!transportId || !this.transports.has(transportId) || !runId) return {
65
+ logs: [],
66
+ total: 0,
67
+ page: page ?? 1,
68
+ perPage: perPage ?? 100,
69
+ hasMore: false
70
+ };
71
+ return this.transports.get(transportId).listLogsByRunId?.({
72
+ runId,
73
+ fromDate,
74
+ toDate,
75
+ logLevel,
76
+ filters,
77
+ page,
78
+ perPage
79
+ }) ?? {
80
+ logs: [],
81
+ total: 0,
82
+ page: page ?? 1,
83
+ perPage: perPage ?? 100,
84
+ hasMore: false
85
+ };
86
+ }
62
87
  };
63
- var ConsoleLogger = class _ConsoleLogger extends MastraLogger {
64
- component;
65
- filter;
66
- constructor(options = {}) {
67
- super(options);
68
- this.component = options.component;
69
- this.filter = options.filter;
70
- }
71
- child(componentOrBindings) {
72
- const component = typeof componentOrBindings === "string" ? componentOrBindings : componentOrBindings?.component ?? this.component;
73
- return new _ConsoleLogger({
74
- name: this.name,
75
- level: this.level,
76
- component,
77
- filter: this.filter
78
- });
79
- }
80
- shouldLog(level, message, args) {
81
- if (!this.filter) return true;
82
- try {
83
- return this.filter({ component: this.component, level, message, args });
84
- } catch (e) {
85
- console.error(`[Logger] Filter error for component=${this.component} level=${level}:`, e);
86
- return true;
87
- }
88
- }
89
- prefix() {
90
- return this.component ? `[${this.component}] ` : "";
91
- }
92
- debug(message, ...args) {
93
- if (this.level === LogLevel.DEBUG && this.shouldLog(LogLevel.DEBUG, message, args)) {
94
- console.info(`${this.prefix()}${message}`, ...args);
95
- }
96
- }
97
- info(message, ...args) {
98
- if ((this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.INFO, message, args)) {
99
- console.info(`${this.prefix()}${message}`, ...args);
100
- }
101
- }
102
- warn(message, ...args) {
103
- if ((this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.WARN, message, args)) {
104
- console.warn(`${this.prefix()}${message}`, ...args);
105
- }
106
- }
107
- error(message, ...args) {
108
- if ((this.level === LogLevel.ERROR || this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.ERROR, message, args)) {
109
- console.error(`${this.prefix()}${message}`, ...args);
110
- }
111
- }
112
- async listLogs(_transportId, _params) {
113
- return { logs: [], total: 0, page: _params?.page ?? 1, perPage: _params?.perPage ?? 100, hasMore: false };
114
- }
115
- async listLogsByRunId(_args) {
116
- return { logs: [], total: 0, page: _args.page ?? 1, perPage: _args.perPage ?? 100, hasMore: false };
117
- }
88
+ var ConsoleLogger = class ConsoleLogger extends MastraLogger {
89
+ component;
90
+ filter;
91
+ constructor(options = {}) {
92
+ super(options);
93
+ this.component = options.component;
94
+ this.filter = options.filter;
95
+ }
96
+ child(componentOrBindings) {
97
+ const component = typeof componentOrBindings === "string" ? componentOrBindings : componentOrBindings?.component ?? this.component;
98
+ return new ConsoleLogger({
99
+ name: this.name,
100
+ level: this.level,
101
+ component,
102
+ filter: this.filter
103
+ });
104
+ }
105
+ shouldLog(level, message, args) {
106
+ if (!this.filter) return true;
107
+ try {
108
+ return this.filter({
109
+ component: this.component,
110
+ level,
111
+ message,
112
+ args
113
+ });
114
+ } catch (e) {
115
+ console.error(`[Logger] Filter error for component=${this.component} level=${level}:`, e);
116
+ return true;
117
+ }
118
+ }
119
+ prefix() {
120
+ return this.component ? `[${this.component}] ` : "";
121
+ }
122
+ debug(message, ...args) {
123
+ if (this.level === LogLevel.DEBUG && this.shouldLog(LogLevel.DEBUG, message, args)) console.info(`${this.prefix()}${message}`, ...args);
124
+ }
125
+ info(message, ...args) {
126
+ if ((this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.INFO, message, args)) console.info(`${this.prefix()}${message}`, ...args);
127
+ }
128
+ warn(message, ...args) {
129
+ if ((this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.WARN, message, args)) console.warn(`${this.prefix()}${message}`, ...args);
130
+ }
131
+ error(message, ...args) {
132
+ if ((this.level === LogLevel.ERROR || this.level === LogLevel.WARN || this.level === LogLevel.INFO || this.level === LogLevel.DEBUG) && this.shouldLog(LogLevel.ERROR, message, args)) console.error(`${this.prefix()}${message}`, ...args);
133
+ }
134
+ async listLogs(_transportId, _params) {
135
+ return {
136
+ logs: [],
137
+ total: 0,
138
+ page: _params?.page ?? 1,
139
+ perPage: _params?.perPage ?? 100,
140
+ hasMore: false
141
+ };
142
+ }
143
+ async listLogsByRunId(_args) {
144
+ return {
145
+ logs: [],
146
+ total: 0,
147
+ page: _args.page ?? 1,
148
+ perPage: _args.perPage ?? 100,
149
+ hasMore: false
150
+ };
151
+ }
118
152
  };
119
-
120
- // ../../packages/_internal-core/dist/base/index.js
153
+ //#endregion
154
+ //#region ../../packages/_internal-core/dist/base/index.js
121
155
  var MastraBase = class {
122
- component = RegisteredLogger.LLM;
123
- logger;
124
- name;
125
- #rawConfig;
126
- constructor({
127
- component,
128
- name,
129
- rawConfig
130
- }) {
131
- this.component = component || RegisteredLogger.LLM;
132
- this.name = name;
133
- this.#rawConfig = rawConfig;
134
- this.logger = new ConsoleLogger({ name: `${this.component} - ${this.name}` });
135
- }
136
- /**
137
- * Returns the raw storage configuration this primitive was created from,
138
- * or undefined if it was created from code.
139
- */
140
- toRawConfig() {
141
- return this.#rawConfig;
142
- }
143
- /**
144
- * Sets the raw storage configuration for this primitive.
145
- * @internal
146
- */
147
- __setRawConfig(rawConfig) {
148
- this.#rawConfig = rawConfig;
149
- }
150
- /**
151
- * Set the logger for the agent
152
- * @param logger
153
- */
154
- __setLogger(logger) {
155
- this.logger = "child" in logger && typeof logger.child === "function" ? logger.child({ component: this.component }) : logger;
156
- }
156
+ component = RegisteredLogger.LLM;
157
+ logger;
158
+ name;
159
+ #rawConfig;
160
+ constructor({ component, name, rawConfig }) {
161
+ this.component = component || RegisteredLogger.LLM;
162
+ this.name = name;
163
+ this.#rawConfig = rawConfig;
164
+ this.logger = new ConsoleLogger({ name: `${this.component} - ${this.name}` });
165
+ }
166
+ /**
167
+ * Returns the raw storage configuration this primitive was created from,
168
+ * or undefined if it was created from code.
169
+ */
170
+ toRawConfig() {
171
+ return this.#rawConfig;
172
+ }
173
+ /**
174
+ * Sets the raw storage configuration for this primitive.
175
+ * @internal
176
+ */
177
+ __setRawConfig(rawConfig) {
178
+ this.#rawConfig = rawConfig;
179
+ }
180
+ /**
181
+ * Set the logger for the agent
182
+ * @param logger
183
+ */
184
+ __setLogger(logger) {
185
+ this.logger = "child" in logger && typeof logger.child === "function" ? logger.child({ component: this.component }) : logger;
186
+ }
157
187
  };
158
-
159
- // ../../packages/_internals/voice/dist/chunk-NWNKSBZV.js
188
+ //#endregion
189
+ //#region ../../packages/_internals/voice/dist/aisdk-C_K-VCwq.js
160
190
  var MastraVoice = class extends MastraBase {
161
- listeningModel;
162
- speechModel;
163
- speaker;
164
- realtimeConfig;
165
- constructor({ listeningModel, speechModel, speaker, realtimeConfig, name } = {}) {
166
- super({
167
- component: "VOICE",
168
- name
169
- });
170
- this.listeningModel = listeningModel;
171
- this.speechModel = speechModel;
172
- this.speaker = speaker;
173
- this.realtimeConfig = realtimeConfig;
174
- }
175
- /**
176
- * Custom serialization for tracing/observability spans.
177
- * Excludes `apiKey` from listeningModel / speechModel / realtimeConfig
178
- * and any provider-specific state held by subclasses. Subclasses that
179
- * need to expose additional non-sensitive fields can override.
180
- */
181
- serializeForSpan() {
182
- return {
183
- component: "VOICE",
184
- name: this.name,
185
- speaker: this.speaker,
186
- listeningModel: this.listeningModel ? { name: this.listeningModel.name } : void 0,
187
- speechModel: this.speechModel ? { name: this.speechModel.name } : void 0,
188
- realtimeModel: this.realtimeConfig?.model
189
- };
190
- }
191
- updateConfig(_options) {
192
- this.logger.debug("updateConfig not implemented by this voice provider");
193
- }
194
- /**
195
- * Initializes a WebSocket or WebRTC connection for real-time communication
196
- * @returns Promise that resolves when the connection is established
197
- */
198
- async connect(_options) {
199
- this.logger.debug("connect not implemented by this voice provider");
200
- }
201
- /**
202
- * Relay audio data to the voice provider for real-time processing
203
- * @param audioData Audio data to relay
204
- */
205
- async send(_audioData) {
206
- this.logger.debug("relay not implemented by this voice provider");
207
- }
208
- /**
209
- * Trigger voice providers to respond
210
- */
211
- async answer(_options) {
212
- this.logger.debug("answer not implemented by this voice provider");
213
- }
214
- /**
215
- * Equip the voice provider with instructions
216
- * @param instructions Instructions to add
217
- */
218
- addInstructions(_instructions) {
219
- }
220
- /**
221
- * Equip the voice provider with tools
222
- * @param tools Array of tools to add
223
- */
224
- addTools(_tools) {
225
- }
226
- /**
227
- * Disconnect from the WebSocket or WebRTC connection
228
- */
229
- close() {
230
- this.logger.debug("close not implemented by this voice provider");
231
- }
232
- /**
233
- * Register an event listener
234
- * @param event Event name (e.g., 'speaking', 'writing', 'error')
235
- * @param callback Callback function that receives event data
236
- */
237
- on(_event, _callback) {
238
- this.logger.debug("on not implemented by this voice provider");
239
- }
240
- /**
241
- * Remove an event listener
242
- * @param event Event name (e.g., 'speaking', 'writing', 'error')
243
- * @param callback Callback function to remove
244
- */
245
- off(_event, _callback) {
246
- this.logger.debug("off not implemented by this voice provider");
247
- }
248
- /**
249
- * Get available speakers/voices
250
- * @returns Array of available voice IDs and their metadata
251
- */
252
- getSpeakers() {
253
- this.logger.debug("getSpeakers not implemented by this voice provider");
254
- return Promise.resolve([]);
255
- }
256
- /**
257
- * Get available speakers/voices
258
- * @returns Array of available voice IDs and their metadata
259
- */
260
- getListener() {
261
- this.logger.debug("getListener not implemented by this voice provider");
262
- return Promise.resolve({ enabled: false });
263
- }
191
+ listeningModel;
192
+ speechModel;
193
+ speaker;
194
+ realtimeConfig;
195
+ constructor({ listeningModel, speechModel, speaker, realtimeConfig, name } = {}) {
196
+ super({
197
+ component: "VOICE",
198
+ name
199
+ });
200
+ this.listeningModel = listeningModel;
201
+ this.speechModel = speechModel;
202
+ this.speaker = speaker;
203
+ this.realtimeConfig = realtimeConfig;
204
+ }
205
+ /**
206
+ * Custom serialization for tracing/observability spans.
207
+ * Excludes `apiKey` from listeningModel / speechModel / realtimeConfig
208
+ * and any provider-specific state held by subclasses. Subclasses that
209
+ * need to expose additional non-sensitive fields can override.
210
+ */
211
+ serializeForSpan() {
212
+ return {
213
+ component: "VOICE",
214
+ name: this.name,
215
+ speaker: this.speaker,
216
+ listeningModel: this.listeningModel ? { name: this.listeningModel.name } : void 0,
217
+ speechModel: this.speechModel ? { name: this.speechModel.name } : void 0,
218
+ realtimeModel: this.realtimeConfig?.model
219
+ };
220
+ }
221
+ updateConfig(_options) {
222
+ this.logger.debug("updateConfig not implemented by this voice provider");
223
+ }
224
+ /**
225
+ * Initializes a WebSocket or WebRTC connection for real-time communication
226
+ * @returns Promise that resolves when the connection is established
227
+ */
228
+ async connect(_options) {
229
+ this.logger.debug("connect not implemented by this voice provider");
230
+ }
231
+ /**
232
+ * Relay audio data to the voice provider for real-time processing
233
+ * @param audioData Audio data to relay
234
+ */
235
+ async send(_audioData) {
236
+ this.logger.debug("relay not implemented by this voice provider");
237
+ }
238
+ /**
239
+ * Trigger voice providers to respond
240
+ */
241
+ async answer(_options) {
242
+ this.logger.debug("answer not implemented by this voice provider");
243
+ }
244
+ /**
245
+ * Equip the voice provider with instructions
246
+ * @param instructions Instructions to add
247
+ */
248
+ addInstructions(_instructions) {}
249
+ /**
250
+ * Equip the voice provider with tools
251
+ * @param tools Array of tools to add
252
+ */
253
+ addTools(_tools) {}
254
+ /**
255
+ * Disconnect from the WebSocket or WebRTC connection
256
+ */
257
+ close() {
258
+ this.logger.debug("close not implemented by this voice provider");
259
+ }
260
+ /**
261
+ * Register an event listener
262
+ * @param event Event name (e.g., 'speaking', 'writing', 'error')
263
+ * @param callback Callback function that receives event data
264
+ */
265
+ on(_event, _callback) {
266
+ this.logger.debug("on not implemented by this voice provider");
267
+ }
268
+ /**
269
+ * Remove an event listener
270
+ * @param event Event name (e.g., 'speaking', 'writing', 'error')
271
+ * @param callback Callback function to remove
272
+ */
273
+ off(_event, _callback) {
274
+ this.logger.debug("off not implemented by this voice provider");
275
+ }
276
+ /**
277
+ * Get available speakers/voices
278
+ * @returns Array of available voice IDs and their metadata
279
+ */
280
+ getSpeakers() {
281
+ this.logger.debug("getSpeakers not implemented by this voice provider");
282
+ return Promise.resolve([]);
283
+ }
284
+ /**
285
+ * Get available speakers/voices
286
+ * @returns Array of available voice IDs and their metadata
287
+ */
288
+ getListener() {
289
+ this.logger.debug("getListener not implemented by this voice provider");
290
+ return Promise.resolve({ enabled: false });
291
+ }
264
292
  };
265
-
266
- // src/index.ts
267
- var resolveAuthConfig = (modelConfig, fallback, vertexConfig) => {
268
- const resolved = {};
269
- if (vertexConfig?.vertexAI) {
270
- const projectId = vertexConfig.project || process.env.GOOGLE_CLOUD_PROJECT;
271
- if (projectId) {
272
- resolved.projectId = projectId;
273
- }
274
- }
275
- const apiKey = modelConfig?.apiKey ?? fallback.apiKey;
276
- if (apiKey && !vertexConfig?.vertexAI) {
277
- resolved.apiKey = apiKey;
278
- }
279
- const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;
280
- if (keyFilename) {
281
- resolved.keyFilename = keyFilename;
282
- }
283
- const credentials = modelConfig?.credentials ?? fallback.credentials;
284
- if (credentials) {
285
- resolved.credentials = credentials;
286
- }
287
- return resolved;
293
+ //#endregion
294
+ //#region src/index.ts
295
+ const resolveAuthConfig = (modelConfig, fallback, vertexConfig) => {
296
+ const resolved = {};
297
+ if (vertexConfig?.vertexAI) {
298
+ const projectId = vertexConfig.project || process.env.GOOGLE_CLOUD_PROJECT;
299
+ if (projectId) resolved.projectId = projectId;
300
+ }
301
+ const apiKey = modelConfig?.apiKey ?? fallback.apiKey;
302
+ if (apiKey && !vertexConfig?.vertexAI) resolved.apiKey = apiKey;
303
+ const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;
304
+ if (keyFilename) resolved.keyFilename = keyFilename;
305
+ const credentials = modelConfig?.credentials ?? fallback.credentials;
306
+ if (credentials) resolved.credentials = credentials;
307
+ return resolved;
288
308
  };
289
- var buildAuthOptions = (config, vertexConfig) => {
290
- const options = {};
291
- if (config.credentials) {
292
- options.credentials = config.credentials;
293
- }
294
- if (config.keyFilename) {
295
- options.keyFilename = config.keyFilename;
296
- }
297
- if (config.apiKey && !vertexConfig?.vertexAI) {
298
- options.apiKey = config.apiKey;
299
- }
300
- if (config.projectId) {
301
- options.projectId = config.projectId;
302
- }
303
- return options;
309
+ const buildAuthOptions = (config, vertexConfig) => {
310
+ const options = {};
311
+ if (config.credentials) options.credentials = config.credentials;
312
+ if (config.keyFilename) options.keyFilename = config.keyFilename;
313
+ if (config.apiKey && !vertexConfig?.vertexAI) options.apiKey = config.apiKey;
314
+ if (config.projectId) options.projectId = config.projectId;
315
+ return options;
304
316
  };
305
- var DEFAULT_VOICE = "en-US-Casual-K";
317
+ const DEFAULT_VOICE = "en-US-Casual-K";
318
+ /**
319
+ * GoogleVoice class provides Text-to-Speech and Speech-to-Text capabilities using Google Cloud services.
320
+ * Supports both standard Google Cloud API authentication and Vertex AI mode for enterprise deployments.
321
+ *
322
+ * @class GoogleVoice
323
+ * @extends MastraVoice
324
+ *
325
+ * @example Standard usage with API key
326
+ * ```typescript
327
+ * const voice = new GoogleVoice({
328
+ * speechModel: { apiKey: 'your-api-key' },
329
+ * speaker: 'en-US-Studio-O',
330
+ * });
331
+ * ```
332
+ *
333
+ * @example Vertex AI mode (recommended for production)
334
+ * ```typescript
335
+ * const voice = new GoogleVoice({
336
+ * vertexAI: true,
337
+ * project: 'your-gcp-project',
338
+ * location: 'us-central1',
339
+ * speaker: 'en-US-Studio-O',
340
+ * });
341
+ * ```
342
+ *
343
+ * @example Vertex AI with service account
344
+ * ```typescript
345
+ * const voice = new GoogleVoice({
346
+ * vertexAI: true,
347
+ * project: 'your-gcp-project',
348
+ * speechModel: {
349
+ * keyFilename: '/path/to/service-account.json',
350
+ * },
351
+ * });
352
+ * ```
353
+ */
306
354
  var GoogleVoice = class extends MastraVoice {
307
- ttsClient;
308
- speechClient;
309
- speechClientV2;
310
- speechOptionsV2;
311
- vertexAI;
312
- project;
313
- location;
314
- /**
315
- * Creates an instance of GoogleVoice
316
- * @param {GoogleVoiceConfig} config - Configuration options
317
- * @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
318
- * @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
319
- * @param {string} [config.speaker] - Default voice ID to use for speech synthesis
320
- * @param {boolean} [config.vertexAI] - Enable Vertex AI mode
321
- * @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)
322
- * @param {string} [config.location] - Google Cloud region (default: 'us-central1')
323
- */
324
- constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location } = {}) {
325
- const defaultApiKey = process.env.GOOGLE_API_KEY;
326
- const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;
327
- const defaultSpeaker = DEFAULT_VOICE;
328
- const resolvedProject = project || process.env.GOOGLE_CLOUD_PROJECT;
329
- const resolvedLocation = location || process.env.GOOGLE_CLOUD_LOCATION || "us-central1";
330
- if (vertexAI && !resolvedProject) {
331
- throw new Error(
332
- "Google Cloud project ID is required when using Vertex AI. Set GOOGLE_CLOUD_PROJECT environment variable or pass project to constructor."
333
- );
334
- }
335
- const vertexConfig = { vertexAI, project: resolvedProject };
336
- const sharedFallback = {
337
- apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,
338
- keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,
339
- credentials: speechModel?.credentials ?? listeningModel?.credentials};
340
- const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);
341
- const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);
342
- super({
343
- speechModel: {
344
- name: "",
345
- apiKey: speechAuthConfig.apiKey ?? defaultApiKey
346
- },
347
- listeningModel: {
348
- name: "",
349
- apiKey: listeningAuthConfig.apiKey ?? defaultApiKey
350
- },
351
- speaker: speaker ?? defaultSpeaker
352
- });
353
- this.vertexAI = vertexAI;
354
- this.project = resolvedProject;
355
- this.location = resolvedLocation;
356
- const ttsOptions = buildAuthOptions(speechAuthConfig, { vertexAI});
357
- const speechOptions = buildAuthOptions(listeningAuthConfig, { vertexAI});
358
- this.ttsClient = new TextToSpeechClient(ttsOptions);
359
- this.speechClient = new SpeechClient(speechOptions);
360
- this.speechOptionsV2 = speechOptions;
361
- }
362
- getV2SpeechClient() {
363
- if (!this.speechClientV2) {
364
- this.speechClientV2 = new v2.SpeechClient(this.speechOptionsV2);
365
- }
366
- return this.speechClientV2;
367
- }
368
- /**
369
- * Check if Vertex AI mode is enabled
370
- * @returns {boolean} True if using Vertex AI
371
- */
372
- isUsingVertexAI() {
373
- return this.vertexAI;
374
- }
375
- /**
376
- * Get the configured Google Cloud project ID
377
- * @returns {string | undefined} The project ID or undefined if not set
378
- */
379
- getProject() {
380
- return this.project;
381
- }
382
- /**
383
- * Get the configured Google Cloud location/region
384
- * @returns {string} The location (default: 'us-central1')
385
- */
386
- getLocation() {
387
- return this.location;
388
- }
389
- /**
390
- * Gets a list of available voices
391
- * @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
392
- */
393
- async getSpeakers({ languageCode = "en-US" } = {}) {
394
- const [response] = await this.ttsClient.listVoices({ languageCode });
395
- return (response?.voices || []).filter((voice) => voice.name && voice.languageCodes).map((voice) => ({
396
- voiceId: voice.name,
397
- languageCodes: voice.languageCodes
398
- }));
399
- }
400
- async streamToString(stream) {
401
- const chunks = [];
402
- for await (const chunk of stream) {
403
- if (typeof chunk === "string") {
404
- chunks.push(Buffer.from(chunk));
405
- } else {
406
- chunks.push(chunk);
407
- }
408
- }
409
- return Buffer.concat(chunks).toString("utf-8");
410
- }
411
- /**
412
- * Converts text to speech.
413
- *
414
- * When `input` is a string or stream, builds a text-only request (existing behaviour).
415
- * Pass `options.input` to send richer proto fields (ssml, markup, prompt,
416
- * customPronunciations, multiSpeakerMarkup) and `options.voice` for fields
417
- * like modelName or multiSpeakerVoiceConfig.
418
- *
419
- * @param {string | NodeJS.ReadableStream} input - Text or stream to convert to speech
420
- * @param {GoogleSpeakOptions} [options] - Speech synthesis options
421
- * @returns {Promise<NodeJS.ReadableStream>} Stream of synthesised audio. Default encoding is LINEAR16.
422
- */
423
- async speak(input, options) {
424
- const defaultVoiceName = options?.speaker || this.speaker;
425
- const defaultLanguageCode = options?.languageCode || defaultVoiceName?.split("-").slice(0, 2).join("-") || "en-US";
426
- const requestInput = options?.input ? { ...options.input } : { text: typeof input === "string" ? input : await this.streamToString(input) };
427
- if (options?.input && !options.input.text && !options.input.ssml && !options.input.markup && !options.input.multiSpeakerMarkup) {
428
- requestInput.text = typeof input === "string" ? input : await this.streamToString(input);
429
- }
430
- const request = {
431
- input: requestInput,
432
- voice: {
433
- name: defaultVoiceName,
434
- languageCode: defaultLanguageCode,
435
- ...options?.voice
436
- },
437
- audioConfig: options?.audioConfig || { audioEncoding: "LINEAR16" }
438
- };
439
- const [response] = await this.ttsClient.synthesizeSpeech(request);
440
- if (!response.audioContent) {
441
- throw new Error("No audio content returned.");
442
- }
443
- if (typeof response.audioContent === "string") {
444
- throw new Error("Audio content is a string.");
445
- }
446
- const stream = new PassThrough();
447
- stream.end(Buffer.from(response.audioContent));
448
- return stream;
449
- }
450
- /**
451
- * Checks if listening capabilities are enabled.
452
- *
453
- * @returns {Promise<{ enabled: boolean }>}
454
- */
455
- async getListener() {
456
- return { enabled: true };
457
- }
458
- /**
459
- * Converts speech to text using Cloud Speech-to-Text v1 or v2.
460
- *
461
- * Pass `{ v2: true }` in options to use the v2 API, which supports additional
462
- * audio formats like AAC-in-MP4 (iOS Safari) via `autoDecodingConfig` or
463
- * `explicitDecodingConfig`. The v1 path remains the default.
464
- *
465
- * @param {NodeJS.ReadableStream} audioStream - Audio stream to transcribe. Default encoding is LINEAR16.
466
- * @param {GoogleListenOptions} [options] - Recognition options
467
- * @returns {Promise<string>} Transcribed text
468
- */
469
- async listen(audioStream, options) {
470
- const chunks = [];
471
- for await (const chunk of audioStream) {
472
- if (typeof chunk === "string") {
473
- chunks.push(Buffer.from(chunk));
474
- } else {
475
- chunks.push(chunk);
476
- }
477
- }
478
- const buffer = Buffer.concat(chunks);
479
- if (options && "v2" in options && options.v2) {
480
- return this.recognizeV2(buffer, options);
481
- }
482
- return this.recognizeV1(buffer, options);
483
- }
484
- async recognizeV1(buffer, options) {
485
- const request = {
486
- config: {
487
- encoding: "LINEAR16",
488
- languageCode: "en-US",
489
- ...options?.config
490
- },
491
- audio: {
492
- content: buffer.toString("base64")
493
- }
494
- };
495
- const [response] = await this.speechClient.recognize(request);
496
- return this.extractTranscription(response?.results);
497
- }
498
- async recognizeV2(buffer, options) {
499
- const config = { ...options.config };
500
- if (!config.autoDecodingConfig && !config.explicitDecodingConfig) {
501
- config.autoDecodingConfig = {};
502
- }
503
- if (!config.languageCodes || config.languageCodes.length === 0) {
504
- config.languageCodes = ["en-US"];
505
- }
506
- if (!config.model) {
507
- config.model = "long";
508
- }
509
- let recognizer = options.recognizer;
510
- if (!recognizer) {
511
- const project = this.project || await this.getV2SpeechClient().getProjectId();
512
- recognizer = `projects/${project}/locations/global/recognizers/_`;
513
- }
514
- const request = {
515
- recognizer,
516
- config,
517
- content: buffer
518
- };
519
- const client = this.getV2SpeechClient();
520
- const [response] = await client.recognize(request);
521
- return this.extractTranscription(response?.results);
522
- }
523
- extractTranscription(results) {
524
- if (!results || results.length === 0) {
525
- throw new Error("No transcription results returned");
526
- }
527
- const transcription = results.map((result) => {
528
- if (!result.alternatives || result.alternatives.length === 0) {
529
- return "";
530
- }
531
- return result.alternatives[0].transcript || "";
532
- }).filter((text) => text.length > 0).join(" ");
533
- if (!transcription) {
534
- throw new Error("No valid transcription found in results");
535
- }
536
- return transcription;
537
- }
355
+ ttsClient;
356
+ speechClient;
357
+ speechClientV2;
358
+ speechOptionsV2;
359
+ vertexAI;
360
+ project;
361
+ location;
362
+ /**
363
+ * Creates an instance of GoogleVoice
364
+ * @param {GoogleVoiceConfig} config - Configuration options
365
+ * @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
366
+ * @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
367
+ * @param {string} [config.speaker] - Default voice ID to use for speech synthesis
368
+ * @param {boolean} [config.vertexAI] - Enable Vertex AI mode
369
+ * @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)
370
+ * @param {string} [config.location] - Google Cloud region (default: 'us-central1')
371
+ */
372
+ constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location } = {}) {
373
+ const defaultApiKey = process.env.GOOGLE_API_KEY;
374
+ const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;
375
+ const defaultSpeaker = DEFAULT_VOICE;
376
+ const resolvedProject = project || process.env.GOOGLE_CLOUD_PROJECT;
377
+ const resolvedLocation = location || process.env.GOOGLE_CLOUD_LOCATION || "us-central1";
378
+ if (vertexAI && !resolvedProject) throw new Error("Google Cloud project ID is required when using Vertex AI. Set GOOGLE_CLOUD_PROJECT environment variable or pass project to constructor.");
379
+ const vertexConfig = {
380
+ vertexAI,
381
+ project: resolvedProject
382
+ };
383
+ const sharedFallback = {
384
+ apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,
385
+ keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,
386
+ credentials: speechModel?.credentials ?? listeningModel?.credentials,
387
+ projectId: resolvedProject
388
+ };
389
+ const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);
390
+ const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);
391
+ super({
392
+ speechModel: {
393
+ name: "",
394
+ apiKey: speechAuthConfig.apiKey ?? defaultApiKey
395
+ },
396
+ listeningModel: {
397
+ name: "",
398
+ apiKey: listeningAuthConfig.apiKey ?? defaultApiKey
399
+ },
400
+ speaker: speaker ?? defaultSpeaker
401
+ });
402
+ this.vertexAI = vertexAI;
403
+ this.project = resolvedProject;
404
+ this.location = resolvedLocation;
405
+ const ttsOptions = buildAuthOptions(speechAuthConfig, {
406
+ vertexAI,
407
+ location: resolvedLocation
408
+ });
409
+ const speechOptions = buildAuthOptions(listeningAuthConfig, {
410
+ vertexAI,
411
+ location: resolvedLocation
412
+ });
413
+ this.ttsClient = new TextToSpeechClient(ttsOptions);
414
+ this.speechClient = new SpeechClient(speechOptions);
415
+ this.speechOptionsV2 = speechOptions;
416
+ }
417
+ getV2SpeechClient() {
418
+ if (!this.speechClientV2) this.speechClientV2 = new v2.SpeechClient(this.speechOptionsV2);
419
+ return this.speechClientV2;
420
+ }
421
+ /**
422
+ * Check if Vertex AI mode is enabled
423
+ * @returns {boolean} True if using Vertex AI
424
+ */
425
+ isUsingVertexAI() {
426
+ return this.vertexAI;
427
+ }
428
+ /**
429
+ * Get the configured Google Cloud project ID
430
+ * @returns {string | undefined} The project ID or undefined if not set
431
+ */
432
+ getProject() {
433
+ return this.project;
434
+ }
435
+ /**
436
+ * Get the configured Google Cloud location/region
437
+ * @returns {string} The location (default: 'us-central1')
438
+ */
439
+ getLocation() {
440
+ return this.location;
441
+ }
442
+ /**
443
+ * Gets a list of available voices
444
+ * @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
445
+ */
446
+ async getSpeakers({ languageCode = "en-US" } = {}) {
447
+ const [response] = await this.ttsClient.listVoices({ languageCode });
448
+ return (response?.voices || []).filter((voice) => voice.name && voice.languageCodes).map((voice) => ({
449
+ voiceId: voice.name,
450
+ languageCodes: voice.languageCodes
451
+ }));
452
+ }
453
+ async streamToString(stream) {
454
+ const chunks = [];
455
+ for await (const chunk of stream) if (typeof chunk === "string") chunks.push(Buffer.from(chunk));
456
+ else chunks.push(chunk);
457
+ return Buffer.concat(chunks).toString("utf-8");
458
+ }
459
+ /**
460
+ * Converts text to speech.
461
+ *
462
+ * When `input` is a string or stream, builds a text-only request (existing behaviour).
463
+ * Pass `options.input` to send richer proto fields (ssml, markup, prompt,
464
+ * customPronunciations, multiSpeakerMarkup) and `options.voice` for fields
465
+ * like modelName or multiSpeakerVoiceConfig.
466
+ *
467
+ * @param {string | NodeJS.ReadableStream} input - Text or stream to convert to speech
468
+ * @param {GoogleSpeakOptions} [options] - Speech synthesis options
469
+ * @returns {Promise<NodeJS.ReadableStream>} Stream of synthesised audio. Default encoding is LINEAR16.
470
+ */
471
+ async speak(input, options) {
472
+ const defaultVoiceName = options?.speaker || this.speaker;
473
+ const defaultLanguageCode = options?.languageCode || defaultVoiceName?.split("-").slice(0, 2).join("-") || "en-US";
474
+ const requestInput = options?.input ? { ...options.input } : { text: typeof input === "string" ? input : await this.streamToString(input) };
475
+ if (options?.input && !options.input.text && !options.input.ssml && !options.input.markup && !options.input.multiSpeakerMarkup) requestInput.text = typeof input === "string" ? input : await this.streamToString(input);
476
+ const request = {
477
+ input: requestInput,
478
+ voice: {
479
+ name: defaultVoiceName,
480
+ languageCode: defaultLanguageCode,
481
+ ...options?.voice
482
+ },
483
+ audioConfig: options?.audioConfig || { audioEncoding: "LINEAR16" }
484
+ };
485
+ const [response] = await this.ttsClient.synthesizeSpeech(request);
486
+ if (!response.audioContent) throw new Error("No audio content returned.");
487
+ if (typeof response.audioContent === "string") throw new Error("Audio content is a string.");
488
+ const stream = new PassThrough();
489
+ stream.end(Buffer.from(response.audioContent));
490
+ return stream;
491
+ }
492
+ /**
493
+ * Checks if listening capabilities are enabled.
494
+ *
495
+ * @returns {Promise<{ enabled: boolean }>}
496
+ */
497
+ async getListener() {
498
+ return { enabled: true };
499
+ }
500
+ /**
501
+ * Converts speech to text using Cloud Speech-to-Text v1 or v2.
502
+ *
503
+ * Pass `{ v2: true }` in options to use the v2 API, which supports additional
504
+ * audio formats like AAC-in-MP4 (iOS Safari) via `autoDecodingConfig` or
505
+ * `explicitDecodingConfig`. The v1 path remains the default.
506
+ *
507
+ * @param {NodeJS.ReadableStream} audioStream - Audio stream to transcribe. Default encoding is LINEAR16.
508
+ * @param {GoogleListenOptions} [options] - Recognition options
509
+ * @returns {Promise<string>} Transcribed text
510
+ */
511
+ async listen(audioStream, options) {
512
+ const chunks = [];
513
+ for await (const chunk of audioStream) if (typeof chunk === "string") chunks.push(Buffer.from(chunk));
514
+ else chunks.push(chunk);
515
+ const buffer = Buffer.concat(chunks);
516
+ if (options && "v2" in options && options.v2) return this.recognizeV2(buffer, options);
517
+ return this.recognizeV1(buffer, options);
518
+ }
519
+ async recognizeV1(buffer, options) {
520
+ const request = {
521
+ config: {
522
+ encoding: "LINEAR16",
523
+ languageCode: "en-US",
524
+ ...options?.config
525
+ },
526
+ audio: { content: buffer.toString("base64") }
527
+ };
528
+ const [response] = await this.speechClient.recognize(request);
529
+ return this.extractTranscription(response?.results);
530
+ }
531
+ async recognizeV2(buffer, options) {
532
+ const config = { ...options.config };
533
+ if (!config.autoDecodingConfig && !config.explicitDecodingConfig) config.autoDecodingConfig = {};
534
+ if (!config.languageCodes || config.languageCodes.length === 0) config.languageCodes = ["en-US"];
535
+ if (!config.model) config.model = "long";
536
+ let recognizer = options.recognizer;
537
+ if (!recognizer) recognizer = `projects/${this.project || await this.getV2SpeechClient().getProjectId()}/locations/global/recognizers/_`;
538
+ const request = {
539
+ recognizer,
540
+ config,
541
+ content: buffer
542
+ };
543
+ const [response] = await this.getV2SpeechClient().recognize(request);
544
+ return this.extractTranscription(response?.results);
545
+ }
546
+ extractTranscription(results) {
547
+ if (!results || results.length === 0) throw new Error("No transcription results returned");
548
+ const transcription = results.map((result) => {
549
+ if (!result.alternatives || result.alternatives.length === 0) return "";
550
+ return result.alternatives[0].transcript || "";
551
+ }).filter((text) => text.length > 0).join(" ");
552
+ if (!transcription) throw new Error("No valid transcription found in results");
553
+ return transcription;
554
+ }
538
555
  };
539
-
556
+ //#endregion
540
557
  export { GoogleVoice };
541
- //# sourceMappingURL=index.js.map
558
+
542
559
  //# sourceMappingURL=index.js.map