name updates, complete custom voices

This commit is contained in:
ouoertheo 2023-08-25 22:51:58 -05:00
parent 1417aa12f1
commit d03af9b41d

View File

@ -6,7 +6,7 @@ TODO:
import { doExtrasFetch, extension_settings, getApiUrl, getContext, modules, ModuleWorkerWrapper } from "../../extensions.js" import { doExtrasFetch, extension_settings, getApiUrl, getContext, modules, ModuleWorkerWrapper } from "../../extensions.js"
import { callPopup } from "../../../script.js" import { callPopup } from "../../../script.js"
import { onTtsProviderSettingsInput } from "./index.js" import { initVoiceMap } from "./index.js"
export { CoquiTtsProvider } export { CoquiTtsProvider }
@ -63,7 +63,8 @@ class CoquiTtsProvider {
settings settings
defaultSettings = { defaultSettings = {
voiceMap: "", voiceMap: {},
customVoices: {},
voiceIds: [], voiceIds: [],
voiceMapDict: {} voiceMapDict: {}
} }
@ -74,8 +75,8 @@ class CoquiTtsProvider {
<div> <div>
<div style="flex: 50%;"> <div style="flex: 50%;">
<small>To use CoquiTTS, select the origin, language, and model, then click Add Voice. The voice will then be available to add to a character. Voices are saved globally. </small><br> <small>To use CoquiTTS, select the origin, language, and model, then click Add Voice. The voice will then be available to add to a character. Voices are saved globally. </small><br>
<label for="coqui_voiceid_select">Select Saved Voice:</label> <label for="coqui_voicename_select">Select Saved Voice:</label>
<select id="coqui_voiceid_select"> <select id="coqui_voicename_select">
<!-- Populated by JS --> <!-- Populated by JS -->
</select> </select>
<div class="tts_block"> <div class="tts_block">
@ -137,7 +138,7 @@ class CoquiTtsProvider {
} }
initLocalModels(); initLocalModels();
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
$("#coqui_api_model_div").hide(); $("#coqui_api_model_div").hide();
$("#coqui_local_model_div").hide(); $("#coqui_local_model_div").hide();
@ -200,48 +201,44 @@ class CoquiTtsProvider {
// Perform a simple readiness check by trying to fetch voiceIds // Perform a simple readiness check by trying to fetch voiceIds
async checkReady(){ async checkReady(){
throwIfModuleMissing() throwIfModuleMissing()
await this.fetchTtsVoiceIds() await this.fetchTtsVoiceObjects()
} }
updateVoiceMap() { updateCustomVoices() {
// Takes voiceMapDict and converts it to a string to save to voiceMap // Takes voiceMapDict and converts it to a string to save to voiceMap
this.settings.voiceMap = ""; this.settings.customVoices = {};
for (let i in this.settings.voiceMapDict) { for (let voiceName in this.settings.voiceMapDict) {
const voice_settings = this.settings.voiceMapDict[i]; const voiceId = this.settings.voiceMapDict[voiceName];
this.settings.voiceMap += i + ":" + voice_settings["model_id"]; this.settings.customVoices[voiceName] = voiceId["model_id"];
if (voice_settings["model_language"] != null) if (voiceId["model_language"] != null)
this.settings.voiceMap += "[" + voice_settings["model_language"] + "]"; this.settings.customVoices[voiceName] += "[" + voiceId["model_language"] + "]";
if (voice_settings["model_speaker"] != null) if (voiceId["model_speaker"] != null)
this.settings.voiceMap += "[" + voice_settings["model_speaker"] + "]"; this.settings.customVoices[voiceName] += "[" + voiceId["model_speaker"] + "]";
this.settings.voiceMap += ",";
} }
// Update UI select list with voices // Update UI select list with voices
$("#coqui_voiceid_select").empty() $("#coqui_voicename_select").empty()
$('#coqui_voiceid_select') $('#coqui_voicename_select')
.find('option') .find('option')
.remove() .remove()
.end() .end()
.append('<option value="none">Select VoiceId</option>') .append('<option value="none">Select Voice</option>')
.val('none') .val('none')
for (const voiceId in this.settings.voiceMapDict) { for (const voiceName in this.settings.voiceMapDict) {
$("#coqui_voiceid_select").append(new Option(voiceId, voiceId)); $("#coqui_voicename_select").append(new Option(voiceName, voiceName));
} }
extension_settings.tts.Coqui = this.settings;
this.onSettingsChange() this.onSettingsChange()
} }
onSettingsChange() { onSettingsChange() {
console.debug(DEBUG_PREFIX, "Settings changes", this.settings); console.debug(DEBUG_PREFIX, "Settings changes", this.settings);
extension_settings.tts.Coqui = this.settings; extension_settings.tts.Coqui = this.settings;
onTtsProviderSettingsInput()
} }
async onApplyClick() { async onRefreshClick() {
this.checkReady() this.checkReady()
} }
@ -251,7 +248,7 @@ class CoquiTtsProvider {
} }
// Ask user for voiceId name to save voice // Ask user for voiceId name to save voice
const voiceId = await callPopup('<h3>Name of Coqui voice to add to voice select dropdown:</h3>', 'input') const voiceName = await callPopup('<h3>Name of Coqui voice to add to voice select dropdown:</h3>', 'input')
const model_origin = $("#coqui_model_origin").val(); const model_origin = $("#coqui_model_origin").val();
const model_language = $("#coqui_api_language").val(); const model_language = $("#coqui_api_language").val();
@ -260,15 +257,15 @@ class CoquiTtsProvider {
let model_setting_speaker = $("#coqui_api_model_settings_speaker").val(); let model_setting_speaker = $("#coqui_api_model_settings_speaker").val();
if (!voiceId) { if (!voiceName) {
toastr.error(`VoiceId empty, please enter one.`, DEBUG_PREFIX + " voice mapping voiceId", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Voice name empty, please enter one.`, DEBUG_PREFIX + " voice mapping voice name", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
if (model_origin == "none") { if (model_origin == "none") {
toastr.error(`Origin not selected, please select one.`, DEBUG_PREFIX + " voice mapping origin", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Origin not selected, please select one.`, DEBUG_PREFIX + " voice mapping origin", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
@ -277,25 +274,25 @@ class CoquiTtsProvider {
if (model_name == "none") { if (model_name == "none") {
toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
this.settings.voiceMapDict[voiceId] = { model_type: "local", model_id: "local/" + model_id }; this.settings.voiceMapDict[voiceName] = { model_type: "local", model_id: "local/" + model_id };
console.debug(DEBUG_PREFIX, "Registered new voice map: ", voiceId, ":", this.settings.voiceMapDict[voiceId]); console.debug(DEBUG_PREFIX, "Registered new voice map: ", voiceName, ":", this.settings.voiceMapDict[voiceName]);
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
if (model_language == "none") { if (model_language == "none") {
toastr.error(`Language not selected, please select one.`, DEBUG_PREFIX + " voice mapping language", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Language not selected, please select one.`, DEBUG_PREFIX + " voice mapping language", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
if (model_name == "none") { if (model_name == "none") {
toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Model not selected, please select one.`, DEBUG_PREFIX + " voice mapping model", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
this.updateVoiceMap(); // Overide any manual modification this.updateCustomVoices(); // Overide any manual modification
return; return;
} }
@ -324,42 +321,48 @@ class CoquiTtsProvider {
return; return;
} }
console.debug(DEBUG_PREFIX, "Current voice map: ", this.settings.voiceMap); console.debug(DEBUG_PREFIX, "Current custom voices: ", this.settings.customVoices);
this.settings.voiceMapDict[voiceId] = { model_type: "coqui-api", model_id: model_id, model_language: model_setting_language, model_speaker: model_setting_speaker }; this.settings.voiceMapDict[voiceName] = { model_type: "coqui-api", model_id: model_id, model_language: model_setting_language, model_speaker: model_setting_speaker };
console.debug(DEBUG_PREFIX, "Registered new voice map: ", voiceId, ":", this.settings.voiceMapDict[voiceId]); console.debug(DEBUG_PREFIX, "Registered new voice map: ", voiceName, ":", this.settings.voiceMapDict[voiceName]);
this.updateVoiceMap(); this.updateCustomVoices();
initVoiceMap() // Update TTS extension voiceMap
let successMsg = voiceId + ":" + model_id; let successMsg = voiceName + ":" + model_id;
if (model_setting_language != null) if (model_setting_language != null)
successMsg += "[" + model_setting_language + "]"; successMsg += "[" + model_setting_language + "]";
if (model_setting_speaker != null) if (model_setting_speaker != null)
successMsg += "[" + model_setting_speaker + "]"; successMsg += "[" + model_setting_speaker + "]";
toastr.info(successMsg, DEBUG_PREFIX + " voice map updated", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.info(successMsg, DEBUG_PREFIX + " voice map updated", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
return return
} }
// DBG: assume voiceName is correct
// TODO: check voice is correct
async getVoice(voiceName) { async getVoice(voiceName) {
console.log(DEBUG_PREFIX, "getVoice", voiceName); let match = await this.fetchTtsVoiceObjects()
const output = { voice_id: voiceName }; match = match.filter(
return output; voice => voice.name == voiceName
)[0]
if (!match) {
throw `TTS Voice name ${voiceName} not found in CoquiTTS Provider voice list`
}
return match;
} }
async onRemoveClick() { async onRemoveClick() {
const voiceId = $("#coqui_voiceid_select").val(); const voiceName = $("#coqui_voicename_select").val();
if (voiceId === "none") { if (voiceName === "none") {
toastr.error(`VoiceId not selected, please select one.`, DEBUG_PREFIX + " voice mapping voiceId", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); toastr.error(`Voice not selected, please select one.`, DEBUG_PREFIX + " voice mapping voiceId", { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true });
return; return;
} }
// Todo erase from voicemap // Todo erase from voicemap
delete (this.settings.voiceMapDict[voiceId]); delete (this.settings.voiceMapDict[voiceName]);
this.updateVoiceMap(); // TODO this.updateCustomVoices();
initVoiceMap() // Update TTS extension voiceMap
} }
async onModelOriginChange() { async onModelOriginChange() {
@ -677,6 +680,8 @@ class CoquiTtsProvider {
// ts_models/ja/kokoro/tacotron2-DDC // ts_models/ja/kokoro/tacotron2-DDC
async generateTts(text, voiceId) { async generateTts(text, voiceId) {
throwIfModuleMissing() throwIfModuleMissing()
voiceId = this.settings.customVoices[voiceId]
const url = new URL(getApiUrl()); const url = new URL(getApiUrl());
url.pathname = '/api/text-to-speech/coqui/generate-tts'; url.pathname = '/api/text-to-speech/coqui/generate-tts';
@ -724,8 +729,11 @@ class CoquiTtsProvider {
} }
// Dirty hack to say not implemented // Dirty hack to say not implemented
async fetchTtsVoiceIds() { async fetchTtsVoiceObjects() {
return [{ name: "Voice samples not implemented for coqui TTS yet, search for the model samples online", voice_id: "", lang: "", }] const voiceIds = Object
.keys(this.settings.voiceMapDict)
.map(voice => ({ name: voice, voice_id: voice, preview_url: false }));
return voiceIds
} }
// Do nothing // Do nothing