mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-04-13 18:32:05 +02:00
Merge branch 'staging' into translation-improvements
This commit is contained in:
commit
fcc00e0b26
@ -15,6 +15,11 @@
|
|||||||
"**/node_modules/*",
|
"**/node_modules/*",
|
||||||
"public/lib",
|
"public/lib",
|
||||||
"backups/*",
|
"backups/*",
|
||||||
"data/*"
|
"data/*",
|
||||||
|
"**/dist/*",
|
||||||
|
"dist/*",
|
||||||
|
"cache/*",
|
||||||
|
"src/tokenizers/*",
|
||||||
|
"docker/*",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ import {
|
|||||||
import { debounce_timeout } from './scripts/constants.js';
|
import { debounce_timeout } from './scripts/constants.js';
|
||||||
|
|
||||||
import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js';
|
import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js';
|
||||||
import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, getSlashCommandsHelp, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js';
|
import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js';
|
||||||
import {
|
import {
|
||||||
tag_map,
|
tag_map,
|
||||||
tags,
|
tags,
|
||||||
@ -911,6 +911,7 @@ async function firstLoadInit() {
|
|||||||
initKeyboard();
|
initKeyboard();
|
||||||
initDynamicStyles();
|
initDynamicStyles();
|
||||||
initTags();
|
initTags();
|
||||||
|
initDefaultSlashCommands();
|
||||||
await getUserAvatars(true, user_avatar);
|
await getUserAvatars(true, user_avatar);
|
||||||
await getCharacters();
|
await getCharacters();
|
||||||
await getBackgrounds();
|
await getBackgrounds();
|
||||||
|
@ -356,6 +356,7 @@ jQuery(async function () {
|
|||||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'llamacpp' && textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) ||
|
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'llamacpp' && textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) ||
|
||||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ooba' && textgenerationwebui_settings.server_urls[textgen_types.OOBA]) ||
|
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ooba' && textgenerationwebui_settings.server_urls[textgen_types.OOBA]) ||
|
||||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'koboldcpp' && textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP]) ||
|
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'koboldcpp' && textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP]) ||
|
||||||
|
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'vllm' && textgenerationwebui_settings.server_urls[textgen_types.VLLM]) ||
|
||||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'custom') ||
|
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'custom') ||
|
||||||
extension_settings.caption.source === 'local' ||
|
extension_settings.caption.source === 'local' ||
|
||||||
extension_settings.caption.source === 'horde';
|
extension_settings.caption.source === 'horde';
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<option value="openai">OpenAI</option>
|
<option value="openai">OpenAI</option>
|
||||||
<option value="openrouter">OpenRouter</option>
|
<option value="openrouter">OpenRouter</option>
|
||||||
<option value="ooba" data-i18n="Text Generation WebUI (oobabooga)">Text Generation WebUI (oobabooga)</option>
|
<option value="ooba" data-i18n="Text Generation WebUI (oobabooga)">Text Generation WebUI (oobabooga)</option>
|
||||||
|
<option value="vllm">vLLM</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||||
@ -66,6 +67,7 @@
|
|||||||
<option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
<option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
||||||
<option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
<option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
||||||
<option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
<option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option>
|
||||||
|
<option data-type="vllm" value="vllm_current" data-i18n="currently_selected">[Currently selected]</option>
|
||||||
<option data-type="custom" value="custom_current" data-i18n="currently_selected">[Currently selected]</option>
|
<option data-type="custom" value="custom_current" data-i18n="currently_selected">[Currently selected]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,7 @@ export async function getMultimodalCaption(base64Img, prompt) {
|
|||||||
const isCustom = extension_settings.caption.multimodal_api === 'custom';
|
const isCustom = extension_settings.caption.multimodal_api === 'custom';
|
||||||
const isOoba = extension_settings.caption.multimodal_api === 'ooba';
|
const isOoba = extension_settings.caption.multimodal_api === 'ooba';
|
||||||
const isKoboldCpp = extension_settings.caption.multimodal_api === 'koboldcpp';
|
const isKoboldCpp = extension_settings.caption.multimodal_api === 'koboldcpp';
|
||||||
|
const isVllm = extension_settings.caption.multimodal_api === 'vllm';
|
||||||
const base64Bytes = base64Img.length * 0.75;
|
const base64Bytes = base64Img.length * 0.75;
|
||||||
const compressionLimit = 2 * 1024 * 1024;
|
const compressionLimit = 2 * 1024 * 1024;
|
||||||
if ((['google', 'openrouter'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) {
|
if ((['google', 'openrouter'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) || isOoba || isKoboldCpp) {
|
||||||
@ -65,6 +66,14 @@ export async function getMultimodalCaption(base64Img, prompt) {
|
|||||||
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.OLLAMA];
|
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.OLLAMA];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isVllm) {
|
||||||
|
if (extension_settings.caption.multimodal_model === 'vllm_current') {
|
||||||
|
requestBody.model = textgenerationwebui_settings.vllm_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.VLLM];
|
||||||
|
}
|
||||||
|
|
||||||
if (isLlamaCpp) {
|
if (isLlamaCpp) {
|
||||||
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP];
|
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP];
|
||||||
}
|
}
|
||||||
@ -151,6 +160,14 @@ function throwIfInvalidModel(useReverseProxy) {
|
|||||||
throw new Error('KoboldCpp server URL is not set.');
|
throw new Error('KoboldCpp server URL is not set.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extension_settings.caption.multimodal_api === 'vllm' && !textgenerationwebui_settings.server_urls[textgen_types.VLLM]) {
|
||||||
|
throw new Error('vLLM server URL is not set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension_settings.caption.multimodal_api === 'vllm' && extension_settings.caption.multimodal_model === 'vllm_current' && !textgenerationwebui_settings.vllm_model) {
|
||||||
|
throw new Error('vLLM model is not set.');
|
||||||
|
}
|
||||||
|
|
||||||
if (extension_settings.caption.multimodal_api === 'custom' && !oai_settings.custom_url) {
|
if (extension_settings.caption.multimodal_api === 'custom' && !oai_settings.custom_url) {
|
||||||
throw new Error('Custom API URL is not set.');
|
throw new Error('Custom API URL is not set.');
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { NovelTtsProvider } from './novel.js';
|
|||||||
import { power_user } from '../../power-user.js';
|
import { power_user } from '../../power-user.js';
|
||||||
import { OpenAITtsProvider } from './openai.js';
|
import { OpenAITtsProvider } from './openai.js';
|
||||||
import { XTTSTtsProvider } from './xtts.js';
|
import { XTTSTtsProvider } from './xtts.js';
|
||||||
|
import { VITSTtsProvider } from './vits.js';
|
||||||
import { GSVITtsProvider } from './gsvi.js';
|
import { GSVITtsProvider } from './gsvi.js';
|
||||||
import { SBVits2TtsProvider } from './sbvits2.js';
|
import { SBVits2TtsProvider } from './sbvits2.js';
|
||||||
import { AllTalkTtsProvider } from './alltalk.js';
|
import { AllTalkTtsProvider } from './alltalk.js';
|
||||||
@ -83,6 +84,7 @@ const ttsProviders = {
|
|||||||
ElevenLabs: ElevenLabsTtsProvider,
|
ElevenLabs: ElevenLabsTtsProvider,
|
||||||
Silero: SileroTtsProvider,
|
Silero: SileroTtsProvider,
|
||||||
XTTSv2: XTTSTtsProvider,
|
XTTSv2: XTTSTtsProvider,
|
||||||
|
VITS: VITSTtsProvider,
|
||||||
GSVI: GSVITtsProvider,
|
GSVI: GSVITtsProvider,
|
||||||
SBVits2: SBVits2TtsProvider,
|
SBVits2: SBVits2TtsProvider,
|
||||||
System: SystemTtsProvider,
|
System: SystemTtsProvider,
|
||||||
|
404
public/scripts/extensions/tts/vits.js
Normal file
404
public/scripts/extensions/tts/vits.js
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
import { getPreviewString, saveTtsProviderSettings } from './index.js';
|
||||||
|
|
||||||
|
export { VITSTtsProvider };
|
||||||
|
|
||||||
|
class VITSTtsProvider {
|
||||||
|
//########//
|
||||||
|
// Config //
|
||||||
|
//########//
|
||||||
|
|
||||||
|
settings;
|
||||||
|
ready = false;
|
||||||
|
voices = [];
|
||||||
|
separator = '. ';
|
||||||
|
audioElement = document.createElement('audio');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform any text processing before passing to TTS engine.
|
||||||
|
* @param {string} text Input text
|
||||||
|
* @returns {string} Processed text
|
||||||
|
*/
|
||||||
|
processText(text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioFormats = ['wav', 'ogg', 'silk', 'mp3', 'flac'];
|
||||||
|
|
||||||
|
languageLabels = {
|
||||||
|
'Auto': 'auto',
|
||||||
|
'Chinese': 'zh',
|
||||||
|
'English': 'en',
|
||||||
|
'Japanese': 'ja',
|
||||||
|
'Korean': 'ko',
|
||||||
|
};
|
||||||
|
|
||||||
|
langKey2LangCode = {
|
||||||
|
'zh': 'zh-CN',
|
||||||
|
'en': 'en-US',
|
||||||
|
'ja': 'ja-JP',
|
||||||
|
'ko': 'ko-KR',
|
||||||
|
};
|
||||||
|
|
||||||
|
modelTypes = {
|
||||||
|
VITS: 'VITS',
|
||||||
|
W2V2_VITS: 'W2V2-VITS',
|
||||||
|
BERT_VITS2: 'BERT-VITS2',
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultSettings = {
|
||||||
|
provider_endpoint: 'http://localhost:23456',
|
||||||
|
format: 'wav',
|
||||||
|
lang: 'auto',
|
||||||
|
length: 1.0,
|
||||||
|
noise: 0.33,
|
||||||
|
noisew: 0.4,
|
||||||
|
segment_size: 50,
|
||||||
|
streaming: false,
|
||||||
|
dim_emotion: 0,
|
||||||
|
sdp_ratio: 0.2,
|
||||||
|
emotion: 0,
|
||||||
|
text_prompt: '',
|
||||||
|
style_text: '',
|
||||||
|
style_weight: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
get settingsHtml() {
|
||||||
|
let html = `
|
||||||
|
<label for="vits_lang">Text Language</label>
|
||||||
|
<select id="vits_lang">`;
|
||||||
|
|
||||||
|
for (let language in this.languageLabels) {
|
||||||
|
if (this.languageLabels[language] == this.settings?.lang) {
|
||||||
|
html += `<option value="${this.languageLabels[language]}" selected="selected">${language}</option>`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
html += `<option value="${this.languageLabels[language]}">${language}</option>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `
|
||||||
|
</select>
|
||||||
|
<label>VITS / W2V2-VITS / Bert-VITS2 Settings:</label><br/>
|
||||||
|
<label for="vits_endpoint">Provider Endpoint:</label>
|
||||||
|
<input id="vits_endpoint" type="text" class="text_pole" maxlength="250" value="${this.defaultSettings.provider_endpoint}"/>
|
||||||
|
<span>Use <a target="_blank" href="https://github.com/Artrajz/vits-simple-api">vits-simple-api</a>.</span><br/>
|
||||||
|
|
||||||
|
<label for="vits_format">Audio format:</label>
|
||||||
|
<select id="vits_format">`;
|
||||||
|
|
||||||
|
for (let format of this.audioFormats) {
|
||||||
|
if (format == this.settings?.format) {
|
||||||
|
html += `<option value="${format}" selected="selected">${format}</option>`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
html += `<option value="${format}">${format}</option>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `
|
||||||
|
</select>
|
||||||
|
<label for="vits_length">Audio length: <span id="vits_length_output">${this.defaultSettings.length}</span></label>
|
||||||
|
<input id="vits_length" type="range" value="${this.defaultSettings.length}" min="0.0" max="5" step="0.01" />
|
||||||
|
|
||||||
|
<label for="vits_noise">Noise: <span id="vits_noise_output">${this.defaultSettings.noise}</span></label>
|
||||||
|
<input id="vits_noise" type="range" value="${this.defaultSettings.noise}" min="0.1" max="2" step="0.01" />
|
||||||
|
|
||||||
|
<label for="vits_noisew">SDP noise: <span id="vits_noisew_output">${this.defaultSettings.noisew}</span></label>
|
||||||
|
<input id="vits_noisew" type="range" value="${this.defaultSettings.noisew}" min="0.1" max="2" step="0.01" />
|
||||||
|
|
||||||
|
<label for="vits_segment_size">Segment Size: <span id="vits_segment_size_output">${this.defaultSettings.segment_size}</span></label>
|
||||||
|
<input id="vits_segment_size" type="range" value="${this.defaultSettings.segment_size}" min="0" max="1000" step="1" />
|
||||||
|
|
||||||
|
<label for="vits_streaming" class="checkbox_label">
|
||||||
|
<input id="vits_streaming" type="checkbox" />
|
||||||
|
<span>Streaming</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>W2V2-VITS Settings:</label><br/>
|
||||||
|
<label for="vits_dim_emotion">Dimensional emotion:</label>
|
||||||
|
<input id="vits_dim_emotion" type="number" class="text_pole" min="0" max="5457" step="1" value="${this.defaultSettings.dim_emotion}"/>
|
||||||
|
|
||||||
|
<label>BERT-VITS2 Settings:</label><br/>
|
||||||
|
<label for="vits_sdp_ratio">sdp_ratio: <span id="vits_sdp_ratio_output">${this.defaultSettings.sdp_ratio}</span></label>
|
||||||
|
<input id="vits_sdp_ratio" type="range" value="${this.defaultSettings.sdp_ratio}" min="0.0" max="1" step="0.01" />
|
||||||
|
|
||||||
|
<label for="vits_emotion">emotion: <span id="vits_emotion_output">${this.defaultSettings.emotion}</span></label>
|
||||||
|
<input id="vits_emotion" type="range" value="${this.defaultSettings.emotion}" min="0" max="9" step="1" />
|
||||||
|
|
||||||
|
<label for="vits_text_prompt">Text Prompt:</label>
|
||||||
|
<input id="vits_text_prompt" type="text" class="text_pole" maxlength="512" value="${this.defaultSettings.text_prompt}"/>
|
||||||
|
|
||||||
|
<label for="vits_style_text">Style text:</label>
|
||||||
|
<input id="vits_style_text" type="text" class="text_pole" maxlength="512" value="${this.defaultSettings.style_text}"/>
|
||||||
|
|
||||||
|
<label for="vits_style_weight">Style weight <span id="vits_style_weight_output">${this.defaultSettings.style_weight}</span></label>
|
||||||
|
<input id="vits_style_weight" type="range" value="${this.defaultSettings.style_weight}" min="0" max="1" step="0.01" />
|
||||||
|
`;
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingsChange() {
|
||||||
|
// Used when provider settings are updated from UI
|
||||||
|
this.settings.provider_endpoint = $('#vits_endpoint').val();
|
||||||
|
this.settings.lang = $('#vits_lang').val();
|
||||||
|
this.settings.format = $('#vits_format').val();
|
||||||
|
this.settings.dim_emotion = $('#vits_dim_emotion').val();
|
||||||
|
this.settings.text_prompt = $('#vits_text_prompt').val();
|
||||||
|
this.settings.style_text = $('#vits_style_text').val();
|
||||||
|
|
||||||
|
// Update the default TTS settings based on input fields
|
||||||
|
this.settings.length = $('#vits_length').val();
|
||||||
|
this.settings.noise = $('#vits_noise').val();
|
||||||
|
this.settings.noisew = $('#vits_noisew').val();
|
||||||
|
this.settings.segment_size = $('#vits_segment_size').val();
|
||||||
|
this.settings.streaming = $('#vits_streaming').is(':checked');
|
||||||
|
this.settings.sdp_ratio = $('#vits_sdp_ratio').val();
|
||||||
|
this.settings.emotion = $('#vits_emotion').val();
|
||||||
|
this.settings.style_weight = $('#vits_style_weight').val();
|
||||||
|
|
||||||
|
// Update the UI to reflect changes
|
||||||
|
$('#vits_length_output').text(this.settings.length);
|
||||||
|
$('#vits_noise_output').text(this.settings.noise);
|
||||||
|
$('#vits_noisew_output').text(this.settings.noisew);
|
||||||
|
$('#vits_segment_size_output').text(this.settings.segment_size);
|
||||||
|
$('#vits_sdp_ratio_output').text(this.settings.sdp_ratio);
|
||||||
|
$('#vits_emotion_output').text(this.settings.emotion);
|
||||||
|
$('#vits_style_weight_output').text(this.settings.style_weight);
|
||||||
|
|
||||||
|
saveTtsProviderSettings();
|
||||||
|
this.changeTTSSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadSettings(settings) {
|
||||||
|
// Pupulate Provider UI given input settings
|
||||||
|
if (Object.keys(settings).length == 0) {
|
||||||
|
console.info('Using default TTS Provider settings');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only accept keys defined in defaultSettings
|
||||||
|
this.settings = this.defaultSettings;
|
||||||
|
|
||||||
|
for (const key in settings) {
|
||||||
|
if (key in this.settings) {
|
||||||
|
this.settings[key] = settings[key];
|
||||||
|
} else {
|
||||||
|
console.debug(`Ignoring non-user-configurable setting: ${key}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set initial values from the settings
|
||||||
|
$('#vits_endpoint').val(this.settings.provider_endpoint);
|
||||||
|
$('#vits_lang').val(this.settings.lang);
|
||||||
|
$('#vits_format').val(this.settings.format);
|
||||||
|
$('#vits_length').val(this.settings.length);
|
||||||
|
$('#vits_noise').val(this.settings.noise);
|
||||||
|
$('#vits_noisew').val(this.settings.noisew);
|
||||||
|
$('#vits_segment_size').val(this.settings.segment_size);
|
||||||
|
$('#vits_streaming').prop('checked', this.settings.streaming);
|
||||||
|
$('#vits_dim_emotion').val(this.settings.dim_emotion);
|
||||||
|
$('#vits_sdp_ratio').val(this.settings.sdp_ratio);
|
||||||
|
$('#vits_emotion').val(this.settings.emotion);
|
||||||
|
$('#vits_text_prompt').val(this.settings.text_prompt);
|
||||||
|
$('#vits_style_text').val(this.settings.style_text);
|
||||||
|
$('#vits_style_weight').val(this.settings.style_weight);
|
||||||
|
|
||||||
|
// Update the UI to reflect changes
|
||||||
|
$('#vits_length_output').text(this.settings.length);
|
||||||
|
$('#vits_noise_output').text(this.settings.noise);
|
||||||
|
$('#vits_noisew_output').text(this.settings.noisew);
|
||||||
|
$('#vits_segment_size_output').text(this.settings.segment_size);
|
||||||
|
$('#vits_sdp_ratio_output').text(this.settings.sdp_ratio);
|
||||||
|
$('#vits_emotion_output').text(this.settings.emotion);
|
||||||
|
$('#vits_style_weight_output').text(this.settings.style_weight);
|
||||||
|
|
||||||
|
// Register input/change event listeners to update settings on user interaction
|
||||||
|
$('#vits_endpoint').on('input', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_lang').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_format').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_length').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_noise').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_noisew').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_segment_size').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_streaming').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_dim_emotion').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_sdp_ratio').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_emotion').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_text_prompt').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_style_text').on('change', () => { this.onSettingsChange(); });
|
||||||
|
$('#vits_style_weight').on('change', () => { this.onSettingsChange(); });
|
||||||
|
|
||||||
|
await this.checkReady();
|
||||||
|
|
||||||
|
console.info('VITS: Settings loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a simple readiness check by trying to fetch voiceIds
|
||||||
|
async checkReady() {
|
||||||
|
await Promise.allSettled([this.fetchTtsVoiceObjects(), this.changeTTSSettings()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async onRefreshClick() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#################//
|
||||||
|
// TTS Interfaces //
|
||||||
|
//#################//
|
||||||
|
|
||||||
|
async getVoice(voiceName) {
|
||||||
|
if (this.voices.length == 0) {
|
||||||
|
this.voices = await this.fetchTtsVoiceObjects();
|
||||||
|
}
|
||||||
|
const match = this.voices.filter(
|
||||||
|
v => v.name == voiceName,
|
||||||
|
)[0];
|
||||||
|
if (!match) {
|
||||||
|
throw `TTS Voice name ${voiceName} not found`;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getVoiceById(voiceId) {
|
||||||
|
if (this.voices.length == 0) {
|
||||||
|
this.voices = await this.fetchTtsVoiceObjects();
|
||||||
|
}
|
||||||
|
const match = this.voices.filter(
|
||||||
|
v => v.voice_id == voiceId,
|
||||||
|
)[0];
|
||||||
|
if (!match) {
|
||||||
|
throw `TTS Voice id ${voiceId} not found`;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateTts(text, voiceId) {
|
||||||
|
const response = await this.fetchTtsGeneration(text, voiceId);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//###########//
|
||||||
|
// API CALLS //
|
||||||
|
//###########//
|
||||||
|
async fetchTtsVoiceObjects() {
|
||||||
|
const response = await fetch(`${this.settings.provider_endpoint}/voice/speakers`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${await response.json()}`);
|
||||||
|
}
|
||||||
|
const jsonData = await response.json();
|
||||||
|
const voices = [];
|
||||||
|
|
||||||
|
const addVoices = (modelType) => {
|
||||||
|
jsonData[modelType].forEach(voice => {
|
||||||
|
voices.push({
|
||||||
|
name: `[${modelType}] ${voice.name} (${voice.lang})`,
|
||||||
|
voice_id: `${modelType}&${voice.id}`,
|
||||||
|
preview_url: false,
|
||||||
|
lang: voice.lang,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
for (const key in this.modelTypes) {
|
||||||
|
addVoices(this.modelTypes[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.voices = voices; // Assign to the class property
|
||||||
|
return voices; // Also return this list
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each time a parameter is changed, we change the configuration
|
||||||
|
async changeTTSSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch TTS generation from the API.
|
||||||
|
* @param {string} inputText Text to generate TTS for
|
||||||
|
* @param {string} voiceId Voice ID to use (model_type&speaker_id))
|
||||||
|
* @returns {Promise<Response|string>} Fetch response
|
||||||
|
*/
|
||||||
|
async fetchTtsGeneration(inputText, voiceId, lang = null, forceNoStreaming = false) {
|
||||||
|
console.info(`Generating new TTS for voice_id ${voiceId}`);
|
||||||
|
|
||||||
|
const streaming = !forceNoStreaming && this.settings.streaming;
|
||||||
|
const [model_type, speaker_id] = voiceId.split('&');
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('text', inputText);
|
||||||
|
params.append('id', speaker_id);
|
||||||
|
if (streaming) {
|
||||||
|
params.append('streaming', streaming);
|
||||||
|
// Streaming response only supports MP3
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params.append('format', this.settings.format);
|
||||||
|
}
|
||||||
|
params.append('lang', lang ?? this.settings.lang);
|
||||||
|
params.append('length', this.settings.length);
|
||||||
|
params.append('noise', this.settings.noise);
|
||||||
|
params.append('noisew', this.settings.noisew);
|
||||||
|
params.append('segment_size', this.settings.segment_size);
|
||||||
|
|
||||||
|
if (model_type == this.modelTypes.W2V2_VITS) {
|
||||||
|
params.append('emotion', this.settings.dim_emotion);
|
||||||
|
}
|
||||||
|
else if (model_type == this.modelTypes.BERT_VITS2) {
|
||||||
|
params.append('sdp_ratio', this.settings.sdp_ratio);
|
||||||
|
params.append('emotion', this.settings.emotion);
|
||||||
|
if (this.settings.text_prompt) {
|
||||||
|
params.append('text_prompt', this.settings.text_prompt);
|
||||||
|
}
|
||||||
|
if (this.settings.style_text) {
|
||||||
|
params.append('style_text', this.settings.style_text);
|
||||||
|
params.append('style_weight', this.settings.style_weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${this.settings.provider_endpoint}/voice/${model_type.toLowerCase()}`;
|
||||||
|
|
||||||
|
if (streaming) {
|
||||||
|
return url + `?${params.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: params,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!response.ok) {
|
||||||
|
toastr.error(response.statusText, 'TTS Generation Failed');
|
||||||
|
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preview TTS for a given voice ID.
|
||||||
|
* @param {string} id Voice ID
|
||||||
|
*/
|
||||||
|
async previewTtsVoice(id) {
|
||||||
|
this.audioElement.pause();
|
||||||
|
this.audioElement.currentTime = 0;
|
||||||
|
const voice = await this.getVoiceById(id);
|
||||||
|
const lang = voice.lang.includes(this.settings.lang) ? this.settings.lang : voice.lang[0];
|
||||||
|
|
||||||
|
let lang_code = this.langKey2LangCode[lang];
|
||||||
|
const text = getPreviewString(lang_code);
|
||||||
|
const response = await this.fetchTtsGeneration(text, id, lang, true);
|
||||||
|
if (typeof response != 'string') {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
|
||||||
|
}
|
||||||
|
const audio = await response.blob();
|
||||||
|
const url = URL.createObjectURL(audio);
|
||||||
|
this.audioElement.src = url;
|
||||||
|
this.audioElement.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface not used
|
||||||
|
async fetchTtsFromHistory(history_item_id) {
|
||||||
|
return Promise.resolve(history_item_id);
|
||||||
|
}
|
||||||
|
}
|
@ -38,13 +38,13 @@ import {
|
|||||||
system_message_types,
|
system_message_types,
|
||||||
this_chid,
|
this_chid,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||||
import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
|
import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
|
||||||
import { getMessageTimeStamp } from './RossAscends-mods.js';
|
import { getMessageTimeStamp } from './RossAscends-mods.js';
|
||||||
import { hideChatMessageRange } from './chats.js';
|
import { hideChatMessageRange } from './chats.js';
|
||||||
import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js';
|
import { getContext, saveMetadataDebounced } from './extensions.js';
|
||||||
import { getRegexedString, regex_placement } from './extensions/regex/engine.js';
|
import { getRegexedString, regex_placement } from './extensions/regex/engine.js';
|
||||||
import { findGroupMemberId, getGroupMembers, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
|
import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
|
||||||
import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js';
|
import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js';
|
||||||
import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockState, togglePersonaLock, user_avatar } from './personas.js';
|
import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockState, togglePersonaLock, user_avatar } from './personas.js';
|
||||||
import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
|
import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
|
||||||
@ -53,7 +53,6 @@ import { decodeTextTokens, getFriendlyTokenizerName, getTextTokens, getTokenCoun
|
|||||||
import { debounce, delay, isFalseBoolean, isTrueBoolean, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';
|
import { debounce, delay, isFalseBoolean, isTrueBoolean, stringToRange, trimToEndSentence, trimToStartSentence, waitUntilCondition } from './utils.js';
|
||||||
import { registerVariableCommands, resolveVariable } from './variables.js';
|
import { registerVariableCommands, resolveVariable } from './variables.js';
|
||||||
import { background_settings } from './backgrounds.js';
|
import { background_settings } from './backgrounds.js';
|
||||||
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
|
||||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||||
import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js';
|
import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js';
|
||||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
@ -75,6 +74,7 @@ export const parser = new SlashCommandParser();
|
|||||||
const registerSlashCommand = SlashCommandParser.addCommand.bind(SlashCommandParser);
|
const registerSlashCommand = SlashCommandParser.addCommand.bind(SlashCommandParser);
|
||||||
const getSlashCommandsHelp = parser.getHelpString.bind(parser);
|
const getSlashCommandsHelp = parser.getHelpString.bind(parser);
|
||||||
|
|
||||||
|
export function initDefaultSlashCommands() {
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: '?',
|
name: '?',
|
||||||
callback: helpCommandCallback,
|
callback: helpCommandCallback,
|
||||||
@ -177,7 +177,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
),
|
),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'at',
|
name: 'at',
|
||||||
description: 'position to insert the message',
|
description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
@ -220,7 +220,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
),
|
),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'at',
|
name: 'at',
|
||||||
description: 'position to insert the message',
|
description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
@ -274,7 +274,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
),
|
),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'at',
|
name: 'at',
|
||||||
description: 'position to insert the message',
|
description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
@ -459,7 +459,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
),
|
),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'at',
|
name: 'at',
|
||||||
description: 'position to insert the message',
|
description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
@ -745,6 +745,32 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
new SlashCommandEnumValue('success', 'success', enumTypes.enum, '✅'),
|
new SlashCommandEnumValue('success', 'success', enumTypes.enum, '✅'),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'timeout',
|
||||||
|
description: 'time in milliseconds to display the toast message. Set this and \'extendedTimeout\' to 0 to show indefinitely until dismissed.',
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
defaultValue: `${toastr.options.timeOut}`,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'extendedTimeout',
|
||||||
|
description: 'time in milliseconds to display the toast message. Set this and \'timeout\' to 0 to show indefinitely until dismissed.',
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
defaultValue: `${toastr.options.extendedTimeOut}`,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'preventDuplicates',
|
||||||
|
description: 'prevent duplicate toasts with the same message from being displayed.',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
defaultValue: 'false',
|
||||||
|
enumList: commonEnumProviders.boolean('trueFalse')(),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'awaitDismissal',
|
||||||
|
description: 'wait for the toast to be dismissed before continuing.',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
defaultValue: 'false',
|
||||||
|
enumList: commonEnumProviders.boolean('trueFalse')(),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@ -1387,6 +1413,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
registerVariableCommands();
|
registerVariableCommands();
|
||||||
|
}
|
||||||
|
|
||||||
const NARRATOR_NAME_KEY = 'narrator_name';
|
const NARRATOR_NAME_KEY = 'narrator_name';
|
||||||
const NARRATOR_NAME_DEFAULT = 'System';
|
const NARRATOR_NAME_DEFAULT = 'System';
|
||||||
@ -1938,31 +1965,66 @@ async function generateCallback(args, value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {{title?: string, severity?: string, timeout?: string, extendedTimeout?: string, preventDuplicates?: string, awaitDismissal?: string}} args - named arguments from the slash command
|
||||||
|
* @param {string} value - The string to echo (unnamed argument from the slash command)
|
||||||
|
* @returns {Promise<string>} The text that was echoed
|
||||||
|
*/
|
||||||
async function echoCallback(args, value) {
|
async function echoCallback(args, value) {
|
||||||
// Note: We don't need to sanitize input, as toastr is set up by default to escape HTML via toastr options
|
// Note: We don't need to sanitize input, as toastr is set up by default to escape HTML via toastr options
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
console.warn('WARN: No argument provided for /echo command');
|
console.warn('WARN: No argument provided for /echo command');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
const title = args?.title !== undefined && typeof args?.title === 'string' ? args.title : undefined;
|
|
||||||
const severity = args?.severity !== undefined && typeof args?.severity === 'string' ? args.severity : 'info';
|
if (args.severity && !['error', 'warning', 'success', 'info'].includes(args.severity)) {
|
||||||
|
toastr.warning(`Invalid severity provided for /echo command: ${args.severity}`);
|
||||||
|
args.severity = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = args.title ? args.title : undefined;
|
||||||
|
const severity = args.severity ? args.severity : 'info';
|
||||||
|
|
||||||
|
/** @type {ToastrOptions} */
|
||||||
|
const options = {};
|
||||||
|
if (args.timeout && !isNaN(parseInt(args.timeout))) options.timeOut = parseInt(args.timeout);
|
||||||
|
if (args.extendedTimeout && !isNaN(parseInt(args.extendedTimeout))) options.extendedTimeOut = parseInt(args.extendedTimeout);
|
||||||
|
if (isTrueBoolean(args.preventDuplicates)) options.preventDuplicates = true;
|
||||||
|
|
||||||
|
// Prepare possible await handling
|
||||||
|
let awaitDismissal = isTrueBoolean(args.awaitDismissal);
|
||||||
|
let resolveToastDismissal;
|
||||||
|
|
||||||
|
if (awaitDismissal) {
|
||||||
|
options.onHidden = () => resolveToastDismissal(value);
|
||||||
|
}
|
||||||
|
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case 'error':
|
case 'error':
|
||||||
toastr.error(value, title);
|
toastr.error(value, title, options);
|
||||||
break;
|
break;
|
||||||
case 'warning':
|
case 'warning':
|
||||||
toastr.warning(value, title);
|
toastr.warning(value, title, options);
|
||||||
break;
|
break;
|
||||||
case 'success':
|
case 'success':
|
||||||
toastr.success(value, title);
|
toastr.success(value, title, options);
|
||||||
break;
|
break;
|
||||||
case 'info':
|
case 'info':
|
||||||
default:
|
default:
|
||||||
toastr.info(value, title);
|
toastr.info(value, title, options);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (awaitDismissal) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
resolveToastDismissal = resolve;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function addSwipeCallback(_, arg) {
|
async function addSwipeCallback(_, arg) {
|
||||||
const lastMessage = chat[chat.length - 1];
|
const lastMessage = chat[chat.length - 1];
|
||||||
@ -2428,7 +2490,14 @@ async function sendUserMessageCallback(args, text) {
|
|||||||
text = text.trim();
|
text = text.trim();
|
||||||
const compact = isTrueBoolean(args?.compact);
|
const compact = isTrueBoolean(args?.compact);
|
||||||
const bias = extractMessageBias(text);
|
const bias = extractMessageBias(text);
|
||||||
const insertAt = Number(args?.at);
|
|
||||||
|
let insertAt = Number(args?.at);
|
||||||
|
|
||||||
|
// Convert possible depth parameter to index
|
||||||
|
if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
|
||||||
|
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
|
||||||
|
insertAt = chat.length + insertAt;
|
||||||
|
}
|
||||||
|
|
||||||
if ('name' in args) {
|
if ('name' in args) {
|
||||||
const name = args.name || '';
|
const name = args.name || '';
|
||||||
@ -2737,7 +2806,13 @@ export async function sendMessageAs(args, text) {
|
|||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const insertAt = Number(args.at);
|
let insertAt = Number(args.at);
|
||||||
|
|
||||||
|
// Convert possible depth parameter to index
|
||||||
|
if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
|
||||||
|
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
|
||||||
|
insertAt = chat.length + insertAt;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
||||||
chat.splice(insertAt, 0, message);
|
chat.splice(insertAt, 0, message);
|
||||||
@ -2784,7 +2859,13 @@ export async function sendNarratorMessage(args, text) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertAt = Number(args.at);
|
let insertAt = Number(args.at);
|
||||||
|
|
||||||
|
// Convert possible depth parameter to index
|
||||||
|
if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
|
||||||
|
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
|
||||||
|
insertAt = chat.length + insertAt;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
||||||
chat.splice(insertAt, 0, message);
|
chat.splice(insertAt, 0, message);
|
||||||
@ -2866,7 +2947,13 @@ async function sendCommentMessage(args, text) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertAt = Number(args.at);
|
let insertAt = Number(args.at);
|
||||||
|
|
||||||
|
// Convert possible depth parameter to index
|
||||||
|
if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) {
|
||||||
|
// Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7)
|
||||||
|
insertAt = chat.length + insertAt;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
if (!isNaN(insertAt) && insertAt >= 0 && insertAt <= chat.length) {
|
||||||
chat.splice(insertAt, 0, message);
|
chat.splice(insertAt, 0, message);
|
||||||
|
@ -59,7 +59,7 @@ export class SlashCommandArgument {
|
|||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
||||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} enumProvider function that returns auto complete options
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} enumProvider function that returns auto complete options
|
||||||
*/
|
*/
|
||||||
constructor(description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], enumProvider = null, forceEnum = true) {
|
constructor(description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], enumProvider = null, forceEnum = false) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.typeList = types ? Array.isArray(types) ? types : [types] : [];
|
this.typeList = types ? Array.isArray(types) ? types : [types] : [];
|
||||||
this.isRequired = isRequired ?? false;
|
this.isRequired = isRequired ?? false;
|
||||||
@ -90,7 +90,7 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
* @param {string|SlashCommandClosure} [props.defaultValue=null] default value if no value is provided
|
* @param {string|SlashCommandClosure} [props.defaultValue=null] default value if no value is provided
|
||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList=[]] list of accepted values
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList=[]] list of accepted values
|
||||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider=null] function that returns auto complete options
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider=null] function that returns auto complete options
|
||||||
* @param {boolean} [props.forceEnum=true] default: true - whether the input must match one of the enum values
|
* @param {boolean} [props.forceEnum=false] default: false - whether the input must match one of the enum values
|
||||||
*/
|
*/
|
||||||
static fromProps(props) {
|
static fromProps(props) {
|
||||||
return new SlashCommandNamedArgument(
|
return new SlashCommandNamedArgument(
|
||||||
@ -103,7 +103,7 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
props.enumList ?? [],
|
props.enumList ?? [],
|
||||||
props.aliasList ?? [],
|
props.aliasList ?? [],
|
||||||
props.enumProvider ?? null,
|
props.enumProvider ?? null,
|
||||||
props.forceEnum ?? true,
|
props.forceEnum ?? false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,9 +120,9 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [enums=[]]
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [enums=[]]
|
||||||
* @param {string[]} [aliases=[]]
|
* @param {string[]} [aliases=[]]
|
||||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [enumProvider=null] function that returns auto complete options
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [enumProvider=null] function that returns auto complete options
|
||||||
* @param {boolean} [forceEnum=true]
|
* @param {boolean} [forceEnum=false]
|
||||||
*/
|
*/
|
||||||
constructor(name, description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], aliases = [], enumProvider = null, forceEnum = true) {
|
constructor(name, description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], aliases = [], enumProvider = null, forceEnum = false) {
|
||||||
super(description, types, isRequired, acceptsMultiple, defaultValue, enums, enumProvider, forceEnum);
|
super(description, types, isRequired, acceptsMultiple, defaultValue, enums, enumProvider, forceEnum);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.aliasList = aliases ? Array.isArray(aliases) ? aliases : [aliases] : [];
|
this.aliasList = aliases ? Array.isArray(aliases) ? aliases : [aliases] : [];
|
||||||
|
@ -43,7 +43,11 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||||||
key = readSecret(request.user.directories, SECRET_KEYS.KOBOLDCPP);
|
key = readSecret(request.user.directories, SECRET_KEYS.KOBOLDCPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key && !request.body.reverse_proxy && ['custom', 'ooba', 'koboldcpp'].includes(request.body.api) === false) {
|
if (request.body.api === 'vllm') {
|
||||||
|
key = readSecret(request.user.directories, SECRET_KEYS.VLLM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key && !request.body.reverse_proxy && ['custom', 'ooba', 'koboldcpp', 'vllm'].includes(request.body.api) === false) {
|
||||||
console.log('No key found for API', request.body.api);
|
console.log('No key found for API', request.body.api);
|
||||||
return response.sendStatus(400);
|
return response.sendStatus(400);
|
||||||
}
|
}
|
||||||
@ -110,7 +114,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.body.api === 'koboldcpp') {
|
if (request.body.api === 'koboldcpp' || request.body.api === 'vllm') {
|
||||||
apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`;
|
apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user