@mastra/voice-playai 0.11.12 → 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.
@@ -0,0 +1,460 @@
1
+ # Voice API Reference
2
+
3
+ > API reference for voice - 4 entries
4
+
5
+
6
+ ---
7
+
8
+ ## Reference: CompositeVoice
9
+
10
+ > Documentation for the CompositeVoice class, which enables combining multiple voice providers for flexible text-to-speech and speech-to-text operations.
11
+
12
+ The CompositeVoice class allows you to combine different voice providers for text-to-speech and speech-to-text operations. This is particularly useful when you want to use the best provider for each operation - for example, using OpenAI for speech-to-text and PlayAI for text-to-speech.
13
+
14
+ CompositeVoice supports both Mastra voice providers and AI SDK model providers
15
+
16
+ ## Constructor Parameters
17
+
18
+ ## Methods
19
+
20
+ ### speak()
21
+
22
+ Converts text to speech using the configured speaking provider.
23
+
24
+ Notes:
25
+
26
+ - If no speaking provider is configured, this method will throw an error
27
+ - Options are passed through to the configured speaking provider
28
+ - Returns a stream of audio data
29
+
30
+ ### listen()
31
+
32
+ Converts speech to text using the configured listening provider.
33
+
34
+ Notes:
35
+
36
+ - If no listening provider is configured, this method will throw an error
37
+ - Options are passed through to the configured listening provider
38
+ - Returns either a string or a stream of transcribed text, depending on the provider
39
+
40
+ ### getSpeakers()
41
+
42
+ Returns a list of available voices from the speaking provider, where each node contains:
43
+
44
+ Notes:
45
+
46
+ - Returns voices from the speaking provider only
47
+ - If no speaking provider is configured, returns an empty array
48
+ - Each voice object will have at least a voiceId property
49
+ - Additional voice properties depend on the speaking provider
50
+
51
+ ## Usage Examples
52
+
53
+ ### Using Mastra Voice Providers
54
+
55
+ ```typescript
56
+ import { CompositeVoice } from "@mastra/core/voice";
57
+ import { OpenAIVoice } from "@mastra/voice-openai";
58
+ import { PlayAIVoice } from "@mastra/voice-playai";
59
+
60
+ // Create voice providers
61
+ const openai = new OpenAIVoice();
62
+ const playai = new PlayAIVoice();
63
+
64
+ // Use OpenAI for listening (speech-to-text) and PlayAI for speaking (text-to-speech)
65
+ const voice = new CompositeVoice({
66
+ input: openai,
67
+ output: playai,
68
+ });
69
+
70
+ // Convert speech to text using OpenAI
71
+ const text = await voice.listen(audioStream);
72
+
73
+ // Convert text to speech using PlayAI
74
+ const audio = await voice.speak("Hello, world!");
75
+ ```
76
+
77
+ ### Using AI SDK Model Providers
78
+
79
+ You can pass AI SDK transcription and speech models directly to CompositeVoice:
80
+
81
+ ```typescript
82
+ import { CompositeVoice } from "@mastra/core/voice";
83
+ import { openai } from "@ai-sdk/openai";
84
+ import { elevenlabs } from "@ai-sdk/elevenlabs";
85
+
86
+ // Use AI SDK models directly - they will be auto-wrapped
87
+ const voice = new CompositeVoice({
88
+ input: openai.transcription('whisper-1'), // AI SDK transcription
89
+ output: elevenlabs.speech('eleven_turbo_v2'), // AI SDK speech
90
+ });
91
+
92
+ // Works the same way as with Mastra providers
93
+ const text = await voice.listen(audioStream);
94
+ const audio = await voice.speak("Hello from AI SDK!");
95
+ ```
96
+
97
+ ### Mix and Match
98
+
99
+ You can combine Mastra providers with AI SDK models:
100
+
101
+ ```typescript
102
+ import { CompositeVoice } from "@mastra/core/voice";
103
+ import { PlayAIVoice } from "@mastra/voice-playai";
104
+ import { groq } from "@ai-sdk/groq";
105
+
106
+ const voice = new CompositeVoice({
107
+ input: groq.transcription('whisper-large-v3'), // AI SDK for STT
108
+ output: new PlayAIVoice(), // Mastra for TTS
109
+ });
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Reference: PlayAI
115
+
116
+ > Documentation for the PlayAI voice implementation, providing text-to-speech capabilities.
117
+
118
+ The PlayAI voice implementation in Mastra provides text-to-speech capabilities using PlayAI's API.
119
+
120
+ ## Usage Example
121
+
122
+ ```typescript
123
+ import { PlayAIVoice } from "@mastra/voice-playai";
124
+
125
+ // Initialize with default configuration (uses PLAYAI_API_KEY environment variable and PLAYAI_USER_ID environment variable)
126
+ const voice = new PlayAIVoice();
127
+
128
+ // Initialize with default configuration
129
+ const voice = new PlayAIVoice({
130
+ speechModel: {
131
+ name: "PlayDialog",
132
+ apiKey: process.env.PLAYAI_API_KEY,
133
+ userId: process.env.PLAYAI_USER_ID,
134
+ },
135
+ speaker: "Angelo", // Default voice
136
+ });
137
+
138
+ // Convert text to speech with a specific voice
139
+ const audioStream = await voice.speak("Hello, world!", {
140
+ speaker:
141
+ "s3://voice-cloning-zero-shot/b27bc13e-996f-4841-b584-4d35801aea98/original/manifest.json", // Dexter voice
142
+ });
143
+ ```
144
+
145
+ ## Constructor Parameters
146
+
147
+ ### PlayAIConfig
148
+
149
+ ## Methods
150
+
151
+ ### speak()
152
+
153
+ Converts text to speech using the configured speech model and voice.
154
+
155
+ Returns: `Promise<NodeJS.ReadableStream>`.
156
+
157
+ ### getSpeakers()
158
+
159
+ Returns an array of available voice options, where each node contains:
160
+
161
+ ### listen()
162
+
163
+ This method is not supported by PlayAI and will throw an error. PlayAI does not provide speech-to-text functionality.
164
+
165
+ ## Notes
166
+
167
+ - PlayAI requires both an API key and a user ID for authentication
168
+ - The service offers two models: 'PlayDialog' and 'Play3.0-mini'
169
+ - Each voice has a unique S3 manifest ID that must be used when making API calls
170
+
171
+ ---
172
+
173
+ ## Reference: voice.listen()
174
+
175
+ > Documentation for the listen() method available in all Mastra voice providers, which converts speech to text.
176
+
177
+ The `listen()` method is a core function available in all Mastra voice providers that converts speech to text. It takes an audio stream as input and returns the transcribed text.
178
+
179
+ ## Parameters
180
+
181
+ ## Return Value
182
+
183
+ Returns one of the following:
184
+
185
+ - `Promise<string>`: A promise that resolves to the transcribed text
186
+ - `Promise<NodeJS.ReadableStream>`: A promise that resolves to a stream of transcribed text (for streaming transcription)
187
+ - `Promise<void>`: For real-time providers that emit 'writing' events instead of returning text directly
188
+
189
+ ## Provider-Specific Options
190
+
191
+ Each voice provider may support additional options specific to their implementation. Here are some examples:
192
+
193
+ ### OpenAI
194
+
195
+ ### Google
196
+
197
+ ### Deepgram
198
+
199
+ ## Usage Example
200
+
201
+ ```typescript
202
+ import { OpenAIVoice } from "@mastra/voice-openai";
203
+ import { getMicrophoneStream } from "@mastra/node-audio";
204
+ import { createReadStream } from "fs";
205
+ import path from "path";
206
+
207
+ // Initialize a voice provider
208
+ const voice = new OpenAIVoice({
209
+ listeningModel: {
210
+ name: "whisper-1",
211
+ apiKey: process.env.OPENAI_API_KEY,
212
+ },
213
+ });
214
+
215
+ // Basic usage with a file stream
216
+ const audioFilePath = path.join(process.cwd(), "audio.mp3");
217
+ const audioStream = createReadStream(audioFilePath);
218
+ const transcript = await voice.listen(audioStream, {
219
+ filetype: "mp3",
220
+ });
221
+ console.log("Transcribed text:", transcript);
222
+
223
+ // Using a microphone stream
224
+ const microphoneStream = getMicrophoneStream(); // Assume this function gets audio input
225
+ const transcription = await voice.listen(microphoneStream);
226
+
227
+ // With provider-specific options
228
+ const transcriptWithOptions = await voice.listen(audioStream, {
229
+ language: "en",
230
+ prompt: "This is a conversation about artificial intelligence.",
231
+ });
232
+ ```
233
+
234
+ ## Using with CompositeVoice
235
+
236
+ When using `CompositeVoice`, the `listen()` method delegates to the configured listening provider:
237
+
238
+ ```typescript
239
+ import { CompositeVoice } from "@mastra/core/voice";
240
+ import { OpenAIVoice } from "@mastra/voice-openai";
241
+ import { PlayAIVoice } from "@mastra/voice-playai";
242
+
243
+ const voice = new CompositeVoice({
244
+ input: new OpenAIVoice(),
245
+ output: new PlayAIVoice(),
246
+ });
247
+
248
+ // This will use the OpenAIVoice provider
249
+ const transcript = await voice.listen(audioStream);
250
+ ```
251
+
252
+ ### Using AI SDK Model Providers
253
+
254
+ You can also use AI SDK transcription models directly with `CompositeVoice`:
255
+
256
+ ```typescript
257
+ import { CompositeVoice } from "@mastra/core/voice";
258
+ import { openai } from "@ai-sdk/openai";
259
+ import { groq } from "@ai-sdk/groq";
260
+
261
+ // Use AI SDK transcription models
262
+ const voice = new CompositeVoice({
263
+ input: openai.transcription('whisper-1'), // AI SDK model
264
+ output: new PlayAIVoice(), // Mastra provider
265
+ });
266
+
267
+ // Works the same way
268
+ const transcript = await voice.listen(audioStream);
269
+
270
+ // Provider-specific options can be passed through
271
+ const transcriptWithOptions = await voice.listen(audioStream, {
272
+ providerOptions: {
273
+ openai: {
274
+ language: 'en',
275
+ prompt: 'This is about AI',
276
+ }
277
+ }
278
+ });
279
+ ```
280
+
281
+ See the [CompositeVoice reference](https://mastra.ai/reference/v1/voice/composite-voice) for more details on AI SDK integration.
282
+
283
+ ## Realtime Voice Providers
284
+
285
+ When using realtime voice providers like `OpenAIRealtimeVoice`, the `listen()` method behaves differently:
286
+
287
+ - Instead of returning transcribed text, it emits 'writing' events with the transcribed text
288
+ - You need to register an event listener to receive the transcription
289
+
290
+ ```typescript
291
+ import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime";
292
+ import { getMicrophoneStream } from "@mastra/node-audio";
293
+
294
+ const voice = new OpenAIRealtimeVoice();
295
+ await voice.connect();
296
+
297
+ // Register event listener for transcription
298
+ voice.on("writing", ({ text, role }) => {
299
+ console.log(`${role}: ${text}`);
300
+ });
301
+
302
+ // This will emit 'writing' events instead of returning text
303
+ const microphoneStream = getMicrophoneStream();
304
+ await voice.listen(microphoneStream);
305
+ ```
306
+
307
+ ## Notes
308
+
309
+ - Not all voice providers support speech-to-text functionality (e.g., PlayAI, Speechify)
310
+ - The behavior of `listen()` may vary slightly between providers, but all implementations follow the same basic interface
311
+ - When using a realtime voice provider, the method might not return text directly but instead emit a 'writing' event
312
+ - The audio format supported depends on the provider. Common formats include MP3, WAV, and M4A
313
+ - Some providers support streaming transcription, where text is returned as it's transcribed
314
+ - For best performance, consider closing or ending the audio stream when you're done with it
315
+
316
+ ## Related Methods
317
+
318
+ - [voice.speak()](./voice.speak) - Converts text to speech
319
+ - [voice.send()](./voice.send) - Sends audio data to the voice provider in real-time
320
+ - [voice.on()](./voice.on) - Registers an event listener for voice events
321
+
322
+ ---
323
+
324
+ ## Reference: voice.speak()
325
+
326
+ > Documentation for the speak() method available in all Mastra voice providers, which converts text to speech.
327
+
328
+ The `speak()` method is a core function available in all Mastra voice providers that converts text to speech. It takes text input and returns an audio stream that can be played or saved.
329
+
330
+ ## Parameters
331
+
332
+ ## Return Value
333
+
334
+ Returns a `Promise<NodeJS.ReadableStream | void>` where:
335
+
336
+ - `NodeJS.ReadableStream`: A stream of audio data that can be played or saved
337
+ - `void`: When using a realtime voice provider that emits audio through events instead of returning it directly
338
+
339
+ ## Provider-Specific Options
340
+
341
+ Each voice provider may support additional options specific to their implementation. Here are some examples:
342
+
343
+ ### OpenAI
344
+
345
+ ### ElevenLabs
346
+
347
+ ### Google
348
+
349
+ ### Murf
350
+
351
+ ## Usage Example
352
+
353
+ ```typescript
354
+ import { OpenAIVoice } from "@mastra/voice-openai";
355
+ // Initialize a voice provider
356
+ const voice = new OpenAIVoice({
357
+ speaker: "alloy", // Default voice
358
+ });
359
+ // Basic usage with default settings
360
+ const audioStream = await voice.speak("Hello, world!");
361
+ // Using a different voice for this specific request
362
+ const audioStreamWithDifferentVoice = await voice.speak("Hello again!", {
363
+ speaker: "nova",
364
+ });
365
+ // Using provider-specific options
366
+ const audioStreamWithOptions = await voice.speak("Hello with options!", {
367
+ speaker: "echo",
368
+ speed: 1.2, // OpenAI-specific option
369
+ });
370
+ // Using a text stream as input
371
+ import { Readable } from "stream";
372
+ const textStream = Readable.from(["Hello", " from", " a", " stream!"]);
373
+ const audioStreamFromTextStream = await voice.speak(textStream);
374
+ ```
375
+
376
+ ## Using with CompositeVoice
377
+
378
+ When using `CompositeVoice`, the `speak()` method delegates to the configured speaking provider:
379
+
380
+ ```typescript
381
+ import { CompositeVoice } from "@mastra/core/voice";
382
+ import { OpenAIVoice } from "@mastra/voice-openai";
383
+ import { PlayAIVoice } from "@mastra/voice-playai";
384
+
385
+ const voice = new CompositeVoice({
386
+ output: new PlayAIVoice(),
387
+ input: new OpenAIVoice(),
388
+ });
389
+
390
+ // This will use the PlayAIVoice provider
391
+ const audioStream = await voice.speak("Hello, world!");
392
+ ```
393
+
394
+ ### Using AI SDK Model Providers
395
+
396
+ You can also use AI SDK speech models directly with `CompositeVoice`:
397
+
398
+ ```typescript
399
+ import { CompositeVoice } from "@mastra/core/voice";
400
+ import { openai } from "@ai-sdk/openai";
401
+ import { elevenlabs } from "@ai-sdk/elevenlabs";
402
+
403
+ // Use AI SDK speech models
404
+ const voice = new CompositeVoice({
405
+ output: elevenlabs.speech('eleven_turbo_v2'), // AI SDK model
406
+ input: openai.transcription('whisper-1'), // AI SDK model
407
+ });
408
+
409
+ // Works the same way
410
+ const audioStream = await voice.speak("Hello from AI SDK!");
411
+
412
+ // Provider-specific options can be passed through
413
+ const audioWithOptions = await voice.speak("Hello with options!", {
414
+ speaker: 'Rachel', // ElevenLabs voice
415
+ providerOptions: {
416
+ elevenlabs: {
417
+ stability: 0.5,
418
+ similarity_boost: 0.75,
419
+ }
420
+ }
421
+ });
422
+ ```
423
+
424
+ See the [CompositeVoice reference](https://mastra.ai/reference/v1/voice/composite-voice) for more details on AI SDK integration.
425
+
426
+ ## Realtime Voice Providers
427
+
428
+ When using realtime voice providers like `OpenAIRealtimeVoice`, the `speak()` method behaves differently:
429
+
430
+ - Instead of returning an audio stream, it emits a 'speaking' event with the audio data
431
+ - You need to register an event listener to receive the audio chunks
432
+
433
+ ```typescript
434
+ import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime";
435
+ import Speaker from "@mastra/node-speaker";
436
+
437
+ const speaker = new Speaker({
438
+ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro
439
+ channels: 1, // Mono audio output (as opposed to stereo which would be 2)
440
+ bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution)
441
+ });
442
+
443
+ const voice = new OpenAIRealtimeVoice();
444
+ await voice.connect();
445
+ // Register event listener for audio chunks
446
+ voice.on("speaker", (stream) => {
447
+ // Handle audio chunk (e.g., play it or save it)
448
+ stream.pipe(speaker);
449
+ });
450
+ // This will emit 'speaking' events instead of returning a stream
451
+ await voice.speak("Hello, this is realtime speech!");
452
+ ```
453
+
454
+ ## Notes
455
+
456
+ - The behavior of `speak()` may vary slightly between providers, but all implementations follow the same basic interface.
457
+ - When using a realtime voice provider, the method might not return an audio stream directly but instead emit a 'speaking' event.
458
+ - If a text stream is provided as input, the provider will typically convert it to a string before processing.
459
+ - The audio format of the returned stream depends on the provider. Common formats include MP3, WAV, and OGG.
460
+ - For best performance, consider closing or ending the audio stream when you're done with it.
package/dist/index.cjs CHANGED
@@ -173,34 +173,32 @@ var PlayAIVoice = class extends voice.MastraVoice {
173
173
  }
174
174
  async speak(input, options) {
175
175
  const text = typeof input === "string" ? input : await this.streamToString(input);
176
- return this.traced(async () => {
177
- const payload = {
178
- text,
179
- voice: options?.speaker || this.speaker,
180
- model: this.speechModel?.name
181
- };
182
- const response = await this.makeRequest("/tts/stream", payload);
183
- if (!response.body) {
184
- throw new Error("No response body received");
185
- }
186
- const stream$1 = new stream.PassThrough();
187
- const reader = response.body.getReader();
188
- void (async () => {
189
- try {
190
- while (true) {
191
- const { done, value } = await reader.read();
192
- if (done) {
193
- stream$1.end();
194
- break;
195
- }
196
- stream$1.write(value);
176
+ const payload = {
177
+ text,
178
+ voice: options?.speaker || this.speaker,
179
+ model: this.speechModel?.name
180
+ };
181
+ const response = await this.makeRequest("/tts/stream", payload);
182
+ if (!response.body) {
183
+ throw new Error("No response body received");
184
+ }
185
+ const stream$1 = new stream.PassThrough();
186
+ const reader = response.body.getReader();
187
+ void (async () => {
188
+ try {
189
+ while (true) {
190
+ const { done, value } = await reader.read();
191
+ if (done) {
192
+ stream$1.end();
193
+ break;
197
194
  }
198
- } catch (error) {
199
- stream$1.destroy(error);
195
+ stream$1.write(value);
200
196
  }
201
- })();
202
- return stream$1;
203
- }, "voice.playai.speak")();
197
+ } catch (error) {
198
+ stream$1.destroy(error);
199
+ }
200
+ })();
201
+ return stream$1;
204
202
  }
205
203
  /**
206
204
  * Checks if listening capabilities are enabled.
@@ -214,19 +212,16 @@ var PlayAIVoice = class extends voice.MastraVoice {
214
212
  throw new Error("PlayAI does not support speech recognition");
215
213
  }
216
214
  async getSpeakers() {
217
- return this.traced(
218
- () => Promise.resolve(
219
- PLAYAI_VOICES.map((voice) => ({
220
- voiceId: voice.id,
221
- name: voice.name,
222
- accent: voice.accent,
223
- gender: voice.gender,
224
- age: voice.age,
225
- style: voice.style
226
- }))
227
- ),
228
- "voice.playai.voices"
229
- )();
215
+ return Promise.resolve(
216
+ PLAYAI_VOICES.map((voice) => ({
217
+ voiceId: voice.id,
218
+ name: voice.name,
219
+ accent: voice.accent,
220
+ gender: voice.gender,
221
+ age: voice.age,
222
+ style: voice.style
223
+ }))
224
+ );
230
225
  }
231
226
  };
232
227
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["MastraVoice","stream","PassThrough"],"mappings":";;;;;;AAaO,IAAM,aAAA,GAAmC;AAAA,EAC9C;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,IAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,OAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,SAAA;AAAA,IACN,MAAA,EAAQ,qBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,SAAA;AAAA,IACN,MAAA,EAAQ,OAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,MAAA;AAAA,IACN,MAAA,EAAQ,IAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,IAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,OAAA;AAAA,IACN,MAAA,EAAQ,qBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,OAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,wBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,KAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,qBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,KAAA;AAAA,IACN,MAAA,EAAQ,IAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,OAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,OAAA;AAAA,IACN,MAAA,EAAQ,qBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,WAAA;AAAA,IACN,MAAA,EAAQ,mBAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,OAAA;AAAA,IACL,KAAA,EAAO,gBAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,SAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,KAAA;AAAA,IACL,KAAA,EAAO,WAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,QAAA;AAAA,IACN,MAAA,EAAQ,IAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,WAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,OAAA;AAAA,IACN,MAAA,EAAQ,YAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,WAAA;AAAA,IACP,EAAA,EAAI;AAAA,GACN;AAAA,EACA;AAAA,IACE,IAAA,EAAM,KAAA;AAAA,IACN,MAAA,EAAQ,YAAA;AAAA,IACR,MAAA,EAAQ,GAAA;AAAA,IACR,GAAA,EAAK,QAAA;AAAA,IACL,KAAA,EAAO,WAAA;AAAA,IACP,EAAA,EAAI;AAAA;AAER;AAQO,IAAM,WAAA,GAAN,cAA0BA,iBAAA,CAAY;AAAA,EACnC,OAAA,GAAU,4BAAA;AAAA,EACV,MAAA;AAAA,EAER,YAAY,EAAE,WAAA,EAAa,OAAA,EAAQ,GAAsD,EAAC,EAAG;AAC3F,IAAA,KAAA,CAAM;AAAA,MACJ,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,aAAa,IAAA,IAAQ,YAAA;AAAA,QAC3B,MAAA,EAAQ,WAAA,EAAa,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI;AAAA,OAC7C;AAAA,MACA,OAAA,EAAS,OAAA,IAAW,aAAA,CAAc,CAAC,CAAA,EAAG;AAAA,KACvC,CAAA;AACD,IAAA,MAAM,MAAA,GAAS,WAAA,EAAa,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,cAAA;AAClD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,oBAAoB,CAAA;AAAA,IACtC;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,MAAc,WAAA,CAAY,QAAA,EAAkB,OAAA,EAAe,SAAyB,MAAA,EAAQ;AAC1F,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ;AAAA,MAC1B,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA,CAAA;AAAA,MACjD,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAa,IAAA,CAAK;AAAA,KACnB,CAAA;AAED,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI;AAAA,MACzD,MAAA;AAAA,MACA,OAAA;AAAA,MACA,IAAA,EAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA,GAAI;AAAA,KAC3C,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAS,MAAM,QAAA,CAAS,IAAA,EAAK;AAEnC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,MAAM,OAAA,IAAW,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,IAC7E;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAc,eAAe,MAAA,EAAgD;AAC3E,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,SAAS,OAAO,CAAA;AAAA,EAC/C;AAAA,EAEA,MAAM,KAAA,CAAM,KAAA,EAAuC,OAAA,EAAgE;AACjH,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,KAAU,QAAA,GAAW,QAAQ,MAAM,IAAA,CAAK,eAAe,KAAK,CAAA;AAEhF,IAAA,OAAO,IAAA,CAAK,OAAO,YAAY;AAC7B,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,IAAA;AAAA,QACA,KAAA,EAAO,OAAA,EAAS,OAAA,IAAW,IAAA,CAAK,OAAA;AAAA,QAChC,KAAA,EAAO,KAAK,WAAA,EAAa;AAAA,OAC3B;AAEA,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,eAAe,OAAO,CAAA;AAC9D,MAAA,IAAI,CAAC,SAAS,IAAA,EAAM;AAClB,QAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,MAC7C;AAGA,MAAA,MAAMC,QAAA,GAAS,IAAIC,kBAAA,EAAY;AAG/B,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,MAAA,KAAA,CAAM,YAAY;AAChB,QAAA,IAAI;AACF,UAAA,OAAO,IAAA,EAAM;AACX,YAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,YAAA,IAAI,IAAA,EAAM;AACR,cAAAD,QAAA,CAAO,GAAA,EAAI;AACX,cAAA;AAAA,YACF;AACA,YAAAA,QAAA,CAAO,MAAM,KAAK,CAAA;AAAA,UACpB;AAAA,QACF,SAAS,KAAA,EAAO;AACd,UAAAA,QAAA,CAAO,QAAQ,KAAc,CAAA;AAAA,QAC/B;AAAA,MACF,CAAA,GAAG;AAEH,MAAA,OAAOA,QAAA;AAAA,IACT,CAAA,EAAG,oBAAoB,CAAA,EAAE;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,EAAE,SAAS,KAAA,EAAM;AAAA,EAC1B;AAAA,EAEA,MAAM,MAAA,CACJ,MAAA,EACA,QAAA,EACyC;AACzC,IAAA,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAAA,EAC9D;AAAA,EAEA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,MACV,MACE,OAAA,CAAQ,OAAA;AAAA,QACN,aAAA,CAAc,IAAI,CAAA,KAAA,MAAU;AAAA,UAC1B,SAAS,KAAA,CAAM,EAAA;AAAA,UACf,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,KAAK,KAAA,CAAM,GAAA;AAAA,UACX,OAAO,KAAA,CAAM;AAAA,SACf,CAAE;AAAA,OACJ;AAAA,MACF;AAAA,KACF,EAAE;AAAA,EACJ;AACF","file":"index.cjs","sourcesContent":["import { PassThrough } from 'stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\n\ninterface PlayAIVoiceInfo {\n name: string;\n accent: string;\n gender: 'M' | 'F';\n age: 'Young' | 'Middle' | 'Old';\n style: 'Conversational' | 'Narrative';\n id: string;\n}\n\nexport const PLAYAI_VOICES: PlayAIVoiceInfo[] = [\n {\n name: 'Angelo',\n accent: 'US',\n gender: 'M',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',\n },\n {\n name: 'Arsenio',\n accent: 'US African American',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/65977f5e-a22a-4b36-861b-ecede19bdd65/original/manifest.json',\n },\n {\n name: 'Cillian',\n accent: 'Irish',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/1591b954-8760-41a9-bc58-9176a68c5726/original/manifest.json',\n },\n {\n name: 'Timo',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/677a4ae3-252f-476e-85ce-eeed68e85951/original/manifest.json',\n },\n {\n name: 'Dexter',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/b27bc13e-996f-4841-b584-4d35801aea98/original/manifest.json',\n },\n {\n name: 'Miles',\n accent: 'US African American',\n gender: 'M',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/29dd9a52-bd32-4a6e-bff1-bbb98dcc286a/original/manifest.json',\n },\n {\n name: 'Briggs',\n accent: 'US Southern (Oklahoma)',\n gender: 'M',\n age: 'Old',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/71cdb799-1e03-41c6-8a05-f7cd55134b0b/original/manifest.json',\n },\n {\n name: 'Deedee',\n accent: 'US African American',\n gender: 'F',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',\n },\n {\n name: 'Nia',\n accent: 'US',\n gender: 'F',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/831bd330-85c6-4333-b2b4-10c476ea3491/original/manifest.json',\n },\n {\n name: 'Inara',\n accent: 'US African American',\n gender: 'F',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/adb83b67-8d75-48ff-ad4d-a0840d231ef1/original/manifest.json',\n },\n {\n name: 'Constanza',\n accent: 'US Latin American',\n gender: 'F',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/b0aca4d7-1738-4848-a80b-307ac44a7298/original/manifest.json',\n },\n {\n name: 'Gideon',\n accent: 'British',\n gender: 'M',\n age: 'Old',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/5a3a1168-7793-4b2c-8f90-aff2b5232131/original/manifest.json',\n },\n {\n name: 'Casper',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/1bbc6986-fadf-4bd8-98aa-b86fed0476e9/original/manifest.json',\n },\n {\n name: 'Mitch',\n accent: 'Australian',\n gender: 'M',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/c14e50f2-c5e3-47d1-8c45-fa4b67803d19/original/manifest.json',\n },\n {\n name: 'Ava',\n accent: 'Australian',\n gender: 'F',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/50381567-ff7b-46d2-bfdc-a9584a85e08d/original/manifest.json',\n },\n];\n\ninterface PlayAIConfig {\n name?: 'PlayDialog' | 'Play3.0-mini';\n apiKey?: string;\n userId?: string;\n}\n\nexport class PlayAIVoice extends MastraVoice {\n private baseUrl = 'https://api.play.ai/api/v1';\n private userId: string;\n\n constructor({ speechModel, speaker }: { speechModel?: PlayAIConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'PlayDialog',\n apiKey: speechModel?.apiKey ?? process.env.PLAYAI_API_KEY,\n },\n speaker: speaker ?? PLAYAI_VOICES[0]?.id,\n });\n const userId = speechModel?.userId ?? process.env.PLAYAI_USER_ID;\n if (!userId) {\n throw new Error('userId is required');\n }\n\n this.userId = userId;\n }\n\n private async makeRequest(endpoint: string, payload?: any, method: 'GET' | 'POST' = 'POST') {\n const headers = new Headers({\n Authorization: `Bearer ${this.speechModel?.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-USER-ID': this.userId,\n });\n\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method,\n headers,\n body: payload ? JSON.stringify(payload) : undefined,\n });\n\n if (!response.ok) {\n const error = (await response.json()) as { message: string };\n\n throw new Error(`PlayAI API Error: ${error.message || response.statusText}`);\n }\n\n return response;\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 async speak(input: string | NodeJS.ReadableStream, options?: { speaker?: string }): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n return this.traced(async () => {\n const payload = {\n text,\n voice: options?.speaker || this.speaker,\n model: this.speechModel?.name,\n };\n\n const response = await this.makeRequest('/tts/stream', payload);\n if (!response.body) {\n throw new Error('No response body received');\n }\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Process the stream\n const reader = response.body.getReader();\n void (async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n stream.end();\n break;\n }\n stream.write(value);\n }\n } catch (error) {\n stream.destroy(error as Error);\n }\n })();\n\n return stream;\n }, 'voice.playai.speak')();\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: false };\n }\n\n async listen(\n _input: NodeJS.ReadableStream,\n _options?: Record<string, unknown>,\n ): Promise<string | NodeJS.ReadableStream> {\n throw new Error('PlayAI does not support speech recognition');\n }\n\n async getSpeakers() {\n return this.traced(\n () =>\n Promise.resolve(\n PLAYAI_VOICES.map(voice => ({\n voiceId: voice.id,\n name: voice.name,\n accent: voice.accent,\n gender: voice.gender,\n age: voice.age,\n style: voice.style,\n })),\n ),\n 'voice.playai.voices',\n )();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["MastraVoice","stream","PassThrough"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\n\ninterface PlayAIVoiceInfo {\n name: string;\n accent: string;\n gender: 'M' | 'F';\n age: 'Young' | 'Middle' | 'Old';\n style: 'Conversational' | 'Narrative';\n id: string;\n}\n\nexport const PLAYAI_VOICES: PlayAIVoiceInfo[] = [\n {\n name: 'Angelo',\n accent: 'US',\n gender: 'M',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',\n },\n {\n name: 'Arsenio',\n accent: 'US African American',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/65977f5e-a22a-4b36-861b-ecede19bdd65/original/manifest.json',\n },\n {\n name: 'Cillian',\n accent: 'Irish',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/1591b954-8760-41a9-bc58-9176a68c5726/original/manifest.json',\n },\n {\n name: 'Timo',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/677a4ae3-252f-476e-85ce-eeed68e85951/original/manifest.json',\n },\n {\n name: 'Dexter',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/b27bc13e-996f-4841-b584-4d35801aea98/original/manifest.json',\n },\n {\n name: 'Miles',\n accent: 'US African American',\n gender: 'M',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/29dd9a52-bd32-4a6e-bff1-bbb98dcc286a/original/manifest.json',\n },\n {\n name: 'Briggs',\n accent: 'US Southern (Oklahoma)',\n gender: 'M',\n age: 'Old',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/71cdb799-1e03-41c6-8a05-f7cd55134b0b/original/manifest.json',\n },\n {\n name: 'Deedee',\n accent: 'US African American',\n gender: 'F',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',\n },\n {\n name: 'Nia',\n accent: 'US',\n gender: 'F',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/831bd330-85c6-4333-b2b4-10c476ea3491/original/manifest.json',\n },\n {\n name: 'Inara',\n accent: 'US African American',\n gender: 'F',\n age: 'Middle',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/adb83b67-8d75-48ff-ad4d-a0840d231ef1/original/manifest.json',\n },\n {\n name: 'Constanza',\n accent: 'US Latin American',\n gender: 'F',\n age: 'Young',\n style: 'Conversational',\n id: 's3://voice-cloning-zero-shot/b0aca4d7-1738-4848-a80b-307ac44a7298/original/manifest.json',\n },\n {\n name: 'Gideon',\n accent: 'British',\n gender: 'M',\n age: 'Old',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/5a3a1168-7793-4b2c-8f90-aff2b5232131/original/manifest.json',\n },\n {\n name: 'Casper',\n accent: 'US',\n gender: 'M',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/1bbc6986-fadf-4bd8-98aa-b86fed0476e9/original/manifest.json',\n },\n {\n name: 'Mitch',\n accent: 'Australian',\n gender: 'M',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/c14e50f2-c5e3-47d1-8c45-fa4b67803d19/original/manifest.json',\n },\n {\n name: 'Ava',\n accent: 'Australian',\n gender: 'F',\n age: 'Middle',\n style: 'Narrative',\n id: 's3://voice-cloning-zero-shot/50381567-ff7b-46d2-bfdc-a9584a85e08d/original/manifest.json',\n },\n];\n\ninterface PlayAIConfig {\n name?: 'PlayDialog' | 'Play3.0-mini';\n apiKey?: string;\n userId?: string;\n}\n\nexport class PlayAIVoice extends MastraVoice {\n private baseUrl = 'https://api.play.ai/api/v1';\n private userId: string;\n\n constructor({ speechModel, speaker }: { speechModel?: PlayAIConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'PlayDialog',\n apiKey: speechModel?.apiKey ?? process.env.PLAYAI_API_KEY,\n },\n speaker: speaker ?? PLAYAI_VOICES[0]?.id,\n });\n const userId = speechModel?.userId ?? process.env.PLAYAI_USER_ID;\n if (!userId) {\n throw new Error('userId is required');\n }\n\n this.userId = userId;\n }\n\n private async makeRequest(endpoint: string, payload?: any, method: 'GET' | 'POST' = 'POST') {\n const headers = new Headers({\n Authorization: `Bearer ${this.speechModel?.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-USER-ID': this.userId,\n });\n\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method,\n headers,\n body: payload ? JSON.stringify(payload) : undefined,\n });\n\n if (!response.ok) {\n const error = (await response.json()) as { message: string };\n\n throw new Error(`PlayAI API Error: ${error.message || response.statusText}`);\n }\n\n return response;\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 async speak(input: string | NodeJS.ReadableStream, options?: { speaker?: string }): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const payload = {\n text,\n voice: options?.speaker || this.speaker,\n model: this.speechModel?.name,\n };\n\n const response = await this.makeRequest('/tts/stream', payload);\n if (!response.body) {\n throw new Error('No response body received');\n }\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Process the stream\n const reader = response.body.getReader();\n void (async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n stream.end();\n break;\n }\n stream.write(value);\n }\n } catch (error) {\n stream.destroy(error as Error);\n }\n })();\n\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: false };\n }\n\n async listen(\n _input: NodeJS.ReadableStream,\n _options?: Record<string, unknown>,\n ): Promise<string | NodeJS.ReadableStream> {\n throw new Error('PlayAI does not support speech recognition');\n }\n\n async getSpeakers() {\n return Promise.resolve(\n PLAYAI_VOICES.map(voice => ({\n voiceId: voice.id,\n name: voice.name,\n accent: voice.accent,\n gender: voice.gender,\n age: voice.age,\n style: voice.style,\n })),\n );\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAChC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAAC;IACtC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,eAAO,MAAM,aAAa,EAAE,eAAe,EAyH1C,CAAC;AAEF,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,YAAY,GAAG,cAAc,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAEX,EAAE,WAAW,EAAE,OAAO,EAAE,GAAE;QAAE,WAAW,CAAC,EAAE,YAAY,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;YAgB7E,WAAW;YAsBX,cAAc;IAYtB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IAuClH;;;;OAIG;IACG,WAAW;;;IAIX,MAAM,CACV,MAAM,EAAE,MAAM,CAAC,cAAc,EAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;IAIpC,WAAW;;;;;;;;CAgBlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAChC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAAC;IACtC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,eAAO,MAAM,aAAa,EAAE,eAAe,EAyH1C,CAAC;AAEF,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,YAAY,GAAG,cAAc,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAEX,EAAE,WAAW,EAAE,OAAO,EAAE,GAAE;QAAE,WAAW,CAAC,EAAE,YAAY,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;YAgB7E,WAAW;YAsBX,cAAc;IAYtB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IAqClH;;;;OAIG;IACG,WAAW;;;IAIX,MAAM,CACV,MAAM,EAAE,MAAM,CAAC,cAAc,EAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;IAIpC,WAAW;;;;;;;;CAYlB"}