* Skip TTS for voices explicitly set to disabled (fixes #4970) * Always show disabled message in commands and fix restoring voice map UI * Always show a message on manual TTS trigger * Fix null current job on disabled * Adjust type annotation * Force update worker when disabled play is attempted * Treat audio control queue as manual * Update TTS message processing to include manual flag * Don't show toast if was already shown by manual playback --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { cancelTtsPlay, eventSource, event_types, getCurrentChatId, isStreamingEnabled, name2, saveSettingsDebounced, substituteParams } from '../../../script.js';
|
||||
import { ModuleWorkerWrapper, extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||
import { delay, escapeRegex, getBase64Async, getStringHash, onlyUnique, regexFromString } from '../../utils.js';
|
||||
import { accountStorage } from '../../util/AccountStorage.js';
|
||||
import { EdgeTtsProvider } from './edge.js';
|
||||
import { ElevenLabsTtsProvider } from './elevenlabs.js';
|
||||
import { SileroTtsProvider } from './silerotts.js';
|
||||
@@ -165,7 +166,7 @@ async function onNarrateOneMessage() {
|
||||
}
|
||||
|
||||
resetTtsPlayback();
|
||||
processAndQueueTtsMessage(message, Number(id));
|
||||
processAndQueueTtsMessage(message, Number(id), { manual: true });
|
||||
moduleWorker();
|
||||
}
|
||||
|
||||
@@ -186,13 +187,20 @@ async function onNarrateText(args, text) {
|
||||
? voiceMap[DEFAULT_VOICE_MARKER]
|
||||
: voiceMap[name];
|
||||
|
||||
if (!voiceMapEntry || voiceMapEntry === DISABLED_VOICE_MARKER) {
|
||||
if (voiceMapEntry === DISABLED_VOICE_MARKER) {
|
||||
toastr.info(`TTS voice for ${name} is disabled.`);
|
||||
await initVoiceMap(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!voiceMapEntry) {
|
||||
toastr.info(`Specified voice for ${name} was not found. Check the TTS extension settings.`);
|
||||
await initVoiceMap(false);
|
||||
return;
|
||||
}
|
||||
|
||||
resetTtsPlayback();
|
||||
processAndQueueTtsMessage({ mes: text, name: name });
|
||||
processAndQueueTtsMessage({ mes: text, name: name }, null, { manual: true });
|
||||
await moduleWorker();
|
||||
|
||||
// Return back to the chat voices
|
||||
@@ -245,7 +253,7 @@ function isTtsProcessing() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {ChatMessage & { id?: number }} TtsMessage
|
||||
* @typedef {ChatMessage & { id?: number, manual?: boolean, segmentText?: string, segmentType?: string }} TtsMessage
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -253,12 +261,15 @@ function isTtsProcessing() {
|
||||
* (if enabled) and adds each part to the TTS job queue.
|
||||
* @param {ChatMessage} message - The message object to be processed.
|
||||
* @param {number|null} [messageId=null] - The chat message index to associate with TTS events.
|
||||
* @param {object} [options={}] - Additional options for processing.
|
||||
* @param {boolean} [options.manual=false] - Whether this TTS job was manually triggered (e.g., from the UI) rather than automatically from a new chat message.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processAndQueueTtsMessage(message, messageId = null) {
|
||||
function processAndQueueTtsMessage(message, messageId = null, { manual = false } = {}) {
|
||||
/** @type {TtsMessage} */
|
||||
const clone = structuredClone(message);
|
||||
clone.id = messageId ?? null;
|
||||
clone.manual = manual ?? false;
|
||||
|
||||
if (!extension_settings.tts.narrate_by_paragraphs) {
|
||||
ttsJobQueue.push(clone);
|
||||
@@ -408,9 +419,10 @@ function onAudioControlClicked() {
|
||||
// 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 {
|
||||
} else if (context?.chat?.length > 0) {
|
||||
// Default play behavior if not processing or playing is to play the last message.
|
||||
processAndQueueTtsMessage(context.chat[context.chat.length - 1]);
|
||||
const id = context.chat.length - 1;
|
||||
processAndQueueTtsMessage(context.chat[id], id, { manual: true });
|
||||
}
|
||||
updateUiAudioPlayState();
|
||||
}
|
||||
@@ -481,8 +493,10 @@ async function processAudioJobQueue() {
|
||||
// TTS Control //
|
||||
//################//
|
||||
|
||||
/** @type {TtsMessage[]} */
|
||||
const ttsJobQueue = [];
|
||||
let currentTtsJob; // Null if nothing is currently being processed
|
||||
/** @type {TtsMessage|null} */
|
||||
let currentTtsJob = null; // Null if nothing is currently being processed
|
||||
|
||||
function completeTtsJob() {
|
||||
console.info(`Current TTS job for ${currentTtsJob?.name} completed.`);
|
||||
@@ -621,7 +635,18 @@ async function processTtsQueue() {
|
||||
|
||||
const voiceMapEntry = voiceMap[voiceMapKey] === DEFAULT_VOICE_MARKER ? voiceMap[DEFAULT_VOICE_MARKER] : voiceMap[voiceMapKey];
|
||||
|
||||
if (!voiceMapEntry || voiceMapEntry === DISABLED_VOICE_MARKER) {
|
||||
if (voiceMapEntry === DISABLED_VOICE_MARKER) {
|
||||
const storageKey = `tts_disabled_warned_${char}`;
|
||||
if (!accountStorage.getItem(storageKey) || currentTtsJob.manual) {
|
||||
accountStorage.setItem(storageKey, 'true');
|
||||
toastr.info(`TTS voice for ${char} is disabled.`);
|
||||
}
|
||||
currentTtsJob = null;
|
||||
setTimeout(() => wrapper.update(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!voiceMapEntry) {
|
||||
throw `${char} not in voicemap. Configure character in extension settings voice map`;
|
||||
}
|
||||
|
||||
@@ -724,6 +749,7 @@ async function processTtsQueue() {
|
||||
mes: currentTtsJob.mes,
|
||||
extra: currentTtsJob.extra,
|
||||
id: currentTtsJob.id,
|
||||
manual: currentTtsJob.manual,
|
||||
};
|
||||
ttsJobQueue.unshift(segmentJob);
|
||||
}
|
||||
@@ -824,7 +850,7 @@ async function playFullConversation() {
|
||||
|
||||
context.chat.forEach((msg, i) => {
|
||||
if (!msg.is_system && msg.mes !== '...' && msg.mes !== '') {
|
||||
processAndQueueTtsMessage(msg, i);
|
||||
processAndQueueTtsMessage(msg, i, { manual: false });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1164,7 +1190,7 @@ async function onMessageEvent(messageId, lastCharIndex) {
|
||||
message.id = messageId;
|
||||
ttsJobQueue.push(message);
|
||||
} else {
|
||||
processAndQueueTtsMessage(message, messageId);
|
||||
processAndQueueTtsMessage(message, messageId, { manual: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user