@mastra/voice-google 0.12.0-beta.0 → 0.12.0-beta.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/CHANGELOG.md +18 -0
- package/README.md +188 -2
- package/dist/index.cjs +63 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -20
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @mastra/voice-google
|
|
2
2
|
|
|
3
|
+
## 0.12.0-beta.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add Vertex AI support to GoogleVoice provider ([#10661](https://github.com/mastra-ai/mastra/pull/10661))
|
|
8
|
+
- Add `vertexAI`, `project`, and `location` configuration options
|
|
9
|
+
- Support Vertex AI authentication via project ID and service accounts
|
|
10
|
+
- Add helper methods: `isUsingVertexAI()`, `getProject()`, `getLocation()`
|
|
11
|
+
- Support `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` environment variables
|
|
12
|
+
- Update README with Vertex AI usage examples
|
|
13
|
+
|
|
14
|
+
This makes `@mastra/voice-google` consistent with `@mastra/voice-google-gemini-live` and enables enterprise deployments using Google Cloud project-based authentication instead of API keys.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [[`ac0d2f4`](https://github.com/mastra-ai/mastra/commit/ac0d2f4ff8831f72c1c66c2be809706d17f65789), [`1a0d3fc`](https://github.com/mastra-ai/mastra/commit/1a0d3fc811482c9c376cdf79ee615c23bae9b2d6), [`85a628b`](https://github.com/mastra-ai/mastra/commit/85a628b1224a8f64cd82ea7f033774bf22df7a7e), [`c237233`](https://github.com/mastra-ai/mastra/commit/c23723399ccedf7f5744b3f40997b79246bfbe64), [`15f9e21`](https://github.com/mastra-ai/mastra/commit/15f9e216177201ea6e3f6d0bfb063fcc0953444f), [`ff94dea`](https://github.com/mastra-ai/mastra/commit/ff94dea935f4e34545c63bcb6c29804732698809), [`5b2ff46`](https://github.com/mastra-ai/mastra/commit/5b2ff4651df70c146523a7fca773f8eb0a2272f8), [`db41688`](https://github.com/mastra-ai/mastra/commit/db4168806d007417e2e60b4f68656dca4e5f40c9), [`5ca599d`](https://github.com/mastra-ai/mastra/commit/5ca599d0bb59a1595f19f58473fcd67cc71cef58), [`bff1145`](https://github.com/mastra-ai/mastra/commit/bff114556b3cbadad9b2768488708f8ad0e91475), [`5c8ca24`](https://github.com/mastra-ai/mastra/commit/5c8ca247094e0cc2cdbd7137822fb47241f86e77), [`e191844`](https://github.com/mastra-ai/mastra/commit/e1918444ca3f80e82feef1dad506cd4ec6e2875f), [`22553f1`](https://github.com/mastra-ai/mastra/commit/22553f11c63ee5e966a9c034a349822249584691), [`7237163`](https://github.com/mastra-ai/mastra/commit/72371635dbf96a87df4b073cc48fc655afbdce3d), [`2500740`](https://github.com/mastra-ai/mastra/commit/2500740ea23da067d6e50ec71c625ab3ce275e64), [`873ecbb`](https://github.com/mastra-ai/mastra/commit/873ecbb517586aa17d2f1e99283755b3ebb2863f), [`4f9bbe5`](https://github.com/mastra-ai/mastra/commit/4f9bbe5968f42c86f4930b8193de3c3c17e5bd36), [`02e51fe`](https://github.com/mastra-ai/mastra/commit/02e51feddb3d4155cfbcc42624fd0d0970d032c0), [`8f3fa3a`](https://github.com/mastra-ai/mastra/commit/8f3fa3a652bb77da092f913ec51ae46e3a7e27dc), [`cd29ad2`](https://github.com/mastra-ai/mastra/commit/cd29ad23a255534e8191f249593849ed29160886), [`bdf4d8c`](https://github.com/mastra-ai/mastra/commit/bdf4d8cdc656d8a2c21d81834bfa3bfa70f56c16), [`854e3da`](https://github.com/mastra-ai/mastra/commit/854e3dad5daac17a91a20986399d3a51f54bf68b), [`ce18d38`](https://github.com/mastra-ai/mastra/commit/ce18d38678c65870350d123955014a8432075fd9), [`cccf9c8`](https://github.com/mastra-ai/mastra/commit/cccf9c8b2d2dfc1a5e63919395b83d78c89682a0), [`61a5705`](https://github.com/mastra-ai/mastra/commit/61a570551278b6743e64243b3ce7d73de915ca8a), [`db70a48`](https://github.com/mastra-ai/mastra/commit/db70a48aeeeeb8e5f92007e8ede52c364ce15287), [`f0fdc14`](https://github.com/mastra-ai/mastra/commit/f0fdc14ee233d619266b3d2bbdeea7d25cfc6d13), [`db18bc9`](https://github.com/mastra-ai/mastra/commit/db18bc9c3825e2c1a0ad9a183cc9935f6691bfa1), [`9b37b56`](https://github.com/mastra-ai/mastra/commit/9b37b565e1f2a76c24f728945cc740c2b09be9da), [`41a23c3`](https://github.com/mastra-ai/mastra/commit/41a23c32f9877d71810f37e24930515df2ff7a0f), [`5d171ad`](https://github.com/mastra-ai/mastra/commit/5d171ad9ef340387276b77c2bb3e83e83332d729), [`f03ae60`](https://github.com/mastra-ai/mastra/commit/f03ae60500fe350c9d828621006cdafe1975fdd8), [`d1e74a0`](https://github.com/mastra-ai/mastra/commit/d1e74a0a293866dece31022047f5dbab65a304d0), [`39e7869`](https://github.com/mastra-ai/mastra/commit/39e7869bc7d0ee391077ce291474d8a84eedccff), [`5761926`](https://github.com/mastra-ai/mastra/commit/57619260c4a2cdd598763abbacd90de594c6bc76), [`c900fdd`](https://github.com/mastra-ai/mastra/commit/c900fdd504c41348efdffb205cfe80d48c38fa33), [`604a79f`](https://github.com/mastra-ai/mastra/commit/604a79fecf276e26a54a3fe01bb94e65315d2e0e), [`887f0b4`](https://github.com/mastra-ai/mastra/commit/887f0b4746cdbd7cb7d6b17ac9f82aeb58037ea5), [`2562143`](https://github.com/mastra-ai/mastra/commit/256214336b4faa78646c9c1776612393790d8784), [`ef11a61`](https://github.com/mastra-ai/mastra/commit/ef11a61920fa0ed08a5b7ceedd192875af119749)]:
|
|
19
|
+
- @mastra/core@1.0.0-beta.6
|
|
20
|
+
|
|
3
21
|
## 0.12.0-beta.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -12,16 +12,50 @@ npm install @mastra/voice-google
|
|
|
12
12
|
|
|
13
13
|
## Configuration
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The module supports multiple authentication methods:
|
|
16
|
+
|
|
17
|
+
### Option 1: API Key (Development)
|
|
18
|
+
|
|
19
|
+
Use an API key from [Google Cloud Console](https://console.cloud.google.com/apis/credentials):
|
|
16
20
|
|
|
17
21
|
```bash
|
|
18
22
|
GOOGLE_API_KEY=your_api_key
|
|
19
|
-
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Option 2: Service Account (Recommended)
|
|
26
|
+
|
|
27
|
+
Use a service account key file:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
20
30
|
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
|
|
21
31
|
```
|
|
22
32
|
|
|
33
|
+
### Option 3: Vertex AI (Recommended for Production)
|
|
34
|
+
|
|
35
|
+
Use OAuth authentication with Google Cloud Platform for enterprise deployments:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Set project ID
|
|
39
|
+
GOOGLE_CLOUD_PROJECT=your_project_id
|
|
40
|
+
|
|
41
|
+
# Optional: Set location (defaults to us-central1)
|
|
42
|
+
GOOGLE_CLOUD_LOCATION=us-central1
|
|
43
|
+
|
|
44
|
+
# Authenticate via gcloud CLI
|
|
45
|
+
gcloud auth application-default login
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or use a service account:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
|
|
52
|
+
GOOGLE_CLOUD_PROJECT=your_project_id
|
|
53
|
+
```
|
|
54
|
+
|
|
23
55
|
## Usage
|
|
24
56
|
|
|
57
|
+
### Standard Usage
|
|
58
|
+
|
|
25
59
|
```typescript
|
|
26
60
|
import { GoogleVoice } from '@mastra/voice-google';
|
|
27
61
|
|
|
@@ -50,6 +84,129 @@ const audioStream = await voice.speak('Hello from Mastra!', {
|
|
|
50
84
|
const text = await voice.listen(audioStream);
|
|
51
85
|
```
|
|
52
86
|
|
|
87
|
+
### Vertex AI Mode
|
|
88
|
+
|
|
89
|
+
For enterprise deployments, use Vertex AI mode which provides better integration with Google Cloud infrastructure:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { GoogleVoice } from '@mastra/voice-google';
|
|
93
|
+
|
|
94
|
+
// Initialize with Vertex AI
|
|
95
|
+
const voice = new GoogleVoice({
|
|
96
|
+
vertexAI: true,
|
|
97
|
+
project: 'your-gcp-project',
|
|
98
|
+
location: 'us-central1', // Optional, defaults to 'us-central1'
|
|
99
|
+
speaker: 'en-US-Studio-O',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Works the same as standard mode
|
|
103
|
+
const audioStream = await voice.speak('Hello from Vertex AI!');
|
|
104
|
+
const text = await voice.listen(audioStream);
|
|
105
|
+
|
|
106
|
+
// Check if using Vertex AI
|
|
107
|
+
console.log(voice.isUsingVertexAI()); // true
|
|
108
|
+
console.log(voice.getProject()); // 'your-gcp-project'
|
|
109
|
+
console.log(voice.getLocation()); // 'us-central1'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Vertex AI with Service Account
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { GoogleVoice } from '@mastra/voice-google';
|
|
116
|
+
|
|
117
|
+
const voice = new GoogleVoice({
|
|
118
|
+
vertexAI: true,
|
|
119
|
+
project: 'your-gcp-project',
|
|
120
|
+
location: 'us-central1',
|
|
121
|
+
speechModel: {
|
|
122
|
+
keyFilename: '/path/to/service-account.json',
|
|
123
|
+
},
|
|
124
|
+
listeningModel: {
|
|
125
|
+
keyFilename: '/path/to/service-account.json',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Vertex AI with In-Memory Credentials
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { GoogleVoice } from '@mastra/voice-google';
|
|
134
|
+
|
|
135
|
+
const voice = new GoogleVoice({
|
|
136
|
+
vertexAI: true,
|
|
137
|
+
project: 'your-gcp-project',
|
|
138
|
+
speechModel: {
|
|
139
|
+
credentials: {
|
|
140
|
+
client_email: 'service-account@project.iam.gserviceaccount.com',
|
|
141
|
+
private_key: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## API Reference
|
|
148
|
+
|
|
149
|
+
### Constructor Options
|
|
150
|
+
|
|
151
|
+
| Option | Type | Description |
|
|
152
|
+
| ---------------- | ------------------- | ------------------------------------------------ |
|
|
153
|
+
| `speechModel` | `GoogleModelConfig` | Configuration for TTS |
|
|
154
|
+
| `listeningModel` | `GoogleModelConfig` | Configuration for STT |
|
|
155
|
+
| `speaker` | `string` | Default voice ID (default: `'en-US-Casual-K'`) |
|
|
156
|
+
| `vertexAI` | `boolean` | Enable Vertex AI mode (default: `false`) |
|
|
157
|
+
| `project` | `string` | Google Cloud project ID (required for Vertex AI) |
|
|
158
|
+
| `location` | `string` | Google Cloud region (default: `'us-central1'`) |
|
|
159
|
+
|
|
160
|
+
### GoogleModelConfig
|
|
161
|
+
|
|
162
|
+
| Option | Type | Description |
|
|
163
|
+
| ------------- | -------- | ------------------------------------- |
|
|
164
|
+
| `apiKey` | `string` | Google Cloud API key |
|
|
165
|
+
| `keyFilename` | `string` | Path to service account JSON key file |
|
|
166
|
+
| `credentials` | `object` | In-memory service account credentials |
|
|
167
|
+
|
|
168
|
+
### Methods
|
|
169
|
+
|
|
170
|
+
#### `speak(input, options?)`
|
|
171
|
+
|
|
172
|
+
Converts text to speech.
|
|
173
|
+
|
|
174
|
+
- `input`: `string | NodeJS.ReadableStream` - Text to convert
|
|
175
|
+
- `options.speaker`: Override default voice
|
|
176
|
+
- `options.languageCode`: Language code (e.g., `'en-US'`)
|
|
177
|
+
- `options.audioConfig`: Audio encoding options
|
|
178
|
+
|
|
179
|
+
Returns: `Promise<NodeJS.ReadableStream>` - Audio stream
|
|
180
|
+
|
|
181
|
+
#### `listen(audioStream, options?)`
|
|
182
|
+
|
|
183
|
+
Converts speech to text.
|
|
184
|
+
|
|
185
|
+
- `audioStream`: `NodeJS.ReadableStream` - Audio to transcribe
|
|
186
|
+
- `options.config`: Recognition configuration
|
|
187
|
+
|
|
188
|
+
Returns: `Promise<string>` - Transcribed text
|
|
189
|
+
|
|
190
|
+
#### `getSpeakers(options?)`
|
|
191
|
+
|
|
192
|
+
Lists available voices.
|
|
193
|
+
|
|
194
|
+
- `options.languageCode`: Filter by language (default: `'en-US'`)
|
|
195
|
+
|
|
196
|
+
Returns: `Promise<Array<{ voiceId: string, languageCodes: string[] }>>`
|
|
197
|
+
|
|
198
|
+
#### `isUsingVertexAI()`
|
|
199
|
+
|
|
200
|
+
Returns `true` if Vertex AI mode is enabled.
|
|
201
|
+
|
|
202
|
+
#### `getProject()`
|
|
203
|
+
|
|
204
|
+
Returns the configured Google Cloud project ID.
|
|
205
|
+
|
|
206
|
+
#### `getLocation()`
|
|
207
|
+
|
|
208
|
+
Returns the configured Google Cloud location/region.
|
|
209
|
+
|
|
53
210
|
## Features
|
|
54
211
|
|
|
55
212
|
- Neural Text-to-Speech synthesis
|
|
@@ -58,6 +215,35 @@ const text = await voice.listen(audioStream);
|
|
|
58
215
|
- Streaming support for both speech and transcription
|
|
59
216
|
- High-quality audio processing
|
|
60
217
|
- Natural-sounding voice synthesis
|
|
218
|
+
- **Vertex AI support for enterprise deployments**
|
|
219
|
+
|
|
220
|
+
## Required Permissions for Vertex AI
|
|
221
|
+
|
|
222
|
+
When using Vertex AI, ensure your service account or user has the appropriate IAM roles and OAuth scopes:
|
|
223
|
+
|
|
224
|
+
### IAM Roles
|
|
225
|
+
|
|
226
|
+
**For Text-to-Speech:**
|
|
227
|
+
|
|
228
|
+
- `roles/texttospeech.admin` - Text-to-Speech Admin (full access)
|
|
229
|
+
- `roles/texttospeech.editor` - Text-to-Speech Editor (create and manage)
|
|
230
|
+
- `roles/texttospeech.viewer` - Text-to-Speech Viewer (read-only)
|
|
231
|
+
|
|
232
|
+
**For Speech-to-Text:**
|
|
233
|
+
|
|
234
|
+
- `roles/speech.client` - Speech-to-Text Client
|
|
235
|
+
|
|
236
|
+
### OAuth Scopes
|
|
237
|
+
|
|
238
|
+
**For synchronous Text-to-Speech synthesis:**
|
|
239
|
+
|
|
240
|
+
- `https://www.googleapis.com/auth/cloud-platform` - Full access to Google Cloud Platform services
|
|
241
|
+
|
|
242
|
+
**For long-audio Text-to-Speech operations:**
|
|
243
|
+
|
|
244
|
+
- `locations.longAudioSynthesize` - Create long-audio synthesis operations
|
|
245
|
+
- `operations.get` - Get operation status
|
|
246
|
+
- `operations.list` - List operations
|
|
61
247
|
|
|
62
248
|
## Voice Options
|
|
63
249
|
|
package/dist/index.cjs
CHANGED
|
@@ -6,10 +6,16 @@ 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) => {
|
|
9
|
+
var resolveAuthConfig = (modelConfig, fallback, vertexConfig) => {
|
|
10
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
|
+
}
|
|
11
17
|
const apiKey = modelConfig?.apiKey ?? fallback.apiKey;
|
|
12
|
-
if (apiKey) {
|
|
18
|
+
if (apiKey && !vertexConfig?.vertexAI) {
|
|
13
19
|
resolved.apiKey = apiKey;
|
|
14
20
|
}
|
|
15
21
|
const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;
|
|
@@ -22,44 +28,57 @@ var resolveAuthConfig = (modelConfig, fallback) => {
|
|
|
22
28
|
}
|
|
23
29
|
return resolved;
|
|
24
30
|
};
|
|
25
|
-
var buildAuthOptions = (config) => {
|
|
31
|
+
var buildAuthOptions = (config, vertexConfig) => {
|
|
32
|
+
const options = {};
|
|
26
33
|
if (config.credentials) {
|
|
27
|
-
|
|
34
|
+
options.credentials = config.credentials;
|
|
28
35
|
}
|
|
29
36
|
if (config.keyFilename) {
|
|
30
|
-
|
|
37
|
+
options.keyFilename = config.keyFilename;
|
|
31
38
|
}
|
|
32
|
-
if (config.apiKey) {
|
|
33
|
-
|
|
39
|
+
if (config.apiKey && !vertexConfig?.vertexAI) {
|
|
40
|
+
options.apiKey = config.apiKey;
|
|
34
41
|
}
|
|
35
|
-
|
|
42
|
+
if (config.projectId) {
|
|
43
|
+
options.projectId = config.projectId;
|
|
44
|
+
}
|
|
45
|
+
return options;
|
|
36
46
|
};
|
|
37
47
|
var DEFAULT_VOICE = "en-US-Casual-K";
|
|
38
48
|
var GoogleVoice = class extends voice.MastraVoice {
|
|
39
49
|
ttsClient;
|
|
40
50
|
speechClient;
|
|
51
|
+
vertexAI;
|
|
52
|
+
project;
|
|
53
|
+
location;
|
|
41
54
|
/**
|
|
42
55
|
* Creates an instance of GoogleVoice
|
|
43
|
-
* @param {
|
|
56
|
+
* @param {GoogleVoiceConfig} config - Configuration options
|
|
44
57
|
* @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
|
|
45
58
|
* @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
|
|
46
59
|
* @param {string} [config.speaker] - Default voice ID to use for speech synthesis
|
|
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')
|
|
47
63
|
*/
|
|
48
|
-
constructor({
|
|
49
|
-
listeningModel,
|
|
50
|
-
speechModel,
|
|
51
|
-
speaker
|
|
52
|
-
} = {}) {
|
|
64
|
+
constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location } = {}) {
|
|
53
65
|
const defaultApiKey = process.env.GOOGLE_API_KEY;
|
|
54
66
|
const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
55
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 };
|
|
56
76
|
const sharedFallback = {
|
|
57
77
|
apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,
|
|
58
78
|
keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,
|
|
59
|
-
credentials: speechModel?.credentials ?? listeningModel?.credentials
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback);
|
|
79
|
+
credentials: speechModel?.credentials ?? listeningModel?.credentials};
|
|
80
|
+
const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);
|
|
81
|
+
const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);
|
|
63
82
|
super({
|
|
64
83
|
speechModel: {
|
|
65
84
|
name: "",
|
|
@@ -71,11 +90,35 @@ var GoogleVoice = class extends voice.MastraVoice {
|
|
|
71
90
|
},
|
|
72
91
|
speaker: speaker ?? defaultSpeaker
|
|
73
92
|
});
|
|
74
|
-
|
|
75
|
-
|
|
93
|
+
this.vertexAI = vertexAI;
|
|
94
|
+
this.project = resolvedProject;
|
|
95
|
+
this.location = resolvedLocation;
|
|
96
|
+
const ttsOptions = buildAuthOptions(speechAuthConfig, { vertexAI});
|
|
97
|
+
const speechOptions = buildAuthOptions(listeningAuthConfig, { vertexAI});
|
|
76
98
|
this.ttsClient = new textToSpeech.TextToSpeechClient(ttsOptions);
|
|
77
99
|
this.speechClient = new speech.SpeechClient(speechOptions);
|
|
78
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;
|
|
121
|
+
}
|
|
79
122
|
/**
|
|
80
123
|
* Gets a list of available voices
|
|
81
124
|
* @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
|
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 * @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\ntype AuthConfig = Pick<GoogleModelConfig, 'apiKey' | 'keyFilename' | 'credentials'>;\n\ntype GoogleClientOptions = AuthConfig;\n\nconst resolveAuthConfig = (modelConfig: GoogleModelConfig | undefined, fallback: AuthConfig): AuthConfig => {\n const resolved: AuthConfig = {};\n\n const apiKey = modelConfig?.apiKey ?? fallback.apiKey;\n if (apiKey) {\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 = (config: AuthConfig): GoogleClientOptions => {\n if (config.credentials) {\n return { credentials: config.credentials };\n }\n\n if (config.keyFilename) {\n return { keyFilename: config.keyFilename };\n }\n\n if (config.apiKey) {\n return { apiKey: config.apiKey };\n }\n\n return {};\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 */\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 defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n const defaultSpeaker = DEFAULT_VOICE;\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 };\n\n const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback);\n const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback);\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 const ttsOptions = buildAuthOptions(speechAuthConfig);\n const speechOptions = buildAuthOptions(listeningAuthConfig);\n\n this.ttsClient = new TextToSpeechClient(ttsOptions);\n\n this.speechClient = new SpeechClient(speechOptions);\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"]}
|
|
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 '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
|
@@ -18,25 +18,102 @@ export interface GoogleModelConfig {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
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
|
+
*
|
|
22
53
|
* @class GoogleVoice
|
|
23
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
|
+
* ```
|
|
24
84
|
*/
|
|
25
85
|
export declare class GoogleVoice extends MastraVoice {
|
|
26
86
|
private ttsClient;
|
|
27
87
|
private speechClient;
|
|
88
|
+
private readonly vertexAI;
|
|
89
|
+
private readonly project?;
|
|
90
|
+
private readonly location;
|
|
28
91
|
/**
|
|
29
92
|
* Creates an instance of GoogleVoice
|
|
30
|
-
* @param {
|
|
93
|
+
* @param {GoogleVoiceConfig} config - Configuration options
|
|
31
94
|
* @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
|
|
32
95
|
* @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
|
|
33
96
|
* @param {string} [config.speaker] - Default voice ID to use for speech synthesis
|
|
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')
|
|
34
100
|
*/
|
|
35
|
-
constructor({ listeningModel, speechModel, speaker, }?:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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;
|
|
40
117
|
/**
|
|
41
118
|
* Gets a list of available voices
|
|
42
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;;;;;;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;
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,16 @@ import { TextToSpeechClient } from '@google-cloud/text-to-speech';
|
|
|
4
4
|
import { MastraVoice } from '@mastra/core/voice';
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
|
-
var resolveAuthConfig = (modelConfig, fallback) => {
|
|
7
|
+
var resolveAuthConfig = (modelConfig, fallback, vertexConfig) => {
|
|
8
8
|
const resolved = {};
|
|
9
|
+
if (vertexConfig?.vertexAI) {
|
|
10
|
+
const projectId = vertexConfig.project || process.env.GOOGLE_CLOUD_PROJECT;
|
|
11
|
+
if (projectId) {
|
|
12
|
+
resolved.projectId = projectId;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
9
15
|
const apiKey = modelConfig?.apiKey ?? fallback.apiKey;
|
|
10
|
-
if (apiKey) {
|
|
16
|
+
if (apiKey && !vertexConfig?.vertexAI) {
|
|
11
17
|
resolved.apiKey = apiKey;
|
|
12
18
|
}
|
|
13
19
|
const keyFilename = modelConfig?.keyFilename ?? fallback.keyFilename;
|
|
@@ -20,44 +26,57 @@ var resolveAuthConfig = (modelConfig, fallback) => {
|
|
|
20
26
|
}
|
|
21
27
|
return resolved;
|
|
22
28
|
};
|
|
23
|
-
var buildAuthOptions = (config) => {
|
|
29
|
+
var buildAuthOptions = (config, vertexConfig) => {
|
|
30
|
+
const options = {};
|
|
24
31
|
if (config.credentials) {
|
|
25
|
-
|
|
32
|
+
options.credentials = config.credentials;
|
|
26
33
|
}
|
|
27
34
|
if (config.keyFilename) {
|
|
28
|
-
|
|
35
|
+
options.keyFilename = config.keyFilename;
|
|
29
36
|
}
|
|
30
|
-
if (config.apiKey) {
|
|
31
|
-
|
|
37
|
+
if (config.apiKey && !vertexConfig?.vertexAI) {
|
|
38
|
+
options.apiKey = config.apiKey;
|
|
32
39
|
}
|
|
33
|
-
|
|
40
|
+
if (config.projectId) {
|
|
41
|
+
options.projectId = config.projectId;
|
|
42
|
+
}
|
|
43
|
+
return options;
|
|
34
44
|
};
|
|
35
45
|
var DEFAULT_VOICE = "en-US-Casual-K";
|
|
36
46
|
var GoogleVoice = class extends MastraVoice {
|
|
37
47
|
ttsClient;
|
|
38
48
|
speechClient;
|
|
49
|
+
vertexAI;
|
|
50
|
+
project;
|
|
51
|
+
location;
|
|
39
52
|
/**
|
|
40
53
|
* Creates an instance of GoogleVoice
|
|
41
|
-
* @param {
|
|
54
|
+
* @param {GoogleVoiceConfig} config - Configuration options
|
|
42
55
|
* @param {GoogleModelConfig} [config.speechModel] - Configuration for speech synthesis
|
|
43
56
|
* @param {GoogleModelConfig} [config.listeningModel] - Configuration for speech recognition
|
|
44
57
|
* @param {string} [config.speaker] - Default voice ID to use for speech synthesis
|
|
58
|
+
* @param {boolean} [config.vertexAI] - Enable Vertex AI mode
|
|
59
|
+
* @param {string} [config.project] - Google Cloud project ID (required for Vertex AI)
|
|
60
|
+
* @param {string} [config.location] - Google Cloud region (default: 'us-central1')
|
|
45
61
|
*/
|
|
46
|
-
constructor({
|
|
47
|
-
listeningModel,
|
|
48
|
-
speechModel,
|
|
49
|
-
speaker
|
|
50
|
-
} = {}) {
|
|
62
|
+
constructor({ listeningModel, speechModel, speaker, vertexAI = false, project, location } = {}) {
|
|
51
63
|
const defaultApiKey = process.env.GOOGLE_API_KEY;
|
|
52
64
|
const defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
53
65
|
const defaultSpeaker = DEFAULT_VOICE;
|
|
66
|
+
const resolvedProject = project || process.env.GOOGLE_CLOUD_PROJECT;
|
|
67
|
+
const resolvedLocation = location || process.env.GOOGLE_CLOUD_LOCATION || "us-central1";
|
|
68
|
+
if (vertexAI && !resolvedProject) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"Google Cloud project ID is required when using Vertex AI. Set GOOGLE_CLOUD_PROJECT environment variable or pass project to constructor."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const vertexConfig = { vertexAI, project: resolvedProject };
|
|
54
74
|
const sharedFallback = {
|
|
55
75
|
apiKey: defaultApiKey ?? speechModel?.apiKey ?? listeningModel?.apiKey,
|
|
56
76
|
keyFilename: defaultKeyFilename ?? speechModel?.keyFilename ?? listeningModel?.keyFilename,
|
|
57
|
-
credentials: speechModel?.credentials ?? listeningModel?.credentials
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback);
|
|
77
|
+
credentials: speechModel?.credentials ?? listeningModel?.credentials};
|
|
78
|
+
const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback, vertexConfig);
|
|
79
|
+
const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback, vertexConfig);
|
|
61
80
|
super({
|
|
62
81
|
speechModel: {
|
|
63
82
|
name: "",
|
|
@@ -69,11 +88,35 @@ var GoogleVoice = class extends MastraVoice {
|
|
|
69
88
|
},
|
|
70
89
|
speaker: speaker ?? defaultSpeaker
|
|
71
90
|
});
|
|
72
|
-
|
|
73
|
-
|
|
91
|
+
this.vertexAI = vertexAI;
|
|
92
|
+
this.project = resolvedProject;
|
|
93
|
+
this.location = resolvedLocation;
|
|
94
|
+
const ttsOptions = buildAuthOptions(speechAuthConfig, { vertexAI});
|
|
95
|
+
const speechOptions = buildAuthOptions(listeningAuthConfig, { vertexAI});
|
|
74
96
|
this.ttsClient = new TextToSpeechClient(ttsOptions);
|
|
75
97
|
this.speechClient = new SpeechClient(speechOptions);
|
|
76
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if Vertex AI mode is enabled
|
|
101
|
+
* @returns {boolean} True if using Vertex AI
|
|
102
|
+
*/
|
|
103
|
+
isUsingVertexAI() {
|
|
104
|
+
return this.vertexAI;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the configured Google Cloud project ID
|
|
108
|
+
* @returns {string | undefined} The project ID or undefined if not set
|
|
109
|
+
*/
|
|
110
|
+
getProject() {
|
|
111
|
+
return this.project;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get the configured Google Cloud location/region
|
|
115
|
+
* @returns {string} The location (default: 'us-central1')
|
|
116
|
+
*/
|
|
117
|
+
getLocation() {
|
|
118
|
+
return this.location;
|
|
119
|
+
}
|
|
77
120
|
/**
|
|
78
121
|
* Gets a list of available voices
|
|
79
122
|
* @returns {Promise<Array<{voiceId: string, languageCodes: string[]}>>} List of available voices and their supported languages. Default language is en-US.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","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 * @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\ntype AuthConfig = Pick<GoogleModelConfig, 'apiKey' | 'keyFilename' | 'credentials'>;\n\ntype GoogleClientOptions = AuthConfig;\n\nconst resolveAuthConfig = (modelConfig: GoogleModelConfig | undefined, fallback: AuthConfig): AuthConfig => {\n const resolved: AuthConfig = {};\n\n const apiKey = modelConfig?.apiKey ?? fallback.apiKey;\n if (apiKey) {\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 = (config: AuthConfig): GoogleClientOptions => {\n if (config.credentials) {\n return { credentials: config.credentials };\n }\n\n if (config.keyFilename) {\n return { keyFilename: config.keyFilename };\n }\n\n if (config.apiKey) {\n return { apiKey: config.apiKey };\n }\n\n return {};\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 */\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 defaultKeyFilename = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n const defaultSpeaker = DEFAULT_VOICE;\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 };\n\n const speechAuthConfig = resolveAuthConfig(speechModel, sharedFallback);\n const listeningAuthConfig = resolveAuthConfig(listeningModel, sharedFallback);\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 const ttsOptions = buildAuthOptions(speechAuthConfig);\n const speechOptions = buildAuthOptions(listeningAuthConfig);\n\n this.ttsClient = new TextToSpeechClient(ttsOptions);\n\n this.speechClient = new SpeechClient(speechOptions);\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/voice-google",
|
|
3
|
-
"version": "0.12.0-beta.
|
|
3
|
+
"version": "0.12.0-beta.1",
|
|
4
4
|
"description": "Mastra Google voice integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -28,14 +28,16 @@
|
|
|
28
28
|
"@google-cloud/text-to-speech": "^6.3.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@types/node": "
|
|
31
|
+
"@types/node": "22.13.17",
|
|
32
|
+
"@vitest/coverage-v8": "4.0.12",
|
|
33
|
+
"@vitest/ui": "4.0.12",
|
|
32
34
|
"eslint": "^9.37.0",
|
|
33
35
|
"tsup": "^8.5.0",
|
|
34
36
|
"typescript": "^5.8.3",
|
|
35
|
-
"vitest": "
|
|
37
|
+
"vitest": "4.0.12",
|
|
36
38
|
"@internal/lint": "0.0.53",
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
+
"@internal/types-builder": "0.0.28",
|
|
40
|
+
"@mastra/core": "1.0.0-beta.6"
|
|
39
41
|
},
|
|
40
42
|
"peerDependencies": {
|
|
41
43
|
"@mastra/core": ">=1.0.0-0 <2.0.0-0",
|