mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-07-24 13:02:16 +00:00
replace bent by native node fetch (#401)
* replace bent by native node fetch * wip * wip * wip
This commit is contained in:
+30
-27
@@ -1,6 +1,5 @@
|
||||
if (!process.env.JAMBONES_HOSTING) return;
|
||||
|
||||
const bent = require('bent');
|
||||
const crypto = require('crypto');
|
||||
const assert = require('assert');
|
||||
const domains = new Map();
|
||||
@@ -26,17 +25,20 @@ const createAuthHeaders = () => {
|
||||
const getDnsDomainId = async(logger, name) => {
|
||||
checkAsserts();
|
||||
const headers = createAuthHeaders();
|
||||
const get = bent(process.env.DME_BASE_URL, 'GET', 'json', headers);
|
||||
try {
|
||||
const result = await get('/dns/managed');
|
||||
debug(result, 'getDnsDomainId: all domains');
|
||||
if (Array.isArray(result.data)) {
|
||||
const domain = result.data.find((o) => o.name === name);
|
||||
if (domain) return domain.id;
|
||||
debug(`getDnsDomainId: failed to find domain ${name}`);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({err}, 'Error retrieving domains');
|
||||
const response = await fetch(`${process.env.DME_BASE_URL}/dns/managed`, {
|
||||
method: 'GET',
|
||||
headers
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving domains');
|
||||
return;
|
||||
}
|
||||
const result = await response.json();
|
||||
debug(result, 'getDnsDomainId: all domains');
|
||||
if (Array.isArray(result.data)) {
|
||||
const domain = result.data.find((o) => o.name === name);
|
||||
if (domain) return domain.id;
|
||||
debug(`getDnsDomainId: failed to find domain ${name}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,21 +82,20 @@ const createDnsRecords = async(logger, domain, name, value, ttl = 3600) => {
|
||||
];
|
||||
const headers = createAuthHeaders();
|
||||
const records = [...a_records, ...srv_records];
|
||||
const post = bent(process.env.DME_BASE_URL, 'POST', 201, 400, headers);
|
||||
logger.debug({records}, 'Attemting to create dns records');
|
||||
const res = await post(`/dns/managed/${domainId}/records/createMulti`,
|
||||
[...a_records, ...srv_records]);
|
||||
|
||||
if (201 === res.statusCode) {
|
||||
const str = await res.text();
|
||||
return JSON.parse(str);
|
||||
const response = await fetch(`${process.env.DME_BASE_URL}/dns/managed/${domainId}/records/createMulti`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify(records)
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error creating records');
|
||||
return;
|
||||
}
|
||||
let body;
|
||||
try {
|
||||
body = await res.json();
|
||||
} catch (err) {
|
||||
const result = await response.json();
|
||||
logger.debug({result}, 'createDnsRecords: created records');
|
||||
if (201 === response.status) {
|
||||
return result;
|
||||
}
|
||||
logger.error({headers: res.headers, body}, `Error creating records, status ${res.statusCode}`);
|
||||
} catch (err) {
|
||||
logger.error({err}, 'Error retrieving domains');
|
||||
}
|
||||
@@ -103,7 +104,6 @@ const createDnsRecords = async(logger, domain, name, value, ttl = 3600) => {
|
||||
const deleteDnsRecords = async(logger, domain, recIds) => {
|
||||
checkAsserts();
|
||||
const headers = createAuthHeaders();
|
||||
const del = bent(process.env.DME_BASE_URL, 'DELETE', 200, headers);
|
||||
try {
|
||||
if (!domains.has(domain)) {
|
||||
const domainId = await getDnsDomainId(logger, domain);
|
||||
@@ -112,7 +112,10 @@ const deleteDnsRecords = async(logger, domain, recIds) => {
|
||||
}
|
||||
const domainId = domains.get(domain);
|
||||
const url = `/dns/managed/${domainId}/records?${recIds.map((r) => `ids=${r}`).join('&')}`;
|
||||
await del(url);
|
||||
await fetch(`${process.env.DME_BASE_URL}${url}`, {
|
||||
method: 'DELETE',
|
||||
headers
|
||||
});
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
+14
-14
@@ -1,7 +1,6 @@
|
||||
const formData = require('form-data');
|
||||
const Mailgun = require('mailgun.js');
|
||||
const mailgun = new Mailgun(formData);
|
||||
const bent = require('bent');
|
||||
const validateEmail = (email) => {
|
||||
// eslint-disable-next-line max-len
|
||||
const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
@@ -19,8 +18,9 @@ const emailSimpleText = async(logger, to, subject, text) => {
|
||||
};
|
||||
|
||||
const sendEmailByCustomVendor = async(logger, from, to, subject, text) => {
|
||||
try {
|
||||
const post = bent('POST', {
|
||||
const response = await fetch(process.env.CUSTOM_EMAIL_VENDOR_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...((process.env.CUSTOM_EMAIL_VENDOR_USERNAME && process.env.CUSTOM_EMAIL_VENDOR_PASSWORD) &&
|
||||
({
|
||||
@@ -28,22 +28,22 @@ const sendEmailByCustomVendor = async(logger, from, to, subject, text) => {
|
||||
`${process.env.CUSTOM_EMAIL_VENDOR_USERNAME}:${process.env.CUSTOM_EMAIL_VENDOR_PASSWORD}`
|
||||
).toString('base64')}`
|
||||
}))
|
||||
});
|
||||
|
||||
const res = await post(process.env.CUSTOM_EMAIL_VENDOR_URL, {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text
|
||||
});
|
||||
logger.debug({
|
||||
res
|
||||
}, 'sent email to custom vendor.');
|
||||
} catch (err) {
|
||||
logger.info({
|
||||
err
|
||||
}, 'Error sending email From Custom email vendor');
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error sending email to custom vendor');
|
||||
return;
|
||||
}
|
||||
const res = await response.json();
|
||||
logger.debug({
|
||||
res
|
||||
}, 'sent email to custom vendor.');
|
||||
};
|
||||
|
||||
const sendEmailByMailgun = async(logger, from, to, subject, text) => {
|
||||
|
||||
+87
-58
@@ -1,15 +1,11 @@
|
||||
const debug = require('debug')('jambonz:api-server');
|
||||
const bent = require('bent');
|
||||
const basicAuth = (apiKey) => {
|
||||
const header = `Bearer ${apiKey}`;
|
||||
return {Authorization: header};
|
||||
};
|
||||
const postJSON = bent(process.env.HOMER_BASE_URL || 'http://127.0.0.1', 'POST', 'json', 200, 201);
|
||||
const postPcap = bent(process.env.HOMER_BASE_URL || 'http://127.0.0.1', 'POST', 200, {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
});
|
||||
|
||||
const SEVEN_DAYS_IN_MS = (1000 * 3600 * 24 * 7);
|
||||
const HOMER_BASE_URL = process.env.HOMER_BASE_URL || 'http://127.0.0.1';
|
||||
|
||||
const getHomerApiKey = async(logger) => {
|
||||
if (!process.env.HOMER_BASE_URL || !process.env.HOMER_USERNAME || !process.env.HOMER_PASSWORD) {
|
||||
@@ -17,11 +13,21 @@ const getHomerApiKey = async(logger) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const obj = await postJSON('/api/v3/auth', {
|
||||
username: process.env.HOMER_USERNAME,
|
||||
password: process.env.HOMER_PASSWORD
|
||||
const response = await fetch(`${HOMER_BASE_URL}/api/v3/auth`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: process.env.HOMER_USERNAME,
|
||||
password: process.env.HOMER_PASSWORD
|
||||
})
|
||||
});
|
||||
debug(obj);
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving apikey');
|
||||
return;
|
||||
}
|
||||
const obj = await response.json();
|
||||
logger.debug({obj}, `getHomerApiKey for user ${process.env.HOMER_USERNAME}`);
|
||||
return obj.token;
|
||||
} catch (err) {
|
||||
@@ -36,28 +42,40 @@ const getHomerSipTrace = async(logger, apiKey, callId) => {
|
||||
}
|
||||
try {
|
||||
const now = Date.now();
|
||||
const obj = await postJSON('/api/v3/call/transaction', {
|
||||
param: {
|
||||
transaction: {
|
||||
call: true,
|
||||
registration: true,
|
||||
rest: false
|
||||
},
|
||||
orlogic: true,
|
||||
search: {
|
||||
'1_call': {
|
||||
callid: [callId]
|
||||
},
|
||||
'1_registration': {
|
||||
callid: [callId]
|
||||
}
|
||||
},
|
||||
const response = await fetch(`${HOMER_BASE_URL}/api/v3/call/transaction`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...basicAuth(apiKey)
|
||||
},
|
||||
timestamp: {
|
||||
from: now - SEVEN_DAYS_IN_MS,
|
||||
to: now
|
||||
}
|
||||
}, basicAuth(apiKey));
|
||||
body: JSON.stringify({
|
||||
param: {
|
||||
transaction: {
|
||||
call: true,
|
||||
registration: true,
|
||||
rest: false
|
||||
},
|
||||
orlogic: true,
|
||||
search: {
|
||||
'1_call': {
|
||||
callid: [callId]
|
||||
},
|
||||
'1_registration': {
|
||||
callid: [callId]
|
||||
}
|
||||
},
|
||||
},
|
||||
timestamp: {
|
||||
from: now - SEVEN_DAYS_IN_MS,
|
||||
to: now
|
||||
}
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving messages');
|
||||
return;
|
||||
}
|
||||
const obj = await response.json();
|
||||
return obj;
|
||||
} catch (err) {
|
||||
logger.info({err}, `getHomerSipTrace: Error retrieving messages for callid ${callId}`);
|
||||
@@ -70,34 +88,45 @@ const getHomerPcap = async(logger, apiKey, callIds, method) => {
|
||||
}
|
||||
try {
|
||||
const now = Date.now();
|
||||
const stream = await postPcap('/api/v3/export/call/messages/pcap', {
|
||||
param: {
|
||||
transaction: {
|
||||
call: method === 'invite',
|
||||
registration: method === 'register',
|
||||
rest: false
|
||||
},
|
||||
orlogic: true,
|
||||
search: {
|
||||
...(method === 'invite' && {
|
||||
'1_call': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
,
|
||||
...(method === 'register' && {
|
||||
'1_registration': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
},
|
||||
const response = await fetch(`${HOMER_BASE_URL}/api/v3/export/call/messages/pcap`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...basicAuth(apiKey)
|
||||
},
|
||||
timestamp: {
|
||||
from: now - SEVEN_DAYS_IN_MS,
|
||||
to: now
|
||||
}
|
||||
}, basicAuth(apiKey));
|
||||
return stream;
|
||||
body: JSON.stringify({
|
||||
param: {
|
||||
transaction: {
|
||||
call: method === 'invite',
|
||||
registration: method === 'register',
|
||||
rest: false
|
||||
},
|
||||
orlogic: true,
|
||||
search: {
|
||||
...(method === 'invite' && {
|
||||
'1_call': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
,
|
||||
...(method === 'register' && {
|
||||
'1_registration': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
timestamp: {
|
||||
from: now - SEVEN_DAYS_IN_MS,
|
||||
to: now
|
||||
}
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving messages');
|
||||
return;
|
||||
}
|
||||
return response.body;
|
||||
} catch (err) {
|
||||
logger.info({err}, `getHomerPcap: Error retrieving messages for callid ${callIds}`);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const bent = require('bent');
|
||||
const getJSON = bent(process.env.JAEGER_BASE_URL || 'http://127.0.0.1', 'GET', 'json', 200);
|
||||
const JAEGER_BASE_URL = process.env.JAEGER_BASE_URL || 'http://127.0.0.1';
|
||||
|
||||
const getJaegerTrace = async(logger, traceId) => {
|
||||
if (!process.env.JAEGER_BASE_URL) {
|
||||
@@ -7,7 +6,12 @@ const getJaegerTrace = async(logger, traceId) => {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return await getJSON(`/api/v3/traces/${traceId}`);
|
||||
const response = await fetch(`${JAEGER_BASE_URL}/api/traces/${traceId}`);
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving spans');
|
||||
return;
|
||||
}
|
||||
return await response.json();
|
||||
} catch (err) {
|
||||
const url = `${process.env.JAEGER_BASE_URL}/api/traces/${traceId}`;
|
||||
logger.error({err, traceId}, `getJaegerTrace: Error retrieving spans from ${url}`);
|
||||
|
||||
+71
-29
@@ -1,7 +1,4 @@
|
||||
const assert = require('assert');
|
||||
const bent = require('bent');
|
||||
const postJSON = bent('POST', 'json', 200);
|
||||
const getJSON = bent('GET', 'json', 200);
|
||||
const {emailSimpleText} = require('./email-utils');
|
||||
const {DbErrorForbidden} = require('../utils/errors');
|
||||
|
||||
@@ -10,13 +7,26 @@ const doGithubAuth = async(logger, payload) => {
|
||||
|
||||
try {
|
||||
/* exchange the code for an access token */
|
||||
const obj = await postJSON('https://github.com/login/oauth/access_token', {
|
||||
client_id: payload.oauth2_client_id,
|
||||
client_secret: process.env.GITHUB_CLIENT_SECRET,
|
||||
code: payload.oauth2_code,
|
||||
state: payload.oauth2_state,
|
||||
redirect_uri: payload.oauth2_redirect_uri
|
||||
const response = await fetch('https://github.com/login/oauth/access_token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: payload.oauth2_client_id,
|
||||
client_secret: process.env.GITHUB_CLIENT_SECRET,
|
||||
code: payload.oauth2_code,
|
||||
state: payload.oauth2_state,
|
||||
redirect_uri: payload.oauth2_redirect_uri
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving access_token from github');
|
||||
throw new DbErrorForbidden(await response.text());
|
||||
}
|
||||
|
||||
const obj = await response.json();
|
||||
if (!obj.access_token) {
|
||||
logger.error({obj}, 'Error retrieving access_token from github');
|
||||
if (obj.error === 'bad_verification_code') throw new Error('bad verification code');
|
||||
@@ -25,17 +35,31 @@ const doGithubAuth = async(logger, payload) => {
|
||||
logger.debug({obj}, 'got response from github for access_token');
|
||||
|
||||
/* use the access token to get basic public info as well as primary email */
|
||||
const userDetails = await getJSON('https://api.github.com/user', null, {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
const userResponse = await fetch('https://api.github.com/user', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
}
|
||||
});
|
||||
if (!userResponse.ok) {
|
||||
logger.error({userResponse}, 'Error retrieving user details from github');
|
||||
throw new DbErrorForbidden(await userResponse.text());
|
||||
}
|
||||
const userDetails = await userResponse.json();
|
||||
|
||||
const emails = await getJSON('https://api.github.com/user/emails', null, {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
const emailsResponse = await fetch('https://api.github.com/user/emails', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
}
|
||||
});
|
||||
if (!emailsResponse.ok) {
|
||||
logger.error({emailsResponse}, 'Error retrieving emails from github');
|
||||
throw new DbErrorForbidden(await emailsResponse.text());
|
||||
}
|
||||
const emails = await emailsResponse.json();
|
||||
const primary = emails.find((e) => e.primary);
|
||||
if (primary) Object.assign(userDetails, {
|
||||
email: primary.email,
|
||||
@@ -55,14 +79,26 @@ const doGoogleAuth = async(logger, payload) => {
|
||||
|
||||
try {
|
||||
/* exchange the code for an access token */
|
||||
const obj = await postJSON('https://oauth2.googleapis.com/token', {
|
||||
client_id: payload.oauth2_client_id,
|
||||
client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET,
|
||||
code: payload.oauth2_code,
|
||||
state: payload.oauth2_state,
|
||||
redirect_uri: payload.oauth2_redirect_uri,
|
||||
grant_type: 'authorization_code'
|
||||
const response = await fetch('https://oauth2.googleapis.com/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: payload.oauth2_client_id,
|
||||
client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET,
|
||||
code: payload.oauth2_code,
|
||||
state: payload.oauth2_state,
|
||||
redirect_uri: payload.oauth2_redirect_uri,
|
||||
grant_type: 'authorization_code'
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.error({response}, 'Error retrieving access_token from google');
|
||||
throw new DbErrorForbidden(await response.text());
|
||||
}
|
||||
const obj = await response.json();
|
||||
if (!obj.access_token) {
|
||||
logger.error({obj}, 'Error retrieving access_token from github');
|
||||
if (obj.error === 'bad_verification_code') throw new Error('bad verification code');
|
||||
@@ -71,12 +107,18 @@ const doGoogleAuth = async(logger, payload) => {
|
||||
logger.debug({obj}, 'got response from google for access_token');
|
||||
|
||||
/* use the access token to get basic public info as well as primary email */
|
||||
const userDetails = await getJSON('https://www.googleapis.com/oauth2/v2/userinfo', null, {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
const userDetailsResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${obj.access_token}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz 1.0'
|
||||
}
|
||||
});
|
||||
|
||||
if (!userDetailsResponse.ok) {
|
||||
logger.error({userDetailsResponse}, 'Error retrieving user details from google');
|
||||
throw new DbErrorForbidden(await userDetailsResponse.text());
|
||||
}
|
||||
const userDetails = await userDetailsResponse.json();
|
||||
logger.info({userDetails}, 'retrieved user details from google');
|
||||
return userDetails;
|
||||
} catch (err) {
|
||||
|
||||
+100
-65
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ assert.ok(process.env.STRIPE_API_KEY || process.env.NODE_ENV === 'test',
|
||||
assert.ok(process.env.STRIPE_BASE_URL || process.env.NODE_ENV === 'test',
|
||||
'missing env STRIPE_BASE_URL for billing operations');
|
||||
|
||||
const bent = require('bent');
|
||||
const formurlencoded = require('form-urlencoded');
|
||||
const qs = require('qs');
|
||||
const toBase64 = (str) => Buffer.from(str || '', 'utf8').toString('base64');
|
||||
@@ -14,10 +13,47 @@ const basicAuth = () => {
|
||||
const header = `Basic ${toBase64(process.env.STRIPE_API_KEY)}`;
|
||||
return {Authorization: header};
|
||||
};
|
||||
const postForm = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'POST', 'string',
|
||||
Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, basicAuth()), 200);
|
||||
const getJSON = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'GET', 'json', basicAuth(), 200);
|
||||
const deleteJSON = bent(process.env.STRIPE_BASE_URL || 'http://127.0.0.1', 'DELETE', 'json', basicAuth(), 200);
|
||||
const STRIPE_BASE_URL = process.env.STRIPE_BASE_URL || 'http://127.0.0.1';
|
||||
const getJSON = async(path) => {
|
||||
const response = await fetch(`${STRIPE_BASE_URL}${path}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...basicAuth()
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error retrieving ${path} from stripe: ${response.status}`);
|
||||
}
|
||||
return await response.json();
|
||||
};
|
||||
|
||||
const postForm = async(path, body) => {
|
||||
const response = await fetch(`${STRIPE_BASE_URL}${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
...basicAuth()
|
||||
},
|
||||
body
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error posting to ${path} from stripe: ${response.status}`);
|
||||
}
|
||||
return await response.text();
|
||||
};
|
||||
const deleteJSON = async(path) => {
|
||||
const response = await fetch(`${STRIPE_BASE_URL}${path}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...basicAuth()
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error deleting ${path} from stripe: ${response.status}`);
|
||||
}
|
||||
return await response.json();
|
||||
};
|
||||
//const debug = require('debug')('jambonz:api-server');
|
||||
|
||||
const listProducts = async(logger) => await getJSON('/products?active=true');
|
||||
|
||||
Reference in New Issue
Block a user