diff --git a/public/index.html b/public/index.html
index 2a37d88c7..e68c9fa14 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2325,6 +2325,7 @@
${characterName}
+
diff --git a/public/scripts/extensions/tts/index.js b/public/scripts/extensions/tts/index.js
index 4eeded46c..31c23ce8b 100644
--- a/public/scripts/extensions/tts/index.js
+++ b/public/scripts/extensions/tts/index.js
@@ -1,4 +1,4 @@
-import { callPopup, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js'
+import { callPopup, cancelTtsPlay, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js'
import { extension_settings, getContext } from '../../extensions.js'
import { getStringHash } from '../../utils.js'
import { ElevenLabsTtsProvider } from './elevenlabs.js'
@@ -24,9 +24,47 @@ let ttsProviders = {
let ttsProvider
let ttsProviderName
+async function onNarrateOneMessage() {
+ cancelTtsPlay();
+ const context = getContext();
+ const id = $(this).closest('.mes').attr('mesid');
+ const message = context.chat[id];
+
+ if (!message) {
+ return;
+ }
+
+ currentTtsJob = null;
+ audioElement.pause();
+ audioElement.currentTime = 0;
+ ttsJobQueue.splice(0, ttsJobQueue.length);
+ audioJobQueue.splice(0, audioJobQueue.length);
+ ttsJobQueue.push(message);
+ moduleWorker();
+}
+
+let isWorkerBusy = false;
+
+async function moduleWorkerWrapper() {
+ // Don't touch me I'm busy...
+ if (isWorkerBusy) {
+ return;
+ }
+
+ // I'm free. Let's update!
+ try {
+ isWorkerBusy = true;
+ await moduleWorker();
+ }
+ finally {
+ isWorkerBusy = false;
+ }
+}
+
async function moduleWorker() {
// Primarily determinign when to add new chat to the TTS queue
const enabled = $('#tts_enabled').is(':checked')
+ $('body').toggleClass('tts', enabled);
if (!enabled) {
return
}
@@ -296,6 +334,7 @@ function loadSettings() {
)
$('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only)
$('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only)
+ $('body').toggleClass('tts', extension_settings.tts.enabled);
}
const defaultSettings = {
@@ -507,10 +546,11 @@ $(document).ready(function () {
$('#tts_provider').append($("
").val(provider).text(provider))
}
$('#tts_provider').on('change', onTtsProviderChange)
+ $(document).on('click', '.mes_narrate', onNarrateOneMessage);
}
addExtensionControls() // No init dependencies
loadSettings() // Depends on Extension Controls and loadTtsProvider
loadTtsProvider(extension_settings.tts.currentProvider) // No dependencies
addAudioControl() // Depends on Extension Controls
- setInterval(moduleWorker, UPDATE_INTERVAL) // Init depends on all the things
+ setInterval(moduleWorkerWrapper, UPDATE_INTERVAL) // Init depends on all the things
})
diff --git a/public/style.css b/public/style.css
index ab0fa88bd..64cb5a345 100644
--- a/public/style.css
+++ b/public/style.css
@@ -203,6 +203,16 @@ table.responsiveTable {
text-align: center;
}
+.mes_narrate,
+body.tts .mes[is_user="true"] .mes_narrate,
+body.tts .mes[is_system="true"] .mes_narrate {
+ display: none;
+}
+
+body.tts .mes_narrate {
+ display: inline-block;
+}
+
code {
font-family: Consolas, monospace;
white-space: pre-wrap;
@@ -2155,6 +2165,7 @@ input[type="range"]::-webkit-slider-thumb {
}
.mes_prompt,
+.mes_narrate,
.mes_copy,
.mes_edit {
cursor: pointer;
@@ -2167,11 +2178,13 @@ input[type="range"]::-webkit-slider-thumb {
.mes_edit:hover,
.mes_copy:hover,
+.mes_narrate:hover,
.mes_stop:hover {
opacity: 1;
}
.last_mes .mes_copy,
+.last_mes .mes_narrate,
.last_mes .mes_prompt {
grid-row-start: 1;
position: relative;