mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-07-23 20:42:16 +00:00
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:
@@ -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
@@ -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,
|
||||
|
||||
Generated
+4099
-1340
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user