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 +5 -1
- package/package.json +1 -1
- package/ttsultimate/ttsultimate.html +50 -1
- package/ttsultimate/ttsultimate.js +30 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
|
-
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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));
|