node-red-contrib-tts-ultimate 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  [![Donate via PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square)](https://www.paypal.me/techtoday)
4
4
 
5
- ## BREAKING CHANGE ! BREAKING CHANGE ! BREAKING CHANGE ! BREAKING CHANGE !
5
+
6
+ <p>
7
+ <b>Version 3.0.1</b> October 2025<br/>
8
+ - Elevenlabs Engine: added more option to personalize the voice.<br/>
9
+ </p>
6
10
 
7
11
  <p>
8
12
  <b>Version 3.0.0</b> June 2025<br/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-tts-ultimate",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Transforms the text in speech and hear it using Sonos player or generate an audio file to be used with third parties nodes. Works with voices from Amazon, Google (without credentials as well), Microsoft TTS Azure, ElevenLabs.io TTS or your own voice. You can also only create a TTS file to be read by third party nodes. Update of the popular SonosPollyTTS node.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -49,6 +49,47 @@
49
49
  <label></label>
50
50
  <input type="checkbox" id="node-input-elevenlabsUse_speaker_boost" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Speaker boost</label>
51
51
  </div>
52
+ <div class="form-row">
53
+ <label for="node-input-elevenlabsModel"><i class="fa fa-cubes"></i> Model</label>
54
+ <select id="node-input-elevenlabsModel" style="width:60%">
55
+ <option value="">Automatic</option>
56
+ <option value="eleven_monolingual_v1">Eleven Monolingual v1</option>
57
+ <option value="eleven_multilingual_v1">Eleven Multilingual v1</option>
58
+ <option value="eleven_multilingual_v2">Eleven Multilingual v2</option>
59
+ <option value="eleven_turbo_v2">Eleven Turbo v2</option>
60
+ <option value="eleven_turbo_v2_5">Eleven Turbo v2.5</option>
61
+ </select>
62
+ </div>
63
+ <div class="form-row">
64
+ <label for="node-input-elevenlabsOptimizeLatency"><i class="fa fa-tachometer"></i> Latency preset</label>
65
+ <select id="node-input-elevenlabsOptimizeLatency" style="width:60%">
66
+ <option value="">Default</option>
67
+ <option value="0">0 - Best quality</option>
68
+ <option value="1">1</option>
69
+ <option value="2">2</option>
70
+ <option value="3">3</option>
71
+ <option value="4">4 - Lowest latency</option>
72
+ </select>
73
+ </div>
74
+ <div class="form-row">
75
+ <label for="node-input-elevenlabsOutputFormat"><i class="fa fa-file-audio-o"></i> Output format</label>
76
+ <select id="node-input-elevenlabsOutputFormat" style="width:60%">
77
+ <option value="">Default (mp3_44100_128)</option>
78
+ <option value="mp3_44100_192">mp3_44100_192</option>
79
+ <option value="mp3_44100_128">mp3_44100_128</option>
80
+ <option value="mp3_44100_64">mp3_44100_64</option>
81
+ <option value="mp3_44100_32">mp3_44100_32</option>
82
+ <option value="mp3_22050_128">mp3_22050_128</option>
83
+ <option value="mp3_22050_64">mp3_22050_64</option>
84
+ <option value="pcm_16000">pcm_16000</option>
85
+ <option value="pcm_22050">pcm_22050</option>
86
+ <option value="ulaw_8000">ulaw_8000</option>
87
+ </select>
88
+ </div>
89
+ <div class="form-row">
90
+ <label for="node-input-elevenlabsSeed"><i class="fa fa-random"></i> Seed</label>
91
+ <input type="text" id="node-input-elevenlabsSeed" style="width:120px" placeholder="Leave blank for random">
92
+ </div>
52
93
  </div>
53
94
  <div class="form-row" id="divSSML">
54
95
  <label></label>
@@ -161,6 +202,10 @@
161
202
  elevenlabsSimilarity_boost: { value: "0.5", required: false },
162
203
  elevenlabsStyle: { value: "0.0", required: false },
163
204
  elevenlabsUse_speaker_boost: { value: true, required: false },
205
+ elevenlabsModel: { value: "", required: false },
206
+ elevenlabsOptimizeLatency: { value: "", required: false },
207
+ elevenlabsOutputFormat: { value: "", required: false },
208
+ elevenlabsSeed: { value: "", required: false },
164
209
  },
165
210
  inputs: 1,
166
211
  outputs: 2,
@@ -184,6 +229,10 @@
184
229
  oneditprepare: function () {
185
230
  var node = this;
186
231
  var oNodeServer = RED.nodes.node($("#node-input-config").val()); // Store the config-node
232
+ if (node.elevenlabsModel !== undefined) $("#node-input-elevenlabsModel").val(node.elevenlabsModel);
233
+ if (node.elevenlabsOptimizeLatency !== undefined) $("#node-input-elevenlabsOptimizeLatency").val(node.elevenlabsOptimizeLatency);
234
+ if (node.elevenlabsOutputFormat !== undefined) $("#node-input-elevenlabsOutputFormat").val(node.elevenlabsOutputFormat);
235
+ if (node.elevenlabsSeed !== undefined) $("#node-input-elevenlabsSeed").val(node.elevenlabsSeed);
187
236
 
188
237
  // 19/02/2020 Used to alert the user if the CSV file has not been loaded and to get the server sooner als deploy
189
238
  // ###########################
@@ -612,4 +661,4 @@ The node has two output pins. The first pin is to signal play status, the second
612
661
  [Find it useful?](https://www.paypal.me/techtoday)
613
662
 
614
663
  <br/>
615
- </script>
664
+ </script>
@@ -660,15 +660,18 @@ module.exports = function (RED) {
660
660
  }
661
661
  } else if (node.server.ttsservice === "elevenlabs") {
662
662
  // VoiceId is: code
663
+ const stability = config.elevenlabsStability !== undefined && config.elevenlabsStability !== "" ? Number(config.elevenlabsStability) : undefined;
664
+ const similarity = config.elevenlabsSimilarity_boost !== undefined && config.elevenlabsSimilarity_boost !== "" ? Number(config.elevenlabsSimilarity_boost) : undefined;
665
+ const resolvedModel = config.elevenlabsModel && config.elevenlabsModel !== "" ? config.elevenlabsModel : "eleven_monolingual_v1";
663
666
  const params = {
664
667
  text: msg,
665
668
  voice: node.voiceId,
666
- model_id: "eleven_monolingual_v1",
667
- voice_settings: {
668
- stability: config.elevenlabsStability,
669
- similarity_boost: config.elevenlabsSimilarity_boost
670
- }
669
+ model_id: resolvedModel,
670
+ voice_settings: {}
671
671
  };
672
+ if (stability !== undefined && !Number.isNaN(stability)) params.voice_settings.stability = stability;
673
+ if (similarity !== undefined && !Number.isNaN(similarity)) params.voice_settings.similarity_boost = similarity;
674
+ if (Object.keys(params.voice_settings).length === 0) delete params.voice_settings;
672
675
  // Download or read from cache
673
676
  node.sFileToBePlayed = getFilename(msg, params);
674
677
  node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
@@ -680,18 +683,29 @@ module.exports = function (RED) {
680
683
  }
681
684
  } else if (node.server.ttsservice === "elevenlabsv2") {
682
685
  // VoiceId is: code
686
+ const stability = config.elevenlabsStability !== undefined && config.elevenlabsStability !== "" ? Number(config.elevenlabsStability) : undefined;
687
+ const similarity = config.elevenlabsSimilarity_boost !== undefined && config.elevenlabsSimilarity_boost !== "" ? Number(config.elevenlabsSimilarity_boost) : undefined;
688
+ const style = config.elevenlabsStyle !== undefined && config.elevenlabsStyle !== "" ? Number(config.elevenlabsStyle) : undefined;
689
+ const resolvedModel = config.elevenlabsModel && config.elevenlabsModel !== "" ? config.elevenlabsModel : "eleven_multilingual_v2";
690
+ const latencyPreset = config.elevenlabsOptimizeLatency && config.elevenlabsOptimizeLatency !== "" ? config.elevenlabsOptimizeLatency : undefined;
691
+ const outputFormat = config.elevenlabsOutputFormat && config.elevenlabsOutputFormat !== "" ? config.elevenlabsOutputFormat : undefined;
692
+ const seed = config.elevenlabsSeed && config.elevenlabsSeed !== "" ? Number(config.elevenlabsSeed) : undefined;
693
+ const useSpeakerBoost = config.elevenlabsUse_speaker_boost === undefined ? true : config.elevenlabsUse_speaker_boost;
683
694
  const params = {
684
695
  stream: false,
685
696
  text: msg,
686
697
  voice: node.voiceId,
687
- model_id: "eleven_multilingual_v2",
688
- voice_settings: {
689
- stability: config.elevenlabsStability,
690
- similarity_boost: config.elevenlabsSimilarity_boost,
691
- style: config.elevenlabsStyle || 0,
692
- use_speaker_boost: config.elevenlabsUse_speaker_boost === undefined ? true : config.elevenlabsUse_speaker_boost
693
- }
698
+ model_id: resolvedModel,
699
+ voice_settings: {}
694
700
  };
701
+ if (stability !== undefined && !Number.isNaN(stability)) params.voice_settings.stability = stability;
702
+ if (similarity !== undefined && !Number.isNaN(similarity)) params.voice_settings.similarity_boost = similarity;
703
+ if (style !== undefined && !Number.isNaN(style)) params.voice_settings.style = style;
704
+ params.voice_settings.use_speaker_boost = useSpeakerBoost;
705
+ if (Object.keys(params.voice_settings).length === 0) delete params.voice_settings;
706
+ if (latencyPreset !== undefined) params.optimize_streaming_latency = latencyPreset;
707
+ if (outputFormat !== undefined) params.output_format = outputFormat;
708
+ if (seed !== undefined && !Number.isNaN(seed)) params.seed = seed;
695
709
  // Download or read from cache
696
710
  node.sFileToBePlayed = getFilename(msg, params);
697
711
  node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
@@ -1194,7 +1208,10 @@ module.exports = function (RED) {
1194
1208
  }
1195
1209
  return new Promise((resolve, reject) => {
1196
1210
  // "model_id": "eleven_multilingual_v1",
1197
- ttsService.textToSpeechStream(node.server.credentials.elevenlabsKey, params.voice, params.text, null, null, "eleven_multilingual_v1").then((res) => {
1211
+ const stability = params.voice_settings && params.voice_settings.stability !== undefined ? params.voice_settings.stability : null;
1212
+ const similarity = params.voice_settings && params.voice_settings.similarity_boost !== undefined ? params.voice_settings.similarity_boost : null;
1213
+ const model = params.model_id !== undefined && params.model_id !== "" ? params.model_id : "eleven_monolingual_v1";
1214
+ ttsService.textToSpeechStream(node.server.credentials.elevenlabsKey, params.voice, params.text, stability, similarity, model).then((res) => {
1198
1215
  try {
1199
1216
  if (res !== undefined) {
1200
1217
  resolve(stream2buffer(res));