allow say.text to accept either a string or an array of strings

This commit is contained in:
Dave Horton
2020-04-29 10:49:16 -04:00
parent a806a4eb46
commit 419c5ea9fd
6 changed files with 50 additions and 24 deletions

View File

@@ -6,7 +6,7 @@ class TaskSay extends Task {
super(logger, opts); super(logger, opts);
this.preconditions = TaskPreconditions.Endpoint; this.preconditions = TaskPreconditions.Endpoint;
this.text = this.data.text; this.text = Array.isArray(this.data.text) ? this.data.text : [this.data.text];
this.loop = this.data.loop || 1; this.loop = this.data.loop || 1;
this.earlyMedia = this.data.earlyMedia === true || (parentTask && parentTask.earlyMedia); this.earlyMedia = this.data.earlyMedia === true || (parentTask && parentTask.earlyMedia);
this.synthesizer = this.data.synthesizer || {}; this.synthesizer = this.data.synthesizer || {};
@@ -20,21 +20,23 @@ class TaskSay extends Task {
await super.exec(cs); await super.exec(cs);
this.ep = ep; this.ep = ep;
try { try {
let filepath; const filepath = [];
const opts = Object.assign({
text: this.text,
vendor: cs.speechSynthesisVendor,
language: cs.speechSynthesisLanguage,
voice: cs.speechSynthesisVoice
}, this.synthesizer);
while (!this.killed && this.loop--) { while (!this.killed && this.loop--) {
if (!filepath) { let segment = 0;
this.logger.debug('TaskSay:exec - retrieving synthesized audio'); do {
filepath = await synthAudio(opts); if (filepath.length <= segment) {
cs.trackTmpFile(filepath); const opts = Object.assign({
} text: this.text[segment],
await ep.play(filepath); vendor: cs.speechSynthesisVendor,
language: cs.speechSynthesisLanguage,
voice: cs.speechSynthesisVoice
}, this.synthesizer);
const path = await synthAudio(opts);
filepath.push(path);
cs.trackTmpFile(path);
}
await ep.play(filepath[segment]);
} while (++segment < this.text.length);
} }
} catch (err) { } catch (err) {
this.logger.info(err, 'TaskSay:exec error'); this.logger.info(err, 'TaskSay:exec error');

View File

@@ -28,7 +28,7 @@
}, },
"say": { "say": {
"properties": { "properties": {
"text": "string", "text": "string|array",
"loop": "number", "loop": "number",
"synthesizer": "#synthesizer", "synthesizer": "#synthesizer",
"earlyMedia": "boolean" "earlyMedia": "boolean"

View File

@@ -117,21 +117,21 @@ class Task extends Emitter {
const dSpec = specData.properties[dKey]; const dSpec = specData.properties[dKey];
debug(`Task:validate validating property ${dKey} with value ${JSON.stringify(dVal)}`); debug(`Task:validate validating property ${dKey} with value ${JSON.stringify(dVal)}`);
if (typeof dSpec === 'string' && ['number', 'string', 'object', 'boolean'].includes(dSpec)) { if (typeof dSpec === 'string' && dSpec === 'array') {
// simple types
if (typeof dVal !== specData.properties[dKey]) {
throw new Error(`${name}: property ${dKey} has invalid data type`);
}
}
else if (typeof dSpec === 'string' && dSpec === 'array') {
if (!Array.isArray(dVal)) throw new Error(`${name}: property ${dKey} is not an array`); if (!Array.isArray(dVal)) throw new Error(`${name}: property ${dKey} is not an array`);
} }
else if (typeof dSpec === 'string' && dSpec.includes('|')) { else if (typeof dSpec === 'string' && dSpec.includes('|')) {
const types = dSpec.split('|').map((t) => t.trim()); const types = dSpec.split('|').map((t) => t.trim());
if (!types.includes(typeof dVal)) { if (!types.includes(typeof dVal) && !(types.includes('array') && Array.isArray(dVal))) {
throw new Error(`${name}: property ${dKey} has invalid data type, must be one of ${types}`); throw new Error(`${name}: property ${dKey} has invalid data type, must be one of ${types}`);
} }
} }
else if (typeof dSpec === 'string' && ['number', 'string', 'object', 'boolean'].includes(dSpec)) {
// simple types
if (typeof dVal !== specData.properties[dKey]) {
throw new Error(`${name}: property ${dKey} has invalid data type`);
}
}
else if (Array.isArray(dSpec) && dSpec[0].startsWith('#')) { else if (Array.isArray(dSpec) && dSpec[0].startsWith('#')) {
const name = dSpec[0].slice(1); const name = dSpec[0].slice(1);
for (const item of dVal) { for (const item of dVal) {

View File

@@ -0,0 +1,9 @@
{
"say": {
"text": ["hi there", "John"],
"synthesizer": {
"vendor": "google",
"language": "en-US"
}
}
}

9
test/data/good/say.json Normal file
View File

@@ -0,0 +1,9 @@
{
"say": {
"text": "hi there",
"synthesizer": {
"vendor": "google",
"language": "en-US"
}
}
}

View File

@@ -39,6 +39,12 @@ test('app payload parsing tests', (t) => {
task = makeTask(logger, require('./data/good/pause')); task = makeTask(logger, require('./data/good/pause'));
t.ok(task.name === 'pause', 'parsed pause'); t.ok(task.name === 'pause', 'parsed pause');
task = makeTask(logger, require('./data/good/say'));
t.ok(task.name === 'say', 'parsed say');
task = makeTask(logger, require('./data/good/say-text-array'));
t.ok(task.name === 'say', 'parsed say with multiple segments');
const alt = require('./data/good/alternate-syntax'); const alt = require('./data/good/alternate-syntax');
const normalize = require('../lib/utils/normalize-jambones'); const normalize = require('../lib/utils/normalize-jambones');
normalize(logger, alt).forEach((t) => { normalize(logger, alt).forEach((t) => {