@mastra/voice-murf 0.12.0 → 0.12.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,118 @@
1
+ # Murf
2
+
3
+ The Murf voice implementation in Mastra provides text-to-speech (TTS) capabilities using Murf's AI voice service. It supports multiple voices across different languages.
4
+
5
+ ## Usage example
6
+
7
+ ```typescript
8
+ import { MurfVoice } from '@mastra/voice-murf'
9
+
10
+ // Initialize with default configuration (uses MURF_API_KEY environment variable)
11
+ const voice = new MurfVoice()
12
+
13
+ // Initialize with custom configuration
14
+ const voice = new MurfVoice({
15
+ speechModel: {
16
+ name: 'GEN2',
17
+ apiKey: 'your-api-key',
18
+ properties: {
19
+ format: 'MP3',
20
+ rate: 1.0,
21
+ pitch: 1.0,
22
+ sampleRate: 48000,
23
+ channelType: 'STEREO',
24
+ },
25
+ },
26
+ speaker: 'en-US-cooper',
27
+ })
28
+
29
+ // Text-to-Speech with default settings
30
+ const audioStream = await voice.speak('Hello, world!')
31
+
32
+ // Text-to-Speech with custom properties
33
+ const audioStream = await voice.speak('Hello, world!', {
34
+ speaker: 'en-UK-hazel',
35
+ properties: {
36
+ format: 'WAV',
37
+ rate: 1.2,
38
+ style: 'casual',
39
+ },
40
+ })
41
+
42
+ // Get available voices
43
+ const voices = await voice.getSpeakers()
44
+ ```
45
+
46
+ ## Constructor parameters
47
+
48
+ **speechModel** (`MurfConfig`): Configuration for text-to-speech functionality (Default: `{ name: 'GEN2' }`)
49
+
50
+ **speechModel.name** (`'GEN1' | 'GEN2'`): The Murf model generation to use
51
+
52
+ **speechModel.apiKey** (`string`): Murf API key. Falls back to MURF\_API\_KEY environment variable
53
+
54
+ **speechModel.properties** (`object`): Default properties for all speech synthesis requests
55
+
56
+ **speechModel.properties.style** (`string`): Speaking style for the voice
57
+
58
+ **speechModel.properties.rate** (`number`): Speech rate multiplier
59
+
60
+ **speechModel.properties.pitch** (`number`): Voice pitch adjustment
61
+
62
+ **speechModel.properties.sampleRate** (`8000 | 24000 | 44100 | 48000`): Audio sample rate in Hz
63
+
64
+ **speechModel.properties.format** (`'MP3' | 'WAV' | 'FLAC' | 'ALAW' | 'ULAW'`): Output audio format
65
+
66
+ **speechModel.properties.channelType** (`'STEREO' | 'MONO'`): Audio channel configuration
67
+
68
+ **speechModel.properties.pronunciationDictionary** (`Record<string, string>`): Custom pronunciation mappings
69
+
70
+ **speechModel.properties.encodeAsBase64** (`boolean`): Whether to encode the audio as base64
71
+
72
+ **speechModel.properties.variation** (`number`): Voice variation parameter
73
+
74
+ **speechModel.properties.audioDuration** (`number`): Target audio duration in seconds
75
+
76
+ **speechModel.properties.multiNativeLocale** (`string`): Locale for multilingual support
77
+
78
+ **speaker** (`string`): Default voice ID to use for text-to-speech (Default: `'en-UK-hazel'`)
79
+
80
+ ## Methods
81
+
82
+ ### `speak()`
83
+
84
+ Converts text to speech using Murf's API.
85
+
86
+ **input** (`string | NodeJS.ReadableStream`): Text to convert to speech. If a stream is provided, it will be converted to text first.
87
+
88
+ **options** (`object`): Speech synthesis options
89
+
90
+ **options.speaker** (`string`): Override the default speaker for this request
91
+
92
+ **options.properties** (`object`): Override default speech properties for this request
93
+
94
+ Returns: `Promise<NodeJS.ReadableStream>`
95
+
96
+ ### `getSpeakers()`
97
+
98
+ Returns an array of available voice options, where each node contains:
99
+
100
+ **voiceId** (`string`): Unique identifier for the voice
101
+
102
+ **name** (`string`): Display name of the voice
103
+
104
+ **language** (`string`): Language code for the voice
105
+
106
+ **gender** (`string`): Gender of the voice
107
+
108
+ ### `listen()`
109
+
110
+ This method isn't supported by Murf and will throw an error. Murf doesn't provide speech-to-text functionality.
111
+
112
+ ## Important notes
113
+
114
+ 1. A Murf API key is required. Set it via the `MURF_API_KEY` environment variable or pass it in the constructor.
115
+ 2. The service uses GEN2 as the default model version.
116
+ 3. Speech properties can be set at the constructor level and overridden per request.
117
+ 4. The service supports extensive audio customization through properties like format, sample rate, and channel type.
118
+ 5. Speech-to-text functionality isn't supported.
package/dist/index.cjs CHANGED
@@ -2,11 +2,6 @@
2
2
 
3
3
  var stream = require('stream');
4
4
  var voice = require('@mastra/core/voice');
5
- var ky = require('ky');
6
-
7
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
-
9
- var ky__default = /*#__PURE__*/_interopDefault(ky);
10
5
 
11
6
  // src/index.ts
12
7
 
@@ -154,8 +149,12 @@ var MURF_VOICES = [
154
149
  ];
155
150
 
156
151
  // src/index.ts
152
+ var DEFAULT_RETRY_COUNT = 2;
153
+ var RETRY_STATUS_CODES = /* @__PURE__ */ new Set([408, 413, 429, 500, 502, 503, 504]);
154
+ var RETRY_DELAY_MS = 300;
157
155
  var MurfVoice = class extends voice.MastraVoice {
158
- client;
156
+ baseUrl = "https://api.murf.ai";
157
+ apiKey;
159
158
  defaultVoice;
160
159
  properties;
161
160
  constructor({ speechModel, speaker } = {}) {
@@ -170,15 +169,10 @@ var MurfVoice = class extends voice.MastraVoice {
170
169
  if (!apiKey) {
171
170
  throw new Error("MURF_API_KEY is not set");
172
171
  }
172
+ this.apiKey = apiKey;
173
173
  this.properties = {
174
174
  ...speechModel?.properties
175
175
  };
176
- this.client = ky__default.default.create({
177
- prefixUrl: "https://api.murf.ai",
178
- headers: {
179
- "api-key": apiKey
180
- }
181
- });
182
176
  this.defaultVoice = speaker ?? MURF_VOICES[0];
183
177
  }
184
178
  async streamToString(stream) {
@@ -194,15 +188,13 @@ var MurfVoice = class extends voice.MastraVoice {
194
188
  }
195
189
  async speak(input, options) {
196
190
  const text = typeof input === "string" ? input : await this.streamToString(input);
197
- const response = await this.client.post("v1/speech/generate", {
198
- json: {
199
- voiceId: options?.speaker || this.defaultVoice,
200
- text,
201
- modelVersion: this.speechModel?.name,
202
- ...this.properties,
203
- ...options?.properties
204
- }
205
- }).json();
191
+ const response = await this.makeRequest("/v1/speech/generate", {
192
+ voiceId: options?.speaker || this.defaultVoice,
193
+ text,
194
+ modelVersion: this.speechModel?.name,
195
+ ...this.properties,
196
+ ...options?.properties
197
+ });
206
198
  const stream$1 = new stream.PassThrough();
207
199
  const audioResponse = await fetch(response.audioFile);
208
200
  if (!audioResponse.body) {
@@ -238,6 +230,37 @@ var MurfVoice = class extends voice.MastraVoice {
238
230
  async listen(_input, _options) {
239
231
  throw new Error("Murf does not support speech recognition");
240
232
  }
233
+ async makeRequest(endpoint, payload) {
234
+ let lastError;
235
+ for (let attempt = 0; attempt <= DEFAULT_RETRY_COUNT; attempt++) {
236
+ if (attempt > 0) {
237
+ await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * 2 ** (attempt - 1)));
238
+ }
239
+ const res = await fetch(`${this.baseUrl}${endpoint}`, {
240
+ method: "POST",
241
+ headers: {
242
+ "api-key": this.apiKey,
243
+ "Content-Type": "application/json"
244
+ },
245
+ body: JSON.stringify(payload)
246
+ });
247
+ if (res.ok) {
248
+ return await res.json();
249
+ }
250
+ if (!RETRY_STATUS_CODES.has(res.status) || attempt === DEFAULT_RETRY_COUNT) {
251
+ let errorMessage;
252
+ try {
253
+ const error = await res.json();
254
+ errorMessage = error.message || res.statusText;
255
+ } catch {
256
+ errorMessage = res.statusText;
257
+ }
258
+ throw new Error(`Murf API Error: ${errorMessage}`);
259
+ }
260
+ lastError = new Error(`Murf API Error: ${res.statusText}`);
261
+ }
262
+ throw lastError ?? new Error("Murf API Error: request failed");
263
+ }
241
264
  async getSpeakers() {
242
265
  return MURF_VOICES.map((voice) => ({
243
266
  voiceId: voice,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":["MastraVoice","ky","stream","PassThrough"],"mappings":";;;;;;;;;;;;;AAGO,IAAM,WAAA,GAAc;AAAA,EACzB,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,iBAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,WAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA;;;AC/FO,IAAM,SAAA,GAAN,cAAwBA,iBAAA,CAAY;AAAA,EACjC,MAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EAER,YAAY,EAAE,WAAA,EAAa,OAAA,EAAQ,GAAoD,EAAC,EAAG;AACzF,IAAA,KAAA,CAAM;AAAA,MACJ,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,aAAa,IAAA,IAAQ,MAAA;AAAA,QAC3B,MAAA,EAAQ,WAAA,EAAa,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI;AAAA,OAC7C;AAAA,MACA,OAAA,EAAS,OAAA,IAAW,WAAA,CAAY,CAAC;AAAA,KAClC,CAAA;AAED,IAAA,MAAM,MAAA,GAAS,KAAK,WAAA,EAAa,MAAA;AACjC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,yBAAyB,CAAA;AAAA,IAC3C;AAEA,IAAA,IAAA,CAAK,UAAA,GAAa;AAAA,MAChB,GAAG,WAAA,EAAa;AAAA,KAClB;AAEA,IAAA,IAAA,CAAK,MAAA,GAASC,oBAAG,MAAA,CAAO;AAAA,MACtB,SAAA,EAAW,qBAAA;AAAA,MACX,OAAA,EAAS;AAAA,QACP,SAAA,EAAW;AAAA;AACb,KACD,CAAA;AAED,IAAA,IAAA,CAAK,YAAA,GAAgB,OAAA,IAA2B,WAAA,CAAY,CAAC,CAAA;AAAA,EAC/D;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,CACJ,KAAA,EACA,OAAA,EACgC;AAChC,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,KAAU,QAAA,GAAW,QAAQ,MAAM,IAAA,CAAK,eAAe,KAAK,CAAA;AAEhF,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CACzB,KAAK,oBAAA,EAAsB;AAAA,MAC1B,IAAA,EAAM;AAAA,QACJ,OAAA,EAAU,OAAA,EAAS,OAAA,IAAW,IAAA,CAAK,YAAA;AAAA,QACnC,IAAA;AAAA,QACA,YAAA,EAAc,KAAK,WAAA,EAAa,IAAA;AAAA,QAChC,GAAG,IAAA,CAAK,UAAA;AAAA,QACR,GAAG,OAAA,EAAS;AAAA;AACd,KACD,EACA,IAAA,EAA2B;AAG9B,IAAA,MAAMC,QAAA,GAAS,IAAIC,kBAAA,EAAY;AAG/B,IAAA,MAAM,aAAA,GAAgB,MAAM,KAAA,CAAM,QAAA,CAAS,SAAS,CAAA;AACpD,IAAA,IAAI,CAAC,cAAc,IAAA,EAAM;AACvB,MAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,IAC7C;AAGA,IAAA,MAAM,MAAA,GAAS,aAAA,CAAc,IAAA,CAAK,SAAA,EAAU;AAC5C,IAAA,CAAC,YAAY;AACX,MAAA,IAAI;AACF,QAAA,OAAO,IAAA,EAAM;AACX,UAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,UAAA,IAAI,IAAA,EAAM;AACR,YAAAD,QAAA,CAAO,GAAA,EAAI;AACX,YAAA;AAAA,UACF;AACA,UAAAA,QAAA,CAAO,MAAM,KAAK,CAAA;AAAA,QACpB;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAAA,QAAA,CAAO,QAAQ,KAAc,CAAA;AAAA,MAC/B;AAAA,IACF,CAAA,GAAG,CAAE,KAAA,CAAM,CAAA,KAAA,KAAS;AAClB,MAAAA,QAAA,CAAO,QAAQ,KAAc,CAAA;AAAA,IAC/B,CAAC,CAAA;AAED,IAAA,OAAOA,QAAA;AAAA,EACT;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,0CAA0C,CAAA;AAAA,EAC5D;AAAA,EAEA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,WAAA,CAAY,IAAI,CAAA,KAAA,MAAU;AAAA,MAC/B,OAAA,EAAS,KAAA;AAAA,MACT,IAAA,EAAM,KAAA;AAAA,MACN,QAAA,EAAU,KAAA,CAAM,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AAAA,MAC5B,MAAA,EAAQ;AAAA,KACV,CAAE,CAAA;AAAA,EACJ;AACF","file":"index.cjs","sourcesContent":["/**\n * List of available voices for Murf TTS\n */\nexport const MURF_VOICES = [\n 'en-UK-hazel',\n 'en-US-cooper',\n 'en-US-imani',\n 'it-IT-giorgio',\n 'en-US-wayne',\n 'en-IN-shivani',\n 'en-US-daniel',\n 'bn-IN-anwesha',\n 'es-MX-alejandro',\n 'en-AU-joyce',\n 'en-US-zion',\n 'en-IN-isha',\n 'en-US-riley',\n 'ko-KR-hwan',\n 'fr-FR-adélie',\n 'en-US-carter',\n 'en-UK-gabriel',\n 'en-UK-juliet',\n 'en-IN-arohi',\n 'fr-FR-maxime',\n 'de-DE-josephine',\n 'en-UK-hugo',\n 'en-US-samantha',\n 'de-DE-erna',\n 'zh-CN-baolin',\n 'pt-BR-isadora',\n 'it-IT-vincenzo',\n 'en-US-terrell',\n 'en-US-denzel',\n 'en-UK-heidi',\n 'en-US-miles',\n 'en-US-abigail',\n 'fr-FR-justine',\n 'it-IT-greta',\n 'en-AU-shane',\n 'en-UK-peter',\n 'nl-NL-famke',\n 'en-AU-ivy',\n 'nl-NL-dirk',\n 'fr-FR-axel',\n 'es-ES-carla',\n 'en-US-claire',\n 'ko-KR-jangmi',\n 'ko-KR-sanghoon',\n 'it-IT-vera',\n 'hi-IN-rahul',\n 'es-ES-elvira',\n 'es-ES-enrique',\n 'en-UK-aiden',\n 'en-US-ronnie',\n 'en-UK-amber',\n 'hi-IN-shweta',\n 'hi-IN-amit',\n 'en-AU-jimm',\n 'en-UK-pearl',\n 'pt-BR-benício',\n 'en-UK-freddie',\n 'en-US-ryan',\n 'pt-BR-eloa',\n 'en-US-charlotte',\n 'de-DE-lia',\n 'en-US-natalie',\n 'en-US-michelle',\n 'en-US-phoebe',\n 'es-ES-carmen',\n 'en-US-caleb',\n 'en-US-iris',\n 'en-UK-harrison',\n 'en-US-marcus',\n 'en-US-josie',\n 'en-US-daisy',\n 'en-US-charles',\n 'en-UK-reggie',\n 'en-US-julia',\n 'en-SCOTT-emily',\n 'en-US-dylan',\n 'es-MX-valeria',\n 'en-IN-eashwar',\n 'en-AU-evelyn',\n 'de-DE-lara',\n 'en-US-evander',\n 'en-SCOTT-rory',\n 'ta-IN-iniya',\n 'en-AU-leyton',\n 'fr-FR-louise',\n 'zh-CN-wei',\n 'ko-KR-gyeong',\n 'de-DE-matthias',\n 'en-IN-rohan',\n 'en-US-delilah',\n 'bn-IN-abhik',\n 'en-US-angela',\n 'en-US-naomi',\n 'es-MX-carlos',\n 'nl-NL-merel',\n 'en-US-alicia',\n 'en-IN-alia',\n 'zh-CN-jiao',\n 'en-US-june',\n 'en-AU-ashton',\n 'en-UK-finley',\n 'pl-PL-blazej',\n 'zh-CN-zhang',\n 'en-AU-kylie',\n 'en-US-jayden',\n 'en-IN-aarav',\n 'de-DE-björn',\n 'bn-IN-ishani',\n 'zh-CN-yuxan',\n 'fr-FR-louis',\n 'ko-KR-jong-su',\n 'en-AU-harper',\n 'en-UK-ruby',\n 'en-US-ken',\n 'ta-IN-mani',\n 'de-DE-ralf',\n 'en-UK-jaxon',\n 'en-US-river',\n 'en-IN-priya',\n 'en-UK-theo',\n 'en-UK-katie',\n 'pl-PL-jacek',\n 'it-IT-lorenzo',\n 'hi-IN-shaan',\n 'en-US-amara',\n 'en-UK-mason',\n 'en-IN-surya',\n 'en-US-finn',\n 'pt-BR-gustavo',\n 'hi-IN-kabir',\n 'es-ES-javier',\n 'en-AU-mitch',\n 'pt-BR-heitor',\n 'en-US-edmund',\n 'hi-IN-ayushi',\n 'pl-PL-kasia',\n 'es-MX-luisa',\n 'zh-CN-tao',\n 'en-US-molly',\n] as const;\n\nexport type MurfVoiceId = (typeof MURF_VOICES)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport ky from 'ky';\n\nimport { MURF_VOICES } from './voices';\nimport type { MurfVoiceId } from './voices';\n\ntype MurfConfig = {\n name: 'GEN1' | 'GEN2';\n apiKey?: string;\n properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n};\n\ntype SpeechCreateParams = {\n voiceId: MurfVoiceId;\n text: string;\n modelVersion: 'GEN1' | 'GEN2';\n style?: string;\n rate?: number;\n pitch?: number;\n sampleRate?: 8000 | 24000 | 44100 | 48000;\n format?: 'MP3' | 'WAV' | 'FLAC' | 'ALAW' | 'ULAW';\n channelType?: 'STEREO' | 'MONO';\n pronunciationDictionary?: Record<string, string>;\n encodeAsBase64?: boolean;\n variation?: number;\n audioDuration?: number;\n multiNativeLocale?: string;\n};\n\ntype SpeechCreateResponse = {\n audioFile: string;\n audioLengthInSeconds: number;\n consumedCharacterCount: number;\n encodedAudio: string;\n remainingCharacterCount: number;\n warning: string;\n wordDurations: {\n endMs: number;\n pitchScaleMaximum: number;\n pitchScaleMinimum: number;\n sourceWordIndex: number;\n startMs: number;\n word: string;\n }[];\n};\n\nexport class MurfVoice extends MastraVoice {\n private client: typeof ky;\n private defaultVoice: MurfVoiceId;\n private properties: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n\n constructor({ speechModel, speaker }: { speechModel?: MurfConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'GEN2',\n apiKey: speechModel?.apiKey ?? process.env.MURF_API_KEY,\n },\n speaker: speaker ?? MURF_VOICES[0],\n });\n\n const apiKey = this.speechModel?.apiKey;\n if (!apiKey) {\n throw new Error('MURF_API_KEY is not set');\n }\n\n this.properties = {\n ...speechModel?.properties,\n };\n\n this.client = ky.create({\n prefixUrl: 'https://api.murf.ai',\n headers: {\n 'api-key': apiKey,\n },\n });\n\n this.defaultVoice = (speaker as MurfVoiceId) ?? MURF_VOICES[0];\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(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: string; properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'> },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const response = await this.client\n .post('v1/speech/generate', {\n json: {\n voiceId: (options?.speaker || this.defaultVoice) as MurfVoiceId,\n text,\n modelVersion: this.speechModel?.name,\n ...this.properties,\n ...options?.properties,\n },\n })\n .json<SpeechCreateResponse>();\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Get the audio file as a stream\n const audioResponse = await fetch(response.audioFile);\n if (!audioResponse.body) {\n throw new Error('No response body received');\n }\n\n // Process the stream\n const reader = audioResponse.body.getReader();\n (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 })().catch(error => {\n stream.destroy(error as Error);\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('Murf does not support speech recognition');\n }\n\n async getSpeakers() {\n return MURF_VOICES.map(voice => ({\n voiceId: voice,\n name: voice,\n language: voice.split('-')[0],\n gender: 'neutral',\n }));\n }\n}\n\nexport type { MurfConfig, MurfVoiceId };\n"]}
1
+ {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":["MastraVoice","stream","PassThrough"],"mappings":";;;;;;;;AAGO,IAAM,WAAA,GAAc;AAAA,EACzB,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,iBAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,WAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA;;;AChGA,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,kBAAA,mBAAqB,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC,CAAA;AACtE,IAAM,cAAA,GAAiB,GAAA;AAEhB,IAAM,SAAA,GAAN,cAAwBA,iBAAA,CAAY;AAAA,EACjC,OAAA,GAAU,qBAAA;AAAA,EACV,MAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EAER,YAAY,EAAE,WAAA,EAAa,OAAA,EAAQ,GAAoD,EAAC,EAAG;AACzF,IAAA,KAAA,CAAM;AAAA,MACJ,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,aAAa,IAAA,IAAQ,MAAA;AAAA,QAC3B,MAAA,EAAQ,WAAA,EAAa,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI;AAAA,OAC7C;AAAA,MACA,OAAA,EAAS,OAAA,IAAW,WAAA,CAAY,CAAC;AAAA,KAClC,CAAA;AAED,IAAA,MAAM,MAAA,GAAS,KAAK,WAAA,EAAa,MAAA;AACjC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,yBAAyB,CAAA;AAAA,IAC3C;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAA,CAAK,UAAA,GAAa;AAAA,MAChB,GAAG,WAAA,EAAa;AAAA,KAClB;AAEA,IAAA,IAAA,CAAK,YAAA,GAAgB,OAAA,IAA2B,WAAA,CAAY,CAAC,CAAA;AAAA,EAC/D;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,CACJ,KAAA,EACA,OAAA,EACgC;AAChC,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,KAAU,QAAA,GAAW,QAAQ,MAAM,IAAA,CAAK,eAAe,KAAK,CAAA;AAEhF,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAkC,qBAAA,EAAuB;AAAA,MACnF,OAAA,EAAU,OAAA,EAAS,OAAA,IAAW,IAAA,CAAK,YAAA;AAAA,MACnC,IAAA;AAAA,MACA,YAAA,EAAc,KAAK,WAAA,EAAa,IAAA;AAAA,MAChC,GAAG,IAAA,CAAK,UAAA;AAAA,MACR,GAAG,OAAA,EAAS;AAAA,KACb,CAAA;AAGD,IAAA,MAAMC,QAAA,GAAS,IAAIC,kBAAA,EAAY;AAG/B,IAAA,MAAM,aAAA,GAAgB,MAAM,KAAA,CAAM,QAAA,CAAS,SAAS,CAAA;AACpD,IAAA,IAAI,CAAC,cAAc,IAAA,EAAM;AACvB,MAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,IAC7C;AAGA,IAAA,MAAM,MAAA,GAAS,aAAA,CAAc,IAAA,CAAK,SAAA,EAAU;AAC5C,IAAA,CAAC,YAAY;AACX,MAAA,IAAI;AACF,QAAA,OAAO,IAAA,EAAM;AACX,UAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,UAAA,IAAI,IAAA,EAAM;AACR,YAAAD,QAAA,CAAO,GAAA,EAAI;AACX,YAAA;AAAA,UACF;AACA,UAAAA,QAAA,CAAO,MAAM,KAAK,CAAA;AAAA,QACpB;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAAA,QAAA,CAAO,QAAQ,KAAc,CAAA;AAAA,MAC/B;AAAA,IACF,CAAA,GAAG,CAAE,KAAA,CAAM,CAAA,KAAA,KAAS;AAClB,MAAAA,QAAA,CAAO,QAAQ,KAAc,CAAA;AAAA,IAC/B,CAAC,CAAA;AAED,IAAA,OAAOA,QAAA;AAAA,EACT;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,0CAA0C,CAAA;AAAA,EAC5D;AAAA,EAEA,MAAc,WAAA,CAAe,QAAA,EAAkB,OAAA,EAA8C;AAC3F,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,mBAAA,EAAqB,OAAA,EAAA,EAAW;AAC/D,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,MAAM,IAAI,QAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,SAAS,cAAA,GAAiB,CAAA,KAAM,OAAA,GAAU,CAAA,CAAE,CAAC,CAAA;AAAA,MACvF;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI;AAAA,QACpD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,WAAW,IAAA,CAAK,MAAA;AAAA,UAChB,cAAA,EAAgB;AAAA,SAClB;AAAA,QACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,OAC7B,CAAA;AAED,MAAA,IAAI,IAAI,EAAA,EAAI;AACV,QAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,MACzB;AAEA,MAAA,IAAI,CAAC,kBAAA,CAAmB,GAAA,CAAI,IAAI,MAAM,CAAA,IAAK,YAAY,mBAAA,EAAqB;AAC1E,QAAA,IAAI,YAAA;AACJ,QAAA,IAAI;AACF,UAAA,MAAM,KAAA,GAAS,MAAM,GAAA,CAAI,IAAA,EAAK;AAC9B,UAAA,YAAA,GAAe,KAAA,CAAM,WAAW,GAAA,CAAI,UAAA;AAAA,QACtC,CAAA,CAAA,MAAQ;AACN,UAAA,YAAA,GAAe,GAAA,CAAI,UAAA;AAAA,QACrB;AACA,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,YAAY,CAAA,CAAE,CAAA;AAAA,MACnD;AAEA,MAAA,SAAA,GAAY,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,SAAA,IAAa,IAAI,KAAA,CAAM,gCAAgC,CAAA;AAAA,EAC/D;AAAA,EAEA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,WAAA,CAAY,IAAI,CAAA,KAAA,MAAU;AAAA,MAC/B,OAAA,EAAS,KAAA;AAAA,MACT,IAAA,EAAM,KAAA;AAAA,MACN,QAAA,EAAU,KAAA,CAAM,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AAAA,MAC5B,MAAA,EAAQ;AAAA,KACV,CAAE,CAAA;AAAA,EACJ;AACF","file":"index.cjs","sourcesContent":["/**\n * List of available voices for Murf TTS\n */\nexport const MURF_VOICES = [\n 'en-UK-hazel',\n 'en-US-cooper',\n 'en-US-imani',\n 'it-IT-giorgio',\n 'en-US-wayne',\n 'en-IN-shivani',\n 'en-US-daniel',\n 'bn-IN-anwesha',\n 'es-MX-alejandro',\n 'en-AU-joyce',\n 'en-US-zion',\n 'en-IN-isha',\n 'en-US-riley',\n 'ko-KR-hwan',\n 'fr-FR-adélie',\n 'en-US-carter',\n 'en-UK-gabriel',\n 'en-UK-juliet',\n 'en-IN-arohi',\n 'fr-FR-maxime',\n 'de-DE-josephine',\n 'en-UK-hugo',\n 'en-US-samantha',\n 'de-DE-erna',\n 'zh-CN-baolin',\n 'pt-BR-isadora',\n 'it-IT-vincenzo',\n 'en-US-terrell',\n 'en-US-denzel',\n 'en-UK-heidi',\n 'en-US-miles',\n 'en-US-abigail',\n 'fr-FR-justine',\n 'it-IT-greta',\n 'en-AU-shane',\n 'en-UK-peter',\n 'nl-NL-famke',\n 'en-AU-ivy',\n 'nl-NL-dirk',\n 'fr-FR-axel',\n 'es-ES-carla',\n 'en-US-claire',\n 'ko-KR-jangmi',\n 'ko-KR-sanghoon',\n 'it-IT-vera',\n 'hi-IN-rahul',\n 'es-ES-elvira',\n 'es-ES-enrique',\n 'en-UK-aiden',\n 'en-US-ronnie',\n 'en-UK-amber',\n 'hi-IN-shweta',\n 'hi-IN-amit',\n 'en-AU-jimm',\n 'en-UK-pearl',\n 'pt-BR-benício',\n 'en-UK-freddie',\n 'en-US-ryan',\n 'pt-BR-eloa',\n 'en-US-charlotte',\n 'de-DE-lia',\n 'en-US-natalie',\n 'en-US-michelle',\n 'en-US-phoebe',\n 'es-ES-carmen',\n 'en-US-caleb',\n 'en-US-iris',\n 'en-UK-harrison',\n 'en-US-marcus',\n 'en-US-josie',\n 'en-US-daisy',\n 'en-US-charles',\n 'en-UK-reggie',\n 'en-US-julia',\n 'en-SCOTT-emily',\n 'en-US-dylan',\n 'es-MX-valeria',\n 'en-IN-eashwar',\n 'en-AU-evelyn',\n 'de-DE-lara',\n 'en-US-evander',\n 'en-SCOTT-rory',\n 'ta-IN-iniya',\n 'en-AU-leyton',\n 'fr-FR-louise',\n 'zh-CN-wei',\n 'ko-KR-gyeong',\n 'de-DE-matthias',\n 'en-IN-rohan',\n 'en-US-delilah',\n 'bn-IN-abhik',\n 'en-US-angela',\n 'en-US-naomi',\n 'es-MX-carlos',\n 'nl-NL-merel',\n 'en-US-alicia',\n 'en-IN-alia',\n 'zh-CN-jiao',\n 'en-US-june',\n 'en-AU-ashton',\n 'en-UK-finley',\n 'pl-PL-blazej',\n 'zh-CN-zhang',\n 'en-AU-kylie',\n 'en-US-jayden',\n 'en-IN-aarav',\n 'de-DE-björn',\n 'bn-IN-ishani',\n 'zh-CN-yuxan',\n 'fr-FR-louis',\n 'ko-KR-jong-su',\n 'en-AU-harper',\n 'en-UK-ruby',\n 'en-US-ken',\n 'ta-IN-mani',\n 'de-DE-ralf',\n 'en-UK-jaxon',\n 'en-US-river',\n 'en-IN-priya',\n 'en-UK-theo',\n 'en-UK-katie',\n 'pl-PL-jacek',\n 'it-IT-lorenzo',\n 'hi-IN-shaan',\n 'en-US-amara',\n 'en-UK-mason',\n 'en-IN-surya',\n 'en-US-finn',\n 'pt-BR-gustavo',\n 'hi-IN-kabir',\n 'es-ES-javier',\n 'en-AU-mitch',\n 'pt-BR-heitor',\n 'en-US-edmund',\n 'hi-IN-ayushi',\n 'pl-PL-kasia',\n 'es-MX-luisa',\n 'zh-CN-tao',\n 'en-US-molly',\n] as const;\n\nexport type MurfVoiceId = (typeof MURF_VOICES)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\n\nimport { MURF_VOICES } from './voices';\nimport type { MurfVoiceId } from './voices';\n\ntype MurfConfig = {\n name: 'GEN1' | 'GEN2';\n apiKey?: string;\n properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n};\n\ntype SpeechCreateParams = {\n voiceId: MurfVoiceId;\n text: string;\n modelVersion: 'GEN1' | 'GEN2';\n style?: string;\n rate?: number;\n pitch?: number;\n sampleRate?: 8000 | 24000 | 44100 | 48000;\n format?: 'MP3' | 'WAV' | 'FLAC' | 'ALAW' | 'ULAW';\n channelType?: 'STEREO' | 'MONO';\n pronunciationDictionary?: Record<string, string>;\n encodeAsBase64?: boolean;\n variation?: number;\n audioDuration?: number;\n multiNativeLocale?: string;\n};\n\ntype SpeechCreateResponse = {\n audioFile: string;\n audioLengthInSeconds: number;\n consumedCharacterCount: number;\n encodedAudio: string;\n remainingCharacterCount: number;\n warning: string;\n wordDurations: {\n endMs: number;\n pitchScaleMaximum: number;\n pitchScaleMinimum: number;\n sourceWordIndex: number;\n startMs: number;\n word: string;\n }[];\n};\n\nconst DEFAULT_RETRY_COUNT = 2;\nconst RETRY_STATUS_CODES = new Set([408, 413, 429, 500, 502, 503, 504]);\nconst RETRY_DELAY_MS = 300;\n\nexport class MurfVoice extends MastraVoice {\n private baseUrl = 'https://api.murf.ai';\n private apiKey: string;\n private defaultVoice: MurfVoiceId;\n private properties: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n\n constructor({ speechModel, speaker }: { speechModel?: MurfConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'GEN2',\n apiKey: speechModel?.apiKey ?? process.env.MURF_API_KEY,\n },\n speaker: speaker ?? MURF_VOICES[0],\n });\n\n const apiKey = this.speechModel?.apiKey;\n if (!apiKey) {\n throw new Error('MURF_API_KEY is not set');\n }\n\n this.apiKey = apiKey;\n\n this.properties = {\n ...speechModel?.properties,\n };\n\n this.defaultVoice = (speaker as MurfVoiceId) ?? MURF_VOICES[0];\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(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: string; properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'> },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const response = await this.makeRequest<SpeechCreateResponse>('/v1/speech/generate', {\n voiceId: (options?.speaker || this.defaultVoice) as MurfVoiceId,\n text,\n modelVersion: this.speechModel?.name,\n ...this.properties,\n ...options?.properties,\n });\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Get the audio file as a stream\n const audioResponse = await fetch(response.audioFile);\n if (!audioResponse.body) {\n throw new Error('No response body received');\n }\n\n // Process the stream\n const reader = audioResponse.body.getReader();\n (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 })().catch(error => {\n stream.destroy(error as Error);\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('Murf does not support speech recognition');\n }\n\n private async makeRequest<T>(endpoint: string, payload: Record<string, unknown>): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= DEFAULT_RETRY_COUNT; attempt++) {\n if (attempt > 0) {\n await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n\n const res = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (res.ok) {\n return (await res.json()) as T;\n }\n\n if (!RETRY_STATUS_CODES.has(res.status) || attempt === DEFAULT_RETRY_COUNT) {\n let errorMessage: string;\n try {\n const error = (await res.json()) as { message?: string };\n errorMessage = error.message || res.statusText;\n } catch {\n errorMessage = res.statusText;\n }\n throw new Error(`Murf API Error: ${errorMessage}`);\n }\n\n lastError = new Error(`Murf API Error: ${res.statusText}`);\n }\n\n throw lastError ?? new Error('Murf API Error: request failed');\n }\n\n async getSpeakers() {\n return MURF_VOICES.map(voice => ({\n voiceId: voice,\n name: voice,\n language: voice.split('-')[0],\n gender: 'neutral',\n }));\n }\n}\n\nexport type { MurfConfig, MurfVoiceId };\n"]}
package/dist/index.d.ts CHANGED
@@ -22,7 +22,8 @@ type SpeechCreateParams = {
22
22
  multiNativeLocale?: string;
23
23
  };
24
24
  export declare class MurfVoice extends MastraVoice {
25
- private client;
25
+ private baseUrl;
26
+ private apiKey;
26
27
  private defaultVoice;
27
28
  private properties;
28
29
  constructor({ speechModel, speaker }?: {
@@ -43,6 +44,7 @@ export declare class MurfVoice extends MastraVoice {
43
44
  enabled: boolean;
44
45
  }>;
45
46
  listen(_input: NodeJS.ReadableStream, _options?: Record<string, unknown>): Promise<string | NodeJS.ReadableStream>;
47
+ private makeRequest;
46
48
  getSpeakers(): Promise<{
47
49
  voiceId: "en-UK-hazel" | "en-US-cooper" | "en-US-imani" | "it-IT-giorgio" | "en-US-wayne" | "en-IN-shivani" | "en-US-daniel" | "bn-IN-anwesha" | "es-MX-alejandro" | "en-AU-joyce" | "en-US-zion" | "en-IN-isha" | "en-US-riley" | "ko-KR-hwan" | "fr-FR-adélie" | "en-US-carter" | "en-UK-gabriel" | "en-UK-juliet" | "en-IN-arohi" | "fr-FR-maxime" | "de-DE-josephine" | "en-UK-hugo" | "en-US-samantha" | "de-DE-erna" | "zh-CN-baolin" | "pt-BR-isadora" | "it-IT-vincenzo" | "en-US-terrell" | "en-US-denzel" | "en-UK-heidi" | "en-US-miles" | "en-US-abigail" | "fr-FR-justine" | "it-IT-greta" | "en-AU-shane" | "en-UK-peter" | "nl-NL-famke" | "en-AU-ivy" | "nl-NL-dirk" | "fr-FR-axel" | "es-ES-carla" | "en-US-claire" | "ko-KR-jangmi" | "ko-KR-sanghoon" | "it-IT-vera" | "hi-IN-rahul" | "es-ES-elvira" | "es-ES-enrique" | "en-UK-aiden" | "en-US-ronnie" | "en-UK-amber" | "hi-IN-shweta" | "hi-IN-amit" | "en-AU-jimm" | "en-UK-pearl" | "pt-BR-benício" | "en-UK-freddie" | "en-US-ryan" | "pt-BR-eloa" | "en-US-charlotte" | "de-DE-lia" | "en-US-natalie" | "en-US-michelle" | "en-US-phoebe" | "es-ES-carmen" | "en-US-caleb" | "en-US-iris" | "en-UK-harrison" | "en-US-marcus" | "en-US-josie" | "en-US-daisy" | "en-US-charles" | "en-UK-reggie" | "en-US-julia" | "en-SCOTT-emily" | "en-US-dylan" | "es-MX-valeria" | "en-IN-eashwar" | "en-AU-evelyn" | "de-DE-lara" | "en-US-evander" | "en-SCOTT-rory" | "ta-IN-iniya" | "en-AU-leyton" | "fr-FR-louise" | "zh-CN-wei" | "ko-KR-gyeong" | "de-DE-matthias" | "en-IN-rohan" | "en-US-delilah" | "bn-IN-abhik" | "en-US-angela" | "en-US-naomi" | "es-MX-carlos" | "nl-NL-merel" | "en-US-alicia" | "en-IN-alia" | "zh-CN-jiao" | "en-US-june" | "en-AU-ashton" | "en-UK-finley" | "pl-PL-blazej" | "zh-CN-zhang" | "en-AU-kylie" | "en-US-jayden" | "en-IN-aarav" | "de-DE-björn" | "bn-IN-ishani" | "zh-CN-yuxan" | "fr-FR-louis" | "ko-KR-jong-su" | "en-AU-harper" | "en-UK-ruby" | "en-US-ken" | "ta-IN-mani" | "de-DE-ralf" | "en-UK-jaxon" | "en-US-river" | "en-IN-priya" | "en-UK-theo" | "en-UK-katie" | "pl-PL-jacek" | "it-IT-lorenzo" | "hi-IN-shaan" | "en-US-amara" | "en-UK-mason" | "en-IN-surya" | "en-US-finn" | "pt-BR-gustavo" | "hi-IN-kabir" | "es-ES-javier" | "en-AU-mitch" | "pt-BR-heitor" | "en-US-edmund" | "hi-IN-ayushi" | "pl-PL-kasia" | "es-MX-luisa" | "zh-CN-tao" | "en-US-molly";
48
50
  name: "en-UK-hazel" | "en-US-cooper" | "en-US-imani" | "it-IT-giorgio" | "en-US-wayne" | "en-IN-shivani" | "en-US-daniel" | "bn-IN-anwesha" | "es-MX-alejandro" | "en-AU-joyce" | "en-US-zion" | "en-IN-isha" | "en-US-riley" | "ko-KR-hwan" | "fr-FR-adélie" | "en-US-carter" | "en-UK-gabriel" | "en-UK-juliet" | "en-IN-arohi" | "fr-FR-maxime" | "de-DE-josephine" | "en-UK-hugo" | "en-US-samantha" | "de-DE-erna" | "zh-CN-baolin" | "pt-BR-isadora" | "it-IT-vincenzo" | "en-US-terrell" | "en-US-denzel" | "en-UK-heidi" | "en-US-miles" | "en-US-abigail" | "fr-FR-justine" | "it-IT-greta" | "en-AU-shane" | "en-UK-peter" | "nl-NL-famke" | "en-AU-ivy" | "nl-NL-dirk" | "fr-FR-axel" | "es-ES-carla" | "en-US-claire" | "ko-KR-jangmi" | "ko-KR-sanghoon" | "it-IT-vera" | "hi-IN-rahul" | "es-ES-elvira" | "es-ES-enrique" | "en-UK-aiden" | "en-US-ronnie" | "en-UK-amber" | "hi-IN-shweta" | "hi-IN-amit" | "en-AU-jimm" | "en-UK-pearl" | "pt-BR-benício" | "en-UK-freddie" | "en-US-ryan" | "pt-BR-eloa" | "en-US-charlotte" | "de-DE-lia" | "en-US-natalie" | "en-US-michelle" | "en-US-phoebe" | "es-ES-carmen" | "en-US-caleb" | "en-US-iris" | "en-UK-harrison" | "en-US-marcus" | "en-US-josie" | "en-US-daisy" | "en-US-charles" | "en-UK-reggie" | "en-US-julia" | "en-SCOTT-emily" | "en-US-dylan" | "es-MX-valeria" | "en-IN-eashwar" | "en-AU-evelyn" | "de-DE-lara" | "en-US-evander" | "en-SCOTT-rory" | "ta-IN-iniya" | "en-AU-leyton" | "fr-FR-louise" | "zh-CN-wei" | "ko-KR-gyeong" | "de-DE-matthias" | "en-IN-rohan" | "en-US-delilah" | "bn-IN-abhik" | "en-US-angela" | "en-US-naomi" | "es-MX-carlos" | "nl-NL-merel" | "en-US-alicia" | "en-IN-alia" | "zh-CN-jiao" | "en-US-june" | "en-AU-ashton" | "en-UK-finley" | "pl-PL-blazej" | "zh-CN-zhang" | "en-AU-kylie" | "en-US-jayden" | "en-IN-aarav" | "de-DE-björn" | "bn-IN-ishani" | "zh-CN-yuxan" | "fr-FR-louis" | "ko-KR-jong-su" | "en-AU-harper" | "en-UK-ruby" | "en-US-ken" | "ta-IN-mani" | "de-DE-ralf" | "en-UK-jaxon" | "en-US-river" | "en-IN-priya" | "en-UK-theo" | "en-UK-katie" | "pl-PL-jacek" | "it-IT-lorenzo" | "hi-IN-shaan" | "en-US-amara" | "en-UK-mason" | "en-IN-surya" | "en-US-finn" | "pt-BR-gustavo" | "hi-IN-kabir" | "es-ES-javier" | "en-AU-mitch" | "pt-BR-heitor" | "en-US-edmund" | "hi-IN-ayushi" | "pl-PL-kasia" | "es-MX-luisa" | "zh-CN-tao" | "en-US-molly";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;CAC5E,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAC1C,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClD,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAmBF,qBAAa,SAAU,SAAQ,WAAW;IACxC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,UAAU,CAAgE;gBAEtE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAE;QAAE,WAAW,CAAC,EAAE,UAAU,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;YA4B3E,cAAc;IAYtB,KAAK,CACT,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EACrC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC,CAAA;KAAE,GACzG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IA8CjC;;;;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;;;;;;CAQlB;AAED,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;CAC5E,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAC1C,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClD,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAuBF,qBAAa,SAAU,SAAQ,WAAW;IACxC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,UAAU,CAAgE;gBAEtE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAE;QAAE,WAAW,CAAC,EAAE,UAAU,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;YAuB3E,cAAc;IAYtB,KAAK,CACT,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,EACrC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC,CAAA;KAAE,GACzG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IA0CjC;;;;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;YAI5B,WAAW;IAsCnB,WAAW;;;;;;CAQlB;AAED,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { PassThrough } from 'stream';
2
2
  import { MastraVoice } from '@mastra/core/voice';
3
- import ky from 'ky';
4
3
 
5
4
  // src/index.ts
6
5
 
@@ -148,8 +147,12 @@ var MURF_VOICES = [
148
147
  ];
149
148
 
150
149
  // src/index.ts
150
+ var DEFAULT_RETRY_COUNT = 2;
151
+ var RETRY_STATUS_CODES = /* @__PURE__ */ new Set([408, 413, 429, 500, 502, 503, 504]);
152
+ var RETRY_DELAY_MS = 300;
151
153
  var MurfVoice = class extends MastraVoice {
152
- client;
154
+ baseUrl = "https://api.murf.ai";
155
+ apiKey;
153
156
  defaultVoice;
154
157
  properties;
155
158
  constructor({ speechModel, speaker } = {}) {
@@ -164,15 +167,10 @@ var MurfVoice = class extends MastraVoice {
164
167
  if (!apiKey) {
165
168
  throw new Error("MURF_API_KEY is not set");
166
169
  }
170
+ this.apiKey = apiKey;
167
171
  this.properties = {
168
172
  ...speechModel?.properties
169
173
  };
170
- this.client = ky.create({
171
- prefixUrl: "https://api.murf.ai",
172
- headers: {
173
- "api-key": apiKey
174
- }
175
- });
176
174
  this.defaultVoice = speaker ?? MURF_VOICES[0];
177
175
  }
178
176
  async streamToString(stream) {
@@ -188,15 +186,13 @@ var MurfVoice = class extends MastraVoice {
188
186
  }
189
187
  async speak(input, options) {
190
188
  const text = typeof input === "string" ? input : await this.streamToString(input);
191
- const response = await this.client.post("v1/speech/generate", {
192
- json: {
193
- voiceId: options?.speaker || this.defaultVoice,
194
- text,
195
- modelVersion: this.speechModel?.name,
196
- ...this.properties,
197
- ...options?.properties
198
- }
199
- }).json();
189
+ const response = await this.makeRequest("/v1/speech/generate", {
190
+ voiceId: options?.speaker || this.defaultVoice,
191
+ text,
192
+ modelVersion: this.speechModel?.name,
193
+ ...this.properties,
194
+ ...options?.properties
195
+ });
200
196
  const stream = new PassThrough();
201
197
  const audioResponse = await fetch(response.audioFile);
202
198
  if (!audioResponse.body) {
@@ -232,6 +228,37 @@ var MurfVoice = class extends MastraVoice {
232
228
  async listen(_input, _options) {
233
229
  throw new Error("Murf does not support speech recognition");
234
230
  }
231
+ async makeRequest(endpoint, payload) {
232
+ let lastError;
233
+ for (let attempt = 0; attempt <= DEFAULT_RETRY_COUNT; attempt++) {
234
+ if (attempt > 0) {
235
+ await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * 2 ** (attempt - 1)));
236
+ }
237
+ const res = await fetch(`${this.baseUrl}${endpoint}`, {
238
+ method: "POST",
239
+ headers: {
240
+ "api-key": this.apiKey,
241
+ "Content-Type": "application/json"
242
+ },
243
+ body: JSON.stringify(payload)
244
+ });
245
+ if (res.ok) {
246
+ return await res.json();
247
+ }
248
+ if (!RETRY_STATUS_CODES.has(res.status) || attempt === DEFAULT_RETRY_COUNT) {
249
+ let errorMessage;
250
+ try {
251
+ const error = await res.json();
252
+ errorMessage = error.message || res.statusText;
253
+ } catch {
254
+ errorMessage = res.statusText;
255
+ }
256
+ throw new Error(`Murf API Error: ${errorMessage}`);
257
+ }
258
+ lastError = new Error(`Murf API Error: ${res.statusText}`);
259
+ }
260
+ throw lastError ?? new Error("Murf API Error: request failed");
261
+ }
235
262
  async getSpeakers() {
236
263
  return MURF_VOICES.map((voice) => ({
237
264
  voiceId: voice,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * List of available voices for Murf TTS\n */\nexport const MURF_VOICES = [\n 'en-UK-hazel',\n 'en-US-cooper',\n 'en-US-imani',\n 'it-IT-giorgio',\n 'en-US-wayne',\n 'en-IN-shivani',\n 'en-US-daniel',\n 'bn-IN-anwesha',\n 'es-MX-alejandro',\n 'en-AU-joyce',\n 'en-US-zion',\n 'en-IN-isha',\n 'en-US-riley',\n 'ko-KR-hwan',\n 'fr-FR-adélie',\n 'en-US-carter',\n 'en-UK-gabriel',\n 'en-UK-juliet',\n 'en-IN-arohi',\n 'fr-FR-maxime',\n 'de-DE-josephine',\n 'en-UK-hugo',\n 'en-US-samantha',\n 'de-DE-erna',\n 'zh-CN-baolin',\n 'pt-BR-isadora',\n 'it-IT-vincenzo',\n 'en-US-terrell',\n 'en-US-denzel',\n 'en-UK-heidi',\n 'en-US-miles',\n 'en-US-abigail',\n 'fr-FR-justine',\n 'it-IT-greta',\n 'en-AU-shane',\n 'en-UK-peter',\n 'nl-NL-famke',\n 'en-AU-ivy',\n 'nl-NL-dirk',\n 'fr-FR-axel',\n 'es-ES-carla',\n 'en-US-claire',\n 'ko-KR-jangmi',\n 'ko-KR-sanghoon',\n 'it-IT-vera',\n 'hi-IN-rahul',\n 'es-ES-elvira',\n 'es-ES-enrique',\n 'en-UK-aiden',\n 'en-US-ronnie',\n 'en-UK-amber',\n 'hi-IN-shweta',\n 'hi-IN-amit',\n 'en-AU-jimm',\n 'en-UK-pearl',\n 'pt-BR-benício',\n 'en-UK-freddie',\n 'en-US-ryan',\n 'pt-BR-eloa',\n 'en-US-charlotte',\n 'de-DE-lia',\n 'en-US-natalie',\n 'en-US-michelle',\n 'en-US-phoebe',\n 'es-ES-carmen',\n 'en-US-caleb',\n 'en-US-iris',\n 'en-UK-harrison',\n 'en-US-marcus',\n 'en-US-josie',\n 'en-US-daisy',\n 'en-US-charles',\n 'en-UK-reggie',\n 'en-US-julia',\n 'en-SCOTT-emily',\n 'en-US-dylan',\n 'es-MX-valeria',\n 'en-IN-eashwar',\n 'en-AU-evelyn',\n 'de-DE-lara',\n 'en-US-evander',\n 'en-SCOTT-rory',\n 'ta-IN-iniya',\n 'en-AU-leyton',\n 'fr-FR-louise',\n 'zh-CN-wei',\n 'ko-KR-gyeong',\n 'de-DE-matthias',\n 'en-IN-rohan',\n 'en-US-delilah',\n 'bn-IN-abhik',\n 'en-US-angela',\n 'en-US-naomi',\n 'es-MX-carlos',\n 'nl-NL-merel',\n 'en-US-alicia',\n 'en-IN-alia',\n 'zh-CN-jiao',\n 'en-US-june',\n 'en-AU-ashton',\n 'en-UK-finley',\n 'pl-PL-blazej',\n 'zh-CN-zhang',\n 'en-AU-kylie',\n 'en-US-jayden',\n 'en-IN-aarav',\n 'de-DE-björn',\n 'bn-IN-ishani',\n 'zh-CN-yuxan',\n 'fr-FR-louis',\n 'ko-KR-jong-su',\n 'en-AU-harper',\n 'en-UK-ruby',\n 'en-US-ken',\n 'ta-IN-mani',\n 'de-DE-ralf',\n 'en-UK-jaxon',\n 'en-US-river',\n 'en-IN-priya',\n 'en-UK-theo',\n 'en-UK-katie',\n 'pl-PL-jacek',\n 'it-IT-lorenzo',\n 'hi-IN-shaan',\n 'en-US-amara',\n 'en-UK-mason',\n 'en-IN-surya',\n 'en-US-finn',\n 'pt-BR-gustavo',\n 'hi-IN-kabir',\n 'es-ES-javier',\n 'en-AU-mitch',\n 'pt-BR-heitor',\n 'en-US-edmund',\n 'hi-IN-ayushi',\n 'pl-PL-kasia',\n 'es-MX-luisa',\n 'zh-CN-tao',\n 'en-US-molly',\n] as const;\n\nexport type MurfVoiceId = (typeof MURF_VOICES)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport ky from 'ky';\n\nimport { MURF_VOICES } from './voices';\nimport type { MurfVoiceId } from './voices';\n\ntype MurfConfig = {\n name: 'GEN1' | 'GEN2';\n apiKey?: string;\n properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n};\n\ntype SpeechCreateParams = {\n voiceId: MurfVoiceId;\n text: string;\n modelVersion: 'GEN1' | 'GEN2';\n style?: string;\n rate?: number;\n pitch?: number;\n sampleRate?: 8000 | 24000 | 44100 | 48000;\n format?: 'MP3' | 'WAV' | 'FLAC' | 'ALAW' | 'ULAW';\n channelType?: 'STEREO' | 'MONO';\n pronunciationDictionary?: Record<string, string>;\n encodeAsBase64?: boolean;\n variation?: number;\n audioDuration?: number;\n multiNativeLocale?: string;\n};\n\ntype SpeechCreateResponse = {\n audioFile: string;\n audioLengthInSeconds: number;\n consumedCharacterCount: number;\n encodedAudio: string;\n remainingCharacterCount: number;\n warning: string;\n wordDurations: {\n endMs: number;\n pitchScaleMaximum: number;\n pitchScaleMinimum: number;\n sourceWordIndex: number;\n startMs: number;\n word: string;\n }[];\n};\n\nexport class MurfVoice extends MastraVoice {\n private client: typeof ky;\n private defaultVoice: MurfVoiceId;\n private properties: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n\n constructor({ speechModel, speaker }: { speechModel?: MurfConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'GEN2',\n apiKey: speechModel?.apiKey ?? process.env.MURF_API_KEY,\n },\n speaker: speaker ?? MURF_VOICES[0],\n });\n\n const apiKey = this.speechModel?.apiKey;\n if (!apiKey) {\n throw new Error('MURF_API_KEY is not set');\n }\n\n this.properties = {\n ...speechModel?.properties,\n };\n\n this.client = ky.create({\n prefixUrl: 'https://api.murf.ai',\n headers: {\n 'api-key': apiKey,\n },\n });\n\n this.defaultVoice = (speaker as MurfVoiceId) ?? MURF_VOICES[0];\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(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: string; properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'> },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const response = await this.client\n .post('v1/speech/generate', {\n json: {\n voiceId: (options?.speaker || this.defaultVoice) as MurfVoiceId,\n text,\n modelVersion: this.speechModel?.name,\n ...this.properties,\n ...options?.properties,\n },\n })\n .json<SpeechCreateResponse>();\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Get the audio file as a stream\n const audioResponse = await fetch(response.audioFile);\n if (!audioResponse.body) {\n throw new Error('No response body received');\n }\n\n // Process the stream\n const reader = audioResponse.body.getReader();\n (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 })().catch(error => {\n stream.destroy(error as Error);\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('Murf does not support speech recognition');\n }\n\n async getSpeakers() {\n return MURF_VOICES.map(voice => ({\n voiceId: voice,\n name: voice,\n language: voice.split('-')[0],\n gender: 'neutral',\n }));\n }\n}\n\nexport type { MurfConfig, MurfVoiceId };\n"]}
1
+ {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * List of available voices for Murf TTS\n */\nexport const MURF_VOICES = [\n 'en-UK-hazel',\n 'en-US-cooper',\n 'en-US-imani',\n 'it-IT-giorgio',\n 'en-US-wayne',\n 'en-IN-shivani',\n 'en-US-daniel',\n 'bn-IN-anwesha',\n 'es-MX-alejandro',\n 'en-AU-joyce',\n 'en-US-zion',\n 'en-IN-isha',\n 'en-US-riley',\n 'ko-KR-hwan',\n 'fr-FR-adélie',\n 'en-US-carter',\n 'en-UK-gabriel',\n 'en-UK-juliet',\n 'en-IN-arohi',\n 'fr-FR-maxime',\n 'de-DE-josephine',\n 'en-UK-hugo',\n 'en-US-samantha',\n 'de-DE-erna',\n 'zh-CN-baolin',\n 'pt-BR-isadora',\n 'it-IT-vincenzo',\n 'en-US-terrell',\n 'en-US-denzel',\n 'en-UK-heidi',\n 'en-US-miles',\n 'en-US-abigail',\n 'fr-FR-justine',\n 'it-IT-greta',\n 'en-AU-shane',\n 'en-UK-peter',\n 'nl-NL-famke',\n 'en-AU-ivy',\n 'nl-NL-dirk',\n 'fr-FR-axel',\n 'es-ES-carla',\n 'en-US-claire',\n 'ko-KR-jangmi',\n 'ko-KR-sanghoon',\n 'it-IT-vera',\n 'hi-IN-rahul',\n 'es-ES-elvira',\n 'es-ES-enrique',\n 'en-UK-aiden',\n 'en-US-ronnie',\n 'en-UK-amber',\n 'hi-IN-shweta',\n 'hi-IN-amit',\n 'en-AU-jimm',\n 'en-UK-pearl',\n 'pt-BR-benício',\n 'en-UK-freddie',\n 'en-US-ryan',\n 'pt-BR-eloa',\n 'en-US-charlotte',\n 'de-DE-lia',\n 'en-US-natalie',\n 'en-US-michelle',\n 'en-US-phoebe',\n 'es-ES-carmen',\n 'en-US-caleb',\n 'en-US-iris',\n 'en-UK-harrison',\n 'en-US-marcus',\n 'en-US-josie',\n 'en-US-daisy',\n 'en-US-charles',\n 'en-UK-reggie',\n 'en-US-julia',\n 'en-SCOTT-emily',\n 'en-US-dylan',\n 'es-MX-valeria',\n 'en-IN-eashwar',\n 'en-AU-evelyn',\n 'de-DE-lara',\n 'en-US-evander',\n 'en-SCOTT-rory',\n 'ta-IN-iniya',\n 'en-AU-leyton',\n 'fr-FR-louise',\n 'zh-CN-wei',\n 'ko-KR-gyeong',\n 'de-DE-matthias',\n 'en-IN-rohan',\n 'en-US-delilah',\n 'bn-IN-abhik',\n 'en-US-angela',\n 'en-US-naomi',\n 'es-MX-carlos',\n 'nl-NL-merel',\n 'en-US-alicia',\n 'en-IN-alia',\n 'zh-CN-jiao',\n 'en-US-june',\n 'en-AU-ashton',\n 'en-UK-finley',\n 'pl-PL-blazej',\n 'zh-CN-zhang',\n 'en-AU-kylie',\n 'en-US-jayden',\n 'en-IN-aarav',\n 'de-DE-björn',\n 'bn-IN-ishani',\n 'zh-CN-yuxan',\n 'fr-FR-louis',\n 'ko-KR-jong-su',\n 'en-AU-harper',\n 'en-UK-ruby',\n 'en-US-ken',\n 'ta-IN-mani',\n 'de-DE-ralf',\n 'en-UK-jaxon',\n 'en-US-river',\n 'en-IN-priya',\n 'en-UK-theo',\n 'en-UK-katie',\n 'pl-PL-jacek',\n 'it-IT-lorenzo',\n 'hi-IN-shaan',\n 'en-US-amara',\n 'en-UK-mason',\n 'en-IN-surya',\n 'en-US-finn',\n 'pt-BR-gustavo',\n 'hi-IN-kabir',\n 'es-ES-javier',\n 'en-AU-mitch',\n 'pt-BR-heitor',\n 'en-US-edmund',\n 'hi-IN-ayushi',\n 'pl-PL-kasia',\n 'es-MX-luisa',\n 'zh-CN-tao',\n 'en-US-molly',\n] as const;\n\nexport type MurfVoiceId = (typeof MURF_VOICES)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\n\nimport { MURF_VOICES } from './voices';\nimport type { MurfVoiceId } from './voices';\n\ntype MurfConfig = {\n name: 'GEN1' | 'GEN2';\n apiKey?: string;\n properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n};\n\ntype SpeechCreateParams = {\n voiceId: MurfVoiceId;\n text: string;\n modelVersion: 'GEN1' | 'GEN2';\n style?: string;\n rate?: number;\n pitch?: number;\n sampleRate?: 8000 | 24000 | 44100 | 48000;\n format?: 'MP3' | 'WAV' | 'FLAC' | 'ALAW' | 'ULAW';\n channelType?: 'STEREO' | 'MONO';\n pronunciationDictionary?: Record<string, string>;\n encodeAsBase64?: boolean;\n variation?: number;\n audioDuration?: number;\n multiNativeLocale?: string;\n};\n\ntype SpeechCreateResponse = {\n audioFile: string;\n audioLengthInSeconds: number;\n consumedCharacterCount: number;\n encodedAudio: string;\n remainingCharacterCount: number;\n warning: string;\n wordDurations: {\n endMs: number;\n pitchScaleMaximum: number;\n pitchScaleMinimum: number;\n sourceWordIndex: number;\n startMs: number;\n word: string;\n }[];\n};\n\nconst DEFAULT_RETRY_COUNT = 2;\nconst RETRY_STATUS_CODES = new Set([408, 413, 429, 500, 502, 503, 504]);\nconst RETRY_DELAY_MS = 300;\n\nexport class MurfVoice extends MastraVoice {\n private baseUrl = 'https://api.murf.ai';\n private apiKey: string;\n private defaultVoice: MurfVoiceId;\n private properties: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'>;\n\n constructor({ speechModel, speaker }: { speechModel?: MurfConfig; speaker?: string } = {}) {\n super({\n speechModel: {\n name: speechModel?.name ?? 'GEN2',\n apiKey: speechModel?.apiKey ?? process.env.MURF_API_KEY,\n },\n speaker: speaker ?? MURF_VOICES[0],\n });\n\n const apiKey = this.speechModel?.apiKey;\n if (!apiKey) {\n throw new Error('MURF_API_KEY is not set');\n }\n\n this.apiKey = apiKey;\n\n this.properties = {\n ...speechModel?.properties,\n };\n\n this.defaultVoice = (speaker as MurfVoiceId) ?? MURF_VOICES[0];\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(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: string; properties?: Omit<SpeechCreateParams, 'modelVersion' | 'voiceId' | 'text'> },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const response = await this.makeRequest<SpeechCreateResponse>('/v1/speech/generate', {\n voiceId: (options?.speaker || this.defaultVoice) as MurfVoiceId,\n text,\n modelVersion: this.speechModel?.name,\n ...this.properties,\n ...options?.properties,\n });\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n\n // Get the audio file as a stream\n const audioResponse = await fetch(response.audioFile);\n if (!audioResponse.body) {\n throw new Error('No response body received');\n }\n\n // Process the stream\n const reader = audioResponse.body.getReader();\n (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 })().catch(error => {\n stream.destroy(error as Error);\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('Murf does not support speech recognition');\n }\n\n private async makeRequest<T>(endpoint: string, payload: Record<string, unknown>): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= DEFAULT_RETRY_COUNT; attempt++) {\n if (attempt > 0) {\n await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n\n const res = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (res.ok) {\n return (await res.json()) as T;\n }\n\n if (!RETRY_STATUS_CODES.has(res.status) || attempt === DEFAULT_RETRY_COUNT) {\n let errorMessage: string;\n try {\n const error = (await res.json()) as { message?: string };\n errorMessage = error.message || res.statusText;\n } catch {\n errorMessage = res.statusText;\n }\n throw new Error(`Murf API Error: ${errorMessage}`);\n }\n\n lastError = new Error(`Murf API Error: ${res.statusText}`);\n }\n\n throw lastError ?? new Error('Murf API Error: request failed');\n }\n\n async getSpeakers() {\n return MURF_VOICES.map(voice => ({\n voiceId: voice,\n name: voice,\n language: voice.split('-')[0],\n gender: 'neutral',\n }));\n }\n}\n\nexport type { MurfConfig, MurfVoiceId };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/voice-murf",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Mastra Murf voice integration",
5
5
  "type": "module",
6
6
  "files": [
@@ -23,20 +23,17 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "license": "Apache-2.0",
26
- "dependencies": {
27
- "ky": "^1.8.2"
28
- },
29
26
  "devDependencies": {
30
- "@types/node": "22.13.17",
31
- "@vitest/coverage-v8": "4.0.12",
32
- "@vitest/ui": "4.0.12",
33
- "eslint": "^9.37.0",
34
- "tsup": "^8.5.0",
35
- "typescript": "^5.9.3",
36
- "vitest": "4.0.16",
37
- "@internal/lint": "0.0.54",
38
- "@mastra/core": "1.0.0",
39
- "@internal/types-builder": "0.0.29"
27
+ "@types/node": "22.19.15",
28
+ "@vitest/coverage-v8": "4.1.5",
29
+ "@vitest/ui": "4.1.5",
30
+ "eslint": "^10.2.1",
31
+ "tsup": "^8.5.1",
32
+ "typescript": "^6.0.3",
33
+ "vitest": "4.1.5",
34
+ "@internal/lint": "0.0.98",
35
+ "@mastra/core": "1.37.0",
36
+ "@internal/types-builder": "0.0.73"
40
37
  },
41
38
  "peerDependencies": {
42
39
  "@mastra/core": ">=1.0.0-0 <2.0.0-0",
@@ -56,7 +53,6 @@
56
53
  },
57
54
  "scripts": {
58
55
  "build": "tsup --silent --config tsup.config.ts",
59
- "postbuild": "pnpx tsx ../../scripts/generate-package-docs.ts voice/murf",
60
56
  "build:watch": "tsup --watch --silent --config tsup.config.ts",
61
57
  "test": "vitest run",
62
58
  "lint": "eslint ."
@@ -1,32 +0,0 @@
1
- # @mastra/voice-murf Documentation
2
-
3
- > Embedded documentation for coding agents
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- # Read the skill overview
9
- cat docs/SKILL.md
10
-
11
- # Get the source map
12
- cat docs/SOURCE_MAP.json
13
-
14
- # Read topic documentation
15
- cat docs/<topic>/01-overview.md
16
- ```
17
-
18
- ## Structure
19
-
20
- ```
21
- docs/
22
- ├── SKILL.md # Entry point
23
- ├── README.md # This file
24
- ├── SOURCE_MAP.json # Export index
25
- ├── agents/ (1 files)
26
- ├── voice/ (2 files)
27
- ```
28
-
29
- ## Version
30
-
31
- Package: @mastra/voice-murf
32
- Version: 0.12.0