support assembly ai (#248)

* support assembly ai

* wip

* wip
This commit is contained in:
Hoan Luu Huu
2023-11-01 19:02:32 +07:00
committed by GitHub
parent 30ba84d57b
commit f15c339a2a
5 changed files with 90 additions and 2 deletions

View File

@@ -20,7 +20,8 @@ const {
testSonioxStt,
testIbmTts,
testIbmStt,
testElevenlabs
testElevenlabs,
testAssemblyStt
} = require('../../utils/speech-utils');
const bent = require('bent');
const {promisePool} = require('../../db');
@@ -211,6 +212,11 @@ const encryptCredential = (obj) => {
const elevenlabsData = JSON.stringify({api_key, model_id});
return encrypt(elevenlabsData);
case 'assemblyai':
assert(api_key, 'invalid assemblyai speech credential: api_key is required');
const assemblyaiData = JSON.stringify({api_key});
return encrypt(assemblyaiData);
default:
if (vendor.startsWith('custom:')) {
const customData = JSON.stringify({auth_token, custom_stt_url, custom_tts_url});
@@ -335,6 +341,9 @@ function decryptCredential(obj, credential, logger) {
obj.auth_token = obscureKey(o.auth_token);
obj.custom_stt_url = o.custom_stt_url;
obj.custom_tts_url = o.custom_tts_url;
} else if ('assemblyai' === obj.vendor) {
const o = JSON.parse(decrypt(credential));
obj.api_key = obscureKey(o.api_key);
}
}
@@ -757,6 +766,18 @@ router.get('/:sid/test', async(req, res) => {
SpeechCredential.ttsTestResult(sid, false);
}
}
} else if (cred.vendor === 'assemblyai') {
const {api_key} = credential;
if (cred.use_for_stt) {
try {
await testAssemblyStt(logger, {api_key});
results.stt.status = 'ok';
SpeechCredential.sttTestResult(sid, true);
} catch (err) {
results.stt = {status: 'fail', reason: err.message};
SpeechCredential.sttTestResult(sid, false);
}
}
}
res.status(200).json(results);

View File

@@ -5,6 +5,7 @@ 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 testSonioxStt = async(logger, credentials) => {
@@ -260,6 +261,32 @@ const testWellSaidStt = async(logger, credentials) => {
return true;
};
const testAssemblyStt = async(logger, credentials) => {
const {api_key} = credentials;
const assemblyai = new AssemblyAI({
apiKey: api_key
});
const audioUrl = `${__dirname}/../../data/test_audio.wav`;
return new Promise((resolve, reject) => {
assemblyai.transcripts
.create({ audio_url: audioUrl })
.then((transcript) => {
logger.debug({transcript}, 'got transcription from AssemblyAi');
if (transcript.status === 'error') {
return reject({message: transcript.error});
}
return resolve(transcript.text);
})
.catch((err) => {
logger.info({err}, 'failed to get assemblyAI transcription');
reject(err);
});
});
};
module.exports = {
testGoogleTts,
testGoogleStt,
@@ -275,5 +302,6 @@ module.exports = {
testIbmTts,
testIbmStt,
testSonioxStt,
testElevenlabs
testElevenlabs,
testAssemblyStt
};

17
package-lock.json generated
View File

@@ -24,6 +24,7 @@
"@jambonz/verb-specifications": "^0.0.29",
"@soniox/soniox-node": "^1.1.1",
"argon2": "^0.30.3",
"assemblyai": "^3.0.1",
"bent": "^7.3.12",
"cors": "^2.8.5",
"debug": "^4.3.4",
@@ -3314,6 +3315,14 @@
"safer-buffer": "~2.1.0"
}
},
"node_modules/assemblyai": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/assemblyai/-/assemblyai-3.0.1.tgz",
"integrity": "sha512-7EW3v00o8s3TSweQERJjoNbXMDU8abwYwpE3gYKQhNY4xlcxb2in344rQi6MsMLVxRtLe8HBXGVRUlZkzfxC3w==",
"dependencies": {
"ws": "^8.13.0"
}
},
"node_modules/assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
@@ -12416,6 +12425,14 @@
"safer-buffer": "~2.1.0"
}
},
"assemblyai": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/assemblyai/-/assemblyai-3.0.1.tgz",
"integrity": "sha512-7EW3v00o8s3TSweQERJjoNbXMDU8abwYwpE3gYKQhNY4xlcxb2in344rQi6MsMLVxRtLe8HBXGVRUlZkzfxC3w==",
"requires": {
"ws": "^8.13.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",

View File

@@ -34,6 +34,7 @@
"@jambonz/verb-specifications": "^0.0.29",
"@soniox/soniox-node": "^1.1.1",
"argon2": "^0.30.3",
"assemblyai": "^3.0.1",
"bent": "^7.3.12",
"cors": "^2.8.5",
"debug": "^4.3.4",

View File

@@ -537,6 +537,27 @@ test('speech credentials tests', async(t) => {
});
t.ok(result.statusCode === 204, 'successfully deleted speech credential for custom voice google');
/* add a credential for assemblyAI */
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
resolveWithFullResponse: true,
auth: authUser,
json: true,
body: {
vendor: 'assemblyai',
use_for_stt: true,
api_key: "APIKEY"
}
});
t.ok(result.statusCode === 201, 'successfully added speech credential for assemblyai');
const assemblyAiSid = result.body.sid;
/* delete the credential */
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${assemblyAiSid}`, {
auth: authUser,
resolveWithFullResponse: true,
});
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
await deleteObjectBySid(request, '/Accounts', account_sid);
await deleteObjectBySid(request, '/ServiceProviders', service_provider_sid);
t.end();