add support for azure custom voices on a per-say basis (#346)

This commit is contained in:
Dave Horton
2023-05-09 13:25:43 -04:00
committed by GitHub
parent 51bcb5a2d2
commit feccc0fca7
6 changed files with 64 additions and 10 deletions

View File

@@ -1291,6 +1291,7 @@ class CallSession extends Emitter {
this.wakeupResolver(resolution);
this.wakeupResolver = null;
}
/*
else {
const {queue, command} = resolution;
const {span} = this.rootSpan.startChildSpan(`recv cmd: ${command}`);
@@ -1300,6 +1301,7 @@ class CallSession extends Emitter {
});
span.end();
}
*/
}
_onWsConnectionDropped() {

View File

@@ -36,6 +36,7 @@ class TaskSay extends Task {
this.earlyMedia = this.data.earlyMedia === true || (parentTask && parentTask.earlyMedia);
this.synthesizer = this.data.synthesizer || {};
this.disableTtsCache = this.data.disableTtsCache;
this.options = this.synthesizer.options || {};
}
get name() { return TaskName.Say; }
@@ -66,7 +67,7 @@ class TaskSay extends Task {
cs.speechSynthesisVoice;
const engine = this.synthesizer.engine || 'standard';
const salt = cs.callSid;
const credentials = cs.getSpeechCredentials(vendor, 'tts');
let credentials = cs.getSpeechCredentials(vendor, 'tts');
/* parse Nuance voices into name and model */
let model;
@@ -78,6 +79,16 @@ class TaskSay extends Task {
}
}
/* allow for microsoft custom region voice and api_key to be specified as an override */
if (vendor === 'microsoft' && this.options.deploymentId) {
credentials = credentials || {};
credentials.use_custom_tts = true;
credentials.custom_tts_endpoint = this.options.deploymentId;
credentials.api_key = this.options.apiKey || credentials.apiKey;
credentials.region = this.options.region || credentials.region;
voice = this.options.voice || voice;
}
this.logger.info({vendor, language, voice, model}, 'TaskSay:exec');
this.ep = ep;
try {

14
package-lock.json generated
View File

@@ -15,7 +15,7 @@
"@jambonz/speech-utils": "^0.0.12",
"@jambonz/stats-collector": "^0.1.8",
"@jambonz/time-series": "^0.2.5",
"@jambonz/verb-specifications": "^0.0.21",
"@jambonz/verb-specifications": "^0.0.22",
"@opentelemetry/api": "^1.4.0",
"@opentelemetry/exporter-jaeger": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.35.0",
@@ -1676,9 +1676,9 @@
}
},
"node_modules/@jambonz/verb-specifications": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@jambonz/verb-specifications/-/verb-specifications-0.0.21.tgz",
"integrity": "sha512-NQTQLI0k7nFmjqiKIbPaux2+ES2etFh/hnMNzPbszXS313mAnMZtv7y+EWrbniXeiXMCwHbkavm1H/N8+Lv5Qg==",
"version": "0.0.22",
"resolved": "https://registry.npmjs.org/@jambonz/verb-specifications/-/verb-specifications-0.0.22.tgz",
"integrity": "sha512-dgvpVh48IX2CVedLKgxYhv5ZwWoeAPtEhCjXqkkVOGgh6eqX1eu+pmcH2D/aKeFdxhXRVGUxfhtLLerfErIpVQ==",
"dependencies": {
"debug": "^4.3.4",
"pino": "^8.8.0"
@@ -10128,9 +10128,9 @@
}
},
"@jambonz/verb-specifications": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@jambonz/verb-specifications/-/verb-specifications-0.0.21.tgz",
"integrity": "sha512-NQTQLI0k7nFmjqiKIbPaux2+ES2etFh/hnMNzPbszXS313mAnMZtv7y+EWrbniXeiXMCwHbkavm1H/N8+Lv5Qg==",
"version": "0.0.22",
"resolved": "https://registry.npmjs.org/@jambonz/verb-specifications/-/verb-specifications-0.0.22.tgz",
"integrity": "sha512-dgvpVh48IX2CVedLKgxYhv5ZwWoeAPtEhCjXqkkVOGgh6eqX1eu+pmcH2D/aKeFdxhXRVGUxfhtLLerfErIpVQ==",
"requires": {
"debug": "^4.3.4",
"pino": "^8.8.0"

View File

@@ -31,7 +31,7 @@
"@jambonz/speech-utils": "^0.0.12",
"@jambonz/stats-collector": "^0.1.8",
"@jambonz/time-series": "^0.2.5",
"@jambonz/verb-specifications": "^0.0.21",
"@jambonz/verb-specifications": "^0.0.22",
"@opentelemetry/api": "^1.4.0",
"@opentelemetry/exporter-jaeger": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.35.0",

View File

@@ -261,7 +261,7 @@ test('\'gather\' test - deepgram', async(t) => {
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
//console.log(JSON.stringify(obj));
t.ok(obj.body.speech.alternatives[0].transcript.toLowerCase().startsWith('i\'d like to speak to customer support'),
t.ok(obj.body.speech.alternatives[0].transcript.toLowerCase().includes('like to speak to customer support'),
'gather: succeeds when using deepgram credentials');
disconnect();
} catch (err) {

View File

@@ -83,3 +83,44 @@ test('\'config\' reset synthesizer tests', async(t) => {
t.error(err);
}
});
const {MICROSOFT_CUSTOM_API_KEY, MICROSOFT_DEPLOYMENT_ID, MICROSOFT_CUSTOM_REGION, MICROSOFT_CUSTOM_VOICE} = process.env;
if (MICROSOFT_CUSTOM_API_KEY && MICROSOFT_DEPLOYMENT_ID && MICROSOFT_CUSTOM_REGION && MICROSOFT_CUSTOM_VOICE) {
test('\'say\' tests - microsoft custom voice', async(t) => {
clearModule.all();
const {srf, disconnect} = require('../app');
try {
await connect(srf);
// GIVEN
const verbs = [
{
verb: 'say',
text: 'hello',
synthesizer: {
vendor: 'microsoft',
voice: MICROSOFT_CUSTOM_VOICE,
options: {
deploymentId: MICROSOFT_DEPLOYMENT_ID,
apiKey: MICROSOFT_CUSTOM_API_KEY,
region: MICROSOFT_CUSTOM_REGION,
}
}
}
];
const from = 'say_test_success';
provisionCallHook(from, verbs)
// THEN
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
t.pass('say: succeeds when using microsoft custom voice');
disconnect();
} catch (err) {
console.log(`error received: ${err}`);
disconnect();
t.error(err);
}
});
}