@loonylabs/tts-middleware 0.9.0 → 0.11.0
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/README.md +44 -17
- package/dist/middleware/services/tts/index.d.ts +4 -3
- package/dist/middleware/services/tts/index.d.ts.map +1 -1
- package/dist/middleware/services/tts/index.js +3 -3
- package/dist/middleware/services/tts/index.js.map +1 -1
- package/dist/middleware/services/tts/providers/index.d.ts +2 -1
- package/dist/middleware/services/tts/providers/index.d.ts.map +1 -1
- package/dist/middleware/services/tts/providers/index.js +3 -3
- package/dist/middleware/services/tts/providers/index.js.map +1 -1
- package/dist/middleware/services/tts/providers/vertex-ai-tts-provider.d.ts +190 -0
- package/dist/middleware/services/tts/providers/vertex-ai-tts-provider.d.ts.map +1 -0
- package/dist/middleware/services/tts/providers/vertex-ai-tts-provider.js +448 -0
- package/dist/middleware/services/tts/providers/vertex-ai-tts-provider.js.map +1 -0
- package/dist/middleware/services/tts/tts.service.js +7 -7
- package/dist/middleware/services/tts/tts.service.js.map +1 -1
- package/dist/middleware/services/tts/types/common.types.d.ts +11 -1
- package/dist/middleware/services/tts/types/common.types.d.ts.map +1 -1
- package/dist/middleware/services/tts/types/common.types.js +1 -1
- package/dist/middleware/services/tts/types/common.types.js.map +1 -1
- package/dist/middleware/services/tts/types/index.d.ts +2 -2
- package/dist/middleware/services/tts/types/index.d.ts.map +1 -1
- package/dist/middleware/services/tts/types/index.js +2 -2
- package/dist/middleware/services/tts/types/index.js.map +1 -1
- package/dist/middleware/services/tts/types/provider-options.types.d.ts +55 -8
- package/dist/middleware/services/tts/types/provider-options.types.d.ts.map +1 -1
- package/dist/middleware/services/tts/types/provider-options.types.js +4 -3
- package/dist/middleware/services/tts/types/provider-options.types.js.map +1 -1
- package/dist/middleware/services/tts/utils/retry.utils.d.ts +11 -0
- package/dist/middleware/services/tts/utils/retry.utils.d.ts.map +1 -1
- package/dist/middleware/services/tts/utils/retry.utils.js +23 -0
- package/dist/middleware/services/tts/utils/retry.utils.js.map +1 -1
- package/dist/middleware/shared/config/tts.config.d.ts +6 -6
- package/dist/middleware/shared/config/tts.config.d.ts.map +1 -1
- package/dist/middleware/shared/config/tts.config.js +8 -8
- package/dist/middleware/shared/config/tts.config.js.map +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# TTS Middleware
|
|
4
4
|
|
|
5
|
-
*Provider-agnostic Text-to-Speech middleware with **GDPR compliance** support. Currently supports Azure Speech Services, EdenAI, Google Cloud TTS, Fish Audio, Inworld AI, and
|
|
5
|
+
*Provider-agnostic Text-to-Speech middleware with **GDPR compliance** support. Currently supports Azure Speech Services, EdenAI, Google Cloud TTS, Fish Audio, Inworld AI, and Vertex AI TTS. Features EU data residency via Azure and Google Cloud, pluggable logging, character-based billing, and comprehensive error handling.*
|
|
6
6
|
|
|
7
7
|
<!-- Horizontal Badge Navigation Bar -->
|
|
8
8
|
[](https://www.npmjs.com/package/@loonylabs/tts-middleware)
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
- **Google Cloud TTS**: Neural2, WaveNet, Studio voices with EU data residency
|
|
44
44
|
- **Fish Audio**: S1 model with 13 languages & 64+ emotions (test/admin only)
|
|
45
45
|
- **Inworld AI**: TTS 1.5 Max/Mini with 15 languages & voice cloning (test/admin only)
|
|
46
|
-
- **
|
|
46
|
+
- **Vertex AI TTS**: Gemini Flash/Pro models with 30 voices, 90+ languages & style prompts (test/admin only)
|
|
47
47
|
- **Ready for:** OpenAI, ElevenLabs, Deepgram (interfaces prepared)
|
|
48
48
|
- **GDPR/DSGVO Compliance**: Built-in EU region support for Azure and Google Cloud
|
|
49
49
|
- **SSML Abstraction**: Auto-generates provider-specific SSML from simple JSON options
|
|
@@ -139,10 +139,10 @@ const inworld = await ttsService.synthesize({
|
|
|
139
139
|
providerOptions: { modelId: 'inworld-tts-1.5-max', temperature: 1.1 },
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
//
|
|
143
|
-
const
|
|
142
|
+
// Vertex AI TTS (test/admin only)
|
|
143
|
+
const vertexAI = await ttsService.synthesize({
|
|
144
144
|
text: 'Have a wonderful day!',
|
|
145
|
-
provider: TTSProvider.
|
|
145
|
+
provider: TTSProvider.VERTEX_AI,
|
|
146
146
|
voice: { id: 'Kore' },
|
|
147
147
|
providerOptions: { model: 'gemini-2.5-flash-preview-tts', stylePrompt: 'Say cheerfully:' },
|
|
148
148
|
});
|
|
@@ -220,6 +220,30 @@ const response = await ttsService.synthesize({
|
|
|
220
220
|
|
|
221
221
|
</details>
|
|
222
222
|
|
|
223
|
+
<details>
|
|
224
|
+
<summary><strong>ffmpeg (for Vertex AI TTS MP3 output)</strong></summary>
|
|
225
|
+
|
|
226
|
+
The Vertex AI TTS provider outputs raw PCM audio which is converted to MP3 using ffmpeg.
|
|
227
|
+
The provider resolves the ffmpeg binary automatically using this priority chain:
|
|
228
|
+
|
|
229
|
+
| Priority | Source | Example |
|
|
230
|
+
|----------|--------|---------|
|
|
231
|
+
| 1 | `ffmpegPath` in config | `new VertexAITTSProvider({ ffmpegPath: '/usr/bin/ffmpeg' })` |
|
|
232
|
+
| 2 | `FFMPEG_PATH` env var | `FFMPEG_PATH=/opt/ffmpeg/bin/ffmpeg` |
|
|
233
|
+
| 3 | `ffmpeg-static` npm package | `npm install ffmpeg-static` (recommended for containers) |
|
|
234
|
+
| 4 | System `ffmpeg` in PATH | `apt install ffmpeg` or `brew install ffmpeg` |
|
|
235
|
+
| 5 | WAV fallback | No ffmpeg needed — outputs WAV instead of MP3 |
|
|
236
|
+
|
|
237
|
+
**Recommended for containerized deployments** (Railway, Docker, etc.):
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
npm install ffmpeg-static
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
This bundles a static ffmpeg binary with your app — no system package needed.
|
|
244
|
+
|
|
245
|
+
</details>
|
|
246
|
+
|
|
223
247
|
## Configuration
|
|
224
248
|
|
|
225
249
|
<details>
|
|
@@ -249,9 +273,9 @@ FISH_AUDIO_API_KEY=your-fish-audio-api-key
|
|
|
249
273
|
# Inworld AI (test/admin only – no EU data residency)
|
|
250
274
|
INWORLD_API_KEY=your-inworld-api-key
|
|
251
275
|
|
|
252
|
-
#
|
|
276
|
+
# Vertex AI TTS (test/admin only – no EU data residency)
|
|
253
277
|
# Reuses GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_CLOUD_PROJECT from above
|
|
254
|
-
|
|
278
|
+
VERTEX_AI_TTS_REGION=us-central1
|
|
255
279
|
|
|
256
280
|
# Logging
|
|
257
281
|
TTS_DEBUG=false
|
|
@@ -317,18 +341,19 @@ LOG_LEVEL=info
|
|
|
317
341
|
| **Pricing** | $10/1M chars (Max), $5/1M chars (Mini) |
|
|
318
342
|
| **EU Compliance** | No data residency guarantees |
|
|
319
343
|
|
|
320
|
-
###
|
|
344
|
+
### Vertex AI TTS (Test/Admin Only)
|
|
321
345
|
|
|
322
346
|
| Feature | Details |
|
|
323
347
|
|---------|---------|
|
|
324
|
-
| **Models** |
|
|
348
|
+
| **Models** | `gemini-2.5-flash-preview-tts` (budget, fast), `gemini-2.5-pro-preview-tts` (premium, natural) |
|
|
325
349
|
| **Languages** | 90+ with auto-detection |
|
|
326
350
|
| **Voices** | 30 multilingual: Kore, Puck, Charon, Zephyr, Fenrir, Sulafat, etc. |
|
|
327
351
|
| **Style Control** | Natural language prompts: "Say cheerfully:", "Read in a spooky whisper:" |
|
|
328
|
-
| **Audio** | MP3 (via ffmpeg), WAV (fallback) |
|
|
329
|
-
| **Auth** |
|
|
352
|
+
| **Audio** | MP3 (via ffmpeg — auto-detected from `ffmpeg-static`, `FFMPEG_PATH`, config, or system PATH), WAV (fallback) |
|
|
353
|
+
| **Auth** | Service Account OAuth2 (reuses `GOOGLE_APPLICATION_CREDENTIALS`) |
|
|
354
|
+
| **Region** | `VERTEX_AI_TTS_REGION` env var (default: `us-central1`) |
|
|
330
355
|
| **Pricing** | $0.50-1.00/M input tokens + $10-20/M audio output tokens |
|
|
331
|
-
| **EU Compliance** |
|
|
356
|
+
| **EU Compliance** | Preview models currently `us-central1` only — no EU data residency yet |
|
|
332
357
|
|
|
333
358
|
## GDPR / Compliance
|
|
334
359
|
|
|
@@ -341,10 +366,12 @@ LOG_LEVEL=info
|
|
|
341
366
|
| **EdenAI** | Yes | Depends* | Depends* | Depends on underlying provider |
|
|
342
367
|
| **Fish Audio** | No | No | No | Test/admin only |
|
|
343
368
|
| **Inworld AI** | No | No | No | Test/admin only |
|
|
344
|
-
| **
|
|
369
|
+
| **Vertex AI TTS** | Yes (Vertex DPA) | Partial | No* | Test/admin only |
|
|
345
370
|
|
|
346
371
|
*EdenAI is an aggregator - compliance depends on the underlying provider.
|
|
347
372
|
|
|
373
|
+
\*Vertex AI TTS: DPA available, no model training on customer data — but preview models are currently `us-central1` only (no EU data residency until GA with EU region support).
|
|
374
|
+
|
|
348
375
|
## API Reference
|
|
349
376
|
|
|
350
377
|
### TTSService
|
|
@@ -530,14 +557,14 @@ graph TD
|
|
|
530
557
|
Registry -->|Select| Eden[EdenAIProvider]
|
|
531
558
|
Registry -->|Select| Fish[FishAudioProvider]
|
|
532
559
|
Registry -->|Select| Inworld[InworldProvider]
|
|
533
|
-
Registry -->|Select|
|
|
560
|
+
Registry -->|Select| VertexAI[VertexAITTSProvider]
|
|
534
561
|
|
|
535
562
|
Azure -->|SSML/SDK| AzureAPI[Azure Speech API]
|
|
536
563
|
GCloud -->|gRPC/SDK| GoogleAPI[Google Cloud TTS API]
|
|
537
564
|
Eden -->|REST| EdenAPI[EdenAI API]
|
|
538
565
|
Fish -->|REST| FishAPI[Fish Audio API]
|
|
539
566
|
Inworld -->|REST| InworldAPI[Inworld AI API]
|
|
540
|
-
|
|
567
|
+
VertexAI -->|REST/OAuth2| VertexAPI[Vertex AI API]
|
|
541
568
|
|
|
542
569
|
GoogleAPI -->|EU Endpoint| EU[eu-texttospeech.googleapis.com]
|
|
543
570
|
EdenAPI -.-> OpenAI[OpenAI TTS]
|
|
@@ -547,7 +574,7 @@ graph TD
|
|
|
547
574
|
## Testing
|
|
548
575
|
|
|
549
576
|
```bash
|
|
550
|
-
# Run all tests (
|
|
577
|
+
# Run all tests (600+ tests, >90% coverage)
|
|
551
578
|
npm test
|
|
552
579
|
|
|
553
580
|
# Unit tests only
|
|
@@ -564,7 +591,7 @@ npx ts-node scripts/manual-test-edenai.ts
|
|
|
564
591
|
npx ts-node scripts/manual-test-google-cloud-tts.ts
|
|
565
592
|
npx ts-node scripts/manual-test-fish-audio.ts [en] [de]
|
|
566
593
|
npx ts-node scripts/manual-test-inworld.ts [en] [de] [mini]
|
|
567
|
-
npx ts-node scripts/manual-test-
|
|
594
|
+
npx ts-node scripts/manual-test-vertex-ai.ts [en] [de] [pro] [style]
|
|
568
595
|
|
|
569
596
|
# List available Google Cloud voices
|
|
570
597
|
npx ts-node scripts/list-google-voices.ts de-DE
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
*/
|
|
21
21
|
export { TTSService, ttsService } from './tts.service';
|
|
22
22
|
export { TTSProvider, TTSErrorCode, AudioFormat, } from './types';
|
|
23
|
-
export type { AudioOptions, VoiceConfig, TTSSynthesizeRequest, TTSResponse, TTSResponseMetadata, TTSBillingInfo, TTSVoice, TTSVoiceMetadata, AzureProviderOptions, OpenAIProviderOptions, ElevenLabsProviderOptions, GoogleCloudProviderOptions, GoogleCloudTTSProviderOptions, DeepgramProviderOptions, EdenAIProviderOptions, FishAudioProviderOptions, InworldProviderOptions,
|
|
24
|
-
export { isAzureOptions, isOpenAIOptions, isElevenLabsOptions, isGoogleCloudOptions, isGoogleCloudTTSOptions, isDeepgramOptions, isEdenAIOptions, isFishAudioOptions, isInworldOptions,
|
|
25
|
-
export { BaseTTSProvider, AzureProvider, EdenAIProvider, FishAudioProvider, GoogleCloudTTSProvider, InworldProvider,
|
|
23
|
+
export type { AudioOptions, VoiceConfig, TTSSynthesizeRequest, TTSResponse, TTSResponseMetadata, TTSBillingInfo, TTSVoice, TTSVoiceMetadata, AzureProviderOptions, OpenAIProviderOptions, ElevenLabsProviderOptions, GoogleCloudProviderOptions, GoogleCloudTTSProviderOptions, DeepgramProviderOptions, EdenAIProviderOptions, FishAudioProviderOptions, InworldProviderOptions, VertexAITTSProviderOptions, ProviderOptions, } from './types';
|
|
24
|
+
export { isAzureOptions, isOpenAIOptions, isElevenLabsOptions, isGoogleCloudOptions, isGoogleCloudTTSOptions, isDeepgramOptions, isEdenAIOptions, isFishAudioOptions, isInworldOptions, isVertexAITTSOptions, } from './types';
|
|
25
|
+
export { BaseTTSProvider, AzureProvider, EdenAIProvider, FishAudioProvider, GoogleCloudTTSProvider, InworldProvider, VertexAITTSProvider, } from './providers';
|
|
26
|
+
export type { VertexAITTSConfig } from './providers';
|
|
26
27
|
export type { GoogleCloudTTSRegion, GoogleCloudTTSConfig, } from './providers';
|
|
27
28
|
export { TTSError, InvalidConfigError, InvalidVoiceError, QuotaExceededError, ProviderUnavailableError, SynthesisFailedError, NetworkError, } from './providers';
|
|
28
29
|
export { countCharacters, countCharactersWithoutSSML, validateCharacterCount, countBillableCharacters, estimateAudioDuration, formatCharacterCount, } from './utils';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/middleware/services/tts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/middleware/services/tts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,YAAY,EACV,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* @module @loonylabs/tts-middleware
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.DEFAULT_RETRY_CONFIG = exports.isRetryableError = exports.executeWithRetry = exports.silentLogger = exports.getLogLevel = exports.setLogLevel = exports.resetLogger = exports.getLogger = exports.setLogger = exports.formatCharacterCount = exports.estimateAudioDuration = exports.countBillableCharacters = exports.validateCharacterCount = exports.countCharactersWithoutSSML = exports.countCharacters = exports.NetworkError = exports.SynthesisFailedError = exports.ProviderUnavailableError = exports.QuotaExceededError = exports.InvalidVoiceError = exports.InvalidConfigError = exports.TTSError = exports.
|
|
23
|
+
exports.DEFAULT_RETRY_CONFIG = exports.isRetryableError = exports.executeWithRetry = exports.silentLogger = exports.getLogLevel = exports.setLogLevel = exports.resetLogger = exports.getLogger = exports.setLogger = exports.formatCharacterCount = exports.estimateAudioDuration = exports.countBillableCharacters = exports.validateCharacterCount = exports.countCharactersWithoutSSML = exports.countCharacters = exports.NetworkError = exports.SynthesisFailedError = exports.ProviderUnavailableError = exports.QuotaExceededError = exports.InvalidVoiceError = exports.InvalidConfigError = exports.TTSError = exports.VertexAITTSProvider = exports.InworldProvider = exports.GoogleCloudTTSProvider = exports.FishAudioProvider = exports.EdenAIProvider = exports.AzureProvider = exports.BaseTTSProvider = exports.isVertexAITTSOptions = exports.isInworldOptions = exports.isFishAudioOptions = exports.isEdenAIOptions = exports.isDeepgramOptions = exports.isGoogleCloudTTSOptions = exports.isGoogleCloudOptions = exports.isElevenLabsOptions = exports.isOpenAIOptions = exports.isAzureOptions = exports.TTSErrorCode = exports.TTSProvider = exports.ttsService = exports.TTSService = void 0;
|
|
24
24
|
// ===== Main Service =====
|
|
25
25
|
var tts_service_1 = require("./tts.service");
|
|
26
26
|
Object.defineProperty(exports, "TTSService", { enumerable: true, get: function () { return tts_service_1.TTSService; } });
|
|
@@ -39,7 +39,7 @@ Object.defineProperty(exports, "isDeepgramOptions", { enumerable: true, get: fun
|
|
|
39
39
|
Object.defineProperty(exports, "isEdenAIOptions", { enumerable: true, get: function () { return types_2.isEdenAIOptions; } });
|
|
40
40
|
Object.defineProperty(exports, "isFishAudioOptions", { enumerable: true, get: function () { return types_2.isFishAudioOptions; } });
|
|
41
41
|
Object.defineProperty(exports, "isInworldOptions", { enumerable: true, get: function () { return types_2.isInworldOptions; } });
|
|
42
|
-
Object.defineProperty(exports, "
|
|
42
|
+
Object.defineProperty(exports, "isVertexAITTSOptions", { enumerable: true, get: function () { return types_2.isVertexAITTSOptions; } });
|
|
43
43
|
// ===== Providers =====
|
|
44
44
|
var providers_1 = require("./providers");
|
|
45
45
|
Object.defineProperty(exports, "BaseTTSProvider", { enumerable: true, get: function () { return providers_1.BaseTTSProvider; } });
|
|
@@ -48,7 +48,7 @@ Object.defineProperty(exports, "EdenAIProvider", { enumerable: true, get: functi
|
|
|
48
48
|
Object.defineProperty(exports, "FishAudioProvider", { enumerable: true, get: function () { return providers_1.FishAudioProvider; } });
|
|
49
49
|
Object.defineProperty(exports, "GoogleCloudTTSProvider", { enumerable: true, get: function () { return providers_1.GoogleCloudTTSProvider; } });
|
|
50
50
|
Object.defineProperty(exports, "InworldProvider", { enumerable: true, get: function () { return providers_1.InworldProvider; } });
|
|
51
|
-
Object.defineProperty(exports, "
|
|
51
|
+
Object.defineProperty(exports, "VertexAITTSProvider", { enumerable: true, get: function () { return providers_1.VertexAITTSProvider; } });
|
|
52
52
|
// ===== Errors =====
|
|
53
53
|
var providers_2 = require("./providers");
|
|
54
54
|
Object.defineProperty(exports, "TTSError", { enumerable: true, get: function () { return providers_2.TTSError; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/middleware/services/tts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAEH,2BAA2B;AAC3B,6CAAuD;AAA9C,yGAAA,UAAU,OAAA;AAAE,yGAAA,UAAU,OAAA;AAE/B,oBAAoB;AACpB,iCAIiB;AAHf,oGAAA,WAAW,OAAA;AACX,qGAAA,YAAY,OAAA;AA0Bd,iCAWiB;AAVf,uGAAA,cAAc,OAAA;AACd,wGAAA,eAAe,OAAA;AACf,4GAAA,mBAAmB,OAAA;AACnB,6GAAA,oBAAoB,OAAA;AACpB,gHAAA,uBAAuB,OAAA;AACvB,0GAAA,iBAAiB,OAAA;AACjB,wGAAA,eAAe,OAAA;AACf,2GAAA,kBAAkB,OAAA;AAClB,yGAAA,gBAAgB,OAAA;AAChB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/middleware/services/tts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAEH,2BAA2B;AAC3B,6CAAuD;AAA9C,yGAAA,UAAU,OAAA;AAAE,yGAAA,UAAU,OAAA;AAE/B,oBAAoB;AACpB,iCAIiB;AAHf,oGAAA,WAAW,OAAA;AACX,qGAAA,YAAY,OAAA;AA0Bd,iCAWiB;AAVf,uGAAA,cAAc,OAAA;AACd,wGAAA,eAAe,OAAA;AACf,4GAAA,mBAAmB,OAAA;AACnB,6GAAA,oBAAoB,OAAA;AACpB,gHAAA,uBAAuB,OAAA;AACvB,0GAAA,iBAAiB,OAAA;AACjB,wGAAA,eAAe,OAAA;AACf,2GAAA,kBAAkB,OAAA;AAClB,yGAAA,gBAAgB,OAAA;AAChB,6GAAA,oBAAoB,OAAA;AAGtB,wBAAwB;AACxB,yCAQqB;AAPnB,4GAAA,eAAe,OAAA;AACf,0GAAA,aAAa,OAAA;AACb,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,mHAAA,sBAAsB,OAAA;AACtB,4GAAA,eAAe,OAAA;AACf,gHAAA,mBAAmB,OAAA;AAUrB,qBAAqB;AACrB,yCAQqB;AAPnB,qGAAA,QAAQ,OAAA;AACR,+GAAA,kBAAkB,OAAA;AAClB,8GAAA,iBAAiB,OAAA;AACjB,+GAAA,kBAAkB,OAAA;AAClB,qHAAA,wBAAwB,OAAA;AACxB,iHAAA,oBAAoB,OAAA;AACpB,yGAAA,YAAY,OAAA;AAGd,wBAAwB;AACxB,iCAOiB;AANf,wGAAA,eAAe,OAAA;AACf,mHAAA,0BAA0B,OAAA;AAC1B,+GAAA,sBAAsB,OAAA;AACtB,gHAAA,uBAAuB,OAAA;AACvB,8GAAA,qBAAqB,OAAA;AACrB,6GAAA,oBAAoB,OAAA;AAGtB,qBAAqB;AACrB,iCAOiB;AANf,kGAAA,SAAS,OAAA;AACT,kGAAA,SAAS,OAAA;AACT,oGAAA,WAAW,OAAA;AACX,oGAAA,WAAW,OAAA;AACX,oGAAA,WAAW,OAAA;AACX,qGAAA,YAAY,OAAA;AAKd,oBAAoB;AACpB,iCAIiB;AAHf,yGAAA,gBAAgB,OAAA;AAChB,yGAAA,gBAAgB,OAAA;AAChB,6GAAA,oBAAoB,OAAA"}
|
|
@@ -10,5 +10,6 @@ export { GoogleCloudTTSProvider } from './google-cloud-tts-provider';
|
|
|
10
10
|
export type { GoogleCloudTTSRegion, GoogleCloudTTSConfig } from './google-cloud-tts-provider';
|
|
11
11
|
export { FishAudioProvider } from './fish-audio-provider';
|
|
12
12
|
export { InworldProvider } from './inworld-provider';
|
|
13
|
-
export {
|
|
13
|
+
export { VertexAITTSProvider } from './vertex-ai-tts-provider';
|
|
14
|
+
export type { VertexAITTSConfig } from './vertex-ai-tts-provider';
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/middleware/services/tts/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/middleware/services/tts/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Export all provider classes and error types
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
8
|
+
exports.VertexAITTSProvider = exports.InworldProvider = exports.FishAudioProvider = exports.GoogleCloudTTSProvider = exports.EdenAIProvider = exports.AzureProvider = exports.NetworkError = exports.SynthesisFailedError = exports.ProviderUnavailableError = exports.QuotaExceededError = exports.InvalidVoiceError = exports.InvalidConfigError = exports.TTSError = exports.BaseTTSProvider = void 0;
|
|
9
9
|
// Base provider and errors
|
|
10
10
|
var base_tts_provider_1 = require("./base-tts-provider");
|
|
11
11
|
Object.defineProperty(exports, "BaseTTSProvider", { enumerable: true, get: function () { return base_tts_provider_1.BaseTTSProvider; } });
|
|
@@ -27,8 +27,8 @@ var fish_audio_provider_1 = require("./fish-audio-provider");
|
|
|
27
27
|
Object.defineProperty(exports, "FishAudioProvider", { enumerable: true, get: function () { return fish_audio_provider_1.FishAudioProvider; } });
|
|
28
28
|
var inworld_provider_1 = require("./inworld-provider");
|
|
29
29
|
Object.defineProperty(exports, "InworldProvider", { enumerable: true, get: function () { return inworld_provider_1.InworldProvider; } });
|
|
30
|
-
var
|
|
31
|
-
Object.defineProperty(exports, "
|
|
30
|
+
var vertex_ai_tts_provider_1 = require("./vertex-ai-tts-provider");
|
|
31
|
+
Object.defineProperty(exports, "VertexAITTSProvider", { enumerable: true, get: function () { return vertex_ai_tts_provider_1.VertexAITTSProvider; } });
|
|
32
32
|
// Future provider implementations will be exported here:
|
|
33
33
|
// export { OpenAIProvider } from './openai-provider';
|
|
34
34
|
// export { ElevenLabsProvider } from './elevenlabs-provider';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/middleware/services/tts/providers/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,2BAA2B;AAC3B,yDAS6B;AAR3B,oHAAA,eAAe,OAAA;AACf,6GAAA,QAAQ,OAAA;AACR,uHAAA,kBAAkB,OAAA;AAClB,sHAAA,iBAAiB,OAAA;AACjB,uHAAA,kBAAkB,OAAA;AAClB,6HAAA,wBAAwB,OAAA;AACxB,yHAAA,oBAAoB,OAAA;AACpB,iHAAA,YAAY,OAAA;AAGd,2BAA2B;AAC3B,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,yEAAqE;AAA5D,mIAAA,sBAAsB,OAAA;AAE/B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AACxB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/middleware/services/tts/providers/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,2BAA2B;AAC3B,yDAS6B;AAR3B,oHAAA,eAAe,OAAA;AACf,6GAAA,QAAQ,OAAA;AACR,uHAAA,kBAAkB,OAAA;AAClB,sHAAA,iBAAiB,OAAA;AACjB,uHAAA,kBAAkB,OAAA;AAClB,6HAAA,wBAAwB,OAAA;AACxB,yHAAA,oBAAoB,OAAA;AACpB,iHAAA,YAAY,OAAA;AAGd,2BAA2B;AAC3B,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,yEAAqE;AAA5D,mIAAA,sBAAsB,OAAA;AAE/B,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AACxB,mEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAG5B,yDAAyD;AACzD,sDAAsD;AACtD,8DAA8D;AAC9D,0DAA0D"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertex AI TTS Provider
|
|
3
|
+
*
|
|
4
|
+
* @description Provider for Google Vertex AI TTS via the generateContent
|
|
5
|
+
* endpoint with responseModalities: ['AUDIO']. Authenticates via Service Account
|
|
6
|
+
* (same as Google Cloud TTS — reuses GOOGLE_APPLICATION_CREDENTIALS).
|
|
7
|
+
*
|
|
8
|
+
* Supports 30 multilingual voices with auto-detect language and natural language
|
|
9
|
+
* style control. Output is raw PCM (24kHz, 16-bit, mono) which is converted to
|
|
10
|
+
* MP3 via ffmpeg (auto-detected from ffmpeg-static, FFMPEG_PATH, config, or system PATH)
|
|
11
|
+
* or WAV as fallback.
|
|
12
|
+
*
|
|
13
|
+
* Test/Admin only -- no EU data residency guarantees.
|
|
14
|
+
*
|
|
15
|
+
* @see https://cloud.google.com/vertex-ai/generative-ai/docs/text-to-speech
|
|
16
|
+
*/
|
|
17
|
+
import type { TTSSynthesizeRequest, TTSResponse } from '../types';
|
|
18
|
+
import { BaseTTSProvider } from './base-tts-provider';
|
|
19
|
+
import type { RegionRotationConfig } from '../types/provider-options.types';
|
|
20
|
+
/**
|
|
21
|
+
* Vertex AI TTS configuration
|
|
22
|
+
*/
|
|
23
|
+
export interface VertexAITTSConfig {
|
|
24
|
+
/**
|
|
25
|
+
* Path to Service Account JSON file
|
|
26
|
+
* @env GOOGLE_APPLICATION_CREDENTIALS
|
|
27
|
+
*/
|
|
28
|
+
keyFilename?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Google Cloud Project ID
|
|
31
|
+
* @env GOOGLE_CLOUD_PROJECT
|
|
32
|
+
*/
|
|
33
|
+
projectId?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Vertex AI region
|
|
36
|
+
* @env VERTEX_AI_TTS_REGION
|
|
37
|
+
* @default 'us-central1'
|
|
38
|
+
*/
|
|
39
|
+
region?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Path to ffmpeg binary for PCM-to-MP3 conversion.
|
|
42
|
+
*
|
|
43
|
+
* Resolution order (first match wins):
|
|
44
|
+
* 1. This config value
|
|
45
|
+
* 2. `FFMPEG_PATH` environment variable
|
|
46
|
+
* 3. `ffmpeg-static` npm package (if installed)
|
|
47
|
+
* 4. System `ffmpeg` in PATH
|
|
48
|
+
*
|
|
49
|
+
* If ffmpeg is not available, the provider falls back to WAV output.
|
|
50
|
+
*/
|
|
51
|
+
ffmpegPath?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Optional region rotation for quota management (429 / Resource Exhausted)
|
|
54
|
+
*
|
|
55
|
+
* @description When configured, the provider automatically rotates through the
|
|
56
|
+
* specified regions on quota errors. Same pattern as llm-middleware and tti-middleware.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* {
|
|
61
|
+
* regions: ['europe-west4', 'europe-west1'],
|
|
62
|
+
* fallback: 'us-central1',
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
regionRotation?: RegionRotationConfig;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Vertex AI TTS provider implementation
|
|
70
|
+
*
|
|
71
|
+
* @description Provides TTS synthesis using Google's Vertex AI generateContent API.
|
|
72
|
+
* Authenticates with Service Account OAuth2 (same credentials as Google Cloud TTS).
|
|
73
|
+
* Outputs raw PCM which is converted to MP3 (via ffmpeg) or WAV (pure Node.js fallback).
|
|
74
|
+
*
|
|
75
|
+
* Billing: Token-based ($0.50-1.00/M input + $10-20/M audio output tokens).
|
|
76
|
+
* For billing compatibility, reports character count like all other providers.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const provider = new VertexAITTSProvider();
|
|
81
|
+
* const response = await provider.synthesize(
|
|
82
|
+
* "Hello World",
|
|
83
|
+
* "Kore",
|
|
84
|
+
* {
|
|
85
|
+
* text: "Hello World",
|
|
86
|
+
* voice: { id: "Kore" },
|
|
87
|
+
* audio: { format: "mp3" },
|
|
88
|
+
* providerOptions: {
|
|
89
|
+
* model: "gemini-2.5-flash-preview-tts",
|
|
90
|
+
* stylePrompt: "Say cheerfully:"
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare class VertexAITTSProvider extends BaseTTSProvider {
|
|
97
|
+
private config;
|
|
98
|
+
private authClient;
|
|
99
|
+
private readonly ffmpegPath;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a new Vertex AI TTS provider
|
|
102
|
+
*
|
|
103
|
+
* @param config - Optional configuration (uses env vars if not provided)
|
|
104
|
+
* @throws {InvalidConfigError} If credentials are missing
|
|
105
|
+
*/
|
|
106
|
+
constructor(config?: Partial<VertexAITTSConfig>);
|
|
107
|
+
/**
|
|
108
|
+
* Validate Vertex AI configuration
|
|
109
|
+
*
|
|
110
|
+
* @private
|
|
111
|
+
* @throws {InvalidConfigError} If configuration is invalid
|
|
112
|
+
*/
|
|
113
|
+
private validateVertexAIConfig;
|
|
114
|
+
/**
|
|
115
|
+
* Get an authenticated access token via Service Account
|
|
116
|
+
*
|
|
117
|
+
* @private
|
|
118
|
+
* @returns OAuth2 access token
|
|
119
|
+
*/
|
|
120
|
+
private getAccessToken;
|
|
121
|
+
/**
|
|
122
|
+
* Synthesize text to speech using Vertex AI TTS
|
|
123
|
+
*
|
|
124
|
+
* @param text - The input text to synthesize
|
|
125
|
+
* @param voiceId - The voice name (e.g. "Kore", "Puck", "Charon")
|
|
126
|
+
* @param request - The full synthesis request with options
|
|
127
|
+
* @returns Promise resolving to the synthesis response
|
|
128
|
+
*/
|
|
129
|
+
synthesize(text: string, voiceId: string, request: TTSSynthesizeRequest): Promise<TTSResponse>;
|
|
130
|
+
/**
|
|
131
|
+
* Build Vertex AI generateContent request payload
|
|
132
|
+
*
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
private buildRequest;
|
|
136
|
+
/**
|
|
137
|
+
* Call the Vertex AI API with optional region rotation on quota errors
|
|
138
|
+
*
|
|
139
|
+
* @private
|
|
140
|
+
* @param requestBody - The request payload
|
|
141
|
+
* @param model - The model to use
|
|
142
|
+
* @param regionOverride - Optional per-request region override (skips rotation)
|
|
143
|
+
* @returns The PCM audio buffer and the region that processed the request
|
|
144
|
+
*/
|
|
145
|
+
private callAPIWithRegionRotation;
|
|
146
|
+
/**
|
|
147
|
+
* Call Vertex AI generateContent API
|
|
148
|
+
*
|
|
149
|
+
* @private
|
|
150
|
+
* @param requestBody - The request payload
|
|
151
|
+
* @param model - The model to use
|
|
152
|
+
* @param region - The Vertex AI region to use
|
|
153
|
+
* @returns Promise resolving to raw PCM audio buffer
|
|
154
|
+
*/
|
|
155
|
+
private callAPI;
|
|
156
|
+
/**
|
|
157
|
+
* Resolve ffmpeg binary path with fallback chain:
|
|
158
|
+
* 1. Explicit config value
|
|
159
|
+
* 2. FFMPEG_PATH environment variable
|
|
160
|
+
* 3. ffmpeg-static npm package (optional peer dependency)
|
|
161
|
+
* 4. System ffmpeg in PATH
|
|
162
|
+
*/
|
|
163
|
+
private resolveFfmpegPath;
|
|
164
|
+
/**
|
|
165
|
+
* Convert raw PCM audio to the requested format
|
|
166
|
+
*
|
|
167
|
+
* @private
|
|
168
|
+
* @param pcmBuffer - Raw PCM buffer (24kHz, 16-bit, mono, little-endian)
|
|
169
|
+
* @param requestedFormat - The desired output format ('mp3', 'wav', etc.)
|
|
170
|
+
* @returns The converted audio buffer and actual format used
|
|
171
|
+
*/
|
|
172
|
+
private convertPcmAudio;
|
|
173
|
+
/**
|
|
174
|
+
* Convert raw PCM to MP3 using ffmpeg via child_process
|
|
175
|
+
*
|
|
176
|
+
* @private
|
|
177
|
+
* @param pcmBuffer - Raw PCM buffer (24kHz, 16-bit, mono, little-endian)
|
|
178
|
+
* @returns Promise resolving to MP3 buffer
|
|
179
|
+
*/
|
|
180
|
+
private pcmToMp3;
|
|
181
|
+
/**
|
|
182
|
+
* Convert raw PCM to WAV by prepending a 44-byte WAV header
|
|
183
|
+
*
|
|
184
|
+
* @private
|
|
185
|
+
* @param pcmBuffer - Raw PCM buffer (24kHz, 16-bit, mono, little-endian)
|
|
186
|
+
* @returns WAV buffer
|
|
187
|
+
*/
|
|
188
|
+
private pcmToWav;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=vertex-ai-tts-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vertex-ai-tts-provider.d.ts","sourceRoot":"","sources":["../../../../../src/middleware/services/tts/providers/vertex-ai-tts-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,EACL,eAAe,EAEhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAA8B,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAGxG;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;IACtD,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAA6E;IAC/F,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC;;;;;OAKG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAsB/C;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;;;;OAKG;YACW,cAAc;IAqB5B;;;;;;;OAOG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,WAAW,CAAC;IA4DvB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IA6BpB;;;;;;;;OAQG;YACW,yBAAyB;IAsDvC;;;;;;;;OAQG;YACW,OAAO;IA6CrB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;;;OAOG;YACW,eAAe;IA0B7B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAkChB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;CAwBjB"}
|