Compare commits

..
10 Commits
Author SHA1 Message Date
Dave Horton 8246dbea21 0.0.17 2023-07-19 10:10:39 -04:00
Dave Horton 0084f6a468 update deps 2023-07-19 10:09:31 -04:00
Dave Horton 98f679f43a 0.0.16 2023-07-19 10:04:17 -04:00
Dave Horton 7e7841b5ff Merge pull request #23 from jambonz/feature/trim-silence
trim trailing silence from azure tts when JAMBONES_TTS_TRIM_SILENCE i…
2023-07-19 10:03:42 -04:00
Dave Horton 75ce537db1 linting 2023-07-19 10:02:10 -04:00
Dave Horton 830be783b8 trim trailing silence from azure tts when JAMBONES_TTS_TRIM_SILENCE is set 2023-07-19 10:00:31 -04:00
Dave Horton 38c3219425 Merge pull request #21 from jambonz/snyk-fix-255777535fcb48b70c964213f7dd9fe8
[Snyk] Security upgrade @aws-sdk/client-polly from 3.303.0 to 3.347.1
2023-06-07 13:09:27 -04:00
snyk-bot e37b96a9c2 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-5668858
2023-06-07 15:35:04 +00:00
Dave Horton c184fbae26 0.0.15 2023-06-03 09:15:48 -04:00
Dave Horton 66d33ebd60 change default tts cache duration to 4 hours 2023-06-03 09:15:45 -04:00
3 changed files with 1512 additions and 1381 deletions
+32 -4
View File
@@ -30,9 +30,27 @@ const {
const {SynthesizeSpeechRequest} = require('../stubs/riva/proto/riva_tts_pb'); const {SynthesizeSpeechRequest} = require('../stubs/riva/proto/riva_tts_pb');
const {AudioEncoding} = require('../stubs/riva/proto/riva_audio_pb'); const {AudioEncoding} = require('../stubs/riva/proto/riva_audio_pb');
const debug = require('debug')('jambonz:realtimedb-helpers'); const debug = require('debug')('jambonz:realtimedb-helpers');
const EXPIRES = (process.env.JAMBONES_TTS_CACHE_DURATION_MINS || 24 * 60) * 60; // cache tts for 24 hours const EXPIRES = (process.env.JAMBONES_TTS_CACHE_DURATION_MINS || 4 * 60) * 60; // cache tts for 4 hours
const TMP_FOLDER = '/tmp'; const TMP_FOLDER = '/tmp';
const trimTrailingSilence = (buffer) => {
assert.ok(buffer instanceof Buffer, 'trimTrailingSilence - argument is not a Buffer');
let offset = buffer.length;
while (offset > 0) {
// Get 16-bit value from the buffer (read in reverse)
const value = buffer.readUInt16BE(offset - 2);
if (value !== 0) {
break;
}
offset -= 2;
}
// Trim the silence from the end
return offset === buffer.length ? buffer : buffer.subarray(0, offset);
};
/** /**
* Synthesize speech to an mp3 file, and also cache the generated speech * Synthesize speech to an mp3 file, and also cache the generated speech
* in redis (base64 format) for 24 hours so as to avoid unnecessarily paying * in redis (base64 format) for 24 hours so as to avoid unnecessarily paying
@@ -104,7 +122,12 @@ async function synthAudio(client, logger, stats, { account_sid,
text text
}); });
let filePath; let filePath;
if (['nuance', 'nvidia'].includes(vendor)) { if (['nuance', 'nvidia'].includes(vendor) ||
(
process.env.JAMBONES_TTS_TRIM_SILENCE &&
['microsoft', 'azure'].includes(vendor)
)
) {
filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.r8`; filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.r8`;
} }
else filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.mp3`; else filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.mp3`;
@@ -284,6 +307,7 @@ const synthMicrosoft = async(logger, {
}) => { }) => {
try { try {
const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint} = credentials; const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint} = credentials;
const trimSilence = filePath.endsWith('.r8');
let content = text; let content = text;
const speechConfig = SpeechConfig.fromSubscription(apiKey, region); const speechConfig = SpeechConfig.fromSubscription(apiKey, region);
speechConfig.speechSynthesisLanguage = language; speechConfig.speechSynthesisLanguage = language;
@@ -297,7 +321,9 @@ const synthMicrosoft = async(logger, {
*/ */
if (!content.startsWith('<speak')) content = `<speak>${text}</speak>`; if (!content.startsWith('<speak')) content = `<speak>${text}</speak>`;
} }
speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3; speechConfig.speechSynthesisOutputFormat = trimSilence ?
SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm :
SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
const synthesizer = new SpeechSynthesizer(speechConfig); const synthesizer = new SpeechSynthesizer(speechConfig);
if (content.startsWith('<speak>')) { if (content.startsWith('<speak>')) {
@@ -323,7 +349,9 @@ const synthMicrosoft = async(logger, {
reject(cancellation.errorDetails); reject(cancellation.errorDetails);
break; break;
case ResultReason.SynthesizingAudioCompleted: case ResultReason.SynthesizingAudioCompleted:
resolve(Buffer.from(result.audioData)); let buffer = Buffer.from(result.audioData);
if (trimSilence) buffer = trimTrailingSilence(buffer);
resolve(buffer);
synthesizer.close(); synthesizer.close();
stats.increment('tts.count', ['vendor:microsoft', 'accepted:yes']); stats.increment('tts.count', ['vendor:microsoft', 'accepted:yes']);
break; break;
+1478 -1375
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@jambonz/speech-utils", "name": "@jambonz/speech-utils",
"version": "0.0.14", "version": "0.0.17",
"description": "TTS-related speech utilities for jambonz", "description": "TTS-related speech utilities for jambonz",
"main": "index.js", "main": "index.js",
"author": "Dave Horton", "author": "Dave Horton",
@@ -24,7 +24,7 @@
}, },
"homepage": "https://github.com/jambonz/speech-utils#readme", "homepage": "https://github.com/jambonz/speech-utils#readme",
"dependencies": { "dependencies": {
"@aws-sdk/client-polly": "^3.303.0", "@aws-sdk/client-polly": "^3.359.0",
"@google-cloud/text-to-speech": "^4.2.1", "@google-cloud/text-to-speech": "^4.2.1",
"@grpc/grpc-js": "^1.8.13", "@grpc/grpc-js": "^1.8.13",
"bent": "^7.3.12", "bent": "^7.3.12",