mirror of
https://github.com/jambonz/speech-utils.git
synced 2026-08-19 09:40:19 +00:00
fix(inworld): read pitch and speakingRate from audioConfig in the say: params (#155)
The streaming say: path guarded on opts.audioConfig?.pitch and opts.audioConfig?.speakingRate but interpolated opts.pitch and opts.speakingRate, which are undefined — so anyone setting them under audioConfig (what the docs and the portal defaults tell you to do) got 'pitch=undefined,speakingRate=undefined' on the wire and their setting silently dropped. Adds a test for the say: params that needs no credentials, since the streaming branch builds the path without calling the vendor. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d89457f67d
commit
c066840f85
+3
-2
@@ -941,8 +941,9 @@ const synthInworld = async(logger, {
|
||||
params += `,voice=${voice}`;
|
||||
params += `,write_cache_file=${disableTtsCache ? 0 : 1}`;
|
||||
if (opts.temperature) params += `,temperature=${opts.temperature}`;
|
||||
if (opts.audioConfig?.pitch) params += `,pitch=${opts.pitch}`;
|
||||
if (opts.audioConfig?.speakingRate) params += `,speakingRate=${opts.speakingRate}`;
|
||||
/* pitch and speakingRate are nested under audioConfig, matching Inworld's API */
|
||||
if (opts.audioConfig?.pitch) params += `,pitch=${opts.audioConfig.pitch}`;
|
||||
if (opts.audioConfig?.speakingRate) params += `,speakingRate=${opts.audioConfig.speakingRate}`;
|
||||
params += '}';
|
||||
|
||||
return {
|
||||
|
||||
@@ -1147,6 +1147,54 @@ test('inworld speech synth', async(t) => {
|
||||
client.quit();
|
||||
});
|
||||
|
||||
test('inworld streaming say: params', async(t) => {
|
||||
const fn = require('..');
|
||||
const {synthAudio, client} = fn(opts, logger);
|
||||
|
||||
/* the streaming branch builds the say: path without calling the vendor,
|
||||
so this needs no credentials
|
||||
*/
|
||||
try {
|
||||
let result = await synthAudio(stats, {
|
||||
vendor: 'inworld',
|
||||
credentials: {api_key: 'test-key', model_id: 'inworld-tts-1.5-mini'},
|
||||
language: 'en',
|
||||
voice: 'Ashley',
|
||||
text: 'This is a test of inworld streaming.',
|
||||
options: {temperature: 0.9, audioConfig: {pitch: 2.5, speakingRate: 1.2}},
|
||||
disableTtsCache: true
|
||||
});
|
||||
t.ok(result.filePath.startsWith('say:'), 'inworld returns streaming say: path');
|
||||
t.ok(result.filePath.includes('vendor=inworld'), 'streaming path contains vendor=inworld');
|
||||
t.ok(result.filePath.includes('voice=Ashley'), 'streaming path contains voice');
|
||||
t.ok(result.filePath.includes('model_id=inworld-tts-1.5-mini'), 'streaming path contains model_id');
|
||||
t.ok(result.filePath.includes('temperature=0.9'), 'streaming path contains temperature');
|
||||
/* pitch and speakingRate are nested under audioConfig; they used to be read
|
||||
from the top level and emitted as "undefined"
|
||||
*/
|
||||
t.ok(result.filePath.includes('speakingRate=1.2'), 'audioConfig.speakingRate reaches the say: params');
|
||||
t.ok(result.filePath.includes('pitch=2.5'), 'audioConfig.pitch reaches the say: params');
|
||||
t.ok(!result.filePath.includes('undefined'), 'no undefined values in the say: params');
|
||||
|
||||
/* options omitted entirely: no stray keys */
|
||||
result = await synthAudio(stats, {
|
||||
vendor: 'inworld',
|
||||
credentials: {api_key: 'test-key', model_id: 'inworld-tts-1.5-mini'},
|
||||
language: 'en',
|
||||
voice: 'Ashley',
|
||||
text: 'This is a test of inworld streaming.',
|
||||
disableTtsCache: true
|
||||
});
|
||||
t.ok(!result.filePath.includes('speakingRate='), 'speakingRate omitted when unset');
|
||||
t.ok(!result.filePath.includes('pitch='), 'pitch omitted when unset');
|
||||
t.ok(!result.filePath.includes('undefined'), 'no undefined values when options are omitted');
|
||||
} catch (err) {
|
||||
console.error(JSON.stringify(err));
|
||||
t.end(err);
|
||||
}
|
||||
client.quit();
|
||||
});
|
||||
|
||||
test('resemble speech synth', async(t) => {
|
||||
const fn = require('..');
|
||||
const {synthAudio, client} = fn(opts, logger);
|
||||
|
||||
Reference in New Issue
Block a user