|
|
|
|
|
|
|
|
|
|
|
|
|
import { doExtrasFetch, extension_settings, getApiUrl, modules } from '../../extensions.js'; |
|
import { initVoiceMap } from './index.js'; |
|
import { POPUP_TYPE, callGenericPopup } from '../../popup.js'; |
|
|
|
export { CoquiTtsProvider }; |
|
|
|
const DEBUG_PREFIX = '<Coqui TTS module> '; |
|
|
|
let inApiCall = false; |
|
let coquiApiModels = {}; |
|
let coquiApiModelsFull = {}; |
|
let coquiLocalModels = []; |
|
let coquiLocalModelsReceived = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const languageLabels = { |
|
'multilingual': 'Multilingual', |
|
'en': 'English', |
|
'fr': 'French', |
|
'es': 'Spanish', |
|
'ja': 'Japanese', |
|
}; |
|
|
|
function throwIfModuleMissing() { |
|
if (!modules.includes('coqui-tts')) { |
|
const message = 'Coqui TTS module not loaded. Add coqui-tts to enable-modules and restart the Extras API.'; |
|
|
|
throw new Error(DEBUG_PREFIX, message); |
|
} |
|
} |
|
|
|
function resetModelSettings() { |
|
$('#coqui_api_model_settings_language').val('none'); |
|
$('#coqui_api_model_settings_speaker').val('none'); |
|
} |
|
|
|
class CoquiTtsProvider { |
|
|
|
|
|
|
|
|
|
settings; |
|
|
|
defaultSettings = { |
|
voiceMap: {}, |
|
customVoices: {}, |
|
voiceIds: [], |
|
voiceMapDict: {}, |
|
}; |
|
|
|
get settingsHtml() { |
|
let html = ` |
|
<div class="flex wide100p flexGap10 alignitemscenter"> |
|
<div> |
|
<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> |
|
<label for="coqui_voicename_select">Select Saved Voice:</label> |
|
<select id="coqui_voicename_select"> |
|
<!-- Populated by JS --> |
|
</select> |
|
<div class="tts_block"> |
|
<input id="coqui_remove_voiceId_mapping" class="menu_button" type="button" value="Remove Voice" /> |
|
<input id="coqui_add_voiceId_mapping" class="menu_button" type="button" value="Add Voice" /> |
|
</div> |
|
<label for="coqui_model_origin">Models:</label> |
|
<select id="coqui_model_origin">gpu_mode |
|
<option value="none">Select Origin</option> |
|
<option value="coqui-api">Coqui API (Tested)</option> |
|
<option value="coqui-api-full">Coqui API (Experimental)</option> |
|
<option value="local">My Models</option> |
|
</select> |
|
|
|
<div id="coqui_api_model_div"> |
|
<select id="coqui_api_language"> |
|
<!-- Populated by JS and request --> |
|
</select> |
|
|
|
<select id="coqui_api_model_name"> |
|
<!-- Populated by JS and request --> |
|
</select> |
|
|
|
<div id="coqui_api_model_settings"> |
|
<select id="coqui_api_model_settings_language"> |
|
<!-- Populated by JS and request --> |
|
</select> |
|
<select id="coqui_api_model_settings_speaker"> |
|
<!-- Populated by JS and request --> |
|
</select> |
|
</div> |
|
<span id="coqui_api_model_install_status">Model installed on extras server</span> |
|
<input id="coqui_api_model_install_button" class="menu_button" type="button" value="Install" /> |
|
</div> |
|
|
|
<div id="coqui_local_model_div"> |
|
<select id="coqui_local_model_name"> |
|
<!-- Populated by JS and request --> |
|
</select> |
|
</div> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
return html; |
|
} |
|
|
|
async loadSettings(settings) { |
|
|
|
this.settings = this.defaultSettings; |
|
|
|
for (const key in settings) { |
|
if (key in this.settings) { |
|
this.settings[key] = settings[key]; |
|
} else { |
|
throw DEBUG_PREFIX + `Invalid setting passed to extension: ${key}`; |
|
} |
|
} |
|
|
|
await initLocalModels(); |
|
this.updateCustomVoices(); |
|
|
|
$('#coqui_api_model_div').hide(); |
|
$('#coqui_local_model_div').hide(); |
|
|
|
$('#coqui_api_language').show(); |
|
$('#coqui_api_model_name').hide(); |
|
$('#coqui_api_model_settings').hide(); |
|
$('#coqui_api_model_install_status').hide(); |
|
$('#coqui_api_model_install_button').hide(); |
|
|
|
let that = this; |
|
$('#coqui_model_origin').on('change', function () { that.onModelOriginChange(); }); |
|
$('#coqui_api_language').on('change', function () { that.onModelLanguageChange(); }); |
|
$('#coqui_api_model_name').on('change', function () { that.onModelNameChange(); }); |
|
|
|
$('#coqui_remove_voiceId_mapping').on('click', function () { that.onRemoveClick(); }); |
|
$('#coqui_add_voiceId_mapping').on('click', function () { that.onAddClick(); }); |
|
|
|
|
|
await fetch('/scripts/extensions/tts/coqui_api_models_settings.json') |
|
.then(response => response.json()) |
|
.then(json => { |
|
coquiApiModels = json; |
|
console.debug(DEBUG_PREFIX,'initialized coqui-api model list to', coquiApiModels); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
await fetch('/scripts/extensions/tts/coqui_api_models_settings_full.json') |
|
.then(response => response.json()) |
|
.then(json => { |
|
coquiApiModelsFull = json; |
|
console.debug(DEBUG_PREFIX,'initialized coqui-api full model list to', coquiApiModelsFull); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}); |
|
} |
|
|
|
|
|
async checkReady(){ |
|
throwIfModuleMissing(); |
|
await this.fetchTtsVoiceObjects(); |
|
} |
|
|
|
updateCustomVoices() { |
|
|
|
this.settings.customVoices = {}; |
|
for (let voiceName in this.settings.voiceMapDict) { |
|
const voiceId = this.settings.voiceMapDict[voiceName]; |
|
this.settings.customVoices[voiceName] = voiceId['model_id']; |
|
|
|
if (voiceId['model_language'] != null) |
|
this.settings.customVoices[voiceName] += '[' + voiceId['model_language'] + ']'; |
|
|
|
if (voiceId['model_speaker'] != null) |
|
this.settings.customVoices[voiceName] += '[' + voiceId['model_speaker'] + ']'; |
|
} |
|
|
|
|
|
$('#coqui_voicename_select').empty(); |
|
$('#coqui_voicename_select') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select Voice</option>') |
|
.val('none'); |
|
for (const voiceName in this.settings.voiceMapDict) { |
|
$('#coqui_voicename_select').append(new Option(voiceName, voiceName)); |
|
} |
|
|
|
this.onSettingsChange(); |
|
} |
|
|
|
onSettingsChange() { |
|
console.debug(DEBUG_PREFIX, 'Settings changes', this.settings); |
|
extension_settings.tts.Coqui = this.settings; |
|
} |
|
|
|
async onRefreshClick() { |
|
this.checkReady(); |
|
} |
|
|
|
async onAddClick() { |
|
if (inApiCall) { |
|
return; |
|
} |
|
|
|
|
|
const voiceName = await callGenericPopup('Name of Coqui voice to add to voice select dropdown:', POPUP_TYPE.INPUT); |
|
|
|
const model_origin = $('#coqui_model_origin').val(); |
|
const model_language = $('#coqui_api_language').val(); |
|
const model_name = $('#coqui_api_model_name').val(); |
|
let model_setting_language = $('#coqui_api_model_settings_language').val(); |
|
let model_setting_speaker = $('#coqui_api_model_settings_speaker').val(); |
|
|
|
|
|
if (!voiceName) { |
|
toastr.error('Voice name empty, please enter one.', DEBUG_PREFIX + ' voice mapping voice name', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
if (model_origin == 'none') { |
|
toastr.error('Origin not selected, please select one.', DEBUG_PREFIX + ' voice mapping origin', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
if (model_origin == 'local') { |
|
const model_id = $('#coqui_local_model_name').val(); |
|
|
|
if (model_name == 'none') { |
|
toastr.error('Model not selected, please select one.', DEBUG_PREFIX + ' voice mapping model', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
this.settings.voiceMapDict[voiceName] = { model_type: 'local', model_id: 'local/' + model_id }; |
|
console.debug(DEBUG_PREFIX, 'Registered new voice map: ', voiceName, ':', this.settings.voiceMapDict[voiceName]); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
if (model_language == 'none') { |
|
toastr.error('Language not selected, please select one.', DEBUG_PREFIX + ' voice mapping language', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
if (model_name == 'none') { |
|
toastr.error('Model not selected, please select one.', DEBUG_PREFIX + ' voice mapping model', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
this.updateCustomVoices(); |
|
return; |
|
} |
|
|
|
if (model_setting_language == 'none') |
|
model_setting_language = null; |
|
|
|
if (model_setting_speaker == 'none') |
|
model_setting_speaker = null; |
|
|
|
const tokens = $('#coqui_api_model_name').val().split('/'); |
|
const model_dataset = tokens[0]; |
|
const model_label = tokens[1]; |
|
const model_id = 'tts_models/' + model_language + '/' + model_dataset + '/' + model_label; |
|
|
|
let modelDict = coquiApiModels; |
|
if (model_origin == 'coqui-api-full') |
|
modelDict = coquiApiModelsFull; |
|
|
|
if (model_setting_language == null & 'languages' in modelDict[model_language][model_dataset][model_label]) { |
|
toastr.error('Model language not selected, please select one.', DEBUG_PREFIX + ' voice mapping model language', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
return; |
|
} |
|
|
|
if (model_setting_speaker == null & 'speakers' in modelDict[model_language][model_dataset][model_label]) { |
|
toastr.error('Model speaker not selected, please select one.', DEBUG_PREFIX + ' voice mapping model speaker', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
return; |
|
} |
|
|
|
console.debug(DEBUG_PREFIX, 'Current custom voices: ', this.settings.customVoices); |
|
|
|
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: ', voiceName, ':', this.settings.voiceMapDict[voiceName]); |
|
|
|
this.updateCustomVoices(); |
|
initVoiceMap(); |
|
|
|
let successMsg = voiceName + ':' + model_id; |
|
if (model_setting_language != null) |
|
successMsg += '[' + model_setting_language + ']'; |
|
if (model_setting_speaker != null) |
|
successMsg += '[' + model_setting_speaker + ']'; |
|
toastr.info(successMsg, DEBUG_PREFIX + ' voice map updated', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
|
|
return; |
|
} |
|
|
|
async getVoice(voiceName) { |
|
let match = await this.fetchTtsVoiceObjects(); |
|
match = match.filter( |
|
voice => voice.name == voiceName, |
|
)[0]; |
|
if (!match) { |
|
throw `TTS Voice name ${voiceName} not found in CoquiTTS Provider voice list`; |
|
} |
|
return match; |
|
} |
|
|
|
async onRemoveClick() { |
|
const voiceName = $('#coqui_voicename_select').val(); |
|
|
|
if (voiceName === 'none') { |
|
toastr.error('Voice not selected, please select one.', DEBUG_PREFIX + ' voice mapping voiceId', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
return; |
|
} |
|
|
|
|
|
delete (this.settings.voiceMapDict[voiceName]); |
|
this.updateCustomVoices(); |
|
initVoiceMap(); |
|
} |
|
|
|
async onModelOriginChange() { |
|
throwIfModuleMissing(); |
|
resetModelSettings(); |
|
const model_origin = $('#coqui_model_origin').val(); |
|
|
|
if (model_origin == 'none') { |
|
$('#coqui_local_model_div').hide(); |
|
$('#coqui_api_model_div').hide(); |
|
} |
|
|
|
|
|
if (model_origin == 'coqui-api') { |
|
$('#coqui_local_model_div').hide(); |
|
|
|
$('#coqui_api_language') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select model language</option>') |
|
.val('none'); |
|
|
|
for(let language in coquiApiModels) { |
|
let languageLabel = language; |
|
if (language in languageLabels) |
|
languageLabel = languageLabels[language]; |
|
$('#coqui_api_language').append(new Option(languageLabel,language)); |
|
console.log(DEBUG_PREFIX,'added language',languageLabel,'(',language,')'); |
|
} |
|
|
|
$('#coqui_api_model_div').show(); |
|
} |
|
|
|
|
|
if (model_origin == 'coqui-api-full') { |
|
$('#coqui_local_model_div').hide(); |
|
|
|
$('#coqui_api_language') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select model language</option>') |
|
.val('none'); |
|
|
|
for(let language in coquiApiModelsFull) { |
|
let languageLabel = language; |
|
if (language in languageLabels) |
|
languageLabel = languageLabels[language]; |
|
$('#coqui_api_language').append(new Option(languageLabel,language)); |
|
console.log(DEBUG_PREFIX,'added language',languageLabel,'(',language,')'); |
|
} |
|
|
|
$('#coqui_api_model_div').show(); |
|
} |
|
|
|
|
|
|
|
if (model_origin == 'local') { |
|
$('#coqui_api_model_div').hide(); |
|
$('#coqui_local_model_div').show(); |
|
} |
|
} |
|
|
|
async onModelLanguageChange() { |
|
throwIfModuleMissing(); |
|
resetModelSettings(); |
|
$('#coqui_api_model_settings').hide(); |
|
const model_origin = $('#coqui_model_origin').val(); |
|
const model_language = $('#coqui_api_language').val(); |
|
console.debug(model_language); |
|
|
|
if (model_language == 'none') { |
|
$('#coqui_api_model_name').hide(); |
|
return; |
|
} |
|
|
|
$('#coqui_api_model_name').show(); |
|
$('#coqui_api_model_name') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select model</option>') |
|
.val('none'); |
|
|
|
let modelDict = coquiApiModels; |
|
if (model_origin == 'coqui-api-full') |
|
modelDict = coquiApiModelsFull; |
|
|
|
for(let model_dataset in modelDict[model_language]) |
|
for(let model_name in modelDict[model_language][model_dataset]) { |
|
const model_id = model_dataset + '/' + model_name; |
|
const model_label = model_name + ' (' + model_dataset + ' dataset)'; |
|
$('#coqui_api_model_name').append(new Option(model_label, model_id)); |
|
} |
|
} |
|
|
|
async onModelNameChange() { |
|
throwIfModuleMissing(); |
|
resetModelSettings(); |
|
$('#coqui_api_model_settings').hide(); |
|
const model_origin = $('#coqui_model_origin').val(); |
|
|
|
|
|
if ($('#coqui_api_model_name').val() == 'none') { |
|
$('#coqui_api_model_install_button').off('click'); |
|
$('#coqui_api_model_install_button').hide(); |
|
return; |
|
} |
|
|
|
|
|
const model_language = $('#coqui_api_language').val(); |
|
const tokens = $('#coqui_api_model_name').val().split('/'); |
|
const model_dataset = tokens[0]; |
|
const model_name = tokens[1]; |
|
|
|
let modelDict = coquiApiModels; |
|
if (model_origin == 'coqui-api-full') |
|
modelDict = coquiApiModelsFull; |
|
|
|
const model_settings = modelDict[model_language][model_dataset][model_name]; |
|
|
|
if ('languages' in model_settings) { |
|
$('#coqui_api_model_settings').show(); |
|
$('#coqui_api_model_settings_language').show(); |
|
$('#coqui_api_model_settings_language') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select language</option>') |
|
.val('none'); |
|
|
|
for (let i = 0; i < model_settings['languages'].length; i++) { |
|
const language_label = JSON.stringify(model_settings['languages'][i]).replaceAll('"', ''); |
|
$('#coqui_api_model_settings_language').append(new Option(language_label, i)); |
|
} |
|
} |
|
else { |
|
$('#coqui_api_model_settings_language').hide(); |
|
} |
|
|
|
if ('speakers' in model_settings) { |
|
$('#coqui_api_model_settings').show(); |
|
$('#coqui_api_model_settings_speaker').show(); |
|
$('#coqui_api_model_settings_speaker') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select speaker</option>') |
|
.val('none'); |
|
|
|
for (let i = 0; i < model_settings['speakers'].length; i++) { |
|
const speaker_label = JSON.stringify(model_settings['speakers'][i]).replaceAll('"', ''); |
|
$('#coqui_api_model_settings_speaker').append(new Option(speaker_label, i)); |
|
} |
|
} |
|
else { |
|
$('#coqui_api_model_settings_speaker').hide(); |
|
} |
|
|
|
$('#coqui_api_model_install_status').text('Requesting model to extras server...'); |
|
$('#coqui_api_model_install_status').show(); |
|
|
|
|
|
const model_id = modelDict[model_language][model_dataset][model_name]['id']; |
|
console.debug(DEBUG_PREFIX,'Check if model is already installed',model_id); |
|
let result = await CoquiTtsProvider.checkmodel_state(model_id); |
|
result = await result.json(); |
|
const model_state = result['model_state']; |
|
|
|
console.debug(DEBUG_PREFIX, ' Model state:', model_state); |
|
|
|
if (model_state == 'installed') { |
|
$('#coqui_api_model_install_status').text('Model already installed on extras server'); |
|
$('#coqui_api_model_install_button').hide(); |
|
} |
|
else { |
|
let action = 'download'; |
|
if (model_state == 'corrupted') { |
|
action = 'repare'; |
|
|
|
$('#coqui_api_model_install_status').text('Model found but incomplete try install again (maybe still downloading)'); |
|
} |
|
else { |
|
toastr.info('Click download button to install the model ' + $('#coqui_api_model_name').find(':selected').text(), DEBUG_PREFIX + ' model not installed', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
$('#coqui_api_model_install_status').text('Model not found on extras server'); |
|
} |
|
|
|
const onModelNameChange_pointer = this.onModelNameChange; |
|
|
|
$('#coqui_api_model_install_button').off('click').on('click', async function () { |
|
try { |
|
$('#coqui_api_model_install_status').text('Downloading model...'); |
|
$('#coqui_api_model_install_button').hide(); |
|
|
|
let apiResult = await CoquiTtsProvider.installModel(model_id, action); |
|
apiResult = await apiResult.json(); |
|
|
|
console.debug(DEBUG_PREFIX, 'Response:', apiResult); |
|
|
|
if (apiResult['status'] == 'done') { |
|
$('#coqui_api_model_install_status').text('Model installed and ready to use!'); |
|
$('#coqui_api_model_install_button').hide(); |
|
onModelNameChange_pointer(); |
|
} |
|
|
|
if (apiResult['status'] == 'downloading') { |
|
toastr.error('Check extras console for progress', DEBUG_PREFIX + ' already downloading', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
$('#coqui_api_model_install_status').text('Already downloading a model, check extras console!'); |
|
$('#coqui_api_model_install_button').show(); |
|
} |
|
} catch (error) { |
|
console.error(error); |
|
toastr.error(error, DEBUG_PREFIX + ' error with model download', { timeOut: 10000, extendedTimeOut: 20000, preventDuplicates: true }); |
|
onModelNameChange_pointer(); |
|
} |
|
|
|
}); |
|
|
|
$('#coqui_api_model_install_button').show(); |
|
return; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async checkmodel_state(model_id) { |
|
throwIfModuleMissing(); |
|
const url = new URL(getApiUrl()); |
|
url.pathname = '/api/text-to-speech/coqui/coqui-api/check-model-state'; |
|
|
|
const apiResult = await doExtrasFetch(url, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Cache-Control': 'no-cache', |
|
}, |
|
body: JSON.stringify({ |
|
'model_id': model_id, |
|
}), |
|
}); |
|
|
|
if (!apiResult.ok) { |
|
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Check model state request failed'); |
|
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`); |
|
} |
|
|
|
return apiResult; |
|
} |
|
|
|
static async installModel(model_id, action) { |
|
throwIfModuleMissing(); |
|
const url = new URL(getApiUrl()); |
|
url.pathname = '/api/text-to-speech/coqui/coqui-api/install-model'; |
|
|
|
const apiResult = await doExtrasFetch(url, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Cache-Control': 'no-cache', |
|
}, |
|
body: JSON.stringify({ |
|
'model_id': model_id, |
|
'action': action, |
|
}), |
|
}); |
|
|
|
if (!apiResult.ok) { |
|
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Install model ' + model_id + ' request failed'); |
|
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`); |
|
} |
|
|
|
return apiResult; |
|
} |
|
|
|
|
|
|
|
|
|
static async getLocalModelList() { |
|
throwIfModuleMissing(); |
|
const url = new URL(getApiUrl()); |
|
url.pathname = '/api/text-to-speech/coqui/local/get-models'; |
|
|
|
const apiResult = await doExtrasFetch(url, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Cache-Control': 'no-cache', |
|
}, |
|
body: JSON.stringify({ |
|
'model_id': 'model_id', |
|
'action': 'action', |
|
}), |
|
}); |
|
|
|
if (!apiResult.ok) { |
|
toastr.error(apiResult.statusText, DEBUG_PREFIX + ' Get local model list request failed'); |
|
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`); |
|
} |
|
|
|
return apiResult; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
async generateTts(text, voiceId) { |
|
throwIfModuleMissing(); |
|
voiceId = this.settings.customVoices[voiceId]; |
|
|
|
const url = new URL(getApiUrl()); |
|
url.pathname = '/api/text-to-speech/coqui/generate-tts'; |
|
|
|
let language = 'none'; |
|
let speaker = 'none'; |
|
const tokens = voiceId.replaceAll(']', '').replaceAll('"', '').split('['); |
|
const model_id = tokens[0]; |
|
|
|
console.debug(DEBUG_PREFIX, 'Preparing TTS request for', tokens); |
|
|
|
|
|
if (tokens.length > 1) { |
|
const option1 = tokens[1]; |
|
|
|
if (model_id.includes('multilingual')) |
|
language = option1; |
|
else |
|
speaker = option1; |
|
} |
|
|
|
|
|
if (tokens.length > 2) |
|
speaker = tokens[2]; |
|
|
|
const apiResult = await doExtrasFetch(url, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Cache-Control': 'no-cache', |
|
}, |
|
body: JSON.stringify({ |
|
'text': text, |
|
'model_id': model_id, |
|
'language_id': parseInt(language), |
|
'speaker_id': parseInt(speaker), |
|
}), |
|
}); |
|
|
|
if (!apiResult.ok) { |
|
toastr.error(apiResult.statusText, 'TTS Generation Failed'); |
|
throw new Error(`HTTP ${apiResult.status}: ${await apiResult.text()}`); |
|
} |
|
|
|
return apiResult; |
|
} |
|
|
|
|
|
async fetchTtsVoiceObjects() { |
|
const voiceIds = Object |
|
.keys(this.settings.voiceMapDict) |
|
.map(voice => ({ name: voice, voice_id: voice, preview_url: false })); |
|
return voiceIds; |
|
} |
|
|
|
|
|
previewTtsVoice(id) { |
|
return; |
|
} |
|
|
|
async fetchTtsFromHistory(history_item_id) { |
|
return Promise.resolve(history_item_id); |
|
} |
|
} |
|
|
|
async function initLocalModels() { |
|
if (!modules.includes('coqui-tts')) |
|
return; |
|
|
|
|
|
if (!coquiLocalModelsReceived) { |
|
let result = await CoquiTtsProvider.getLocalModelList(); |
|
result = await result.json(); |
|
|
|
coquiLocalModels = result['models_list']; |
|
|
|
$('#coqui_local_model_name').show(); |
|
$('#coqui_local_model_name') |
|
.find('option') |
|
.remove() |
|
.end() |
|
.append('<option value="none">Select model</option>') |
|
.val('none'); |
|
|
|
for (const model_dataset of coquiLocalModels) |
|
$('#coqui_local_model_name').append(new Option(model_dataset, model_dataset)); |
|
|
|
coquiLocalModelsReceived = true; |
|
} |
|
} |
|
|