node-red-contrib-tts-ultimate 2.0.7 → 2.0.8
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,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
|
+
<p>
|
|
6
|
+
<b>Version 2.0.8</b> November 2024<br/>
|
|
7
|
+
- NEW: ElevenLabs V2 Multilingual TTS Engine has been added.<br/>
|
|
8
|
+
- ElevenLabs V1 is now in legacy/deprecation state.<br/>
|
|
9
|
+
</p>
|
|
5
10
|
<p>
|
|
6
11
|
<b>Version 2.0.7</b> January 2024<br/>
|
|
7
12
|
- NEW: input messages can override selected voice.<br/>
|
package/README.md
CHANGED
|
@@ -42,11 +42,10 @@ This is a major ***upgrade from the previously popular node SonosPollyTTS*** (So
|
|
|
42
42
|
* **Amazon Voices, Gooogle Translate Voices, Google TTS Voices, Microsoft TTS Azure voices and Elevenlabs.io voices** are all supported, with all avaiables languages and genders.
|
|
43
43
|
* **Automatic grouping** is supported. You can group all players you want to play your announcements.
|
|
44
44
|
* **Automatic discovery** of your players.
|
|
45
|
-
* **Automatic resume of music** queue (including radio stations, but here, some users reports problem resuming ***radio stations*** and, because of lack of Sonos API documentation, the issue cannot currently be fixed), at exact track, at exact time.
|
|
46
|
-
* **TTS caching**. Amazon AWS and Google charges you if you use they tts service for a high rate of text to speech requests. TTS-Ultimate caches the TTS files. It downloads the TTS audio from Amazon or Google only once. The second time, the node will read it from the cache. The caches is resilient, that means it survives reboots and updates.
|
|
47
|
-
* **UPLOAD your own audio files**. You can upload your own audio files with OwnFile node.
|
|
45
|
+
* **Automatic resume of music** queue (including radio stations, but here, some users reports problem resuming ***radio stations*** and, because of lack of Sonos API documentation, the issue cannot currently be fixed), at exact track, at exact time. **Be aware that this could not work with all music queues**.
|
|
46
|
+
* **TTS caching**. Elevenlabs, Amazon AWS and Google charges you if you use they tts service for a high rate of text to speech requests. TTS-Ultimate caches the TTS files. It downloads the TTS audio from Amazon or Google only once. The second time, the node will read it from the cache. The caches is resilient, that means it survives reboots and updates.
|
|
48
47
|
* **Can work offline**. You can use your own audio files (with OwnFile node) to make the node works offline.
|
|
49
|
-
*
|
|
48
|
+
* **UPLOAD your own audio files**. You can also upload your own audio files with OwnFile node.
|
|
50
49
|
|
|
51
50
|
>
|
|
52
51
|
> ***UPDATE PATH FROM SONOSPOLLYTTS TO TTS-ULTIMATE***
|
|
@@ -75,7 +74,7 @@ PORT USED BY THE NODE ARE 1980 (DEFAULT) AND 1400 (FOR SONOS DISCOVER). <br/>
|
|
|
75
74
|
PLEASE ALLOW MDNS AND UDP AS WELL
|
|
76
75
|
|
|
77
76
|
**TTS Service**<br/>
|
|
78
|
-
You can choose between Google (without credentials), Amazon AWS (Polly), Google TTS (require credentials and registration to google) or Microsoft Azure TTS engines.<br/>
|
|
77
|
+
You can choose between Elevenlabs.io, Google (without credentials), Amazon AWS (Polly), Google TTS (require credentials and registration to google) or Microsoft Azure TTS engines.<br/>
|
|
79
78
|
For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
80
79
|
<br/>
|
|
81
80
|
<br/>
|
|
@@ -114,6 +113,11 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
114
113
|
|
|
115
114
|
<br/>
|
|
116
115
|
|
|
116
|
+
* **TTS Service using ElevenLabs**<br/>
|
|
117
|
+
Please use the V2 engine, as the V1 is deprecated and will not longer be supported. The V2 has multilingual voices and is more powerful.
|
|
118
|
+
You have two choiches: To register to eventlabs, or not to register. If you don't register to elevenlabs.io, you will either have access on a limited amount of voices, or no access at all.
|
|
119
|
+
After registration at elevenlabs.io, you can add any language to your personal list. The personal list will be then show in the node voice's list.<br/>
|
|
120
|
+
<br/>
|
|
117
121
|
|
|
118
122
|
**Node-Red IP**<br/>
|
|
119
123
|
set IP of your node-red machine. Write **AUTODISCOVER** to allow the node to auto discover your IP.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-tts-ultimate",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
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": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"homepage": "https://github.com/Supergiovane/node-red-contrib-tts-ultimate",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"aws-sdk": "2.1444.0",
|
|
44
|
-
"fs": "0.0.1-security",
|
|
45
44
|
"sonos": "1.14.1",
|
|
46
45
|
"formidable": "1.2.2",
|
|
47
46
|
"path": ">=0.12.7",
|
|
48
47
|
"@google-cloud/text-to-speech": "4.2.2",
|
|
49
48
|
"google-translate-tts": ">=0.3.0",
|
|
50
49
|
"microsoft-cognitiveservices-speech-sdk": "1.29.0",
|
|
51
|
-
"elevenlabs-node": "1.1.3"
|
|
50
|
+
"elevenlabs-node": "1.1.3",
|
|
51
|
+
"elevenlabs": "0.18.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"eslint": ">=4.18.2",
|
|
@@ -63,27 +63,27 @@
|
|
|
63
63
|
// 22/12/2020 Hide parts of the ui
|
|
64
64
|
// ##########################################################
|
|
65
65
|
$("#node-config-input-ttsservice").change(function (e) {
|
|
66
|
-
if ($("#node-config-input-ttsservice").val()
|
|
66
|
+
if ($("#node-config-input-ttsservice").val() === "polly") {
|
|
67
67
|
$("#GoogleForm").hide();
|
|
68
68
|
$("#microsoftAzureForm").hide();
|
|
69
69
|
$("#elevenlabsForm").hide();
|
|
70
70
|
$("#pollyForm").show();
|
|
71
|
-
} else if ($("#node-config-input-ttsservice").val()
|
|
71
|
+
} else if ($("#node-config-input-ttsservice").val() === "googletts") {
|
|
72
72
|
$("#microsoftAzureForm").hide();
|
|
73
73
|
$("#pollyForm").hide();
|
|
74
74
|
$("#elevenlabsForm").hide();
|
|
75
75
|
$("#GoogleForm").show();
|
|
76
|
-
} else if ($("#node-config-input-ttsservice").val()
|
|
76
|
+
} else if ($("#node-config-input-ttsservice").val() === "googletranslate") {
|
|
77
77
|
$("#pollyForm").hide();
|
|
78
78
|
$("#GoogleForm").hide();
|
|
79
79
|
$("#microsoftAzureForm").hide();
|
|
80
80
|
$("#elevenlabsForm").hide();
|
|
81
|
-
} else if ($("#node-config-input-ttsservice").val()
|
|
81
|
+
} else if ($("#node-config-input-ttsservice").val() === "microsoftazuretts") {
|
|
82
82
|
$("#pollyForm").hide();
|
|
83
83
|
$("#GoogleForm").hide();
|
|
84
84
|
$("#elevenlabsForm").hide();
|
|
85
85
|
$("#microsoftAzureForm").show();
|
|
86
|
-
} else if ($("#node-config-input-ttsservice").val()
|
|
86
|
+
} else if ($("#node-config-input-ttsservice").val().includes("elevenlabs")) {
|
|
87
87
|
$("#pollyForm").hide();
|
|
88
88
|
$("#GoogleForm").hide();
|
|
89
89
|
$("#microsoftAzureForm").hide();
|
|
@@ -182,9 +182,10 @@
|
|
|
182
182
|
<select id="node-config-input-ttsservice">
|
|
183
183
|
<option value="polly">Amazon Polly</option>
|
|
184
184
|
<option value="googletts">Google TTS</option>
|
|
185
|
-
<option value="googletranslate">Google
|
|
185
|
+
<option value="googletranslate">Google free TTS</option>
|
|
186
186
|
<option value="microsoftazuretts">Microsoft Azure TTS</option>
|
|
187
|
-
<option value="elevenlabs">ElevenLabs TTS (
|
|
187
|
+
<option value="elevenlabs">ElevenLabs TTS V1 (deprecated)</option>
|
|
188
|
+
<option value="elevenlabsv2">ElevenLabs TTS V2 Multilingual</option>
|
|
188
189
|
</select>  <b><span style="color:red"><i class="fa fa-question-circle"></i> <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-tts-ultimate"><u>Help configure</u></a></span>
|
|
189
190
|
</div>
|
|
190
191
|
<div id="pollyForm">
|
|
@@ -252,7 +253,8 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
252
253
|
<br/>
|
|
253
254
|
<br/>
|
|
254
255
|
|
|
255
|
-
* **TTS Service using Amazon AWS (Polly)
|
|
256
|
+
* **TTS Service using Amazon AWS (Polly)**
|
|
257
|
+
|
|
256
258
|
> HOW-TO in Deutsch: for german users, there is a very helpful how-to, where you can learn how to use the node and how to register to Amazon AWS Polly as well: here: https://technikkram.net/blog/2020/09/26/sonos-sprachausgabe-mit-raspberry-pi-node-red-und-amazon-polly-fuer-homematic-oder-knx-systeme
|
|
257
259
|
|
|
258
260
|
**AWS Access key**<br/>
|
|
@@ -262,12 +264,14 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
262
264
|
AWS access Secret key.
|
|
263
265
|
<br/>
|
|
264
266
|
|
|
265
|
-
* **TTS Service using Google (without credentials)
|
|
267
|
+
* **TTS Service using Google (without credentials)**
|
|
268
|
+
|
|
266
269
|
This is the simplest way. Just select the voice and you're done. You don't need any credential and you don't even need to be registered to any google service. The voice list is more limited than other services, but it works without hassles.
|
|
267
270
|
|
|
268
271
|
<br/>
|
|
269
272
|
|
|
270
|
-
* **TTS Service using Google TTS
|
|
273
|
+
* **TTS Service using Google TTS**
|
|
274
|
+
|
|
271
275
|
For Google TTS Engine, you can choose pitch and speed rate of the voice.<br/>
|
|
272
276
|
**Google credentials file path**<br/>
|
|
273
277
|
Here you must select your credential file, previously downloaded from Google, [with these steps](https://www.npmjs.com/package/@google-cloud/text-to-speech):
|
|
@@ -275,10 +279,10 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
275
279
|
> [Enable billing for your project](https://support.google.com/cloud/answer/6293499#enable-billing)<br/>
|
|
276
280
|
> [Enable the Google Cloud Text-to-Speech API](https://console.cloud.google.com/flows/enableapi?apiid=texttospeech.googleapis.com)<br/>
|
|
277
281
|
|
|
278
|
-
|
|
279
282
|
<br/>
|
|
280
283
|
|
|
281
|
-
* **TTS Service using Microsot Azure TTS
|
|
284
|
+
* **TTS Service using Microsot Azure TTS**
|
|
285
|
+
|
|
282
286
|
For Microsoft Azure TTS Engine, you need to have a microsoft account and register to the Azure portal.<br/>
|
|
283
287
|
See my **YOUTUBE video**, here! https://youtu.be/asXajNpRWME<br/>
|
|
284
288
|
You need to register here https://portal.azure.com, then ceate a Voice Service (please click here https://portal.azure.com/#create/Microsoft.CognitiveServicesSpeechServices), then click on the left "Keys and Endpoint" menu and copy/paste the KEY and your Location (for example westus).<br/>
|
|
@@ -286,6 +290,13 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
286
290
|
|
|
287
291
|
<br/>
|
|
288
292
|
|
|
293
|
+
* **TTS Service using ElevenLabs**
|
|
294
|
+
|
|
295
|
+
Please use the V2 engine, as the V1 is deprecated and will not longer be supported. The V2 has multilingual voices and is more powerful.
|
|
296
|
+
You have two choiches: To register to eventlabs, or not to register. If you don't register to elevenlabs.io, you will either have access on a limited amount of voices, or no access at all.
|
|
297
|
+
After registration at elevenlabs.io, you can add any language to your personal list. The personal list will be then show in the node voice's list.<br/>
|
|
298
|
+
<br/>
|
|
299
|
+
|
|
289
300
|
|
|
290
301
|
**Node-Red IP**<br/>
|
|
291
302
|
set IP of your node-red machine. Write **AUTODISCOVER** to allow the node to auto discover your IP.
|
|
@@ -16,6 +16,7 @@ module.exports = function (RED) {
|
|
|
16
16
|
const GoogleTranslate = require('google-translate-tts'); // TTS without credentials, limited to 200 chars per row.
|
|
17
17
|
const microsoftAzureTTS = require("microsoft-cognitiveservices-speech-sdk"); // 12/10/2021
|
|
18
18
|
const elevenlabsTTS = require("elevenlabs-node"); // 03/08/2023
|
|
19
|
+
const ElevenLabsClient = require("elevenlabs").ElevenLabsClient;
|
|
19
20
|
|
|
20
21
|
var fs = require('fs');
|
|
21
22
|
var path = require("path");
|
|
@@ -217,7 +218,7 @@ module.exports = function (RED) {
|
|
|
217
218
|
}
|
|
218
219
|
// #########################################
|
|
219
220
|
|
|
220
|
-
// elevenlabsTTS
|
|
221
|
+
// elevenlabsTTS v1 deprecated
|
|
221
222
|
if (node.ttsservice === "elevenlabs") {
|
|
222
223
|
node.elevenlabsTTSVoiceList = []
|
|
223
224
|
try {
|
|
@@ -234,12 +235,12 @@ module.exports = function (RED) {
|
|
|
234
235
|
if (x < y) { return -1; }
|
|
235
236
|
if (x > y) { return 1; }
|
|
236
237
|
return 0;
|
|
237
|
-
});
|
|
238
|
+
});
|
|
238
239
|
} catch (error) {
|
|
239
240
|
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabs 2 voices: ' + error.message);
|
|
240
241
|
node.elevenlabsTTSVoiceList.push({ name: "Error getting elevenlabs 2 voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
|
|
241
242
|
}
|
|
242
|
-
|
|
243
|
+
|
|
243
244
|
});
|
|
244
245
|
} catch (error) {
|
|
245
246
|
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabs voices: ' + error.message);
|
|
@@ -254,6 +255,46 @@ module.exports = function (RED) {
|
|
|
254
255
|
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
255
256
|
}
|
|
256
257
|
|
|
258
|
+
// elevenlabsTTS v2
|
|
259
|
+
if (node.ttsservice === "elevenlabsv2") {
|
|
260
|
+
const elevenlabsv2 = new ElevenLabsClient({
|
|
261
|
+
apiKey: node.credentials.elevenlabsKey
|
|
262
|
+
});
|
|
263
|
+
node.elevenlabsTTSVoiceList = []
|
|
264
|
+
try {
|
|
265
|
+
node.elevenlabsTTS = elevenlabsv2;
|
|
266
|
+
try {
|
|
267
|
+
node.elevenlabsTTS.voices.getAll().then((res) => {
|
|
268
|
+
try {
|
|
269
|
+
res.voices.forEach(element => {
|
|
270
|
+
node.elevenlabsTTSVoiceList.push({ name: element.labels.accent + (element.labels.language !== undefined ? " (" + element.labels.language + ")" : "") + " - " + element.name + " (" + element.labels.gender + ")", id: element.voice_id })
|
|
271
|
+
});
|
|
272
|
+
node.elevenlabsTTSVoiceList.sort(function (a, b) {
|
|
273
|
+
let x = a.name.toLowerCase();
|
|
274
|
+
let y = b.name.toLowerCase();
|
|
275
|
+
if (x < y) { return -1; }
|
|
276
|
+
if (x > y) { return 1; }
|
|
277
|
+
return 0;
|
|
278
|
+
});
|
|
279
|
+
} catch (error) {
|
|
280
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabsv2 voices: ' + error.message);
|
|
281
|
+
node.elevenlabsTTSVoiceList.push({ name: "Error getting elevenlabsv2 voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
});
|
|
285
|
+
} catch (error) {
|
|
286
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabsv2 voices: ' + error.message);
|
|
287
|
+
node.elevenlabsTTSVoiceList.push({ name: "Error getting elevenlabsv2 voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
|
|
288
|
+
}
|
|
289
|
+
RED.log.info("ttsultimate-config " + node.id + ": elevenlabsTTS servicev2 enabled.")
|
|
290
|
+
} catch (error) {
|
|
291
|
+
RED.log.warn("ttsultimate-config " + node.id + ": elevenlabsTTS servicev2 disabled. " + error.message)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
} else {
|
|
295
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
296
|
+
}
|
|
297
|
+
|
|
257
298
|
|
|
258
299
|
//#endregion
|
|
259
300
|
|
|
@@ -494,7 +535,7 @@ module.exports = function (RED) {
|
|
|
494
535
|
|
|
495
536
|
} else if (ttsservice === "microsoftazuretts") {
|
|
496
537
|
res.json(node.microsoftAzureTTSVoiceList);
|
|
497
|
-
} else if (ttsservice
|
|
538
|
+
} else if (ttsservice.includes("elevenlabs")) {
|
|
498
539
|
res.json(node.elevenlabsTTSVoiceList);
|
|
499
540
|
}
|
|
500
541
|
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
</div>
|
|
45
45
|
<div class="form-row" id="divSSML">
|
|
46
46
|
<label></label>
|
|
47
|
-
<input type="checkbox" id="node-input-ssml" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Enable SSML (unsupported by Google
|
|
47
|
+
<input type="checkbox" id="node-input-ssml" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Enable SSML (unsupported by Google free TTS)</label>
|
|
48
48
|
</div>
|
|
49
49
|
<div class="form-row">
|
|
50
50
|
<label for="node-input-sonoshailing"><i class="fa fa-bell"></i> Hailing</label>
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
if (oNodeServer.ttsservice === "googletts") {
|
|
176
176
|
$("#divGoogleTTSAudioConfig").show();
|
|
177
177
|
$("#divElevenLabsOptions").hide();
|
|
178
|
-
} else if (oNodeServer.ttsservice
|
|
178
|
+
} else if (oNodeServer.ttsservice.includes("elevenlabs")) {
|
|
179
179
|
$("#divGoogleTTSAudioConfig").hide();
|
|
180
180
|
$("#divElevenLabsOptions").show();
|
|
181
181
|
$("#divSSML").hide();
|
|
@@ -600,7 +600,7 @@ module.exports = function (RED) {
|
|
|
600
600
|
node.sFileToBePlayed = getFilename(msg, params);
|
|
601
601
|
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
602
602
|
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
603
|
-
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using' + node.server.ttsservice });
|
|
603
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
604
604
|
data = await synthesizeSpeechPolly([node.server.polly, params]);
|
|
605
605
|
} else {
|
|
606
606
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
@@ -619,7 +619,7 @@ module.exports = function (RED) {
|
|
|
619
619
|
node.sFileToBePlayed = getFilename(msg, params);
|
|
620
620
|
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
621
621
|
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
622
|
-
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using' + node.server.ttsservice });
|
|
622
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
623
623
|
data = await synthesizeSpeechGoogleTTS([node.server.googleTTS, params]);
|
|
624
624
|
} else {
|
|
625
625
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
@@ -637,7 +637,7 @@ module.exports = function (RED) {
|
|
|
637
637
|
node.sFileToBePlayed = getFilename(msg, params);
|
|
638
638
|
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
639
639
|
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
640
|
-
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using' + node.server.ttsservice });
|
|
640
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
641
641
|
data = await synthesizeSpeechGoogleTranslate(node.server.googleTranslateTTS, params);
|
|
642
642
|
} else {
|
|
643
643
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
@@ -653,7 +653,7 @@ module.exports = function (RED) {
|
|
|
653
653
|
node.sFileToBePlayed = getFilename(msg, params);
|
|
654
654
|
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
655
655
|
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
656
|
-
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using' + node.server.ttsservice });
|
|
656
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
657
657
|
data = await synthesizeSpeechMicrosoftAzureTTS(node.server.microsoftAzureTTS, params);
|
|
658
658
|
} else {
|
|
659
659
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
@@ -673,17 +673,38 @@ module.exports = function (RED) {
|
|
|
673
673
|
node.sFileToBePlayed = getFilename(msg, params);
|
|
674
674
|
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
675
675
|
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
676
|
-
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using' + node.server.ttsservice });
|
|
676
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
677
677
|
data = await synthesizeSpeechElevenLabs(node.server.elevenlabsTTS, params);
|
|
678
678
|
} else {
|
|
679
679
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
680
680
|
}
|
|
681
|
+
} else if (node.server.ttsservice === "elevenlabsv2") {
|
|
682
|
+
// VoiceId is: code
|
|
683
|
+
const params = {
|
|
684
|
+
stream: false,
|
|
685
|
+
text: msg,
|
|
686
|
+
voice: node.voiceId,
|
|
687
|
+
model_id: "eleven_multilingual_v2",
|
|
688
|
+
voice_settings: {
|
|
689
|
+
stability: config.elevenlabsStability,
|
|
690
|
+
similarity_boost: config.elevenlabsSimilarity_boost
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
// Download or read from cache
|
|
694
|
+
node.sFileToBePlayed = getFilename(msg, params);
|
|
695
|
+
node.sFileToBePlayed = path.join(node.userDir, "ttsfiles", node.sFileToBePlayed);
|
|
696
|
+
if (!fs.existsSync(node.sFileToBePlayed)) {
|
|
697
|
+
node.setNodeStatus({ fill: 'blue', shape: 'ring', text: 'Download using ' + node.server.ttsservice });
|
|
698
|
+
data = await synthesizeSpeechElevenLabsV2(node.server.elevenlabsTTS, params);
|
|
699
|
+
} else {
|
|
700
|
+
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Reading offline from cache' });
|
|
701
|
+
}
|
|
681
702
|
}
|
|
682
703
|
|
|
683
704
|
// Save the downloaded file into the cache
|
|
684
705
|
if (data !== undefined) {
|
|
685
706
|
try {
|
|
686
|
-
console.log("Salvelox " + node.sFileToBePlayed)
|
|
707
|
+
//console.log("Salvelox " + node.sFileToBePlayed)
|
|
687
708
|
fs.writeFileSync(node.sFileToBePlayed, data);
|
|
688
709
|
} catch (error) {
|
|
689
710
|
RED.log.error("ttsultimate: node id: " + node.id + " Unable to save the file " + error.message);
|
|
@@ -1182,6 +1203,20 @@ module.exports = function (RED) {
|
|
|
1182
1203
|
});
|
|
1183
1204
|
});
|
|
1184
1205
|
}
|
|
1206
|
+
// elevenLabs TTS Service
|
|
1207
|
+
async function synthesizeSpeechElevenLabsV2(ttsService, params) {
|
|
1208
|
+
try {
|
|
1209
|
+
const audioStream = await ttsService.generate(params);
|
|
1210
|
+
const chunks = [];
|
|
1211
|
+
for await (const chunk of audioStream) {
|
|
1212
|
+
chunks.push(chunk);
|
|
1213
|
+
}
|
|
1214
|
+
const content = Buffer.concat(chunks);
|
|
1215
|
+
return content;
|
|
1216
|
+
} catch (error) {
|
|
1217
|
+
throw (error);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1185
1220
|
|
|
1186
1221
|
// 04/01/2021 hashing filename to avoid issues with long filenames.
|
|
1187
1222
|
function getFilename(_text, _params) {
|