diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js
index 8e6527ee0..0380f065f 100644
--- a/public/scripts/extensions.js
+++ b/public/scripts/extensions.js
@@ -24,7 +24,7 @@ const extension_settings = {
caption: {},
expressions: {},
dice: {},
- elevenlabstts: {},
+ tts: {},
};
let modules = [];
diff --git a/public/scripts/extensions/elevenlabstts/elevenlabs.js b/public/scripts/extensions/tts/elevenlabs.js
similarity index 56%
rename from public/scripts/extensions/elevenlabstts/elevenlabs.js
rename to public/scripts/extensions/tts/elevenlabs.js
index e033de663..f0d0c19ed 100644
--- a/public/scripts/extensions/elevenlabstts/elevenlabs.js
+++ b/public/scripts/extensions/tts/elevenlabs.js
@@ -1,13 +1,93 @@
export { ElevenLabsTtsProvider }
class ElevenLabsTtsProvider {
+ //########//
+ // Config //
+ //########//
+
API_KEY
+ settings = this.defaultSettings
+ voices = []
+
set API_KEY(apiKey) {
this.API_KEY = apiKey
}
get API_KEY() {
return this.API_KEY
}
+ get settings() {
+ return this.settings
+ }
+
+ updateSettings(settings) {
+ console.info("Settings updated")
+ if("stability" in settings && "similarity_boost" in settings){
+ this.settings = settings
+ $('#elevenlabs_tts_stability').val(this.settings.stability)
+ $('#elevenlabs_tts_similarity_boost').val(this.settings.similarity_boost)
+ this.onSettingsChange()
+ } else {
+ throw `Invalid settings passed to ElevenLabs: ${JSON.stringify(settings)}`
+ }
+ }
+
+ defaultSettings = {
+ stability: 0.75,
+ similarity_boost: 0.75
+ }
+
+ onSettingsChange() {
+ this.settings = {
+ stability: $('#elevenlabs_tts_stability').val(),
+ similarity_boost: $('#elevenlabs_tts_similarity_boost').val()
+ }
+ $('#elevenlabs_tts_stability_output').text(this.settings.stability)
+ $('#elevenlabs_tts_similarity_boost_output').text(this.settings.similarity_boost)
+ }
+
+ get settingsHtml() {
+ let html = `
+
+
+
+
+ `
+ return html
+ }
+
+ //#############//
+ // Management //
+ //#############//
+
+ async getVoice(voiceName) {
+ if (this.voices.length == 0) {
+ this.voices = await this.fetchTtsVoiceIds()
+ }
+ const match = this.voices.filter(
+ elevenVoice => elevenVoice.name == voiceName
+ )[0]
+ if (!match) {
+ throw `TTS Voice name ${voiceName} not found in ElevenLabs account`
+ }
+ return match
+ }
+
+ async findTtsGenerationInHistory(message, voiceId) {
+ const ttsHistory = await this.fetchTtsHistory()
+ for (const history of ttsHistory) {
+ const text = history.text
+ const itemId = history.history_item_id
+ if (message === text && history.voice_id == voiceId) {
+ console.info(`Existing TTS history item ${itemId} found: ${text} `)
+ return itemId
+ }
+ }
+ return ''
+ }
+
+ //###########//
+ // API CALLS //
+ //###########//
async fetchTtsVoiceIds() {
const headers = {
'xi-api-key': this.API_KEY
@@ -48,7 +128,10 @@ class ElevenLabsTtsProvider {
'xi-api-key': this.API_KEY,
'Content-Type': 'application/json'
},
- body: JSON.stringify({ text: text })
+ body: JSON.stringify({
+ text: text,
+ voice_settings: this.settings
+ })
}
)
if (!response.ok) {
@@ -86,17 +169,4 @@ class ElevenLabsTtsProvider {
const responseJson = await response.json()
return responseJson.history
}
-
- async findTtsGenerationInHistory(message, voiceId) {
- const ttsHistory = await this.fetchTtsHistory()
- for (const history of ttsHistory) {
- const text = history.text
- const itemId = history.history_item_id
- if (message === text && history.voice_id == voiceId) {
- console.info(`Existing TTS history item ${itemId} found: ${text} `)
- return itemId
- }
- }
- return ''
- }
}
diff --git a/public/scripts/extensions/elevenlabstts/index.js b/public/scripts/extensions/tts/index.js
similarity index 69%
rename from public/scripts/extensions/elevenlabstts/index.js
rename to public/scripts/extensions/tts/index.js
index 1b0716ca3..479828d05 100644
--- a/public/scripts/extensions/elevenlabstts/index.js
+++ b/public/scripts/extensions/tts/index.js
@@ -6,7 +6,6 @@ import { ElevenLabsTtsProvider } from './elevenlabs.js'
const UPDATE_INTERVAL = 1000
let voiceMap = {} // {charName:voiceid, charName2:voiceid2}
-let elevenlabsTtsVoices = []
let audioControl
let lastCharacterId = null
@@ -14,11 +13,16 @@ let lastGroupId = null
let lastChatId = null
let lastMessageHash = null
-let ttsProvider = new ElevenLabsTtsProvider()
+
+let ttsProviders = {
+ elevenLabs: ElevenLabsTtsProvider
+}
+let ttsProvider
+let ttsProviderName
async function moduleWorker() {
// Primarily determinign when to add new chat to the TTS queue
- const enabled = $('#elevenlabs_enabled').is(':checked')
+ const enabled = $('#tts_enabled').is(':checked')
if (!enabled) {
return
}
@@ -104,19 +108,19 @@ async function playAudioData(audioBlob) {
})
}
-window['elevenlabsPreview'] = function (id) {
+window['tts_preview'] = function (id) {
const audio = document.getElementById(id)
audio.play()
}
-async function onElevenlabsVoicesClick() {
+async function onTtsVoicesClick() {
let popupText = ''
try {
const voiceIds = await ttsProvider.fetchTtsVoiceIds()
for (const voice of voiceIds) {
- popupText += `
${voice.name}
`
+ popupText += `${voice.name}
`
popupText += ``
}
} catch {
@@ -213,7 +217,7 @@ async function processTtsQueue() {
if (!voiceMap[char]) {
throw `${char} not in voicemap. Configure character in extension settings voice map`
}
- const voice = await getTtsVoice(voiceMap[char])
+ const voice = await ttsProvider.getVoice((voiceMap[char]))
const voiceId = voice.voice_id
if (voiceId == null) {
throw `Unable to attain voiceId for ${char}`
@@ -239,50 +243,53 @@ window.playFullConversation = playFullConversation
function loadSettings() {
const context = getContext()
- if (Object.keys(extension_settings.elevenlabstts).length === 0) {
- Object.assign(extension_settings.elevenlabstts, defaultSettings)
+ if (!ttsProviderName in extension_settings.tts){
+ extension_settings.tts[ttsProviderName] = {}
+ }
+ if (Object.keys(extension_settings.tts[ttsProviderName]).length === 0) {
+ Object.assign(extension_settings.tts[ttsProviderName], defaultSettings)
}
- $('#elevenlabs_api_key').val(
- extension_settings.elevenlabstts.elevenlabsApiKey
+ $('#tts_api_key').val(
+ extension_settings.tts[ttsProviderName].apiKey
)
- $('#elevenlabs_voice_map').val(
- extension_settings.elevenlabstts.elevenlabsVoiceMap
+ $('#tts_voice_map').val(
+ extension_settings.tts[ttsProviderName].voiceMap
)
- $('#elevenlabs_enabled').prop(
+ $('#tts_enabled').prop(
'checked',
- extension_settings.elevenlabstts.enabled
+ extension_settings.tts.enabled
)
- onElevenlabsApplyClick()
+ ttsProvider.updateSettings(extension_settings.tts[ttsProviderName].settings)
+ onApplyClick()
}
const defaultSettings = {
- elevenlabsApiKey: '',
- elevenlabsVoiceMap: '',
- elevenlabsEnabed: false
+ apiKey: '',
+ voiceMap: '',
+ ttsEnabled: false
}
-function setElevenLabsStatus(status, success) {
- $('#elevenlabs_status').text(status)
+function setTtsStatus(status, success) {
+ $('#tts_status').text(status)
if (success) {
- $('#elevenlabs_status').removeAttr('style')
+ $('#tts_status').removeAttr('style')
} else {
- $('#elevenlabs_status').css('color', 'red')
+ $('#tts_status').css('color', 'red')
}
}
async function updateApiKey() {
- const context = getContext()
- const value = $('#elevenlabs_api_key').val()
+ const value = $('#tts_api_key').val()
// Using this call to validate API key
ttsProvider.API_KEY = String(value)
await ttsProvider.fetchTtsVoiceIds().catch(error => {
ttsProvider.API_KEY = null
- throw `ElevenLabs TTS API key invalid`
+ throw `TTS API key invalid`
})
- extension_settings.elevenlabstts.elevenlabsApiKey = String(value)
+ extension_settings.tts[ttsProviderName].apiKey = String(value)
console.debug(`Saved new API_KEY: ${value}`)
saveSettingsDebounced()
}
@@ -299,26 +306,12 @@ function parseVoiceMap(voiceMapString) {
return parsedVoiceMap
}
-async function getTtsVoice(name) {
- // We're caching the list of voice_ids. This might cause trouble if the user creates a new voice without restarting
- if (elevenlabsTtsVoices.length == 0) {
- elevenlabsTtsVoices = await ttsProvider.fetchTtsVoiceIds()
- }
- const match = elevenlabsTtsVoices.filter(
- elevenVoice => elevenVoice.name == name
- )[0]
- if (!match) {
- throw `TTS Voice name ${name} not found in ElevenLabs account`
- }
- return match
-}
-
async function voicemapIsValid(parsedVoiceMap) {
let valid = true
for (const characterName in parsedVoiceMap) {
const parsedVoiceName = parsedVoiceMap[characterName]
try {
- await getTtsVoice(parsedVoiceName)
+ await ttsProvider.getVoice(parsedVoiceName)
} catch (error) {
console.error(error)
valid = false
@@ -330,13 +323,13 @@ async function voicemapIsValid(parsedVoiceMap) {
async function updateVoiceMap() {
let isValidResult = false
const context = getContext()
- // console.debug("onElevenlabsVoiceMapSubmit");
- const value = $('#elevenlabs_voice_map').val()
+ // console.debug("onvoiceMapSubmit");
+ const value = $('#tts_voice_map').val()
const parsedVoiceMap = parseVoiceMap(value)
isValidResult = await voicemapIsValid(parsedVoiceMap)
if (isValidResult) {
- extension_settings.elevenlabstts.elevenlabsVoiceMap = String(value)
- context.elevenlabsVoiceMap = String(value)
+ extension_settings.tts[ttsProviderName].voiceMap = String(value)
+ context.voiceMap = String(value)
voiceMap = parsedVoiceMap
console.debug(`Saved new voiceMap: ${value}`)
saveSettingsDebounced()
@@ -345,19 +338,19 @@ async function updateVoiceMap() {
}
}
-function onElevenlabsApplyClick() {
+function onApplyClick() {
Promise.all([updateApiKey(), updateVoiceMap()])
.then(([result1, result2]) => {
updateUiAudioPlayState()
- setElevenLabsStatus('Successfully applied settings', true)
+ setTtsStatus('Successfully applied settings', true)
})
.catch(error => {
- setElevenLabsStatus(error, false)
+ setTtsStatus(error, false)
})
}
-function onElevenlabsEnableClick() {
- extension_settings.elevenlabstts.enabled = $('#elevenlabs_enabled').is(
+function onEnableClick() {
+ extension_settings.tts.enabled = $('#tts_enabled').is(
':checked'
)
updateUiAudioPlayState()
@@ -365,7 +358,7 @@ function onElevenlabsEnableClick() {
}
function updateUiAudioPlayState() {
- if (extension_settings.elevenlabstts.enabled == true) {
+ if (extension_settings.tts.enabled == true) {
audioControl.style.display = 'flex'
const img = !audioElement.paused
? 'fa-solid fa-circle-pause'
@@ -388,44 +381,75 @@ function addAudioControl() {
updateUiAudioPlayState()
}
+function addUiTtsProviderConfig() {
+ $('#tts_provider_settings').append(ttsProvider.settingsHtml)
+ ttsProvider.onSettingsChange()
+}
+
+function loadTtsProvider(provider){
+ // Set up provider references. No init dependencies
+ extension_settings.tts.currentProvider = provider
+ ttsProviderName = provider
+ ttsProvider = new ttsProviders[provider]
+ saveSettingsDebounced()
+}
+
+function onTtsProviderSettingsInput(){
+ ttsProvider.onSettingsChange()
+ extension_settings.tts[ttsProviderName].settings = ttsProvider.settings
+ saveSettingsDebounced()
+}
+
$(document).ready(function () {
function addExtensionControls() {
const settingsHtml = `
-
+
`
$('#extensions_settings').append(settingsHtml)
- $('#elevenlabs_apply').on('click', onElevenlabsApplyClick)
- $('#elevenlabs_enabled').on('click', onElevenlabsEnableClick)
- $('#elevenlabs_voices').on('click', onElevenlabsVoicesClick)
+ $('#tts_apply').on('click', onApplyClick)
+ $('#tts_enabled').on('click', onEnableClick)
+ $('#tts_voices').on('click', onTtsVoicesClick)
+ $('#tts_provider_settings').on('input', onTtsProviderSettingsInput)
}
- addAudioControl()
- addExtensionControls()
- loadSettings()
- setInterval(moduleWorker, UPDATE_INTERVAL)
+ loadTtsProvider("elevenLabs") // No init dependencies
+ addExtensionControls() // No init dependencies
+ addUiTtsProviderConfig() // Depends on ttsProvider being loaded
+ loadSettings() // Depends on Extension Controls and ttsProvider
+ addAudioControl() // Depends on Extension Controls
+ setInterval(moduleWorker, UPDATE_INTERVAL) // Init depends on all the things
})
diff --git a/public/scripts/extensions/elevenlabstts/manifest.json b/public/scripts/extensions/tts/manifest.json
similarity index 100%
rename from public/scripts/extensions/elevenlabstts/manifest.json
rename to public/scripts/extensions/tts/manifest.json
diff --git a/public/scripts/extensions/elevenlabstts/style.css b/public/scripts/extensions/tts/style.css
similarity index 100%
rename from public/scripts/extensions/elevenlabstts/style.css
rename to public/scripts/extensions/tts/style.css