replace bent by native node fetch (#401)

* replace bent by native node fetch

* wip

* wip

* wip
This commit is contained in:
Hoan Luu Huu
2025-04-24 17:50:15 +07:00
committed by GitHub
parent b05b32d73e
commit ffda2398f4
41 changed files with 678 additions and 667 deletions
+100 -65
View File
@@ -3,7 +3,6 @@ const { TranscribeClient, ListVocabulariesCommand } = require('@aws-sdk/client-t
const { Deepgram } = require('@deepgram/sdk');
const sdk = require('microsoft-cognitiveservices-speech-sdk');
const { SpeechClient } = require('@soniox/soniox-node');
const bent = require('bent');
const fs = require('fs');
const { AssemblyAI } = require('assemblyai');
const {decrypt, obscureKey} = require('./encrypt-decrypt');
@@ -288,44 +287,46 @@ const testMicrosoftTts = async(logger, synthAudio, credentials) => {
const testWellSaidTts = async(logger, credentials) => {
const {api_key} = credentials;
try {
const post = bent('https://api.wellsaidlabs.com', 'POST', 'buffer', {
const response = await fetch('https://api.wellsaidlabs.com/v1/tts/stream', {
method: 'POST',
headers: {
'X-Api-Key': api_key,
'Accept': 'audio/mpeg',
'Content-Type': 'application/json'
});
const mp3 = await post('/v1/tts/stream', {
},
body: JSON.stringify({
text: 'Hello, world',
speaker_id: '3'
});
return mp3;
} catch (err) {
logger.info({err}, 'testWellSaidTts returned error');
throw err;
})
});
if (!response.ok) {
throw new Error('failed to synthesize speech');
}
return response.body;
};
const testElevenlabs = async(logger, credentials) => {
const {api_key, model_id} = credentials;
try {
const post = bent('https://api.elevenlabs.io', 'POST', 'buffer', {
const response = await fetch('https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', {
method: 'POST',
headers: {
'xi-api-key': api_key,
'Accept': 'audio/mpeg',
'Content-Type': 'application/json'
});
const mp3 = await post('/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', {
},
body: JSON.stringify({
text: 'Hello',
model_id,
voice_settings: {
stability: 0.5,
similarity_boost: 0.5
}
});
return mp3;
} catch (err) {
logger.info({err}, 'synthEvenlabs returned error');
throw err;
})
});
if (!response.ok) {
throw new Error('failed to synthesize speech');
}
return response.body;
};
const testPlayHT = async(logger, synthAudio, credentials) => {
@@ -466,18 +467,18 @@ const testVerbioTts = async(logger, synthAudio, credentials) => {
};
const testVerbioStt = async(logger, getVerbioAccessToken, credentials) => {
const token = await getVerbioAccessToken(credentials);
try {
const post = bent('https://us.rest.speechcenter.verbio.com', 'POST', 'json', {
const response = await fetch('https://us.rest.speechcenter.verbio.com/api/v1/recognize?language=en-US&version=V1', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token.access_token}`,
'User-Agent': 'jambonz',
'Content-Type': 'audio/wav'
});
const json = await post('/api/v1/recognize?language=en-US&version=V1',
fs.readFileSync(`${__dirname}/../../data/test_audio.wav`));
logger.debug({json}, 'successfully speech to text from verbio');
} catch (err) {
logger.info({err}, 'testWellSaidTts returned error');
throw err;
},
body: fs.readFileSync(`${__dirname}/../../data/test_audio.wav`)
});
if (!response.ok) {
logger.error({Error: await response.text()}, 'Error transcribing speech');
throw new Error('failed to transcribe speech');
}
};
@@ -546,16 +547,17 @@ const testAssemblyStt = async(logger, credentials) => {
const testVoxistStt = async(logger, credentials) => {
const {api_key} = credentials;
try {
const get = bent('https://api-asr.voxist.com', 'GET', 'json', {
const response = await fetch('https://api-asr.voxist.com/clients', {
headers: {
'Accept': 'application/json',
'x-lvl-key': api_key
});
await get('/clients');
} catch (err) {
logger.info({err}, 'failed to get clients from Voxist');
throw err;
}
});
if (!response.ok) {
logger.error({response}, 'Error retrieving clients');
throw new Error('failed to get clients');
}
return response.json();
};
const getSpeechCredential = (credential, logger) => {
@@ -812,17 +814,18 @@ async function getLanguagesVoicesForAws(credential, getTtsVoices, logger) {
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);
const response = await fetch('https://westus.tts.speech.microsoft.com/cognitiveservices/voices/list', {
headers: {
'Ocp-Apim-Subscription-Key': credential.api_key
}
});
if (!response.ok) {
logger.error({response}, 'Error fetching Microsoft voices');
throw new Error('failed to list voices');
}
const voices = await response.json();
const tts = parseMicrosoftLanguagesVoices(voices);
return tranform(tts, SttMicrosoftLanguagesVoices);
}
return tranform(TtsMicrosoftLanguagesVoices, SttMicrosoftLanguagesVoices);
}
@@ -885,14 +888,27 @@ async function getLanguagesVoicesForSpeechmatics(credential) {
async function getLanguagesVoicesForElevenlabs(credential) {
if (credential) {
const get = bent('https://api.elevenlabs.io', 'GET', 'json', {
'xi-api-key' : credential.api_key
const headers = {
'xi-api-key': credential.api_key
};
const getModelPromise = fetch('https://api.elevenlabs.io/v1/models', {
headers
});
const getVoicePromise = fetch('https://api.elevenlabs.io/v1/voices', {
headers
});
const [langResp, voiceResp] = await Promise.all([getModelPromise, getVoicePromise]);
const [langResp, voiceResp] = await Promise.all([get('/v1/models'), get('/v1/voices')]);
if (!langResp.ok || !voiceResp.ok) {
throw new Error('failed to list voices');
}
const model = langResp.find((m) => m.model_id === credential.model_id);
const models = langResp.map((m) => {
const langs = await langResp.json();
const voicesR = await voiceResp.json();
const model = langs.find((m) => m.model_id === credential.model_id);
const models = langs.map((m) => {
return {
value: m.model_id,
name: m.name
@@ -908,7 +924,7 @@ async function getLanguagesVoicesForElevenlabs(credential) {
if (languages && languages.length > 0) {
// using if condition to avoid \n character in name
const voices = voiceResp ? voiceResp.voices.map((v) => {
const voices = voicesR ? voicesR.voices.map((v) => {
let name = `${v.name}${v.category !== 'premade' ? ` (${v.category.trim()})` : ''} - (`;
if (v.labels.accent) name += `${v.labels.accent}, `;
if (v.labels.description) name += `${v.labels.description}, `;
@@ -946,18 +962,28 @@ const concat = (a) => {
const fetchLayHTVoices = async(credential) => {
if (credential) {
const get = bent('https://api.play.ht', 'GET', 'json', {
'AUTHORIZATION' : credential.api_key,
const headers = {
'AUTHORIZATION': credential.api_key,
'X-USER-ID': credential.user_id,
'Accept': 'application/json'
};
const response = await fetch('https://api.play.ht/api/v2/voices', {
headers
});
const voices = await get('/api/v2/voices');
if (!response.ok) {
throw new Error('failed to list voices');
}
const voices = await response.json();
let clone_voices = [];
try {
// try if the account has permission to cloned voice
//otherwise ignore this.
clone_voices = await get('/api/v2/cloned-voices');
const clone_voices_Response = await fetch('https://api.play.ht/api/v2/cloned-voices', {
headers
});
if (clone_voices_Response.ok) {
clone_voices = await clone_voices_Response.json();
}
} catch {}
return [clone_voices, voices];
}
@@ -1032,10 +1058,15 @@ async function getLanguagesVoicesForPlayHT(credential) {
async function getLanguagesVoicesForRimelabs(credential) {
const model_id = credential ? credential.model_id : null;
const get = bent('https://users.rime.ai', 'GET', 'json', {
'Accept': 'application/json'
const response = await fetch('https://users.rime.ai//data/voices/all-v2.json', {
headers: {
'Accept': 'application/json'
}
});
const voices = await get('/data/voices/all-v2.json');
if (!response.ok) {
throw new Error('failed to list models');
}
const voices = await response.json();
const modelVoices = model_id ? voices[model_id] :
Object.keys(voices).length > 0 ? voices[Object.keys(voices)[0]] : [];
const ttsVoices = Object.entries(modelVoices).map(([key, voices]) => ({
@@ -1238,14 +1269,18 @@ function parseVerbioLanguagesVoices(data) {
const fetchCartesiaVoices = async(credential) => {
if (credential) {
const get = bent('https://api.cartesia.ai', 'GET', 'json', {
'X-API-Key' : credential.api_key,
'Cartesia-Version': '2024-06-10',
'Accept': 'application/json'
const response = await fetch('https://api.cartesia.ai/voices', {
headers: {
'X-API-Key': credential.api_key,
'Cartesia-Version': '2024-06-10',
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error('failed to list voices');
}
const voices = await get('/voices');
return voices;
return await response.json();
}
};