diff --git a/public/scripts/extensions/tts/index.js b/public/scripts/extensions/tts/index.js index 4ac7b4e47..f5e760109 100644 --- a/public/scripts/extensions/tts/index.js +++ b/public/scripts/extensions/tts/index.js @@ -23,24 +23,6 @@ let ttsProviders = { } let ttsProvider let ttsProviderName -let autoGeneration = true; - -function resetTtsPlayback() { - // Clear currently processing jobs - currentTtsJob = null; - currentAudioJob = null; - - // Reset audio element - audioElement.currentTime = 0; - audioElement.src = null; - - // Clearn any queue items - ttsJobQueue.splice(0, ttsJobQueue.length); - audioJobQueue.splice(0, audioJobQueue.length); - - // Set audio ready to process again - audioQueueProcessorReady = true; -} async function onNarrateOneMessage() { cancelTtsPlay(); @@ -89,6 +71,12 @@ async function moduleWorker() { processTtsQueue() processAudioJobQueue() updateUiAudioPlayState() + + + // Auto generation is disabled + if (extension_settings.tts.auto_generation == false){ + return + } // no characters or group selected if (!context.groupId && context.characterId === undefined) { @@ -141,6 +129,38 @@ async function moduleWorker() { ttsJobQueue.push(message) } + +function resetTtsPlayback() { + // Clear currently processing jobs + currentTtsJob = null; + currentAudioJob = null; + + // Reset audio element + audioElement.currentTime = 0; + audioElement.src = null; + + // Clear any queue items + ttsJobQueue.splice(0, ttsJobQueue.length); + audioJobQueue.splice(0, audioJobQueue.length); + + // Set audio ready to process again + audioQueueProcessorReady = true; +} + +function isTtsProcessing() { + let processing = false + + // Check job queues + if (ttsJobQueue.length > 0 || audioJobQueue > 0){ + processing = true + } + // Check current jobs + if (currentTtsJob != null || currentAudioJob != null) { + processing = true + } + return processing +} + //##################// // Audio Control // //##################// @@ -155,6 +175,10 @@ let audioQueueProcessorReady = true let lastAudioPosition = 0 async function playAudioData(audioBlob) { + // Since current audio job can be cancelled, don't playback if it is null + if (currentAudioJob == null){ + console.log("Cancelled TTS playback because currentAudioJob was null") + } const reader = new FileReader() reader.onload = function (e) { const srcUrl = e.target.result @@ -199,9 +223,13 @@ async function onTtsVoicesClick() { function updateUiAudioPlayState() { if (extension_settings.tts.enabled == true) { audioControl.style.display = 'flex' - const img = !audioElement.paused - ? 'fa-solid fa-circle-pause' - : 'fa-solid fa-circle-play' + let img + // Give user feedback that TTS is active by setting the stop icon if processing or playing + if (!audioElement.paused || isTtsProcessing()){ + img = 'fa-solid fa-stop-circle' + } else { + img = 'fa-solid fa-circle-play' + } audioControl.className = img } else { audioControl.style.display = 'none' @@ -209,7 +237,14 @@ function updateUiAudioPlayState() { } function onAudioControlClicked() { - audioElement.paused ? audioElement.play() : audioElement.pause() + let context = getContext() + // Not pausing, doing a full stop to anything TTS is doing. Better UX as pause is not as useful + if (!audioElement.paused || isTtsProcessing()){ + resetTtsPlayback() + } else { + // Default play behavior if not processing or playing is to play the last message. + ttsJobQueue.push(context.chat[context.chat.length - 1]) + } updateUiAudioPlayState() } @@ -222,6 +257,7 @@ function addAudioControl() { function completeCurrentAudioJob() { audioQueueProcessorReady = true + currentAudioJob = null lastAudioPosition = 0 // updateUiPlayState(); } @@ -259,7 +295,7 @@ async function processAudioJobQueue() { //################// let ttsJobQueue = [] -let currentTtsJob +let currentTtsJob // Null if nothing is currently being processed let currentMessageNumber = 0 function completeTtsJob() { @@ -348,14 +384,15 @@ function loadSettings() { ) $('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only) $('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only) + $('#tts_auto_generation').prop('checked', extension_settings.tts.auto_generation) $('body').toggleClass('tts', extension_settings.tts.enabled); } const defaultSettings = { voiceMap: '', ttsEnabled: false, - currentProvider: "ElevenLabs" - + currentProvider: "ElevenLabs", + auto_generation: true } function setTtsStatus(status, success) { @@ -435,6 +472,11 @@ function onEnableClick() { saveSettingsDebounced() } +function onAutoGenerationClick() { + extension_settings.tts.auto_generation = $('#tts_auto_generation').prop('checked'); + saveSettingsDebounced() +} + function onNarrateDialoguesClick() { extension_settings.tts.narrate_dialogues_only = $('#tts_narrate_dialogues').prop('checked'); @@ -523,6 +565,10 @@ $(document).ready(function () { Enabled +