This commit is contained in:
+31
-2
@@ -89,6 +89,7 @@
|
||||
let pendingDialogue = null;
|
||||
let latestAssistantText = '';
|
||||
let latestAssistantVoice = {role: 'narrator', voiceIdentity: 'neutral'};
|
||||
let speechRecoveryElement = null;
|
||||
const voiceSettingsKey = 'ai-spel.voice-settings.v2';
|
||||
let voiceSettings = window.GameVoice.loadSettings(localStorage, voiceSettingsKey, 'ai-spel.voice-settings.v1');
|
||||
let voiceController;
|
||||
@@ -117,7 +118,7 @@
|
||||
latestAssistantText = content;
|
||||
latestAssistantVoice = options.voice || {role: 'narrator', voiceIdentity: 'neutral'};
|
||||
if (options.speak !== false && location.pathname !== '/admin') {
|
||||
voiceController?.speak(content, latestAssistantVoice);
|
||||
voiceController?.speak(content, {...latestAssistantVoice, onStart: clearSpeechRecovery});
|
||||
}
|
||||
}
|
||||
return line;
|
||||
@@ -156,6 +157,33 @@
|
||||
const authVoiceStatus = document.querySelector('#auth-voice-status');
|
||||
if (authVoiceStatus && !auth.hidden && message) authVoiceStatus.textContent = message;
|
||||
}
|
||||
function clearSpeechRecovery() {
|
||||
speechRecoveryElement?.remove();
|
||||
speechRecoveryElement = null;
|
||||
const status = document.querySelector('#voice-status');
|
||||
if (status?.textContent.startsWith('Uppläsningen startade inte')) setVoiceStatus('Läser upp dialog.');
|
||||
}
|
||||
function showSpeechRecovery(message) {
|
||||
clearSpeechRecovery();
|
||||
const item = document.createElement('li');
|
||||
item.dataset.role = 'voice-controls';
|
||||
item.setAttribute('aria-label', 'Uppläsning kunde inte starta');
|
||||
const explanation = document.createElement('p');
|
||||
explanation.textContent = message;
|
||||
const retry = document.createElement('button');
|
||||
retry.type = 'button';
|
||||
retry.textContent = 'Läs senaste repliken';
|
||||
retry.addEventListener('click', () => {
|
||||
voiceController.activateFromUserGesture();
|
||||
if (voiceController.speak(latestAssistantText, {...latestAssistantVoice, onStart: clearSpeechRecovery})) {
|
||||
clearSpeechRecovery();
|
||||
}
|
||||
});
|
||||
item.append(explanation, retry);
|
||||
transcript.append(item);
|
||||
item.scrollIntoView({block: 'end'});
|
||||
speechRecoveryElement = item;
|
||||
}
|
||||
function refreshMicrophone() {
|
||||
const button = document.querySelector('#microphone');
|
||||
if (button) button.disabled = play.hidden || messageField.disabled || submitBusy;
|
||||
@@ -191,6 +219,7 @@
|
||||
microphone.textContent = listening ? 'Avsluta mikrofon' : 'Starta mikrofon';
|
||||
refreshMicrophone();
|
||||
if (message) setVoiceStatus(message);
|
||||
if (/Uppläsningen startade inte/.test(message)) showSpeechRecovery(message);
|
||||
playVoiceSignal(state === 'IDLE' && /Mikrofonen är avstängd/.test(message) ? 'STOPPED' : state);
|
||||
},
|
||||
onTranscript(text) {
|
||||
@@ -238,7 +267,7 @@
|
||||
signalLabel.append(signals, document.createTextNode(' Ljudsignal vid röstinmatning')); fieldset.append(signalLabel);
|
||||
item.append(fieldset);
|
||||
const speakLatest = () => {
|
||||
if (!voiceController.speak(latestAssistantText, latestAssistantVoice)) setVoiceStatus('Talsyntes stöds inte i den här webbläsaren. Dialogen finns kvar som text.');
|
||||
if (!voiceController.speak(latestAssistantText, {...latestAssistantVoice, onStart: clearSpeechRecovery})) setVoiceStatus('Talsyntes stöds inte i den här webbläsaren. Dialogen finns kvar som text.');
|
||||
};
|
||||
addVoiceButton(item, 'Läs senaste repliken', speakLatest);
|
||||
addVoiceButton(item, 'Upprepa', speakLatest);
|
||||
|
||||
Reference in New Issue
Block a user