@mastra/voice-google 0.0.0-toolOptionTypes-20250917085558 → 0.0.0-top-level-fix-20251211111608
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 +195 -3
- package/README.md +192 -3
- package/dist/index.cjs +145 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +92 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +145 -83
- package/dist/index.js.map +1 -1
- package/package.json +14 -9
package/dist/index.cjs
CHANGED
|
@@ -6,61 +6,129 @@ var textToSpeech = require('@google-cloud/text-to-speech');
|
|
|
6
6
|
var voice = require('@mastra/core/voice');
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
+
var resolveAuthConfig = (modelConfig, fallback, vertexConfig) => {
|
|
10
|
+
const resolved = {};
|
|
11
|
+
if (vertexConfig?.vertexAI) {
|
|
12
|
+
const projectId = vertexConfig.project || process.env.GOOGLE_CLOUD_PROJECT;
|
|
13
|
+
if (projectId) {
|
|
14
|
+
resolved.projectId = projectId;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const apiKey = modelConfig?.apiKey ?? fallback.apiKey;
|
|
18
|
+
if (apiKey && !vertexConfig?.vertexAI) {
|
|
19
|
+
resolved.apiKey = apiKey;
|
|
20
|
+
}
|
|
21
|
+
const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;
|
|
22
|
+
if (keyFilename) {
|
|
23
|
+
resolved.keyFilename = keyFilename;
|
|
24
|
+
}
|
|
25
|
+
const credentials = modelConfig?.credentials ?? fallback.credentials;
|
|
26
|
+
if (credentials) {
|
|
27
|
+
resolved.credentials = credentials;
|
|
28
|
+
}
|
|
29
|
+
return resolved;
|
|
30
|
+
};
|
|
31
|
+
var buildAuthOptions = (config, vertexConfig) => {
|
|
32
|
+
const options = {};
|
|
33
|
+
if (config.credentials) {
|
|
34
|
+
options.credentials = config.credentials;
|
|
35
|
+
}
|
|
36
|
+
if (config.keyFilename) {
|
|
37
|
+
options.keyFilename = config.keyFilename;
|
|
38
|
+
}
|
|
39
|
+
if (config.apiKey && !vertexConfig?.vertexAI) {
|
|
40
|
+
options.apiKey = config.apiKey;
|
|
41
|
+
}
|
|
42
|
+
if (config.projectId) {
|
|
43
|
+
options.projectId = config.projectId;
|
|
44
|
+
}
|
|
45
|
+
return options;
|
|
46
|
+
};
|
|
9
47
|
var DEFAULT_VOICE = "en-US-Casual-K";
|
|
10
48
|
var GoogleVoice = class extends voice.MastraVoice {
|
|
11
49
|
ttsClient;
|
|
12
50
|
speechClient;
|
|
51
|
+
vertexAI;
|
|
52
|
+
project;
|
|
53
|
+
location;
|
|
13
54
|
/**
|
|
14
55
|
* Creates an instance of GoogleVoice
|
|
15
|
-
* @param {
|
|
56
|
+
* @param {GoogleVoiceConfig} config - Configuration options
|
|
16
57
|
* @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
|
|
17
58
|
* @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
|
|
18
59
|
* @param {string} [config.speaker] - Default voice ID to use for speech synthesis
|
|
19
|
-
* @
|
|
60
|
+
* @param {boolean} [config.vertexAI] - Enable Vertex AI mode
|
|
61
|
+
* @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)
|
|
62
|
+
* @param {string} [config.location] - Google Cloud region (default: 'us-central1')
|
|
20
63
|
*/
|
|
21
|
-
constructor({
|
|
22
|
-
listeningModel,
|
|
23
|
-
speechModel,
|
|
24
|
-
speaker
|
|
25
|
-
} = {}) {
|
|
64
|
+
constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location } = {}) {
|
|
26
65
|
const defaultApiKey = process.env.GOOGLE_API_KEY;
|
|
66
|
+
const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
27
67
|
const defaultSpeaker = DEFAULT_VOICE;
|
|
68
|
+
const resolvedProject = project || process.env.GOOGLE_CLOUD_PROJECT;
|
|
69
|
+
const resolvedLocation = location || process.env.GOOGLE_CLOUD_LOCATION || "us-central1";
|
|
70
|
+
if (vertexAI && !resolvedProject) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
"Google Cloud project ID is required when using Vertex AI. Set GOOGLE_CLOUD_PROJECT environment variable or pass project to constructor."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const vertexConfig = { vertexAI, project: resolvedProject };
|
|
76
|
+
const sharedFallback = {
|
|
77
|
+
apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,
|
|
78
|
+
keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,
|
|
79
|
+
credentials: speechModel?.credentials ?? listeningModel?.credentials};
|
|
80
|
+
const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);
|
|
81
|
+
const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);
|
|
28
82
|
super({
|
|
29
83
|
speechModel: {
|
|
30
84
|
name: "",
|
|
31
|
-
apiKey:
|
|
85
|
+
apiKey: speechAuthConfig.apiKey ?? defaultApiKey
|
|
32
86
|
},
|
|
33
87
|
listeningModel: {
|
|
34
88
|
name: "",
|
|
35
|
-
apiKey:
|
|
89
|
+
apiKey: listeningAuthConfig.apiKey ?? defaultApiKey
|
|
36
90
|
},
|
|
37
91
|
speaker: speaker ?? defaultSpeaker
|
|
38
92
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
93
|
+
this.vertexAI = vertexAI;
|
|
94
|
+
this.project = resolvedProject;
|
|
95
|
+
this.location = resolvedLocation;
|
|
96
|
+
const ttsOptions = buildAuthOptions(speechAuthConfig, { vertexAI});
|
|
97
|
+
const speechOptions = buildAuthOptions(listeningAuthConfig, { vertexAI});
|
|
98
|
+
this.ttsClient = new textToSpeech.TextToSpeechClient(ttsOptions);
|
|
99
|
+
this.speechClient = new speech.SpeechClient(speechOptions);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if Vertex AI mode is enabled
|
|
103
|
+
* @returns {boolean} True if using Vertex AI
|
|
104
|
+
*/
|
|
105
|
+
isUsingVertexAI() {
|
|
106
|
+
return this.vertexAI;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get the configured Google Cloud project ID
|
|
110
|
+
* @returns {string | undefined} The project ID or undefined if not set
|
|
111
|
+
*/
|
|
112
|
+
getProject() {
|
|
113
|
+
return this.project;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the configured Google Cloud location/region
|
|
117
|
+
* @returns {string} The location (default: 'us-central1')
|
|
118
|
+
*/
|
|
119
|
+
getLocation() {
|
|
120
|
+
return this.location;
|
|
51
121
|
}
|
|
52
122
|
/**
|
|
53
123
|
* Gets a list of available voices
|
|
54
124
|
* @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
|
|
55
125
|
*/
|
|
56
126
|
async getSpeakers({ languageCode = "en-US" } = {}) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}));
|
|
63
|
-
}, "voice.google.getSpeakers")();
|
|
127
|
+
const [response] = await this.ttsClient.listVoices({ languageCode });
|
|
128
|
+
return (response?.voices || []).filter((voice) => voice.name && voice.languageCodes).map((voice) => ({
|
|
129
|
+
voiceId: voice.name,
|
|
130
|
+
languageCodes: voice.languageCodes
|
|
131
|
+
}));
|
|
64
132
|
}
|
|
65
133
|
async streamToString(stream) {
|
|
66
134
|
const chunks = [];
|
|
@@ -83,27 +151,25 @@ var GoogleVoice = class extends voice.MastraVoice {
|
|
|
83
151
|
* @returns {Promise<NodeJS.ReadableStream>} Stream of synthesized audio. Default encoding is LINEAR16.
|
|
84
152
|
*/
|
|
85
153
|
async speak(input, options) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return stream$1;
|
|
106
|
-
}, "voice.google.speak")();
|
|
154
|
+
const text = typeof input === "string" ? input : await this.streamToString(input);
|
|
155
|
+
const request = {
|
|
156
|
+
input: { text },
|
|
157
|
+
voice: {
|
|
158
|
+
name: options?.speaker || this.speaker,
|
|
159
|
+
languageCode: options?.languageCode || options?.speaker?.split("-").slice(0, 2).join("-") || "en-US"
|
|
160
|
+
},
|
|
161
|
+
audioConfig: options?.audioConfig || { audioEncoding: "LINEAR16" }
|
|
162
|
+
};
|
|
163
|
+
const [response] = await this.ttsClient.synthesizeSpeech(request);
|
|
164
|
+
if (!response.audioContent) {
|
|
165
|
+
throw new Error("No audio content returned.");
|
|
166
|
+
}
|
|
167
|
+
if (typeof response.audioContent === "string") {
|
|
168
|
+
throw new Error("Audio content is a string.");
|
|
169
|
+
}
|
|
170
|
+
const stream$1 = new stream.PassThrough();
|
|
171
|
+
stream$1.end(Buffer.from(response.audioContent));
|
|
172
|
+
return stream$1;
|
|
107
173
|
}
|
|
108
174
|
/**
|
|
109
175
|
* Checks if listening capabilities are enabled.
|
|
@@ -121,43 +187,39 @@ var GoogleVoice = class extends voice.MastraVoice {
|
|
|
121
187
|
* @returns {Promise<string>} Transcribed text
|
|
122
188
|
*/
|
|
123
189
|
async listen(audioStream, options) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
chunks.push(chunk);
|
|
131
|
-
}
|
|
190
|
+
const chunks = [];
|
|
191
|
+
for await (const chunk of audioStream) {
|
|
192
|
+
if (typeof chunk === "string") {
|
|
193
|
+
chunks.push(Buffer.from(chunk));
|
|
194
|
+
} else {
|
|
195
|
+
chunks.push(chunk);
|
|
132
196
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
144
|
-
console.log(`BEFORE REQUEST`);
|
|
145
|
-
const [response] = await this.speechClient.recognize(request);
|
|
146
|
-
console.log(`AFTER REQUEST`);
|
|
147
|
-
if (!response.results || response.results.length === 0) {
|
|
148
|
-
throw new Error("No transcription results returned");
|
|
197
|
+
}
|
|
198
|
+
const buffer = Buffer.concat(chunks);
|
|
199
|
+
let request = {
|
|
200
|
+
config: {
|
|
201
|
+
encoding: "LINEAR16",
|
|
202
|
+
languageCode: "en-US",
|
|
203
|
+
...options?.config
|
|
204
|
+
},
|
|
205
|
+
audio: {
|
|
206
|
+
content: buffer.toString("base64")
|
|
149
207
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (!
|
|
157
|
-
|
|
208
|
+
};
|
|
209
|
+
const [response] = await this.speechClient.recognize(request);
|
|
210
|
+
if (!response.results || response.results.length === 0) {
|
|
211
|
+
throw new Error("No transcription results returned");
|
|
212
|
+
}
|
|
213
|
+
const transcription = response.results.map((result) => {
|
|
214
|
+
if (!result.alternatives || result.alternatives.length === 0) {
|
|
215
|
+
return "";
|
|
158
216
|
}
|
|
159
|
-
return
|
|
160
|
-
}
|
|
217
|
+
return result.alternatives[0].transcript || "";
|
|
218
|
+
}).filter((text) => text.length > 0).join(" ");
|
|
219
|
+
if (!transcription) {
|
|
220
|
+
throw new Error("No valid transcription found in results");
|
|
221
|
+
}
|
|
222
|
+
return transcription;
|
|
161
223
|
}
|
|
162
224
|
};
|
|
163
225
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["MastraVoice","TextToSpeechClient","SpeechClient","stream","PassThrough"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PassThrough } from 'stream';\n\nimport { SpeechClient } from '@google-cloud/speech';\nimport type { google as SpeechTypes } from '@google-cloud/speech/build/protos/protos';\nimport { TextToSpeechClient } from '@google-cloud/text-to-speech';\nimport type { google as TextToSpeechTypes } from '@google-cloud/text-to-speech/build/protos/protos';\nimport { MastraVoice } from '@mastra/core/voice';\n\n/**\n * Configuration for Google Cloud Voice models\n * @interface GoogleModelConfig\n * @property {string} [apiKey] - Optional Google Cloud API key. If not provided, will use GOOGLE_API_KEY environment variable\n */\nexport interface GoogleModelConfig {\n apiKey?: string;\n}\n\nconst DEFAULT_VOICE = 'en-US-Casual-K';\n\n/**\n * GoogleVoice class provides Text-to-Speech and Speech-to-Text capabilities using Google Cloud services\n * @class GoogleVoice\n * @extends MastraVoice\n */\nexport class GoogleVoice extends MastraVoice {\n private ttsClient: TextToSpeechClient;\n private speechClient: SpeechClient;\n\n /**\n * Creates an instance of GoogleVoice\n * @param {Object} config - Configuration options\n * @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis\n * @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition\n * @param {string} [config.speaker] - Default voice ID to use for speech synthesis\n * @throws {Error} If no API key is provided via config or environment variable\n */\n constructor({\n listeningModel,\n speechModel,\n speaker,\n }: {\n listeningModel?: GoogleModelConfig;\n speechModel?: GoogleModelConfig;\n speaker?: string;\n } = {}) {\n const defaultApiKey = process.env.GOOGLE_API_KEY;\n const defaultSpeaker = DEFAULT_VOICE;\n\n super({\n speechModel: {\n name: '',\n apiKey: speechModel?.apiKey ?? defaultApiKey,\n },\n listeningModel: {\n name: '',\n apiKey: listeningModel?.apiKey ?? defaultApiKey,\n },\n speaker: speaker ?? defaultSpeaker,\n });\n\n const apiKey = defaultApiKey || speechModel?.apiKey || listeningModel?.apiKey;\n if (!apiKey) {\n throw new Error(\n 'Google API key is not set, set GOOGLE_API_KEY environment variable or pass apiKey to constructor',\n );\n }\n\n this.ttsClient = new TextToSpeechClient({\n apiKey: this.speechModel?.apiKey || defaultApiKey,\n });\n\n this.speechClient = new SpeechClient({\n apiKey: this.listeningModel?.apiKey || defaultApiKey,\n });\n }\n\n /**\n * Gets a list of available voices\n * @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.\n */\n async getSpeakers({ languageCode = 'en-US' }: { languageCode?: string } = {}) {\n return this.traced(async () => {\n const [response] = await this.ttsClient.listVoices({ languageCode: languageCode });\n return (response?.voices || [])\n .filter(voice => voice.name && voice.languageCodes)\n .map(voice => ({\n voiceId: voice.name!,\n languageCodes: voice.languageCodes!,\n }));\n }, 'voice.google.getSpeakers')();\n }\n\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n\n /**\n * Converts text to speech\n * @param {string | NodeJS.ReadableStream} input - Text or stream to convert to speech\n * @param {Object} [options] - Speech synthesis options\n * @param {string} [options.speaker] - Voice ID to use\n * @param {string} [options.languageCode] - Language code for the voice\n * @param {TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest['audioConfig']} [options.audioConfig] - Audio configuration options\n * @returns {Promise<NodeJS.ReadableStream>} Stream of synthesized audio. Default encoding is LINEAR16.\n */\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: {\n speaker?: string;\n languageCode?: string;\n audioConfig?: TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest['audioConfig'];\n },\n ): Promise<NodeJS.ReadableStream> {\n return this.traced(async () => {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const request: TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest = {\n input: { text },\n voice: {\n name: options?.speaker || this.speaker,\n languageCode: options?.languageCode || options?.speaker?.split('-').slice(0, 2).join('-') || 'en-US',\n },\n audioConfig: options?.audioConfig || { audioEncoding: 'LINEAR16' },\n };\n\n const [response] = await this.ttsClient.synthesizeSpeech(request);\n\n if (!response.audioContent) {\n throw new Error('No audio content returned.');\n }\n\n if (typeof response.audioContent === 'string') {\n throw new Error('Audio content is a string.');\n }\n\n const stream = new PassThrough();\n stream.end(Buffer.from(response.audioContent));\n return stream;\n }, 'voice.google.speak')();\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n /**\n * Converts speech to text\n * @param {NodeJS.ReadableStream} audioStream - Audio stream to transcribe. Default encoding is LINEAR16.\n * @param {Object} [options] - Recognition options\n * @param {SpeechTypes.cloud.speech.v1.IRecognitionConfig} [options.config] - Recognition configuration\n * @returns {Promise<string>} Transcribed text\n */\n async listen(\n audioStream: NodeJS.ReadableStream,\n options?: { stream?: boolean; config?: SpeechTypes.cloud.speech.v1.IRecognitionConfig },\n ): Promise<string> {\n return this.traced(async () => {\n const chunks: Buffer[] = [];\n for await (const chunk of audioStream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const buffer = Buffer.concat(chunks);\n\n let request = {\n config: {\n encoding: 'LINEAR16',\n languageCode: 'en-US',\n ...options?.config,\n },\n audio: {\n content: buffer.toString('base64'),\n },\n };\n console.log(`BEFORE REQUEST`);\n const [response] = await this.speechClient.recognize(request as SpeechTypes.cloud.speech.v1.IRecognizeRequest);\n console.log(`AFTER REQUEST`);\n\n if (!response.results || response.results.length === 0) {\n throw new Error('No transcription results returned');\n }\n\n const transcription = response.results\n .map((result: any) => {\n if (!result.alternatives || result.alternatives.length === 0) {\n return '';\n }\n return result.alternatives[0].transcript || '';\n })\n .filter((text: string) => text.length > 0)\n .join(' ');\n\n if (!transcription) {\n throw new Error('No valid transcription found in results');\n }\n\n return transcription;\n }, 'voice.google.listen')();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["MastraVoice","TextToSpeechClient","SpeechClient","stream","PassThrough"],"mappings":";;;;;;;;AA6DA,IAAM,iBAAA,GAAoB,CACxB,WAAA,EACA,QAAA,EACA,YAAA,KACe;AACf,EAAA,MAAM,WAAuB,EAAC;AAG9B,EAAA,IAAI,cAAc,QAAA,EAAU;AAC1B,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,oBAAA;AACtD,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,QAAA,CAAS,SAAA,GAAY,SAAA;AAAA,IACvB;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,WAAA,EAAa,MAAA,IAAU,QAAA,CAAS,MAAA;AAE/C,EAAA,IAAI,MAAA,IAAU,CAAC,YAAA,EAAc,QAAA,EAAU;AACrC,IAAA,QAAA,CAAS,MAAA,GAAS,MAAA;AAAA,EACpB;AAEA,EAAA,MAAM,WAAA,GAAc,WAAA,EAAa,WAAA,IAAe,QAAA,CAAS,WAAA;AACzD,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,QAAA,CAAS,WAAA,GAAc,WAAA;AAAA,EACzB;AAEA,EAAA,MAAM,WAAA,GAAc,WAAA,EAAa,WAAA,IAAe,QAAA,CAAS,WAAA;AACzD,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,QAAA,CAAS,WAAA,GAAc,WAAA;AAAA,EACzB;AAEA,EAAA,OAAO,QAAA;AACT,CAAA;AAEA,IAAM,gBAAA,GAAmB,CACvB,MAAA,EACA,YAAA,KACwB;AACxB,EAAA,MAAM,UAA+B,EAAC;AAEtC,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,OAAA,CAAQ,cAAc,MAAA,CAAO,WAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,OAAA,CAAQ,cAAc,MAAA,CAAO,WAAA;AAAA,EAC/B;AAGA,EAAA,IAAI,MAAA,CAAO,MAAA,IAAU,CAAC,YAAA,EAAc,QAAA,EAAU;AAC5C,IAAA,OAAA,CAAQ,SAAS,MAAA,CAAO,MAAA;AAAA,EAC1B;AAGA,EAAA,IAAI,OAAO,SAAA,EAAW;AACpB,IAAA,OAAA,CAAQ,YAAY,MAAA,CAAO,SAAA;AAAA,EAC7B;AAEA,EAAA,OAAO,OAAA;AACT,CAAA;AAEA,IAAM,aAAA,GAAgB,gBAAA;AAsCf,IAAM,WAAA,GAAN,cAA0BA,iBAAA,CAAY;AAAA,EACnC,SAAA;AAAA,EACA,YAAA;AAAA,EACS,QAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYjB,WAAA,CAAY,EAAE,cAAA,EAAgB,WAAA,EAAa,OAAA,EAAS,QAAA,GAAW,KAAA,EAAO,OAAA,EAAS,QAAA,EAAS,GAAuB,EAAC,EAAG;AACjH,IAAA,MAAM,aAAA,GAAgB,QAAQ,GAAA,CAAI,cAAA;AAClC,IAAA,MAAM,kBAAA,GAAqB,QAAQ,GAAA,CAAI,8BAAA;AACvC,IAAA,MAAM,cAAA,GAAiB,aAAA;AAGvB,IAAA,MAAM,eAAA,GAAkB,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,oBAAA;AAC/C,IAAA,MAAM,gBAAA,GAAmB,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,qBAAA,IAAyB,aAAA;AAG1E,IAAA,IAAI,QAAA,IAAY,CAAC,eAAA,EAAiB;AAChC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OAEF;AAAA,IACF;AAEA,IAAA,MAAM,YAAA,GAAe,EAAE,QAAA,EAAU,OAAA,EAAS,eAAA,EAAgB;AAE1D,IAAA,MAAM,cAAA,GAA6B;AAAA,MACjC,MAAA,EAAQ,aAAA,IAAiB,WAAA,EAAa,MAAA,IAAU,cAAA,EAAgB,MAAA;AAAA,MAChE,WAAA,EAAa,kBAAA,IAAsB,WAAA,EAAa,WAAA,IAAe,cAAA,EAAgB,WAAA;AAAA,MAC/E,WAAA,EAAa,WAAA,EAAa,WAAA,IAAe,cAAA,EAAgB,WAE3D,CAAA;AAEA,IAAA,MAAM,gBAAA,GAAmB,iBAAA,CAAkB,WAAA,EAAa,cAAA,EAAgB,YAAY,CAAA;AACpF,IAAA,MAAM,mBAAA,GAAsB,iBAAA,CAAkB,cAAA,EAAgB,cAAA,EAAgB,YAAY,CAAA;AAE1F,IAAA,KAAA,CAAM;AAAA,MACJ,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,EAAA;AAAA,QACN,MAAA,EAAQ,iBAAiB,MAAA,IAAU;AAAA,OACrC;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,IAAA,EAAM,EAAA;AAAA,QACN,MAAA,EAAQ,oBAAoB,MAAA,IAAU;AAAA,OACxC;AAAA,MACA,SAAS,OAAA,IAAW;AAAA,KACrB,CAAA;AAED,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,OAAA,GAAU,eAAA;AACf,IAAA,IAAA,CAAK,QAAA,GAAW,gBAAA;AAEhB,IAAA,MAAM,aAAa,gBAAA,CAAiB,gBAAA,EAAkB,EAAE,QAAqC,CAAC,CAAA;AAC9F,IAAA,MAAM,gBAAgB,gBAAA,CAAiB,mBAAA,EAAqB,EAAE,QAAqC,CAAC,CAAA;AAEpG,IAAA,IAAA,CAAK,SAAA,GAAY,IAAIC,+BAAA,CAAmB,UAAU,CAAA;AAClD,IAAA,IAAA,CAAK,YAAA,GAAe,IAAIC,mBAAA,CAAa,aAAa,CAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAA,GAA2B;AACzB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAA,GAAiC;AAC/B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAA,GAAsB;AACpB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAA,CAAY,EAAE,eAAe,OAAA,EAAQ,GAA+B,EAAC,EAAG;AAC5E,IAAA,MAAM,CAAC,QAAQ,CAAA,GAAI,MAAM,KAAK,SAAA,CAAU,UAAA,CAAW,EAAE,YAAA,EAA4B,CAAA;AACjF,IAAA,OAAA,CAAQ,QAAA,EAAU,MAAA,IAAU,EAAC,EAC1B,MAAA,CAAO,CAAA,KAAA,KAAS,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,aAAa,CAAA,CACjD,GAAA,CAAI,CAAA,KAAA,MAAU;AAAA,MACb,SAAS,KAAA,CAAM,IAAA;AAAA,MACf,eAAe,KAAA,CAAM;AAAA,KACvB,CAAE,CAAA;AAAA,EACN;AAAA,EAEA,MAAc,eAAe,MAAA,EAAgD;AAC3E,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,SAAS,OAAO,CAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,KAAA,CACJ,KAAA,EACA,OAAA,EAKgC;AAChC,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,KAAU,QAAA,GAAW,QAAQ,MAAM,IAAA,CAAK,eAAe,KAAK,CAAA;AAEhF,IAAA,MAAM,OAAA,GAA4E;AAAA,MAChF,KAAA,EAAO,EAAE,IAAA,EAAK;AAAA,MACd,KAAA,EAAO;AAAA,QACL,IAAA,EAAM,OAAA,EAAS,OAAA,IAAW,IAAA,CAAK,OAAA;AAAA,QAC/B,YAAA,EAAc,OAAA,EAAS,YAAA,IAAgB,OAAA,EAAS,SAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK;AAAA,OAC/F;AAAA,MACA,WAAA,EAAa,OAAA,EAAS,WAAA,IAAe,EAAE,eAAe,UAAA;AAAW,KACnE;AAEA,IAAA,MAAM,CAAC,QAAQ,CAAA,GAAI,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAiB,OAAO,CAAA;AAEhE,IAAA,IAAI,CAAC,SAAS,YAAA,EAAc;AAC1B,MAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,IAC9C;AAEA,IAAA,IAAI,OAAO,QAAA,CAAS,YAAA,KAAiB,QAAA,EAAU;AAC7C,MAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,IAC9C;AAEA,IAAA,MAAMC,QAAA,GAAS,IAAIC,kBAAA,EAAY;AAC/B,IAAAD,QAAA,CAAO,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,YAAY,CAAC,CAAA;AAC7C,IAAA,OAAOA,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,EAAE,SAAS,IAAA,EAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAA,CACJ,WAAA,EACA,OAAA,EACiB;AACjB,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,WAAA,MAAiB,SAAS,WAAA,EAAa;AACrC,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AAEnC,IAAA,IAAI,OAAA,GAAU;AAAA,MACZ,MAAA,EAAQ;AAAA,QACN,QAAA,EAAU,UAAA;AAAA,QACV,YAAA,EAAc,OAAA;AAAA,QACd,GAAG,OAAA,EAAS;AAAA,OACd;AAAA,MACA,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,MAAA,CAAO,QAAA,CAAS,QAAQ;AAAA;AACnC,KACF;AACA,IAAA,MAAM,CAAC,QAAQ,CAAA,GAAI,MAAM,IAAA,CAAK,YAAA,CAAa,UAAU,OAAwD,CAAA;AAE7G,IAAA,IAAI,CAAC,QAAA,CAAS,OAAA,IAAW,QAAA,CAAS,OAAA,CAAQ,WAAW,CAAA,EAAG;AACtD,MAAA,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAAA,IACrD;AAEA,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,OAAA,CAC5B,GAAA,CAAI,CAAC,MAAA,KAAgB;AACpB,MAAA,IAAI,CAAC,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,YAAA,CAAa,WAAW,CAAA,EAAG;AAC5D,QAAA,OAAO,EAAA;AAAA,MACT;AACA,MAAA,OAAO,MAAA,CAAO,YAAA,CAAa,CAAC,CAAA,CAAE,UAAA,IAAc,EAAA;AAAA,IAC9C,CAAC,CAAA,CACA,MAAA,CAAO,CAAC,IAAA,KAAiB,KAAK,MAAA,GAAS,CAAC,CAAA,CACxC,IAAA,CAAK,GAAG,CAAA;AAEX,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,IAC3D;AAEA,IAAA,OAAO,aAAA;AAAA,EACT;AACF","file":"index.cjs","sourcesContent":["import { PassThrough } from 'node:stream';\n\nimport { SpeechClient } from '@google-cloud/speech';\nimport type { google as SpeechTypes } from '@google-cloud/speech/build/protos/protos';\nimport { TextToSpeechClient } from '@google-cloud/text-to-speech';\nimport type { google as TextToSpeechTypes } from '@google-cloud/text-to-speech/build/protos/protos';\nimport { MastraVoice } from '@mastra/core/voice';\n\n/**\n * Configuration for Google Cloud Voice models\n * @interface GoogleModelConfig\n * @property {string} [apiKey] - Optional Google Cloud API key. If not provided, will use GOOGLE_API_KEY environment variable\n * @property {string} [keyFilename] - Optional path to a service account key file. If not provided, will use GOOGLE_APPLICATION_CREDENTIALS environment variable\n * @property {{ client_email?: string; private_key?: string }} [credentials] - Optional in-memory service account credentials\n */\nexport interface GoogleModelConfig {\n apiKey?: string;\n keyFilename?: string;\n credentials?: {\n client_email?: string;\n private_key?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Configuration options for GoogleVoice\n * @interface GoogleVoiceConfig\n */\nexport interface GoogleVoiceConfig {\n /** Configuration for speech synthesis (TTS) */\n speechModel?: GoogleModelConfig;\n /** Configuration for speech recognition (STT) */\n listeningModel?: GoogleModelConfig;\n /** Default voice ID to use for speech synthesis */\n speaker?: string;\n /**\n * Enable Vertex AI mode for enterprise deployments.\n * When true, uses Google Cloud project-based authentication instead of API keys.\n * Requires `project` to be set or GOOGLE_CLOUD_PROJECT environment variable.\n */\n vertexAI?: boolean;\n /**\n * Google Cloud project ID (required when vertexAI is true).\n * Falls back to GOOGLE_CLOUD_PROJECT environment variable.\n */\n project?: string;\n /**\n * Google Cloud region for Vertex AI endpoints.\n * Falls back to GOOGLE_CLOUD_LOCATION environment variable.\n * @default 'us-central1'\n */\n location?: string;\n}\n\ntype AuthConfig = Pick<GoogleModelConfig, 'apiKey' | 'keyFilename' | 'credentials'> & {\n projectId?: string;\n};\n\ntype GoogleClientOptions = AuthConfig;\n\nconst resolveAuthConfig = (\n modelConfig: GoogleModelConfig | undefined,\n fallback: AuthConfig,\n vertexConfig?: { vertexAI?: boolean; project?: string },\n): AuthConfig => {\n const resolved: AuthConfig = {};\n\n // For Vertex AI, prioritize project-based auth over API keys\n if (vertexConfig?.vertexAI) {\n const projectId = vertexConfig.project || process.env.GOOGLE_CLOUD_PROJECT;\n if (projectId) {\n resolved.projectId = projectId;\n }\n }\n\n const apiKey = modelConfig?.apiKey ?? fallback.apiKey;\n // Only use API key if not in Vertex AI mode\n if (apiKey && !vertexConfig?.vertexAI) {\n resolved.apiKey = apiKey;\n }\n\n const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;\n if (keyFilename) {\n resolved.keyFilename = keyFilename;\n }\n\n const credentials = modelConfig?.credentials ?? fallback.credentials;\n if (credentials) {\n resolved.credentials = credentials;\n }\n\n return resolved;\n};\n\nconst buildAuthOptions = (\n config: AuthConfig,\n vertexConfig?: { vertexAI?: boolean; location?: string },\n): GoogleClientOptions => {\n const options: GoogleClientOptions = {};\n\n if (config.credentials) {\n options.credentials = config.credentials;\n }\n\n if (config.keyFilename) {\n options.keyFilename = config.keyFilename;\n }\n\n // Only use API key if not using Vertex AI\n if (config.apiKey && !vertexConfig?.vertexAI) {\n options.apiKey = config.apiKey;\n }\n\n // For Vertex AI, set the project ID\n if (config.projectId) {\n options.projectId = config.projectId;\n }\n\n return options;\n};\n\nconst DEFAULT_VOICE = 'en-US-Casual-K';\n\n/**\n * GoogleVoice class provides Text-to-Speech and Speech-to-Text capabilities using Google Cloud services.\n * Supports both standard Google Cloud API authentication and Vertex AI mode for enterprise deployments.\n *\n * @class GoogleVoice\n * @extends MastraVoice\n *\n * @example Standard usage with API key\n * ```typescript\n * const voice = new GoogleVoice({\n * speechModel: { apiKey: 'your-api-key' },\n * speaker: 'en-US-Studio-O',\n * });\n * ```\n *\n * @example Vertex AI mode (recommended for production)\n * ```typescript\n * const voice = new GoogleVoice({\n * vertexAI: true,\n * project: 'your-gcp-project',\n * location: 'us-central1',\n * speaker: 'en-US-Studio-O',\n * });\n * ```\n *\n * @example Vertex AI with service account\n * ```typescript\n * const voice = new GoogleVoice({\n * vertexAI: true,\n * project: 'your-gcp-project',\n * speechModel: {\n * keyFilename: '/path/to/service-account.json',\n * },\n * });\n * ```\n */\nexport class GoogleVoice extends MastraVoice {\n private ttsClient: TextToSpeechClient;\n private speechClient: SpeechClient;\n private readonly vertexAI: boolean;\n private readonly project?: string;\n private readonly location: string;\n\n /**\n * Creates an instance of GoogleVoice\n * @param {GoogleVoiceConfig} config - Configuration options\n * @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis\n * @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition\n * @param {string} [config.speaker] - Default voice ID to use for speech synthesis\n * @param {boolean} [config.vertexAI] - Enable Vertex AI mode\n * @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)\n * @param {string} [config.location] - Google Cloud region (default: 'us-central1')\n */\n constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location }: GoogleVoiceConfig = {}) {\n const defaultApiKey = process.env.GOOGLE_API_KEY;\n const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n const defaultSpeaker = DEFAULT_VOICE;\n\n // Resolve Vertex AI configuration\n const resolvedProject = project || process.env.GOOGLE_CLOUD_PROJECT;\n const resolvedLocation = location || process.env.GOOGLE_CLOUD_LOCATION || 'us-central1';\n\n // Validate Vertex AI configuration\n if (vertexAI && !resolvedProject) {\n throw new Error(\n 'Google Cloud project ID is required when using Vertex AI. ' +\n 'Set GOOGLE_CLOUD_PROJECT environment variable or pass project to constructor.',\n );\n }\n\n const vertexConfig = { vertexAI, project: resolvedProject };\n\n const sharedFallback: AuthConfig = {\n apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,\n keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,\n credentials: speechModel?.credentials ?? listeningModel?.credentials,\n projectId: resolvedProject,\n };\n\n const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);\n const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);\n\n super({\n speechModel: {\n name: '',\n apiKey: speechAuthConfig.apiKey ?? defaultApiKey,\n },\n listeningModel: {\n name: '',\n apiKey: listeningAuthConfig.apiKey ?? defaultApiKey,\n },\n speaker: speaker ?? defaultSpeaker,\n });\n\n this.vertexAI = vertexAI;\n this.project = resolvedProject;\n this.location = resolvedLocation;\n\n const ttsOptions = buildAuthOptions(speechAuthConfig, { vertexAI, location: resolvedLocation });\n const speechOptions = buildAuthOptions(listeningAuthConfig, { vertexAI, location: resolvedLocation });\n\n this.ttsClient = new TextToSpeechClient(ttsOptions);\n this.speechClient = new SpeechClient(speechOptions);\n }\n\n /**\n * Check if Vertex AI mode is enabled\n * @returns {boolean} True if using Vertex AI\n */\n isUsingVertexAI(): boolean {\n return this.vertexAI;\n }\n\n /**\n * Get the configured Google Cloud project ID\n * @returns {string | undefined} The project ID or undefined if not set\n */\n getProject(): string | undefined {\n return this.project;\n }\n\n /**\n * Get the configured Google Cloud location/region\n * @returns {string} The location (default: 'us-central1')\n */\n getLocation(): string {\n return this.location;\n }\n\n /**\n * Gets a list of available voices\n * @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.\n */\n async getSpeakers({ languageCode = 'en-US' }: { languageCode?: string } = {}) {\n const [response] = await this.ttsClient.listVoices({ languageCode: languageCode });\n return (response?.voices || [])\n .filter(voice => voice.name && voice.languageCodes)\n .map(voice => ({\n voiceId: voice.name!,\n languageCodes: voice.languageCodes!,\n }));\n }\n\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n\n /**\n * Converts text to speech\n * @param {string | NodeJS.ReadableStream} input - Text or stream to convert to speech\n * @param {Object} [options] - Speech synthesis options\n * @param {string} [options.speaker] - Voice ID to use\n * @param {string} [options.languageCode] - Language code for the voice\n * @param {TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest['audioConfig']} [options.audioConfig] - Audio configuration options\n * @returns {Promise<NodeJS.ReadableStream>} Stream of synthesized audio. Default encoding is LINEAR16.\n */\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: {\n speaker?: string;\n languageCode?: string;\n audioConfig?: TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest['audioConfig'];\n },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const request: TextToSpeechTypes.cloud.texttospeech.v1.ISynthesizeSpeechRequest = {\n input: { text },\n voice: {\n name: options?.speaker || this.speaker,\n languageCode: options?.languageCode || options?.speaker?.split('-').slice(0, 2).join('-') || 'en-US',\n },\n audioConfig: options?.audioConfig || { audioEncoding: 'LINEAR16' },\n };\n\n const [response] = await this.ttsClient.synthesizeSpeech(request);\n\n if (!response.audioContent) {\n throw new Error('No audio content returned.');\n }\n\n if (typeof response.audioContent === 'string') {\n throw new Error('Audio content is a string.');\n }\n\n const stream = new PassThrough();\n stream.end(Buffer.from(response.audioContent));\n return stream;\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n /**\n * Converts speech to text\n * @param {NodeJS.ReadableStream} audioStream - Audio stream to transcribe. Default encoding is LINEAR16.\n * @param {Object} [options] - Recognition options\n * @param {SpeechTypes.cloud.speech.v1.IRecognitionConfig} [options.config] - Recognition configuration\n * @returns {Promise<string>} Transcribed text\n */\n async listen(\n audioStream: NodeJS.ReadableStream,\n options?: { stream?: boolean; config?: SpeechTypes.cloud.speech.v1.IRecognitionConfig },\n ): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of audioStream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const buffer = Buffer.concat(chunks);\n\n let request = {\n config: {\n encoding: 'LINEAR16',\n languageCode: 'en-US',\n ...options?.config,\n },\n audio: {\n content: buffer.toString('base64'),\n },\n };\n const [response] = await this.speechClient.recognize(request as SpeechTypes.cloud.speech.v1.IRecognizeRequest);\n\n if (!response.results || response.results.length === 0) {\n throw new Error('No transcription results returned');\n }\n\n const transcription = response.results\n .map((result: any) => {\n if (!result.alternatives || result.alternatives.length === 0) {\n return '';\n }\n return result.alternatives[0].transcript || '';\n })\n .filter((text: string) => text.length > 0)\n .join(' ');\n\n if (!transcription) {\n throw new Error('No valid transcription found in results');\n }\n\n return transcription;\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,31 +5,115 @@ import { MastraVoice } from '@mastra/core/voice';
|
|
|
5
5
|
* Configuration for Google Cloud Voice models
|
|
6
6
|
* @interface GoogleModelConfig
|
|
7
7
|
* @property {string} [apiKey] - Optional Google Cloud API key. If not provided, will use GOOGLE_API_KEY environment variable
|
|
8
|
+
* @property {string} [keyFilename] - Optional path to a service account key file. If not provided, will use GOOGLE_APPLICATION_CREDENTIALS environment variable
|
|
9
|
+
* @property {{ client_email?: string; private_key?: string }} [credentials] - Optional in-memory service account credentials
|
|
8
10
|
*/
|
|
9
11
|
export interface GoogleModelConfig {
|
|
10
12
|
apiKey?: string;
|
|
13
|
+
keyFilename?: string;
|
|
14
|
+
credentials?: {
|
|
15
|
+
client_email?: string;
|
|
16
|
+
private_key?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
11
19
|
}
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
21
|
+
* Configuration options for GoogleVoice
|
|
22
|
+
* @interface GoogleVoiceConfig
|
|
23
|
+
*/
|
|
24
|
+
export interface GoogleVoiceConfig {
|
|
25
|
+
/** Configuration for speech synthesis (TTS) */
|
|
26
|
+
speechModel?: GoogleModelConfig;
|
|
27
|
+
/** Configuration for speech recognition (STT) */
|
|
28
|
+
listeningModel?: GoogleModelConfig;
|
|
29
|
+
/** Default voice ID to use for speech synthesis */
|
|
30
|
+
speaker?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Enable Vertex AI mode for enterprise deployments.
|
|
33
|
+
* When true, uses Google Cloud project-based authentication instead of API keys.
|
|
34
|
+
* Requires `project` to be set or GOOGLE_CLOUD_PROJECT environment variable.
|
|
35
|
+
*/
|
|
36
|
+
vertexAI?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Google Cloud project ID (required when vertexAI is true).
|
|
39
|
+
* Falls back to GOOGLE_CLOUD_PROJECT environment variable.
|
|
40
|
+
*/
|
|
41
|
+
project?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Google Cloud region for Vertex AI endpoints.
|
|
44
|
+
* Falls back to GOOGLE_CLOUD_LOCATION environment variable.
|
|
45
|
+
* @default 'us-central1'
|
|
46
|
+
*/
|
|
47
|
+
location?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* GoogleVoice class provides Text-to-Speech and Speech-to-Text capabilities using Google Cloud services.
|
|
51
|
+
* Supports both standard Google Cloud API authentication and Vertex AI mode for enterprise deployments.
|
|
52
|
+
*
|
|
14
53
|
* @class GoogleVoice
|
|
15
54
|
* @extends MastraVoice
|
|
55
|
+
*
|
|
56
|
+
* @example Standard usage with API key
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const voice = new GoogleVoice({
|
|
59
|
+
* speechModel: { apiKey: 'your-api-key' },
|
|
60
|
+
* speaker: 'en-US-Studio-O',
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example Vertex AI mode (recommended for production)
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const voice = new GoogleVoice({
|
|
67
|
+
* vertexAI: true,
|
|
68
|
+
* project: 'your-gcp-project',
|
|
69
|
+
* location: 'us-central1',
|
|
70
|
+
* speaker: 'en-US-Studio-O',
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example Vertex AI with service account
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const voice = new GoogleVoice({
|
|
77
|
+
* vertexAI: true,
|
|
78
|
+
* project: 'your-gcp-project',
|
|
79
|
+
* speechModel: {
|
|
80
|
+
* keyFilename: '/path/to/service-account.json',
|
|
81
|
+
* },
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
16
84
|
*/
|
|
17
85
|
export declare class GoogleVoice extends MastraVoice {
|
|
18
86
|
private ttsClient;
|
|
19
87
|
private speechClient;
|
|
88
|
+
private readonly vertexAI;
|
|
89
|
+
private readonly project?;
|
|
90
|
+
private readonly location;
|
|
20
91
|
/**
|
|
21
92
|
* Creates an instance of GoogleVoice
|
|
22
|
-
* @param {
|
|
93
|
+
* @param {GoogleVoiceConfig} config - Configuration options
|
|
23
94
|
* @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
|
|
24
95
|
* @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
|
|
25
96
|
* @param {string} [config.speaker] - Default voice ID to use for speech synthesis
|
|
26
|
-
* @
|
|
97
|
+
* @param {boolean} [config.vertexAI] - Enable Vertex AI mode
|
|
98
|
+
* @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)
|
|
99
|
+
* @param {string} [config.location] - Google Cloud region (default: 'us-central1')
|
|
27
100
|
*/
|
|
28
|
-
constructor({ listeningModel, speechModel, speaker, }?:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
101
|
+
constructor({ listeningModel, speechModel, speaker, vertexAI, project, location }?: GoogleVoiceConfig);
|
|
102
|
+
/**
|
|
103
|
+
* Check if Vertex AI mode is enabled
|
|
104
|
+
* @returns {boolean} True if using Vertex AI
|
|
105
|
+
*/
|
|
106
|
+
isUsingVertexAI(): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Get the configured Google Cloud project ID
|
|
109
|
+
* @returns {string | undefined} The project ID or undefined if not set
|
|
110
|
+
*/
|
|
111
|
+
getProject(): string | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Get the configured Google Cloud location/region
|
|
114
|
+
* @returns {string} The location (default: 'us-central1')
|
|
115
|
+
*/
|
|
116
|
+
getLocation(): string;
|
|
33
117
|
/**
|
|
34
118
|
* Gets a list of available voices
|
|
35
119
|
* @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAEtF,OAAO,KAAK,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAEtF,OAAO,KAAK,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,iDAAiD;IACjD,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAuED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC;;;;;;;;;OASG;gBACS,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,QAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAE,iBAAsB;IAoDjH;;;OAGG;IACH,eAAe,IAAI,OAAO;IAI1B;;;OAGG;IACH,UAAU,IAAI,MAAM,GAAG,SAAS;IAIhC;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB;;;OAGG;IACG,WAAW,CAAC,EAAE,YAAsB,EAAE,GAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAO;;;;YAU9D,cAAc;IAY5B;;;;;;;;OAQG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EACrC,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;KAC/F,GACA,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IA2BjC;;;;OAIG;IACG,WAAW;;;IAIjB;;;;;;OAMG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,CAAC,cAAc,EAClC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAA;KAAE,GACtF,OAAO,CAAC,MAAM,CAAC;CA2CnB"}
|