fetch list of tts voices from provider (#289)

* fetch list of tts voices from provider

* revert serve-integration

* fix

* fix for aws

* fix for aws

* fix for aws

* update speech-utils version
This commit is contained in:
Hoan Luu Huu
2024-01-26 00:03:02 +07:00
committed by GitHub
parent 832a4e8032
commit 54dd72ff66
4 changed files with 4305 additions and 1362 deletions
+2 -2
View File
@@ -752,7 +752,7 @@ router.get('/:sid/test', async(req, res) => {
*/
router.get('/speech/supportedLanguagesAndVoices', async(req, res) => {
const logger = req.app.locals.logger;
const {logger, getTtsVoices} = req.app.locals;
try {
const {vendor, label} = req.query;
if (!vendor) {
@@ -767,7 +767,7 @@ router.get('/speech/supportedLanguagesAndVoices', async(req, res) => {
const tmp = credentials && credentials.length > 0 ? credentials[0] : null;
const cred = tmp ? JSON.parse(decrypt(tmp.credential)) : null;
try {
const data = await getLanguagesAndVoicesForVendor(logger, vendor, cred);
const data = await getLanguagesAndVoicesForVendor(logger, vendor, cred, getTtsVoices);
res.status(200).json(data);
} catch (err) {
throw new DbErrorUnprocessableRequest(err.message);
+203 -19
View File
@@ -464,49 +464,90 @@ function decryptCredential(obj, credential, logger, isObscureKey = true) {
]
}
*/
async function getLanguagesAndVoicesForVendor(logger, vendor, credential) {
async function getLanguagesAndVoicesForVendor(logger, vendor, credential, getTtsVoices) {
switch (vendor) {
case 'google':
return await getLanguagesVoicesForGoogle(credential);
return await getLanguagesVoicesForGoogle(credential, getTtsVoices, logger);
case 'aws':
return await getLanguagesVoicesForAws(credential);
return await getLanguagesVoicesForAws(credential, getTtsVoices, logger);
case 'microsoft':
return await getLanguagesVoicesForMicrosoft(credential);
return await getLanguagesVoicesForMicrosoft(credential, getTtsVoices, logger);
case 'wellsaid':
return await getLanguagesVoicesForWellsaid(credential);
return await getLanguagesVoicesForWellsaid(credential, getTtsVoices, logger);
case 'nuance':
return await getLanguagesVoicesForNuane(credential);
return await getLanguagesVoicesForNuane(credential, getTtsVoices, logger);
case 'deepgram':
return await getLanguagesVoicesForDeepgram(credential);
return await getLanguagesVoicesForDeepgram(credential, getTtsVoices, logger);
case 'ibm':
return await getLanguagesVoicesForIbm(credential);
return await getLanguagesVoicesForIbm(credential, getTtsVoices, logger);
case 'nvidia':
return await getLanguagesVoicesForNvida(credential);
return await getLanguagesVoicesForNvida(credential, getTtsVoices, logger);
case 'cobalt':
return await getLanguagesVoicesForCobalt(credential);
return await getLanguagesVoicesForCobalt(credential, getTtsVoices, logger);
case 'soniox':
return await getLanguagesVoicesForSoniox(credential);
return await getLanguagesVoicesForSoniox(credential, getTtsVoices, logger);
case 'elevenlabs':
return await getLanguagesVoicesForElevenlabs(credential);
return await getLanguagesVoicesForElevenlabs(credential, getTtsVoices, logger);
case 'assemblyai':
return await getLanguagesVoicesForAssemblyAI(credential);
return await getLanguagesVoicesForAssemblyAI(credential, getTtsVoices, logger);
case 'whisper':
return await getLanguagesVoicesForWhisper(credential);
return await getLanguagesVoicesForWhisper(credential, getTtsVoices, logger);
default:
logger.info(`invalid vendor ${vendor}, return empty result`);
throw new Error(`Invalid vendor ${vendor}`);
}
}
async function getLanguagesVoicesForGoogle(credential) {
async function getLanguagesVoicesForGoogle(credential, getTtsVoices, logger) {
if (credential) {
try {
const [result] = await getTtsVoices({
vendor: 'google',
credentials: credential
});
const tts = parseGooglelanguagesVoices(result.voices);
return tranform(tts, SttGoogleLanguagesVoices);
} catch (err) {
logger.info('Error while fetching google languages, voices, return predefined values', err);
}
}
return tranform(TtsGoogleLanguagesVoices, SttGoogleLanguagesVoices);
}
async function getLanguagesVoicesForAws(credential) {
async function getLanguagesVoicesForAws(credential, getTtsVoices, logger) {
if (credential) {
try {
const result = await getTtsVoices({
vendor: 'aws',
credentials: {
accessKeyId: credential.access_key_id,
secretAccessKey: credential.secret_access_key,
region: credential.aws_region || process.env.AWS_REGION
}
});
const tts = parseAwsLanguagesVoices(result.Voices);
return tranform(tts, SttAwsLanguagesVoices);
} catch (err) {
logger.info('Error while fetching AWS languages, voices, return predefined values', err);
}
}
return tranform(TtsAwsLanguagesVoices, SttAwsLanguagesVoices);
}
async function getLanguagesVoicesForMicrosoft(credential) {
async function getLanguagesVoicesForMicrosoft(credential, getTtsVoices, logger) {
if (credential) {
try {
const get = bent('https://westus.tts.speech.microsoft.com', 'GET', 'json', {
'Ocp-Apim-Subscription-Key' : credential.api_key
});
const voices = await get('/cognitiveservices/voices/list');
const tts = parseMicrosoftLanguagesVoices(voices);
return tranform(tts, SttMicrosoftLanguagesVoices);
} catch (err) {
logger.info('Error while fetching Microsoft languages, voices, return predefined values', err);
}
}
return tranform(TtsMicrosoftLanguagesVoices, SttMicrosoftLanguagesVoices);
}
@@ -514,7 +555,19 @@ async function getLanguagesVoicesForWellsaid(credential) {
return tranform(TtsWellsaidLanguagesVoices);
}
async function getLanguagesVoicesForNuane(credential) {
async function getLanguagesVoicesForNuane(credential, getTtsVoices, logger) {
if (credential) {
try {
const result = await getTtsVoices({
vendor: 'nuance',
credentials: credential
});
const tts = parseNuanceLanguagesVoices(result.result.voices);
return tranform(tts, SttNuanceLanguagesVoices);
} catch (err) {
logger.info('Error while fetching IBM languages, voices, return predefined values', err);
}
}
return tranform(TtsNuanceLanguagesVoices, SttNuanceLanguagesVoices);
}
@@ -522,7 +575,19 @@ async function getLanguagesVoicesForDeepgram(credential) {
return tranform(undefined, SttDeepgramLanguagesVoices, TtsModelDeepgram);
}
async function getLanguagesVoicesForIbm(credential) {
async function getLanguagesVoicesForIbm(credential, getTtsVoices, logger) {
if (credential) {
try {
const result = await getTtsVoices({
vendor: 'ibm',
credentials: credential
});
const tts = parseIBMLanguagesVoices(result.result.voices);
return tranform(tts, SttIbmLanguagesVoices);
} catch (err) {
logger.info('Error while fetching IBM languages, voices, return predefined values', err);
}
}
return tranform(TtsIbmLanguagesVoices, SttIbmLanguagesVoices);
}
@@ -596,6 +661,125 @@ function tranform(tts, stt, models) {
};
}
function parseGooglelanguagesVoices(data) {
return data.reduce((acc, voice) => {
const languageCode = voice.languageCodes[0];
const existingLanguage = acc.find((lang) => lang.value === languageCode);
if (existingLanguage) {
existingLanguage.voices.push({
value: voice.name,
name: `${voice.name.substring(languageCode.length + 1, voice.name.length)} (${voice.ssmlGender})`
});
} else {
acc.push({
value: languageCode,
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
voices: [{
value: voice.name,
name: `${voice.name.substring(languageCode.length + 1, voice.name.length)} (${voice.ssmlGender})`
}]
});
}
return acc;
}, []);
}
function parseIBMLanguagesVoices(data) {
return data.reduce((acc, voice) => {
const languageCode = voice.language;
const existingLanguage = acc.find((lang) => lang.value === languageCode);
if (existingLanguage) {
existingLanguage.voices.push({
value: voice.name,
name: `(${voice.gender}) ${voice.description}`
});
} else {
acc.push({
value: languageCode,
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
voices: [{
value: voice.name,
name: `(${voice.gender}) ${voice.description}`
}]
});
}
return acc;
}, []);
}
function parseAwsLanguagesVoices(data) {
return data.reduce((acc, voice) => {
const languageCode = voice.LanguageCode;
const existingLanguage = acc.find((lang) => lang.value === languageCode);
if (existingLanguage) {
existingLanguage.voices.push({
value: voice.Id,
name: `(${voice.Gender}) ${voice.Name}`
});
} else {
acc.push({
value: languageCode,
name: voice.LanguageName,
voices: [{
value: voice.Id,
name: `(${voice.Gender}) ${voice.Name}`
}]
});
}
return acc;
}, []);
}
function parseNuanceLanguagesVoices(data) {
return data.reduce((acc, voice) => {
const languageCode = voice.language;
const existingLanguage = acc.find((lang) => lang.value === languageCode);
if (existingLanguage) {
existingLanguage.voices.push({
value: voice.name,
name: voice.name,
model: voice.model
});
} else {
acc.push({
value: languageCode,
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
voices: [{
value: voice.name,
name: voice.name,
model: voice.model
}]
});
}
return acc;
}, []);
}
function parseMicrosoftLanguagesVoices(data) {
return data.reduce((acc, voice) => {
const languageCode = voice.Locale;
const existingLanguage = acc.find((lang) => lang.value === languageCode);
if (existingLanguage) {
existingLanguage.voices.push({
value: voice.ShortName,
name: `${voice.DisplayName} (${voice.Gender})`,
});
} else {
acc.push({
value: voice.Locale,
name: voice.LocaleName,
voices: [{
value: voice.ShortName,
name: `${voice.DisplayName} (${voice.Gender})`,
}]
});
}
return acc;
}, []);
}
module.exports = {
testGoogleTts,
testGoogleStt,
+4099 -1340
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -29,7 +29,7 @@
"@jambonz/lamejs": "^1.2.2",
"@jambonz/mw-registrar": "^0.2.7",
"@jambonz/realtimedb-helpers": "^0.8.7",
"@jambonz/speech-utils": "^0.0.33",
"@jambonz/speech-utils": "^0.0.35",
"@jambonz/time-series": "^0.2.8",
"@jambonz/verb-specifications": "^0.0.45",
"@soniox/soniox-node": "^1.1.1",