Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
albho committed Feb 15, 2024
1 parent 39e0dd1 commit 668e3fb
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 58 deletions.
9 changes: 3 additions & 6 deletions binding/web/src/orca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ type pv_orca_delete_type = (object: number) => Promise<void>;
type pv_orca_valid_characters_type = (object: number, numCharacters: number, validCharacters: number) => Promise<number>;
type pv_orca_valid_characters_delete_type = (validCharacters: number) => Promise<void>;
type pv_orca_sample_rate_type = (object: number, sampleRate: number) => Promise<number>;
type pv_orca_max_character_limit_type = () => Promise<number>;
type pv_orca_synthesize_params_init_type = (object: number) => Promise<number>;
type pv_orca_synthesize_params_delete_type = (object: number) => Promise<void>;
type pv_orca_synthesize_params_set_speech_rate_type = (object: number, speechRate: number) => Promise<number>;
Expand Down Expand Up @@ -83,6 +82,7 @@ type OrcaWasmOutput = {
};

const PV_STATUS_SUCCESS = 10000;
const WEB_MAX_CHAR_LIMIT = 200;

export class Orca {
private readonly _pvOrcaDelete: pv_orca_delete_type;
Expand Down Expand Up @@ -447,7 +447,7 @@ export class Orca {

private static async initWasm(accessKey: string, wasmBase64: string, modelPath: string): Promise<any> {
// A WebAssembly page has a constant size of 64KiB. -> 1MiB ~= 16 pages
const memory = new WebAssembly.Memory({ initial: 60000 });
const memory = new WebAssembly.Memory({ initial: 7500 });

const memoryBufferUint8 = new Uint8Array(memory.buffer);

Expand All @@ -462,7 +462,6 @@ export class Orca {
const pv_orca_valid_characters = exports.pv_orca_valid_characters as pv_orca_valid_characters_type;
const pv_orca_valid_characters_delete = exports.pv_orca_valid_characters_delete as pv_orca_valid_characters_delete_type;
const pv_orca_sample_rate = exports.pv_orca_sample_rate as pv_orca_sample_rate_type;
const pv_orca_max_character_limit = exports.pv_orca_max_character_limit as pv_orca_max_character_limit_type;
const pv_orca_synthesize_params_init = exports.pv_orca_synthesize_params_init as pv_orca_synthesize_params_init_type;
const pv_orca_synthesize_params_delete = exports.pv_orca_synthesize_params_delete as pv_orca_synthesize_params_delete_type;
const pv_orca_synthesize_params_set_speech_rate = exports.pv_orca_synthesize_params_set_speech_rate as pv_orca_synthesize_params_set_speech_rate_type;
Expand Down Expand Up @@ -634,8 +633,6 @@ export class Orca {
await pv_free(validCharactersAddressAddressAddress);
await pv_orca_valid_characters_delete(validCharactersAddressAddress);

const maxCharacterLimit = await pv_orca_max_character_limit();

const versionAddress = await pv_orca_version();
const version = arrayBufferToStringAtIndex(
memoryBufferUint8,
Expand All @@ -650,7 +647,7 @@ export class Orca {
objectAddress: objectAddress,
version: version,
sampleRate: sampleRate,
maxCharacterLimit: maxCharacterLimit,
maxCharacterLimit: WEB_MAX_CHAR_LIMIT,
validCharacters: validCharacters,
messageStackAddressAddressAddress: messageStackAddressAddressAddress,
messageStackDepthAddress: messageStackDepthAddress,
Expand Down
153 changes: 105 additions & 48 deletions binding/web/test/orca.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@ import testData from '../cypress/fixtures/.test/test_data.json';

const ACCESS_KEY = Cypress.env('ACCESS_KEY');

const EXPECTED_VALID_CHARACTERS = ['.', ':', ',', '"', '?', '!'];
const EXPECTED_MAX_CHARACTER_LIMIT = 2000;
const EXPECTED_MAX_CHARACTER_LIMIT = 200;
const EXPECTED_SAMPLE_RATE = 22050;
const EXPECTED_VALID_CHARACTERS = [
'.', ':', ',', '"', '?', '!', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '\'', '{', '}', '|', ' ', '-',
];

const levenshteinDistance = (words1: string[], words2: string[]) => {
const res = Array.from(Array(words1.length + 1), () => new Array(words2.length + 1));
Expand Down Expand Up @@ -58,10 +67,11 @@ const runInitTest = async (
expectFailure = false,
} = params;

let orca = null;
let isFailed = false;

try {
const orca = await instance.create(accessKey, () => {
orca = await instance.create(accessKey, () => {
}, model);

expect(typeof orca.version).to.eq('string');
Expand All @@ -72,22 +82,26 @@ const runInitTest = async (
orca.validCharacters.forEach((symbol: string, i: number) => {
expect(symbol).to.eq(EXPECTED_VALID_CHARACTERS[i]);
});

if (orca instanceof OrcaWorker) {
orca.terminate();
} else {
await orca.release();
}
} catch (e) {
if (expectFailure) {
isFailed = true;
} else {
expect(e).to.be.undefined;
}
} finally {
if (orca !== null) {
if (orca instanceof OrcaWorker) {
orca.terminate();
} else {
await orca.release();
}
}
}

if (expectFailure) {
expect(isFailed).to.be.true;
} else {
expect(isFailed).to.be.false;
}
};

Expand All @@ -98,60 +112,83 @@ const runProcTest = async (
params: {
accessKey?: string;
model?: PvModel;
isTestWER?: boolean
isTestWER?: boolean;
expectFailure?: boolean;
} = {},
) => {
const {
accessKey = ACCESS_KEY,
model = { publicPath: '/test/orca_params_male.pv', forceWrite: true },
isTestWER = true,
expectFailure = false,
} = params;
try {
const checkWER = async (pcm: Int16Array) => {
const leopard = await LeopardWorker.create(
accessKey,
{ publicPath: '/test/leopard_params.pv', forceWrite: true },
);

const { transcript } = await leopard.process(pcm);
const wer = wordErrorRate(transcript, testData.test_sentences.text_no_punctuation);
expect(wer).lt(testData.wer_threshold);
leopard.terminate();
};

let orca: any = null;
const setOrcaSpeech = () => new Promise<Int16Array | null>(async (resolve, reject) => {
orca = await instance.create(
accessKey,
orcaSpeech => {
resolve(orcaSpeech.speech);
},
model,
{
synthesizeErrorCallback: (error: OrcaError) => {
expect(error.message).to.be.undefined;
reject(null);
},
let orca = null;
let isFailed = false;

const checkWER = async (pcm: Int16Array) => {
const leopard = await LeopardWorker.create(
accessKey,
{ publicPath: '/test/leopard_params.pv', forceWrite: true },
);

const { transcript } = await leopard.process(pcm);
const wer = wordErrorRate(transcript, testData.test_sentences.text_no_punctuation);
expect(wer).lt(testData.wer_threshold);
leopard.terminate();
};

const setOrcaSpeech = () => new Promise<Int16Array | null>(async (resolve, reject) => {
orca = await instance.create(
accessKey,
orcaSpeech => {
resolve(orcaSpeech.speech);
},
model,
{
synthesizeErrorCallback: () => {
isFailed = true;
reject(null);
},
);
},
);

try {
await orca.synthesize(text, speechRate);
});
} catch (e) {
isFailed = true;
}
});

try {
const speech = await setOrcaSpeech();
if (isTestWER) {
await checkWER(speech);
} else {
expect(speech.length).gt(0);
}

if (orca instanceof OrcaWorker) {
orca.terminate();
} else if (orca instanceof Orca) {
await orca.release();
if (!isTestWER && !expectFailure) {
expect(speech.length).gt(0);
}
;

Check failure on line 172 in binding/web/test/orca.test.ts

View workflow job for this annotation

GitHub Actions / check-web-codestyle

Unnecessary semicolon

Check warning on line 172 in binding/web/test/orca.test.ts

View workflow job for this annotation

GitHub Actions / check-web-codestyle

Block must not be padded by blank lines

} catch (e) {
expect(e).to.be.undefined;
if (expectFailure) {
isFailed = true;
}
} finally {
if (orca !== null) {
if (orca instanceof OrcaWorker) {
orca.terminate();
} else if (orca instanceof Orca) {
await orca.release();
}
}
}

if (expectFailure) {
expect(isFailed).to.be.true;
} else {
expect(isFailed).to.be.false;
}
};

Expand Down Expand Up @@ -197,10 +234,8 @@ describe('Orca Binding', function() {
}
});

for (const instance of [OrcaWorker]) {
for (const instance of [Orca, OrcaWorker]) {
const instanceString = instance === OrcaWorker ? 'worker' : 'main';
// for (const instance of [Orca, OrcaWorker]) {
// const instanceString = instance === OrcaWorker ? 'worker' : 'main';

it(`should be able to handle invalid public path (${instanceString})`, () => {
cy.wrap(null).then(async () => {
Expand Down Expand Up @@ -229,7 +264,7 @@ describe('Orca Binding', function() {
});
});

for (const modelFileSuffix of ['male']) {
for (const modelFileSuffix of ['male', 'female']) {
const publicPath = modelFileSuffix === 'male' ? `/test/orca_params_male.pv` : `/test/orca_params_female.pv`;
const base64Path = modelFileSuffix === 'male' ? orcaParamsMale : orcaParamsFemale;

Expand Down Expand Up @@ -415,6 +450,28 @@ describe('Orca Binding', function() {
expect(e).to.be.undefined;
}
});

for (const failureCase of testData.test_sentences.text_invalid) {
it(`should handle invalid text (${failureCase}) [${modelFileSuffix}] (${instanceString})`, async () => {
try {
await runProcTest(
instance,
failureCase,
1.0,
{
model: {
publicPath,
forceWrite: true,
},
isTestWER: false,
expectFailure: true,
},
);
} catch (e) {
expect(e).to.be.undefined;
}
});
}
}
}
});
7 changes: 3 additions & 4 deletions demo/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@
}
}

function validateInput(input, orcaValidChars) {
function validateInput(input, validChars) {
let nonAllowedCharacters = [];
const validChars = [...orcaValidChars, ' '];

for (let i = 0; i < input.length; i++) {
if (!validChars.includes(input[i]) && !nonAllowedCharacters.includes(input[i])) {
Expand All @@ -64,7 +63,7 @@
}

if (nonAllowedCharacters.length > 0) {
textToSynthesizeErrorEl.innerText = `Error: Character${nonAllowedCharacters.length > 1 ? 's' : ''} ${JSON.stringify(nonAllowedCharacters)} are not allowed.`;
textToSynthesizeErrorEl.innerText = `Error: Characters ${JSON.stringify(nonAllowedCharacters)} are not allowed.`;
synthesizeBtnEl.disabled = true;
} else {
textToSynthesizeErrorEl.innerHTML = '&nbsp;';
Expand Down Expand Up @@ -182,7 +181,7 @@ <h1>Orca Web Demo</h1>
<br />
<textarea id="text-to-synthesize" rows="4" cols="50" disabled maxlength="200">
</textarea>
<p id="text-to-synthesize-error">&nbsp;</p>
<div id="text-to-synthesize-error">&nbsp;</div>
<label>
Speech Rate: <span id="speech-rate-display">1.0</span>
<input
Expand Down

0 comments on commit 668e3fb

Please sign in to comment.