Compare commits

...
2 Commits
Author SHA1 Message Date
Gitea Actions 474fd80a95 Release 0.1.43 [auto-version-bump] 2026-10-16 06:31:31 +02:00
Ein Anderssono bf5ee88610 Honor the system default speech voice
Build and publish frontend / publish (push) Successful in 43s
2026-10-16 06:31:07 +02:00
4 changed files with 15 additions and 8 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.42 0.1.43
+2 -2
View File
@@ -2,5 +2,5 @@ apiVersion: v2
name: ai-spel-frontend name: ai-spel-frontend
description: Static web frontend for the Swedish life simulator description: Static web frontend for the Swedish life simulator
type: application type: application
version: 0.1.42 version: 0.1.43
appVersion: "0.1.42" appVersion: "0.1.43"
+4 -2
View File
@@ -117,17 +117,19 @@ test('recognition watchdog closes a session that never ends and permits retry',
assert.equal(h.recognitions.length, 2); assert.equal(h.recognitions.length, 2);
}); });
test('TTS selects Swedish fallback, applies rate, and cancellation invalidates callbacks', () => { test('TTS uses the system default voice unless a named Swedish voice is selected', () => {
const h = makeHarness(); const h = makeHarness();
h.controller.update({mode: 'game-voice', rate: 1.4}); h.controller.update({mode: 'game-voice', rate: 1.4});
assert.equal(h.controller.speak('Hej.'), true); assert.equal(h.controller.speak('Hej.'), true);
const first = h.utterances[0]; const first = h.utterances[0];
assert.equal(first.lang, 'sv-SE'); assert.equal(first.lang, 'sv-SE');
assert.equal(first.rate, 1.4); assert.equal(first.rate, 1.4);
assert.equal(first.voice.name, 'Svensk'); assert.equal(first.voice, null);
h.controller.cancelSpeech(); h.controller.cancelSpeech();
first.onend(); first.onend();
assert.equal(h.controller.getState(), 'IDLE'); assert.equal(h.controller.getState(), 'IDLE');
assert.equal(h.controller.speak('Namngiven röst.', {voiceName: 'Svensk'}), true);
assert.equal(h.utterances.at(-1).voice.name, 'Svensk');
}); });
test('a player gesture restores the iOS speech primer after cancelling a queued reply', () => { test('a player gesture restores the iOS speech primer after cancelling a queued reply', () => {
+8 -3
View File
@@ -233,9 +233,14 @@
utterance.pitch = isNarrator ? 1 : Math.min(2, Math.max(0, Number(voiceOptions.pitch ?? profile.pitch ?? identityProfile.pitch) || 1)); utterance.pitch = isNarrator ? 1 : Math.min(2, Math.max(0, Number(voiceOptions.pitch ?? profile.pitch ?? identityProfile.pitch) || 1));
const requestedName = voiceOptions.voiceName || profile.voiceName || settings.voiceName; const requestedName = voiceOptions.voiceName || profile.voiceName || settings.voiceName;
const voices = availableVoices(); const voices = availableVoices();
utterance.voice = voices.find(voice => voice.name === requestedName) // An empty selection means the operating system should choose its
|| voices.find(voice => /^sv(-|$)/i.test(voice.lang)) // default voice for the requested language. Forcing the first voice
|| null; // returned by WebKit can select a voice that is listed but cannot speak.
utterance.voice = requestedName
? voices.find(voice => voice.name === requestedName)
|| voices.find(voice => /^sv(-|$)/i.test(voice.lang))
|| null
: null;
utterance.onstart = () => { utterance.onstart = () => {
if (token !== generation) return; if (token !== generation) return;
if (speechStartTimer !== null) win.clearTimeout(speechStartTimer); if (speechStartTimer !== null) win.clearTimeout(speechStartTimer);