Merge pull request #330 from ouoertheo/ouoertheo/manualtts

Ouoertheo/manualtts
This commit is contained in:
Cohee
2023-05-17 12:48:04 +03:00
committed by GitHub

View File

@@ -34,11 +34,7 @@ async function onNarrateOneMessage() {
return; return;
} }
currentTtsJob = null; resetTtsPlayback()
audioElement.pause();
audioElement.currentTime = 0;
ttsJobQueue.splice(0, ttsJobQueue.length);
audioJobQueue.splice(0, audioJobQueue.length);
ttsJobQueue.push(message); ttsJobQueue.push(message);
moduleWorker(); moduleWorker();
} }
@@ -62,7 +58,7 @@ async function moduleWorkerWrapper() {
} }
async function moduleWorker() { async function moduleWorker() {
// Primarily determinign when to add new chat to the TTS queue // Primarily determining when to add new chat to the TTS queue
const enabled = $('#tts_enabled').is(':checked') const enabled = $('#tts_enabled').is(':checked')
$('body').toggleClass('tts', enabled); $('body').toggleClass('tts', enabled);
if (!enabled) { if (!enabled) {
@@ -75,6 +71,12 @@ async function moduleWorker() {
processTtsQueue() processTtsQueue()
processAudioJobQueue() processAudioJobQueue()
updateUiAudioPlayState() updateUiAudioPlayState()
// Auto generation is disabled
if (extension_settings.tts.auto_generation == false){
return
}
// no characters or group selected // no characters or group selected
if (!context.groupId && context.characterId === undefined) { if (!context.groupId && context.characterId === undefined) {
@@ -127,6 +129,38 @@ async function moduleWorker() {
ttsJobQueue.push(message) 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 // // Audio Control //
//##################// //##################//
@@ -136,11 +170,15 @@ let audioElement = new Audio()
let audioJobQueue = [] let audioJobQueue = []
let currentAudioJob let currentAudioJob
let audioPaused = false let audioPaused = false
let queueProcessorReady = true let audioQueueProcessorReady = true
let lastAudioPosition = 0 let lastAudioPosition = 0
async function playAudioData(audioBlob) { 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() const reader = new FileReader()
reader.onload = function (e) { reader.onload = function (e) {
const srcUrl = e.target.result const srcUrl = e.target.result
@@ -185,9 +223,13 @@ async function onTtsVoicesClick() {
function updateUiAudioPlayState() { function updateUiAudioPlayState() {
if (extension_settings.tts.enabled == true) { if (extension_settings.tts.enabled == true) {
audioControl.style.display = 'flex' audioControl.style.display = 'flex'
const img = !audioElement.paused let img
? 'fa-solid fa-circle-pause' // Give user feedback that TTS is active by setting the stop icon if processing or playing
: 'fa-solid fa-circle-play' if (!audioElement.paused || isTtsProcessing()){
img = 'fa-solid fa-stop-circle'
} else {
img = 'fa-solid fa-circle-play'
}
audioControl.className = img audioControl.className = img
} else { } else {
audioControl.style.display = 'none' audioControl.style.display = 'none'
@@ -195,7 +237,14 @@ function updateUiAudioPlayState() {
} }
function onAudioControlClicked() { 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() updateUiAudioPlayState()
} }
@@ -207,7 +256,8 @@ function addAudioControl() {
} }
function completeCurrentAudioJob() { function completeCurrentAudioJob() {
queueProcessorReady = true audioQueueProcessorReady = true
currentAudioJob = null
lastAudioPosition = 0 lastAudioPosition = 0
// updateUiPlayState(); // updateUiPlayState();
} }
@@ -227,16 +277,16 @@ async function addAudioJob(response) {
async function processAudioJobQueue() { async function processAudioJobQueue() {
// Nothing to do, audio not completed, or audio paused - stop processing. // Nothing to do, audio not completed, or audio paused - stop processing.
if (audioJobQueue.length == 0 || !queueProcessorReady || audioPaused) { if (audioJobQueue.length == 0 || !audioQueueProcessorReady || audioPaused) {
return return
} }
try { try {
queueProcessorReady = false audioQueueProcessorReady = false
currentAudioJob = audioJobQueue.pop() currentAudioJob = audioJobQueue.pop()
playAudioData(currentAudioJob) playAudioData(currentAudioJob)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
queueProcessorReady = true audioQueueProcessorReady = true
} }
} }
@@ -245,7 +295,7 @@ async function processAudioJobQueue() {
//################// //################//
let ttsJobQueue = [] let ttsJobQueue = []
let currentTtsJob let currentTtsJob // Null if nothing is currently being processed
let currentMessageNumber = 0 let currentMessageNumber = 0
function completeTtsJob() { function completeTtsJob() {
@@ -334,14 +384,15 @@ function loadSettings() {
) )
$('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only) $('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only)
$('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_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); $('body').toggleClass('tts', extension_settings.tts.enabled);
} }
const defaultSettings = { const defaultSettings = {
voiceMap: '', voiceMap: '',
ttsEnabled: false, ttsEnabled: false,
currentProvider: "ElevenLabs" currentProvider: "ElevenLabs",
auto_generation: true
} }
function setTtsStatus(status, success) { function setTtsStatus(status, success) {
@@ -421,6 +472,11 @@ function onEnableClick() {
saveSettingsDebounced() saveSettingsDebounced()
} }
function onAutoGenerationClick() {
extension_settings.tts.auto_generation = $('#tts_auto_generation').prop('checked');
saveSettingsDebounced()
}
function onNarrateDialoguesClick() { function onNarrateDialoguesClick() {
extension_settings.tts.narrate_dialogues_only = $('#tts_narrate_dialogues').prop('checked'); extension_settings.tts.narrate_dialogues_only = $('#tts_narrate_dialogues').prop('checked');
@@ -509,6 +565,10 @@ $(document).ready(function () {
<input type="checkbox" id="tts_enabled" name="tts_enabled"> <input type="checkbox" id="tts_enabled" name="tts_enabled">
Enabled Enabled
</label> </label>
<label class="checkbox_label" for="tts_auto_generation">
<input type="checkbox" id="tts_auto_generation">
Auto Generation
</label>
<label class="checkbox_label" for="tts_narrate_dialogues"> <label class="checkbox_label" for="tts_narrate_dialogues">
<input type="checkbox" id="tts_narrate_dialogues"> <input type="checkbox" id="tts_narrate_dialogues">
Narrate dialogues only Narrate dialogues only
@@ -540,6 +600,7 @@ $(document).ready(function () {
$('#tts_enabled').on('click', onEnableClick) $('#tts_enabled').on('click', onEnableClick)
$('#tts_narrate_dialogues').on('click', onNarrateDialoguesClick); $('#tts_narrate_dialogues').on('click', onNarrateDialoguesClick);
$('#tts_narrate_quoted').on('click', onNarrateQuotedClick); $('#tts_narrate_quoted').on('click', onNarrateQuotedClick);
$('#tts_auto_generation').on('click', onAutoGenerationClick);
$('#tts_voices').on('click', onTtsVoicesClick) $('#tts_voices').on('click', onTtsVoicesClick)
$('#tts_provider_settings').on('input', onTtsProviderSettingsInput) $('#tts_provider_settings').on('input', onTtsProviderSettingsInput)
for (const provider in ttsProviders) { for (const provider in ttsProviders) {